将EC2用户数据shell脚本存储在私有S3存储桶中是否安全?

20

我在AWS上有一个EC2 ASG,我想把用于实例化任何给定实例的shell脚本存储在S3存储桶中,并在实例化时下载和运行它,但即使我使用IAM Instance Role,通过HTTPS传输并在S3存储桶中静止加密脚本,整个过程仍感觉有些不稳定。 使用KMS 我使用 S3服务器端加密因为KMS方法会引发“未知”错误)。

设置

  • 创建了一个 IAM 实例角色,在任何实例被实例化时都会分配给我的 ASG,从而将我的 AWS 凭证作为 ENV 变量嵌入到实例中
  • 将我的 Instance-Init.sh 脚本上传并加密到 S3 中,结果是生成了一个私有终端节点,如下所示:https://s3.amazonaws.com/super-secret-bucket/Instance-Init.sh

User-Data 字段中

当我想要使用 Launch Configuration 创建我的 ASG 时,我将以下内容输入到 User Data 字段中:

#!/bin/bash

apt-get update
apt-get -y install python-pip
apt-get -y install awscli
cd /home/ubuntu
aws s3 cp s3://super-secret-bucket/Instance-Init.sh . --region us-east-1
chmod +x Instance-Init.sh
. Instance-Init.sh
shred -u -z -n 27 Instance-Init.sh

上面的操作会执行以下内容:
  • 更新包列表
  • 安装Python(运行 aws-cli 所需)
  • 安装 aws-cli
  • 切换到 /home/ubuntu 用户目录
  • 使用 aws-cliS3 下载 Instance-Init.sh 文件。由于我的实例分配了 IAM Role,因此 aws-cli 自动发现了我的 AWS 凭据。该 IAM Role 还授予我的实例解密文件所需的权限。
  • 将其设为可执行文件
  • 运行脚本
  • 完成后删除脚本。

Instance-Init.sh 脚本

脚本本身将执行诸如设置 env 变量和在我的实例上部署所需的容器等操作。就像这样:

#!/bin/bash

export MONGO_USER='MyMongoUserName'
export MONGO_PASS='Top-Secret-Dont-Tell-Anyone'

docker login -u <username> -p <password> -e <email>
docker run - e MONGO_USER=${MONGO_USER} -e MONGO_PASS=${MONGO_PASS} --name MyContainerName quay.io/myQuayNameSpace/MyAppName:latest


非常方便

这样可以非常方便地更新User-Data脚本,而不需要每次需要进行微小更改时创建新的Launch Config。它能够很好地将env变量从代码库中取出,并放入一个狭窄、可控的空间(Instance-Init.sh脚本本身)。

但是所有这一切都感觉有点不安全。把我的主数据库凭据放在S3上的文件中让人不安。

问题

  1. 这是常见的做法还是我在想一个坏主意?
  2. 事实上,该文件被下载并存储(虽然是暂时的),是否构成漏洞?
  3. 是否有更好的方法以更安全的方式删除文件?
  4. 是否在运行后删除该文件甚至重要?考虑到密码正在传输到env变量中,删除Instance-Init.sh文件似乎是多余的。
  5. 在我刚开始运维的日子里,是否有我忽略的东西?

提前感谢任何帮助。


我不确定这个内容是否完全符合本站的范围,但它可能更适合发布在 https://security.stackexchange.com/ 上。 - Etan Reisner
我同意这应该提交到security.stackexchange.com。不用说,把任何凭据放入任何明文文件中都是一个巨大的安全风险。永远不要那样做。如果可能的话,让它通过终端从用户输入凭据或找出其他方法来获取凭据。 - nln
关于问题本身。@nln,你没有错,但凭证并不是以明文形式存储的,而是使用“S3服务器端加密”进行加密。AWS提供了这种加密方式,据我所知,每个对象都使用自己的密钥进行加密,该密钥本身又用AWS主密钥进行加密,由AWS负责。对象密钥会定期更换(我不记得多久一次),所以说,老实说,他们的流程比我自己设立的还要好。 - AJB
无法通过cli输入凭据,因为需要凭据的任何实例都将是自动扩展组的一部分,在启动时没有人类交互。 - AJB
1
我个人会使用带有参数的CloudFormation脚本来设置所有组件,然后将凭据作为变量注入到用户数据中作为启动配置的一部分。然后,当您需要更新用户数据时,只需更新CloudFormation模板,AWS将处理对堆栈的更新。如果这意味着更改了启动配置,则可以进行缩放并最终获得一组已更新的实例。话虽如此,您的方法相当常见,但必须仔细审查存储桶策略和IAM权限。 - sysconfig
显示剩余2条评论
2个回答

