在 CloudFormation 模板中引用 AWS Parameter Store 的安全字符串
Posted
技术标签:
【中文标题】在 CloudFormation 模板中引用 AWS Parameter Store 的安全字符串【英文标题】:Referencing AWS Parameter Store's Secure String in CloudFormation template 【发布时间】:2019-11-15 09:17:06 【问题描述】:坚持使用 AWS Parameter Store 中的 SecureString。我试图将数据库密码称为:
DatabasePassword:
Type: AWS::SSM::Parameter::Value<SecureString>
NoEcho: 'true'
Default: /environment/default/database_password
Description: The database admin account password
这会引发错误:
调用CreateStack操作时发生错误(ValidationError):模板格式错误:无法识别的参数类型:SecureString
但是,如果我将此参数称为String
而不是SecureString
,则会引发不同的错误:
调用 CreateStack 操作时发生错误(ValidationError):模板引用的参数 [/environment/default/database_password] 具有 CloudFormation 不支持的类型。
我确实尝试过使用'resolve:ssm-secure:parameter-name:version'
,它适用于数据库配置:
MasterUsername: !Ref DatabaseUsername
MasterUserPassword: 'resolve:ssm-secure:/environment/default/database_password:1'
但是,我使用的是 AWS Fargate docker 容器,我将这些值作为环境变量提供:
Environment:
- Name: DATABASE_HOSTNAME
Value: !Ref DatabaseHostname
- Name: DATABASE_USERNAME
Value: !Ref DatabaseUsername
- Name: DATABASE_PASSWORD
Value: 'resolve:ssm-secure:/environment/default/database_password:1'
这会引发错误:
调用 CreateStack 操作时发生错误 (ValidationError):[AWS::ECS::TaskDefinition/Properties/ContainerDefinitions/Environment] 中不支持 SSM 安全引用
无法在我的实现中使用安全字符串。这个问题有什么解决方法吗? AWS 去年宣布支持SecureString
,但找不到文档。我发现的只是使用resolve
,它只在某些情况下有效。
参考资料:
1
2
【问题讨论】:
【参考方案1】:CloudFormation 不支持 SecureString
作为模板参数类型。您可以在下面的文档中确认,让我引用它。
另外,AWS CloudFormation 不支持定义模板 参数作为 SecureString Systems Manager 参数类型。然而, 您可以将安全字符串指定为某些参数值 使用动态参数模式来获取资源。
参考:https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html#aws-ssm-parameter-types
正如您提到的,您“可以”使用dynamic parameter patterns
解决它,但只有有限的资源支持它。 ECS
和 Fargate
没有。
参考:https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html
也许您可以使用Secrets Manager
解决它,而不是将密码设置为容器的环境变量,您的应用程序在运行时从Secrets Manager
获取密码,这也提高了您的安全性,密码不会很清楚容器内的文本。
您可以在下面看到此解决方案的一个示例,它不适用于容器,但使用环境变量和Secrets Manager
的“工作方式”相同。
参考:https://aws.amazon.com/blogs/security/how-to-securely-provide-database-credentials-to-lambda-functions-by-using-aws-secrets-manager/
【讨论】:
我确实考虑过使用 Secrets Manager 的这个选项。如果我在我的应用程序中进行更改以从 Secrets Manager 中引用这些变量,那么如果我直接从 docker 容器内的 Secrets Manager 中提取凭据,它将起作用。但是,对于我的本地开发,我不想依赖 AWS,我指的是我的本地数据库实例而不是 AWS RDS 实例。 为什么 AWS 只为String
而不是 SecureString
发布此功能?支持这个有什么问题?他们使使用 CloudFormation 进行开发变得非常困难。 :-(【参考方案2】:
AWS Secrets Manager 可用于获取 CloudFormation 模板的秘密,即使它们不是数据库密码之类的东西。
这里是文档的链接:https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html#dynamic-references-secretsmanager
Secrets Manager 密钥包含 3 个部分:
秘密名称,例如PROD_DB_PASSWORD 秘密的钥匙,例如DB_PASSWORD 以及实际的秘密值然后,您将使用以下方法在 CloudFormation 模板中解析上述机密:
'resolve:secretsmanager:PROD_DB_PASSWORD:SecretString:DB_PASSWORD'
【讨论】:
【参考方案3】:我知道这篇文章已经很老了,但我遇到了需要使用 SecureString 的情况,并找到了这篇文章和描述解决方法的博客文章。我认为这可以帮助某些人。
Original Post Here
基本上,您可以像这样在.ebextensions
文件夹中创建一个.conf
文件:
---
packages:
yum:
bash: []
curl: []
jq: []
perl: []
files:
/opt/elasticbeanstalk/hooks/restartappserver/pre/00_resolve_ssm_environment_variables.sh:
mode: "000700"
owner: root
group: root
content: |
#!/usr/bin/env bash
/usr/local/bin/resolve_ssm_environment_variables.sh
/opt/elasticbeanstalk/hooks/appdeploy/pre/00_resolve_ssm_environment_variables.sh:
mode: "000700"
owner: root
group: root
content: |
#!/usr/bin/env bash
/usr/local/bin/resolve_ssm_environment_variables.sh
/opt/elasticbeanstalk/hooks/configdeploy/pre/00_resolve_ssm_environment_variables.sh:
mode: "000700"
owner: root
group: root
content: |
#!/usr/bin/env bash
/usr/local/bin/resolve_ssm_environment_variables.sh
/usr/local/bin/resolve_ssm_environment_variables.sh:
mode: "000700"
owner: root
group: root
content: |
#!/usr/bin/env bash
set -Eeuo pipefail
# Resolve SSM parameter references in the elasticbeanstalk option_settings environment variables.
# SSM parameter references must take the same form used in CloudFormation, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html#dynamic-references-ssm-secure-strings
# supported forms are:
# resolve:ssm-secure-env:path:version
# resolve:ssm-secure-env:path
# resolve:ssm-env:path:version
# resolve:ssm-env:path
# where "path" is the SSM parameter path and "version" is the parameter version.
if [[ -z "$AWS_DEFAULT_REGION:-" ]]; then
# not set so get from configuration
AWS_DEFAULT_REGION="$(aws configure get region)" || :
fi
if [[ -z "$AWS_DEFAULT_REGION:-" ]]; then
# not set so get from metadata
AWS_DEFAULT_REGION="$(curl -s http://169.254.169.254/latest/dynamic/instance-identity/document | jq -r .region)" || :
fi
if [[ -z "$AWS_DEFAULT_REGION:-" ]]; then
echo "Could not determine region." 1>&2
exit 1
fi
export AWS_DEFAULT_REGION
readonly CONTAINER_CONFIG_FILE="$1:-/opt/elasticbeanstalk/deploy/configuration/containerconfiguration"
readonly TEMP_CONTAINER_CONFIG_FILE="$(mktemp)"
i=0
for envvar in $(jq -r ".optionsettings[\"aws:elasticbeanstalk:application:environment\"][]" "$CONTAINER_CONFIG_FILE"); do
envvar="$(echo "$envvar" | perl -p \
-e 's|resolve:ssm(?:-secure)-env:([a-zA-Z0-9_.-/]+?):(\d+?)|qx(aws ssm get-parameter-history --name "$1" --with-decryption --query Parameters[?Version==\\\x60$2\\\x60].Value --output text) or die("Failed to get SSM parameter named \"$1\" with version \"$2\"")|eg;' \
-e 's|resolve:ssm(?:-secure)-env:([a-zA-Z0-9_.-/]+?)|qx(aws ssm get-parameter --name "$1" --with-decryption --query Parameter.Value --output text) or die("Failed to get SSM parameter named \"$1\"")|eg;')"
export envvar
jq ".optionsettings[\"aws:elasticbeanstalk:application:environment\"][$i]=env.envvar" < "$CONTAINER_CONFIG_FILE" > "$TEMP_CONTAINER_CONFIG_FILE"
cp "$TEMP_CONTAINER_CONFIG_FILE" "$CONTAINER_CONFIG_FILE"
rm "$TEMP_CONTAINER_CONFIG_FILE"
((i++)) || :
done
然后您可以像在 CloudFormation 模板中那样使用它(或者实际上任何您想要的方式,我将它与 Terraform 一起使用)。请注意,有一个额外的-env
后缀来与原生解析器区分开来。
---
AWSTemplateFormatVersion: '2010-09-09'
Resoures:
BeanstalkEnvironment:
Type: AWS::ElasticBeanstalk::Environment
Properties:
OptionSettings:
-
Namespace: "aws:elasticbeanstalk:application:environment"
OptionName: SPRING_DATASOURCE_PASSWORD
Value: !Sub "resolve:ssm-secure-env:/my/parameter:42
【讨论】:
以上是关于在 CloudFormation 模板中引用 AWS Parameter Store 的安全字符串的主要内容,如果未能解决你的问题,请参考以下文章
在 AWS CloudFormation 模板中引用 !Ref DynamoDB 表名
在 CloudFormation 模板中引用 AWS Parameter Store 的安全字符串
在 Cloudformation 模板中,我如何在 IoT Rule 中引用动态生成的 Lambda 函数 ARN?