如何(安全地)使用 cloudinit 将私有 S3 资产下载到新的 EC2 实例上?
Posted
技术标签:
【中文标题】如何(安全地)使用 cloudinit 将私有 S3 资产下载到新的 EC2 实例上?【英文标题】:How can I (securely) download a private S3 asset onto a new EC2 instance with cloudinit? 【发布时间】:2012-07-07 02:53:51 【问题描述】:我正在使用 CloudFormation 来管理 Tomcat 网络服务器堆栈,但我厌倦了为新的应用程序版本进行原始 AMI 管理。我想朝大厨的方向前进,但现在没有时间。相反,我试图解决网络服务器实例化中的一个简单问题:当新机器启动时,如何下载“当前”WAR?
我的想法是使用私有 S3 存储桶和 cloudinit,但我对如何处理 IAM 凭证感到有些困惑。我可以将它们放入模板的用户数据中,但我不愿意这样做,特别是因为我正在控制该文件的版本。我能想到的唯一选择是在 AMI 本身中使用环境变量。它们必须是纯文本的,但是……嗯,如果你能闯入我的实例,你可以压缩并下载我的整个网络服务器。只要 IAM 用户不被重复用于其他任何事情并且定期轮换,这似乎是解决问题的合理方法。我错过了什么吗?如何使用 cloudinit 安全下载私有 S3 资产?
【问题讨论】:
【参考方案1】:亚马逊最近宣布了一项新功能,您可以将“IAM 角色”赋予您的 EC2 实例。这使得允许特定实例具有读取特定 S3 资源的权限变得相当容易。
这是他们宣布新功能的博客文章:
http://aws.typepad.com/aws/2012/06/iam-roles-for-ec2-instances-simplified-secure-access-to-aws-service-apis-from-ec2.html
这是 EC2 文档中的部分:
http://docs.amazonwebservices.com/AWSEC2/latest/UserGuide/UsingIAM.html#UsingIAMrolesWithAmazonEC2Instances
这是 IAM 文档中的部分:
http://docs.amazonwebservices.com/IAM/latest/UserGuide/WorkingWithRoles.html
IAM 角色通过 HTTP 向实例提供凭证,因此在实例上运行的任何用户或进程都可以看到它们。
【讨论】:
是否有完整的从头到尾的 AWS CLI 示例或教程来展示如何设置和使用 IAM 机制?非常感谢这个参考看起来如此复杂和完整的示例,按命令执行。【参考方案2】:具有 IAM 角色的实例具有自动轮换的临时安全凭证。它们可以通过 http 访问 http://169.254.169.254/latest/meta-data/iam/security-credentials/RoleName
,其中 RoleName 是您所称的角色。因此它们很容易从您的实例中获取,但它们会定期过期。
使用它们有点困难。 CloudFormation 不能直接使用临时凭证。 Amazon Linux AMI 安装了 Python boto,现在它足够智能,可以自动为您查找和使用这些凭证。这是一个单行代码,您可以将其放入脚本中以从 S3 存储桶 b 中获取文件,将 k 键设置为本地文件 f: p>
python -c "import boto;boto.connect_s3().get_bucket('b').get_key('k').get_contents_to_filename('f')"
boto 会为您查找并使用角色的临时凭证,这使得它非常易于使用。
【讨论】:
什么是“key k”?它是带有临时凭据的文件吗? 对于未来的用户,密钥 k 是您想要从 S3 获得的文件名。如果你有文件夹结构,那么关键是,文件夹名/file.sh【参考方案3】:稍微更新一下这个问题的答案:
与 IAM 角色一起,新的 AWS command-line client 使获取这些资产变得轻而易举。它将自动从环境中提取通过 IAM 授予的 AWS 凭证并处理这些凭证的刷新。
以下是在用户数据脚本中从安全 S3 存储桶中获取单个资产的示例:
# Install the AWS command-line tools
pip install awscli
# Fetch the asset
aws s3 cp --region us-east-1 s3://my-private-bucket/a-folder/an-asset.zip /some/destination
就这么简单。您还可以从 S3 复制整个目录内容并上传等。有关更多详细信息和选项,请参阅the reference material。
【讨论】:
是的,新的 cli 工具基于botocore
,这似乎是 boto
v3 的基础。总的来说,如果您了解 AWS API 的结构,botocore 是一个很棒的界面。
优秀、简洁的答案@James van Dyke。但我仍然怀疑这有多安全,我在此处的类似问题中对此进行了说明:***.com/questions/29932355/…【参考方案4】:
要安全地将私有 S3 资产下载到新的 EC2 实例上,您应该使用 IAM Roles for EC2 为您的 EC2 实例授予必要的 S3 权限,然后在您实例的 UserData cloudinit script 中调用 aws s3 cp
以下载资产。
要从 CloudFormation 模板为 EC2 设置 IAM 角色,请使用 AWS::IAM::InstanceProfile
资源,引用 AWS::IAM::Role
资源和 AssumeRolePolicyDocument
委派对 ec2.amazonaws.com
的访问权限,以及设计为 grant least privilege 的策略(在在这种情况下,仅允许 's3:GetObject'
用于正在下载的特定 S3 资产)。
这是一个完整的示例模板,它使用 cloudinit 将 S3 资产下载到新的 EC2 实例上,并将其内容作为 Stack Output 返回:
Description: (securely) download a private S3 asset onto a new EC2 instance with cloudinit
Parameters:
S3Bucket:
Description: S3 bucket name
Type: String
S3Key:
Description: S3 object key
Type: String
Mappings:
# amzn-ami-hvm-2016.09.1.20161221-x86_64-gp2
RegionMap:
us-east-1:
"64": "ami-9be6f38c"
Resources:
EC2Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal: Service: [ ec2.amazonaws.com ]
Action: ["sts:AssumeRole"]
Path: /
Policies:
- PolicyName: EC2Policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: ['s3:GetObject']
Resource: !Sub 'arn:aws:s3:::$S3Bucket/$S3Key'
RootInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: /
Roles: [ !Ref EC2Role ]
WebServer:
Type: AWS::EC2::Instance
Properties:
ImageId: !FindInMap [ RegionMap, !Ref "AWS::Region", 64 ]
InstanceType: m3.medium
IamInstanceProfile: !Ref RootInstanceProfile
UserData:
"Fn::Base64":
!Sub |
#!/bin/bash
DATA=$(aws s3 cp s3://$S3Bucket/$S3Key -)
/opt/aws/bin/cfn-signal \
-e $? \
-d "$DATA" \
'$Handle'
Handle:
Type: AWS::CloudFormation::WaitConditionHandle
Wait:
Type: AWS::CloudFormation::WaitCondition
Properties:
Handle: !Ref Handle
Timeout: 300
Outputs:
Result:
Value: !GetAtt Wait.Data
【讨论】:
以上是关于如何(安全地)使用 cloudinit 将私有 S3 资产下载到新的 EC2 实例上?的主要内容,如果未能解决你的问题,请参考以下文章
如何建立从GAE(具有公共访问权限)到私有GKE集群的安全连接。