编程

在Laravel 中使用 AWS Parameter Store 管理密钥

Martin Hwang 1468 2021-12-05 22:12:00

密钥是指你不想暴露的于公众的一串数据,比如 API 凭据, 私钥。

在 Laravel 中, 通常会被存在 .env 文件中。这些私钥可能是 Laravel Passport 生成的,或者是其他应用需要的。 

如何管理私钥很大程度上取决于你的部署处理。Forge 允许你从服务器中直接加载和编辑 .env 文件。 对于更多的定制化主机方案,你可能会将 .env 文件保存在 S3 buket 中,然后在部署时下载下来。

一个更安全且易用的方案是,使用 AWS Parameter Store 来管理密钥。

There is also an AWS service appropriately named Secrets Manager.

Secrets Manager has a lot more features, but you may not necessarily need or want them for this use case. It's also more expensive. Parameter Store pricing is here. Secrets Manager pricing is here.

使用 Parameter Store

Parameter store 以 key-value 键值对存储。它是 AWS 系统管理 (SSM) 服务的一部分。

它有许多特性!本文将我们管理 Laravel 应用私钥所需要的罗列出来:

  • 保存加密数据
  • 保存大数值
  • 创建参数
  • 查询参数
  • 安全 (IAM 权限)

保存加密数据

以下是可以存储的数据类型:

  • 字符串
  • 字符串列表(本质上是字符串数组)
  • 安全字符串(SecureString)

我们将使用安全字符串(SecureString), 它适合于存储密钥。使用这种类型会加密参数值。需要加密的值使用 KMS 服务 (Key Management Service) 来提供用于加密的一对 key。

你可以在 KMS 内创建和管理你自己的 key, 或者使用默认key.

Creating your own key gives you more fine-grained control over who has access to data encrypted with the key. KMS is used EVERYTHING in AWS where things are encrypted - such as encrypted EBS drives, Parameter Store, and Secrets Manager.

在本例中我使用了默认KMS key。具体情况取决于你的团队规模及谁由权限来获取该密钥。

保存大量数据

费用由参数的数量及你通过 API 调用的频率决定。由两个级别 - 标准 (Standard) 和 高级 (advanced) 。

标准版最多 10, 000 个参数, 每个不大于 4 KB 。参数是免费的( API 调用仍然是收费的)。

高级版最多 100,000 个参数,每个参数限制在 8 KB 以内,带有额外的安全特性。每个参数按月收费。 

由于我们将整个 .env 文件存入一个参数,内容可能会超过 4 KB 限额。因此你可能需要使用高级版或者分开保存一些独立的密钥。

创建密钥

要将密钥保存到 Parameter Store, 我们要使用 AWS CLI 命令 ssm put-parameter。

这里我们保存真整个 .env 文件:

aws ssm put-parameter \
    --name /cloudcasts/staging/env \
    --type SecureString \
    --value file://.env

有几点需要注意:

  1. 参数的 name 使用参数分层结构, 有利于参数分类和强制安全政策。
    • 比如,我们的 env 参数 cloudcasts 命名空间 的 staging 环境下
  2. 我们使用的类型是 SecureString, 但是我们没有通过 --key-id 定义 KMS key. 这将在我们工作的区域使用默认的 KMS key。
  3. 我们使用 file://path/to/file.ext 方法告诉 AWS CLI 让它在本地文件中查找参数内容

这就能将密钥加密并保存到 Parameter Store!

生成你的 .env 文件

我想在每次部署中抓取一份最新的密钥副本(复原 .env 文件)。

If you'd like to see how to create a fully automated, auto-scaled infrastructure on AWS, checkout the Simple Auto Scaling course on CloudCasts! Within it, we use Parameter Store during deployments to retrieve secrets.

如果你的密钥是动态变更的(部署之外),你可能需要一些更为动态的东西。无论如何,需要避免的是,将参数保存在比如 应用的.zip 压缩包内。如果这些压缩包被存在某些公开空间里(如 开放公共权限的S3 bucket),你可能泄露重要的机密.

要创建新的 .env 文件(可能部署),我们可以使用命令 ssm get-parameter :

aws ssm get-parameter \
    --with-decryption \
    --name /cloudcasts/staging/env \
    --output text \
    --query 'Parameter.Value' > .env

需要注意的几点:

  1. 我们使用 --with-decryption 使我们收到的值是经过解密的
    • 如果不使用默认 KMS key, 调用此命令的用户需要有对应的 KMS key 的权限
  2. 通过 --output text 将结果以 text 输出结果
  3. 使用 --query 只恢复加密的值(而非所有你可能其他地方获取的元数据)
  4. 我们直接在当前目录输出 .env 文件, 正如我们运行 echo "foo" > .env 一样

 --output--query 在所有 AWS CLI 命令中都可用. .

处理大的 .env 文件

如果你有一个很大的 .env 文件,已将它分成几个独立的参数,你可能想在 .env 文件中追加内容而非覆盖.

比如你基础的 .env 文件放在一个参数里,还有一些其他的密钥放在另外的参数里。你可如下操作:

 # Create the initial .env file创建初始的 .env文件
 aws ssm get-parameter \
     --with-decryption \
     --name /cloudcasts/staging/base-env \
     --output text \
     --query 'Parameter.Value' > .env
  
 # Append a long secret to .env for each追加内容到.env中
 # additional secret
SOME_LONG_SECRET_VALUE=$(aws ssm get-parameter \
    --with-decryption \
    --name /cloudcasts/staging/SOME_LONG_SECRET \
    --output text \
    --query 'Parameter.Value')

echo "SOME_LONG_SECRET=\"$SOME_LONG_SECRET_VALUE\"" >> .env

没什么特别的操作!

IAM 权限

使用 IAM 用户/角色 可以通过多种方法锁住 get-parameter 的调用。使用分层结构名(e.g. /cloudcasts/staging/env) 可以帮我们锁住特定应用或者环境的密钥.

比如, 我有一个 IAM 角色用于自动部署 cloudcasts 应用的 staging 环境,我可以这样设置该角色的 IAM 政策: 

{
   "Version": "2012-10-17",
   "Statement": [
     {
       "Effect": "Allow",
       "Action": [
         "ssm:GetParameter"
       ],
       "Resource": "arn:aws:ssm:us-east-2:012345678910:parameter/cloudcasts/staging/*"
   }
  ]
}

因此,对于 us-east-2, 在账号ID 012345678910,  拥有以上 IAM 政策 的这个角色可以在以 /cloudcasts/staging 开头的参数中运行 GetParameter。