我正在使用 CloudFormation 模板来启动自定义视窗AMI,一旦启动就需要从 S3 存储桶中检索一些代码并执行它。
在能够使用 AWS CLI ( s3 sync
) 手动快速完成此操作后,我一直在努力通过 CloudFormation 使其工作超过 8 个小时,但无济于事。实际上,此命令总是失败,并显示:
“NoCredentialsError:无法找到凭证”
最初,我尝试以多种不同的方式设置/.aws/credentials
和/.aws/config
文件,直到我最终意识到正在运行的用户身份cfn-init.exe
及其子进程根本无法访问这些文件,这是行不通的。因此,我选择使用来设置环境变量setx
,但这似乎也不起作用,我仍然收到相同的错误。
我对此感到非常沮丧,因为每个测试都需要更改 CF 模板,上传到 S3,创建堆栈,等待 5-10 分钟才能完成引导到 RDP 并发现它失败了,再次。
这是init > config
我的模板的一部分:
"commands" : {
"0-Tester" : {
"command" : "echo \"I am OK.\" > \"d:\\test.txt\""
},
"1-SetAK" : {
"command" : { "Fn::Join" : ["", [
"setx AWS_ACCESS_KEY_ID ",
{ "Ref": "AutomationUserAK" }
]] }
},
"2-SetSK" : {
"command" : { "Fn::Join" : ["", [
"setx AWS_SECRET_ACCESS_KEY ",
{ "Ref": "AutomationUserSK" }
]] }
},
"3-Pullcode" : {
"command" : "aws s3 sync s3://some-s3-bucket d:/dev/ --debug"
}
}
前 3 个命令 (Tester、SetAK、SetSK) 运行正常。最后一个命令 (Pullcode) 每次都失败。
所以现在我假设我做错了。也许我需要为 CF 堆栈配置一个特定的 IAM,也许我应该使用setx ... /M
,也许还有一百万个其他选项,但由于这种反复试验已经持续了我整个工作日的时间,然后我想问一下也无妨。
答案1
你的每一个命令在单独的 PowerShell 中运行,因此setx AWS_ACCESS_KEY_ID
在中设置变量一shell 实例并退出。然后setx AWS_SECRET_ACCESS_KEY
在新的shell 并退出。然后aws s3 sync
运行完后还有shell 中,前面的变量都不存在,并且失败,因为凭据变量不存在那壳。
除了从元数据调用它之外,您还可以执行以下操作:
"UserData": {
"Fn::Base64": { "Fn::Join": ["", [
"<script>\n",
"cfn-init.exe -v -s [...]\n",
"setx AWS_ACCESS_KEY_ID ", { "Ref": "AutomationUserAK" }, "\n",
"setx AWS_SECRET_ACCESS_KEY ", { "Ref": "AutomationUserSK" }, "\n",
"aws s3 sync s3://some-s3-bucket d:/dev/\n",
"</script>"
] ] }
}
在这种情况下,它将在同一个 shell 实例中运行,并且当您调用时键仍将被设置aws s3 sync
。
改用 IAM 角色
不过,我必须说,将访问权和密钥传递给 CloudFormation 模板是不好 不好实践。相反,CloudFormation 模板应该创建IAM 角色具有访问 S3 存储桶的适当权限并将其分配给 EC2 实例。然后,aws
实例上的工具将透明地访问 S3,而无需提供访问和密钥。您的 CloudFormation 模板应该这样做:
首先创建IAM 角色和S3 访问策略(根据您的需要调整政策):
"InstanceRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Service": [ "ec2.amazonaws.com" ] },
"Action": [ "sts:AssumeRole" ]
}
]
},
"Path": "/",
"Policies": [
{
"PolicyName": "S3_Access",
"PolicyDocument": {
"Statement": [
{
"Effect": "Allow",
"Action": [ "s3:List*", "s3:Get*" ],
"Resource": "*"
}
]
}
}
]
}
},
然后创建一个IAM 实例配置文件指的是上述 IAM 角色……
"InstanceProfile": {
"Type": "AWS::IAM::InstanceProfile",
"Properties": {
"Path": "/",
"Roles": [ { "Ref": "InstanceRole" }
]
}
},
最后创建获取该信息的 EC2 实例IAM 简介分配(反过来IAM 角色使用 S3 访问策略)。
"Instance": {
"Type": "AWS::EC2::Instance",
"Properties": {
"IamInstanceProfile": { "Ref": "InstanceProfile" },
[...],
"UserData": {
"Fn::Base64": { "Fn::Join": ["", [
"<script>\n",
"cfn-init.exe -v -s ", { "Ref" : "AWS::StackId" }, " -r Instance --region ", { "Ref" : "AWS::Region" }, "\n",
"</script>"
] ] }
}
},
"Metadata": {
"AWS::CloudFormation::Init": {
"config": {
"commands" : {
"Pullcode" : {
"command" : "aws s3 sync s3://some-s3-bucket d:/dev/ --debug"
}
}
}
}
}
},
使用时IAM 角色这AWS 凭证是通过命令动态生成并透明获取的aws
。这更安全,也是让 EC2 实例访问 AWS 资源的首选方式。
例如,在此处了解有关 EC2 实例角色的更多信息:https://aws.nz/best-practice/ec2-instance-roles/
希望有帮助:)