我按照 https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/single-container-docker-configuration.html#docker-configuration.remote-repo 的说明从 Secrets 注入机密管理器(“使用 AWS Secrets Manager”部分)
我在 Elastic Beanstalk 上使用 Docker 平台
arn:aws:elasticbeanstalk:ap-southeast-2::platform/Docker running on 64bit Amazon Linux 2/3.6.1
我在 Secrets Manager 中有以下秘密 blob,名为“AppSecret”
{ "username": "Bruce.Wayne", "password": "I_AM_BATMAN" }
在
.ebextensions/options.config
我有以下内容
option_settings:
aws:elasticbeanstalk:application:environment:
USER: '{{resolve:secretsmanager:AppSecret:SecretString:username}}'
PASSWORD: '{{resolve:secretsmanager:AppSecret:SecretString:password}}'
我还有一个
.platform/hooks/postdeploy/dump.sh
(用于测试),其中包含
#! /usr/bin/env bash
echo "PASSWORD $(/opt/elasticbeanstalk/bin/get-config environment -k PASSWORD)"
IAM 角色 (
aws-elasticbeanstalk-ec2-role
) 附加了 SecretsManagerReadWrite
策略,其中包含 IAM 操作 "secretsmanager:*"
。这应该满足要求(来自https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html#dynamic-references-secretsmanager)
要指定存储在 Secrets Manager 中的密钥,您必须有权调用该密钥的 GetSecretValue。
问题在于,当 ZIP 部署到 Elastic Beanstalk 时,秘密并未得到解析。日志的输出
eb-hooks.log
是
PASSWORD {{resolve:secretsmanager:AppSecret:SecretString:password}}
同样的
options.config
已正确解析 SSM 引用,只是 secretsmanager
失败了。
这可能是云形成的一些模糊部分,或者是我忽略的简单部分,但我不知道为什么会失败。
(或者,如果有人可以指导我如何将 SSM SecureString 与 Elastic Beanstalk 结合使用,那就更好了)
最近我面临着同样的挑战,如何在我的应用程序中传递凭据。弹性豆茎确实不能解开秘密。有几种方法可以做到这一点。我要分享一个对我有用的。
先决条件 您在 Elastic Beanstalk 中的 IAM 角色应该能够检索机密。 下面我将向您提供 CloudFormation 堆栈,我在其中添加了我的 Elastic Beanstalk IAM 角色,并授予其从 AWS Secret Manager 检索密钥的权限,密钥名称为 name/ofyoursecret/db
EBInstanceRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: 'ec2.amazonaws.com'
Action: 'sts:AssumeRole'
Path: '/'
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/AWSElasticBeanstalkWebTier'
Policies:
- PolicyName: 'AdditionalPermissions'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: 'secretsmanager:GetSecretValue'
Resource: !Sub 'arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:name/ofyoursecret/db*'
- Effect: Allow
Action: 'ecr:GetAuthorizationToken'
Resource: "*"
- Effect: Allow
Action:
- 'ecr:BatchCheckLayerAvailability'
- 'ecr:GetDownloadUrlForLayer'
- 'ecr:GetRepositoryPolicy'
- 'ecr:DescribeRepositories'
- 'ecr:ListImages'
- 'ecr:DescribeImages'
- 'ecr:BatchGetImage'
Resource:
- !Sub 'arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/name-repository*'
EBInstanceProfile:
Type: 'AWS::IAM::InstanceProfile'
Properties:
Path: "/"
Roles:
- !Ref EBInstanceRole
ElasticBeanstalkApplication:
Type: 'AWS::ElasticBeanstalk::Application'
Properties:
ApplicationName: !Ref Project
ElasticBeanstalkEnvironment:
Type: 'AWS::ElasticBeanstalk::Environment'
Properties:
EnvironmentName: !Sub '${Project}-${Environment}'
ApplicationName: !Ref ElasticBeanstalkApplication
SolutionStackName: '64bit Amazon Linux 2 v3.7.1 running Docker'
OptionSettings:
- Namespace: 'aws:elasticbeanstalk:application:environment'
OptionName: 'HOST_URL'
Value: !ImportValue
'Fn::Sub': "${Environment}-${Project}-DBEndpoint"
- Namespace: 'aws:elasticbeanstalk:application:environment'
OptionName: 'DATABASE_SECRET_ARN'
Value: !Sub 'arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:name/ofyoursecret/db'
现在我将使用 sh 脚本从 AWS Secret Manager 检索密钥。因为我传入了环境变量 DATABASE_SECRET_ARN,所以它是我的密钥的 ARN(Amazon 资源名称 (ARN) 不是密钥) 我在这里传递了数据库主机 URL。
获取_credentials.sh
#!/bin/sh
# Get the AWS region from EC2 instance metadata
AWS_REGION=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed 's/[a-zA-Z]$//')
# Check if AWS_REGION is obtained successfully
if [ -z "$AWS_REGION" ]; then
echo "Failed to get AWS region from EC2 metadata."
exit 1
fi
# Get DATABASE_SECRET_ARN and HOST_URL from environment variables
DATABASE_SECRET_ARN=$(printenv DATABASE_SECRET_ARN)
HOST_URL=$(printenv HOST_URL)
if [ -z "$DATABASE_SECRET_ARN" ]; then
echo "DATABASE_SECRET_ARN environment variable not found."
exit 1
fi
if [ -z "$HOST_URL" ]; then
echo "HOST_URL environment variable not found."
exit 1
fi
# Use AWS CLI to get the secret value
SECRET_STRING=$(aws secretsmanager get-secret-value --secret-id $DATABASE_SECRET_ARN --region $AWS_REGION --query SecretString --output text)
# Check if SECRET_STRING is obtained successfully
if [ -z "$SECRET_STRING" ]; then
echo "Failed to retrieve secret string from Secrets Manager."
exit 1
fi
# Extract credentials from SECRET_STRING
USERNAME=$(echo $SECRET_STRING | jq -r .username)
DBPASSWORD=$(echo $SECRET_STRING | jq -r .dbpassword)
DBNAME=$(echo $SECRET_STRING | jq -r .dbname)
# Optionally, export DATABASE_URL to be available to other processes started by this script
export DATABASE_URL="postgresql+asyncpg://${USERNAME}:${DBPASSWORD}@${HOST_URL}:5432/${DBNAME}"
在我的 Dockerfile 中,我使用入口点脚本并在 .env 文件中传递我的值
入口点.sh
#!/bin/sh
echo "Starting the entrypoint script at $(date)"
echo "Sourcing get_cred_db.sh to set environment variables..."
. ./get_credentials.sh
# Assuming get_cred_db.sh successfully sets and exports DATABASE_URL
# Now, write DATABASE_URL and potentially other environment variables to a .env file
echo "DATABASE_URL=$DATABASE_URL" > /usr/src/app/.env
echo "Environment variables recorded in .env file."
# Execute the passed command
exec "$@"