Я использую шаблон CloudFormation для загрузки пользовательского окна AMI, которому необходимо получить некоторый код из корзины S3 и выполнить его после загрузки.
После того, как вы быстро сможете сделать это вручную с помощью интерфейса командной строки AWS (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) работают нормально. Последний (код запроса) каждый раз не работает.
Итак, на данный момент я предполагаю, что ошибаюсь. Возможно, мне нужно настроить конкретный IAM для стека CF, возможно, мне стоит использовать setx ... /M
, может быть, миллион других вариантов, но поскольку этот метод проб и ошибок длился весь мой рабочий день, а затем и некоторые, я подумал, что спросить не повредит.
Каждый из ваших команды запускается в отдельной PowerShell, поэтому setx AWS_ACCESS_KEY_ID
устанавливает переменную в один экземпляр оболочки и завершает работу. затем setx AWS_SECRET_ACCESS_KEY
устанавливает другую переменную в новый оболочка и выходы. Тогда ты бежишь aws s3 sync
в еще один оболочка, где ни одна из предыдущих переменных не существует, и она не работает, потому что переменные учетных данных не существуют в который оболочка.
Вместо вызова его из метаданных вы можете сделать что-то вроде:
"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>"
] ] }
}
В этом случае все будет запущено в одном экземпляре оболочки, и ключи все равно будут установлены, когда вы вызовете aws s3 sync
.
Однако я должен сказать, что передача доступа и секретных ключей в шаблон 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/
Надеюсь, это поможет :)