7
您所描述的内容几乎与我们使用的方法非常相似,即从我们的注册表中实例化Docker容器(现在我们使用v2自托管/私有、基于S3的docker-registry代替Quay)到生产环境中。顺便说一句,当我第一次尝试这种方法时,也有您所描述的“这感觉很脆弱”的感觉,但是现在已经使用了将近一年,与将敏感配置数据存储在仓库或镜像中的替代方法相比,我相信这是处理这些数据的更好方式之一。话虽如此,我们目前正在考虑使用Hashicorp 的新 Vault 软件来部署配置密钥,以替换这个“共享”的加密密钥 shell 脚本容器(快速说五遍)。我们认为 Vault 将相当于将加密外包给开源社区(它应该属于那里),但用于配置存储。

简而言之,我们已经使用非常相似的方法约一年时间,未遇到多少问题,但我们现在正在考虑使用一个外部的开源项目(Hashicorp 的 Vault)来替换自己编写的方法。祝你好运!


2
是的,就是这个。谢谢@L0j1k,这基本上就是我要找的答案。感觉有点不对劲,是吧?无论如何,很高兴知道我不是在完全未知的领域冒险。Vault看起来像是一个升级版的etcd,非常酷。我喜欢“动态密钥”的概念。现在我要去读他们的网站了。干杯。 - AJB
1
非常好。就我个人而言,当我看到Hashicorp的Vault项目时,我知道我们正在正确的轨道上,因为它在机械上与你和我解决这个问题的方式非常相似。如果您愿意,这是一种验证。 :) - L0j1k
1
是的。我的凭证管理思路已经发生了巨大变化。我曾经认为凭证是独立的对象,从用户到用户漂浮。现在我把它们看作是精心设计的“秘密层”的副产品。这极大地减少了凭证的攻击面。我通过这个“S3”黑客技巧成功地将它们全部放在一个地方,但我不确定如何使它们动态化。Vault似乎非常好地解决了这个问题。 - AJB
2
这是一种完全合法和常见的做法!我认为将IAM角色权限严密地限制是一个好主意,即使是在执行后也应该销毁脚本。我见过一些人为了在SQS队列中生成消息而付出了很大的努力,然后触发S3中的签名URL,他们可以作为引导的一部分下载,但这似乎不太可靠。我唯一建议您更改的是在AMI中已经安装了pip和awscli,并且我认为使用pip安装awscli要比apt-get更新。 - Neal Magee

2
一种替代Vault的方法是使用credstash,它利用AWS KMS和DynamoDB来实现类似的目标。
我实际上使用credstash通过一个简单的入口脚本在容器启动时动态导入敏感配置数据——这样敏感数据就不会通过docker inspect或docker logs等方式暴露出来。
以下是一个Python应用程序的示例入口脚本——优点在于你仍然可以通过环境变量传递凭据以供非AWS/dev环境使用。
#!/bin/bash
set -e

# Activate virtual environment
. /app/venv/bin/activate

# Pull sensitive credentials from AWS credstash if CREDENTIAL_STORE is set with a little help from jq
# AWS_DEFAULT_REGION must also be set
# Note values are Base64 encoded in this example
if [[ -n $CREDENTIAL_STORE ]]; then
  items=$(credstash -t $CREDENTIAL_STORE getall -f json | jq 'to_entries | .[]' -r)
  keys=$(echo $items | jq .key -r)
  for key in $keys
  do
    export $key=$(echo $items | jq 'select(.key=="'$key'") | .value' -r | base64 --decode)
  done
fi

exec $@

非常酷。感谢 @mixja 的提示。喜欢它如何从 docker inspect/logs 中“隐藏”凭据。 - AJB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接