AWS CloudFormation - 从 Init 调用 CLI 无法获取凭证

AWS CloudFormation - 从 Init 调用 CLI 无法获取凭证

我正在使用 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/

希望有帮助:)

相关内容