AWS Elastic Beanstalk 和 Secret Manager

AWS Elastic Beanstalk and Secret Manager

有谁知道可以在 Elastic Beanstalk 中将秘密值作为环境变量传递吗? 另一种方法显然是在我们的代码库中使用 sdk,但我想先探索环境变量方法

干杯 达米安

遗憾的是,EB 目前不支持机密,这可能会在以后添加。您可以在环境变量中将它们用作 the documentation suggests but they will appear in plain text in the console. Another, and IMO better, approach would be to use ebextensions, and use AWS CLI commands to grab secrets from the secrets manager,这需要进行一些设置(例如,安装 AWS CLI 并将您的机密存储在 SM 中)。您可以在相同的 eb 配置中将它们设置为环境变量。希望这对您有所帮助!

根据@Ali 的 , it is not built-in at this point. However, it is relatively easy to use .ebextensions 和 AWS cli。这是一个根据 MY_ENV 环境变量将秘密提取到文件的示例。然后可以将该值设置为环境变量,但请记住环境变量特定于 shell。您需要将它们传递给您正在启动的任何内容。

  10-extract-htpasswd:
    env:
      MY_ENV: 
        "Fn::GetOptionSetting":
          Namespace: "aws:elasticbeanstalk:application:environment"
          OptionName: MY_ENV
    command: |
      aws secretsmanager get-secret-value --secret-id myproj/$MY_ENV/htpasswd --region=us-east-1 --query=SecretString --output text > /etc/nginx/.htpasswd
      chmod o-rwx /etc/nginx/.htpasswd
      chgrp nginx /etc/nginx/.htpasswd

这还需要为 EB 服务角色授予机密的 IAM 权限。即政策如:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "xxxxxxxxxx",
            "Effect": "Allow",
            "Action": "secretsmanager:GetSecretValue",
            "Resource": "arn:aws:secretsmanager:us-east-1:xxxxxxxxxxxx:secret:myproj*"
        }
    ]
}

此答案仅在您使用代码管道时适用。

I think you can add a secret in the environment variables section now

如果您使用 AWS CodeBuild 使用 pre_build,请在项目的 buildspec.yml 中添加以下命令以从 检索您的环境变量AWS Secrets Manager 使用 sed 做一些 substituting/formatting 并将它们附加到 .ebextensions/options.configaws:elasticbeanstalk:application:environment 命名空间:

phases:
  pre_build:
    commands:
      - secret=$(aws secretsmanager get-secret-value --secret-id foo-123 --region=bar-xyz --query=SecretString --output text)
      - regex=$(cat ./sed_substitute)
      - echo $secret | sed "${regex}" >> .ebextensions/options.config

有点破解,但上面命令中使用的 sed_substitute 用于获得 .ebextensions/options.config 要求的正确 indentation/formatting 是:

s/",/\n /g; s/":/": /g; s/{"/ /g; s/"}//g; s/"//g;

正如上面的答案所提到的,如果你想在 Elastic Beanstalk 中这样做,仍然没有内置的解决方案。然而,解决方案是使用“平台挂钩”。不幸的是,此时它的记录很少。

要存储您的秘密,最好的解决方案是在 AWS-Secret-Manager. In secret manager you can create a new secret by clicking "Store a new secret", then selecting "Other type of secret" and entering your secret key/value (see 中创建一个自定义秘密。在下一步中,您需要提供一个秘密名称(例如“your_secret_name”),您可以将其他所有内容保留为默认设置。

然后,您需要允许Elastic Beanstalk 获取此密钥。您可以通过创建新的 IAM 策略来实现,例如使用以下内容:

{
"Version": "2012-10-17",
"Statement": [
    {
        "Sid": "Getsecretvalue",
        "Effect": "Allow",
        "Action": [
            "secretsmanager:GetResourcePolicy",
            "secretsmanager:GetSecretValue",
            "secretsmanager:DescribeSecret",
            "secretsmanager:ListSecretVersionIds"
        ],
        "Resource": "your-secret-arn"
    }
]}

您需要将 "your-secret-arn" 替换为您可以在 AWS-secret-manager 界面上获取的秘密 ARN。然后,您需要将您创建的策略添加到 EB 角色(它应该是“aws-elasticbeanstalk-ec2-role”或“aws-elasticbeanstalk-service-role”)。

最后你需要在你的应用程序中添加一个钩子文件。从你的应用程序的根位置应该是“.platform/hooks/prebuild/your_hook.sh”。您的文件内容可以是这样的:

#!/bin/sh
export your_secret_key=$(aws secretsmanager get-secret-value --secret-id your-secret-name --region us-east-1 | jq -r '.SecretString' | jq -r '. your_secret_key')

touch .env
{
  printf "SECRET_KEY=%s\n" "$your_secret_key"
  # printf whatever other variable you want to pass
} > .env

显然你需要用你自己的值替换“your_secret_name”和另一个变量,并将区域设置为你的秘密存储的区域(如果它不是 us-east-1)。并且不要忘记使其可执行(“chmod +x your_hook.sh”)。

这假定您的应用程序可以从 .env 文件加载其环境(例如,它可以很好地与 docker / docker-compose 一起工作)。

另一种选择是将变量存储在“.ebextensions”配置文件中,但遗憾的是它似乎不适用于新的 Amazon Linux 2 平台。更重要的是,您不应该直接在您的应用程序构建中存储敏感信息,例如凭据。任何具有 Elastic Beanstalk 读取权限的人都可以访问应用程序的构建,并且它们还以未加密的方式存储在 S3 上。

使用挂钩方法,秘密仅存储在本地的 Elastic Beanstalk 底层 EC2 实例上,您可以(应该!)限制对它们的直接 SSH 访问。

我只是添加到@kaliatech 的回答中,因为虽然它非常有帮助,但它有一些差距让我无法让这个工作几天。基本上,您需要将配置文件添加到 .ebextensions directory of your EB app, which uses a container_commands 部分以检索您的秘密(以 JSON 格式)并将其作为 .env. 文件输出到 EC2 的 /var/app/current 目录中您的应用程序代码所在的实例:

# .ebextensions/setup-env.config
container_commands:
  01-extract-env:
    env:
      AWS_SECRET_ID:
        "Fn::GetOptionSetting":
          Namespace: "aws:elasticbeanstalk:application:environment"
          OptionName: AWS_SECRET_ID
      AWS_REGION: {"Ref" : "AWS::Region"}
      ENVFILE: .env

    command: >
        aws secretsmanager get-secret-value --secret-id $AWS_SECRET_ID --region $AWS_REGION |
        jq -r '.SecretString' |
        jq -r 'to_entries|map("\(.key)=\(.value|tostring)")|.[]' > $ENVFILE

注意:这假设 AWS_SECRET_ID 是在应用程序环境中配置的,但它也可以很容易地在此处进行硬编码。

此脚本运行所需的所有实用程序都已嵌入到 EC2 Linux 映像中,但您需要向 IamInstanceProfile 角色(通常名为 aws-elasticbeanstalk-ec2-role) 由 EC2 假定允许它访问 SecretManager:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "SecretManagerAccess",
            "Effect": "Allow",
            "Action": "secretsmanager:GetSecretValue",
            "Resource": "arn:aws:secretsmanager:ap-southeast-2:xxxxxxxxxxxx:secret:my-secret-name*"
        }
    ]
}

最后,调试 EC2 实例 bootstrap、download the EB logs and check the EC2 log files/var/log/cfn-init.log/var/log/cfn-init-cmd.log 期间遇到的任何问题。