我正在构建一个堆栈,该堆栈需要访问专用S3存储桶才能下载我的应用程序的最新版本。我使用的是IAM角色,这是一个相对较新的AWS功能,允许为EC2实例分配特定的角色,然后将其与IAM策略相结合。不幸的是,这些角色带有在实例化时生成的临时API证书。这并不严重,但它迫使我做一些事情,比如这个云初始化脚本(简化为相关的部分):
#!/bin/sh
# Grab our credentials from the meta-data and parse the response
CREDENTIALS=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/s3access)
S3_ACCESS_KEY=$(echo $CREDENTIALS | ruby -e "require 'rubygems'; require 'json'; puts JSON[STDIN.read]['AccessKeyId'];")
S3_SECRET_KEY=$(echo $CREDENTIALS | ruby -e "require 'rubygems'; require 'json'; puts JSON[STDIN.read]['SecretAccessKey'];")
S3_TOKEN=$(echo $CREDENTIALS | ruby -e "require 'rubygems'; require 'json'; puts JSON[STDIN.read]['Token'];")
# Create an executable script to pull the file
cat << EOF > /tmp/pullS3.rb
require 'rubygems'
require 'aws-sdk'
AWS.config(
:access_key_id => "$S3_ACCESS_KEY",
:secret_access_key => "$S3_SECRET_KEY",
:session_token => "$S3_TOKEN")
s3 = AWS::S3.new()
myfile = s3.buckets['mybucket'].objects["path/to/my/file"]
File.open("/path/to/save/myfile", "w") do |f|
f.write(myfile.read)
end
EOF
# Downloading the file
ruby /tmp/pullS3.rb
首先也是最重要的:这很有效,而且效果很好。尽管如此,我还是希望使用CloudFormation现有的对源代码访问的支持。具体来说,cfn-init
支持使用身份验证资源来获取受保护的数据,包括S3存储桶。是否可以从cfn-init
中获取这些密钥,或者将IAM角色绑定到身份验证资源?
我想一个替代方案是将我的源代码放在其他经过身份验证的服务后面,但目前这不是一个可行的选择。
另一个有前景的线索是AWS::IAM::AccessKey资源,但文档不建议它可以与角色一起使用。我无论如何都要试试。
我不确定何时添加了支持,但同时您可以使用IAM角色来验证AWS::CloudFormation::Init中files
和sources
部分的S3下载。
只需使用CCD_ 5而不是CCD_;secretKey
(详见AWS::CloudFormation::Authentication),例如:
"Metadata": {
"AWS::CloudFormation::Init": {
"download": {
"files": {
"/tmp/test.txt": {
"source": "http://myBucket.s3.amazonaws.com/test.txt"
}
}
}
},
"AWS::CloudFormation::Authentication": {
"default" : {
"type": "s3",
"buckets": [ "myBucket" ],
"roleName": { "Ref": "myRole" }
}
}
}
用aws-cfn-bootstrap-1.3-11
测试
我设法做到了。我使用的是来自此交易所的代码:https://forums.aws.amazon.com/message.jspa?messageID=319465
该代码不使用IAM策略,而是使用AWS::S3::BucketPolicy。
云形成代码片段:
"Resources" : {
"CfnUser" : {
"Type" : "AWS::IAM::User",
"Properties" : {
"Path": "/",
"Policies": [{
"PolicyName": "root",
"PolicyDocument": { "Statement":[{
"Effect" : "Allow",
"Action" : [
"cloudformation:DescribeStackResource",
"s3:GetObject"
],
"Resource" :"*"
}]}
}]
}
},
"CfnKeys" : {
"Type" : "AWS::IAM::AccessKey",
"Properties" : {
"UserName" : {"Ref": "CfnUser"}
}
},
"BucketPolicy" : {
"Type" : "AWS::S3::BucketPolicy",
"Properties" : {
"PolicyDocument": {
"Version" : "2008-10-17",
"Id" : "CfAccessPolicy",
"Statement" : [{
"Sid" : "ReadAccess",
"Action" : ["s3:GetObject"],
"Effect" : "Allow",
"Resource" : { "Fn::Join" : ["", ["arn:aws:s3:::<MY_BUCKET>/*"]]},
"Principal" : { "AWS": {"Fn::GetAtt" : ["CfnUser", "Arn"]} }
}]
},
"Bucket" : "<MY_BUCKET>"
}
},
"WebServer": {
"Type": "AWS::EC2::Instance",
"DependsOn" : "BucketPolicy",
"Metadata" : {
"AWS::CloudFormation::Init" : {
"config" : {
"sources" : {
"/etc/<MY_PATH>" : "https://s3.amazonaws.com/<MY_BUCKET>/<MY_FILE>"
}
}
},
"AWS::CloudFormation::Authentication" : {
"S3AccessCreds" : {
"type" : "S3",
"accessKeyId" : { "Ref" : "CfnKeys" },
"secretKey" : {"Fn::GetAtt": ["CfnKeys", "SecretAccessKey"]},
"buckets" : [ "<MY_BUCKET>" ]
}
}
},
"Properties": {
"ImageId" : "<MY_INSTANCE_ID>",
"InstanceType" : { "Ref" : "WebServerInstanceType" },
"KeyName" : {"Ref": "KeyName"},
"SecurityGroups" : [ "<MY_SECURITY_GROUP>" ],
"UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
"#!/bin/bashn",
"# Helper functionn",
"function error_exitn",
"{n",
" cfn-signal -e 1 -r "$1" '", { "Ref" : "WaitHandle" }, "'n",
" exit 1n",
"}n",
"# Install Webserver Packages etc n",
"cfn-init -v --region ", { "Ref" : "AWS::Region" },
" -s ", { "Ref" : "AWS::StackName" }, " -r WebServer ",
" --access-key ", { "Ref" : "CfnKeys" },
" --secret-key ", {"Fn::GetAtt": ["CfnKeys", "SecretAccessKey"]}, " || error_exit 'Failed to run cfn-init'n",
"# All is well so signal successn",
"cfn-signal -e 0 -r "Setup complete" '", { "Ref" : "WaitHandle" }, "'n"
]]}}
}
}
显然,用您的值替换MY_BUCKET、MY_FILE、MY_INSTANCE_ID、MY_SECURITY_GROUP。