在CoreOS上将私钥安全地分发给Docker

我们开始使用Docker / CoreOS作为我们的基础架构。 我们正在部署EC2。 CoreOS集群由一个自动扩展组pipe理,所以新主机进出。 另外,还有很多。 我试图find一种方法来向所有主机分发一个秘密(私有RSA密钥或对称密码的共享密钥),以便我可以使用它来安全地分发数据库凭证,某些服务的AWS访问密钥等。

我想服从“最小特权原则”。 具体来说,如果我在同一主机上运行的两个不同容器中有两个应用程序,则每个应用程序只能访问应用程序所需的机密。 例如,应用程序A可能有权访问MySQL凭据,应用程序B可能有权访问Dynamo的AWS Access密钥,但A不能访问Dynamo,B无法访问MySQL。

如果我在每个服务器上都有一个秘密,那么这不会很难。 我可以使用像Crypt这样的工具从etcd中读取encryption的configuration数据,然后使用卷映射来select性地将凭据提供给单个容器。

问题是,我怎么安全地把钥匙到主机上。

以下是我考虑的一些事情,以及为什么他们不工作:

  • 使用AWSangular色为每个主机授予对encryptionS3存储桶的访问权限。 主机然后可以从那里读取一个共享的秘密。 但是这不起作用,因为S3有一个REST API,Docker不限制networking访问容器有,而且angular色适用于整个主机。 因此,该主机上的任何容器都可以读取S3中的密钥,然后读取etcd(其中也包含不受限制的REST API)中的所有值并对其进行解密。
  • 在我的CloudFormation模板中,我可以有一个密钥的参数。 然后embedded到UserData中并分发给所有主机。 不幸的是,任何容器都可以通过元数据服务REST API检索密钥。
  • 使用船队向全部主机提交全局单元,并且该单元复制密钥。 但是,容器可以通过它的REST API访问队列,并执行“fleetctl cat”来查看密钥。
  • 把密钥放在一个私人回购的容器中。 然后,可以将其作为全局单元分发给所有主机,并且该容器中的应用程序可以将密钥复制到卷装载。 不过,我认为,鉴于私人回购证书,有人可以用标准的networking工具下载容器,并提取密钥(尽pipe有一些努力)。 然后,问题就变成了如何安全地分发.dockercfg和私人回购的凭据,我想我们马上就回到了开始的地方。

基本上,似乎核心问题是,每个东西都有一个REST API,我不知道有什么办法来阻止容器访问某些networking资源。

想法?

如果你愿意把这个秘密保存在AMI中,你可以使用你提到的Crypt解决scheme。 我执行类似如下:

  1. 生成公钥/私钥对
  2. 将私钥烘焙到用于自动缩放组的AMI中
  3. 使用公钥encryption引导脚本,包括秘密
  4. Base64对encryption的引导脚本进行编码
  5. 将编码的文本embedded到使用私钥解密的包装脚本中,并将其用作AWS启动configuration的用户数据。

例如,引导脚本可能如下所示:

db="mysql://username:password@somehost:3306/somedb" apikey="some_api_secret_key" docker run --name "first container" -e db=$db -d MyImage MyCommand docker run --name "second container" -e apikey=$apikey -d MyOtherImage MyOtherCommand 

要进行encryption,请使用openssl和smime来解决rsautl的低限问题。 假设bootstrap脚本位于/tmp/bootstrap.txt中,它可以像这样被encryption和编码:

 $ openssl smime --encrypt -aes256 -binary -outform D -in /tmp/bootstrap.txt /tmp/public.key | openssl base64 -e > /tmp/encrypted.b64 

成为用户数据的包装脚本可能如下所示:

 #!/usr/bin/env bash -x exec >> /tmp/userdata.log 2>&1 cat << END > /tmp/bootstrap.dat <contents of /tmp/encrypted.b64> END decrypted_blob=$(cat /tmp/bootstrap.dat | openssl base64 -d | openssl smime -decrypt -inform -D binary -inkey /path/to/secret.key eval "${decrypted_blob}" rm /tmp/bootstrap.dat 

现在,如果容器访问EC2元数据,他们将看到userdata脚本,但它只是encryption的blob。 私钥在主机上,哪些容器不能访问(理论上)。

另请注意,用户数据大小限制为16KB,因此脚本及其encryption数据必须小于此值。