3. 创建客户管理型 CMK:三种姿势,一种信任

咱们直接进入正题。客户管理型 CMK,说白了就是你自己全权掌控的密钥。AWS 提供三种创建方式:Console 点点点、CLI 敲命令、CloudFormation 写模板。我三种都用过,今天把心得和坑都抖出来。

先给个全景图——下面是三种创建方式的逻辑对比,你看完心里就有谱了。

三种方式创建客户管理型 CMK 对比 创建客户管理型 CMK 三种方式核心流程 AWS Console KMS → 客户管理型密钥 → 创建密钥 配置类型、别名、标签、策略 审查并完成创建 AWS CLI aws kms create-key 参数:KeyUsage, KeySpec, Origin, Policy, Tags, etc. 创建成功后设置别名 CloudFormation 定义 AWS::KMS::Key 嵌套:KeyPolicy, Alias, Tags SupportConditions stack deploy 完成创建 关键差异 Console:操作直观,适合初次尝试或单次创建 CLI:脚本友好,适合 CI/CD 流水线 CloudFormation:声明式,适合基建即代码(IaC)全生命周期管理

3.1 AWS Console 操作:从零到一,5 分钟搞定

Console 是最直观的方式。我记得刚接手项目时,同事给了我一张截图让我照着配,结果因为没选对密钥类型,S3 加密一直报错。嗯,这里我重点提醒:默认的「Symmetric」就是加密最常用的,不要手滑选成 asymmetric。

操作步骤

  1. 登录 AWS Console,进入 KMS 服务。
  2. 左侧点击「客户管理型密钥」→「创建密钥」。
  3. 密钥类型:选择对称(Symmetric),一般场景用这个就够了。如果你需要在外部加密、AWS 内部解密(比如 S3 SSE-KMS),必须选对称。
  4. 密钥材料来源:
    • KMS(默认):AWS 帮你生成并托管密钥材料。
    • 外部(导入密钥材料):你自己在本地生成密钥材料,然后导入。这个场景我遇到过——合规要求密钥材料必须由安全团队生成,不能交给云厂商。但注意,一旦选择外部导入,后续轮换策略要手动实现,KMS 自动轮换不支持导入的密钥。
  5. 别名(Alias):建议遵循公司命名规范,比如 alias/myapp/prod、alias/s3-ssekms。别名可以随时改,但创建时最好一次到位,否则后面改起来还要排查引用。
  6. 描述(Description):简单说明用途,比如「用于 prod 环境 S3 存储桶加密」。
  7. 密钥策略:这是最重要的部分。Console 默认提供「Allow root user + 当前 IAM 用户」的简化策略,但生产环境建议你直接用「切换到策略视图」自定义。我曾经见过团队一路点默认,结果后来加授权时发现策略冲突,折腾了半天。
  8. 标签(Tags):按项目、环境、团队打标签,方便按标签做权限隔离。
  9. 预览并创建。
💡 我的习惯:创建 CMK 时,我会先在策略里显式拒绝 kms:DeleteKey(除非特定条件),防止误删。另外,记得设置 kms:EnableKeyRotation 权限给管理员组,后面做自动轮换要用。

3.2 AWS CLI 创建:摆脱鼠标,效率翻倍

如果你管理几十个账号,Console 点来点去会疯掉。CLI 命令一次执行,又快又准。我当年做大规模密钥迁移时,写了个 shell 脚本批量创建了 200 多个 CMK,全程没出过岔子——当然,前提是参数要对。

基本命令

# 创建对称 CMK,使用 AWS 托管的密钥材料(默认)
aws kms create-key \
    --key-usage ENCRYPT_DECRYPT \
    --key-spec SYMMETRIC_DEFAULT \
    --description "用于 S3 SSE-KMS 的 CMK" \
    --tags TagKey=Environment,TagValue=Prod \
    --policy file://key-policy.json

解密一下参数:

  • --key-usage:ENCRYPT_DECRYPT 是最常见的,要是用于签名验签用 SIGN_VERIFY。
  • --key-spec:对称密钥固定 SYMMETRIC_DEFAULT。异步用 RSA_2048 等等。
  • --policy:推荐从文件加载策略,比 inline 长串好维护。
  • --tags:不能少,特别是做成本分配时。

创建完密钥,你会得到一个 KeyId(UUID)。通常我们还要绑定别名,方便使用:

aws kms create-alias \
    --alias-name alias/myapp-prod-key \
    --target-key-id <YourKeyId>
⚠️ 避坑:CLI 创建 CMK 时 不会自动添加任何权限(除了 root)。你必须显式在 policy 里授权给需要的 IAM 角色或用户。我曾经有次忘了写策略,结果创建完密钥后所有 API 调用都被 Deny,排查了半天才发现是策略缺失——记住,KMS 对未授权的请求默认拒绝。

另外,如果你要创建带有外部密钥材料的 CMK,需要多一步:

# 先创建没有密钥材料的 CMK
aws kms create-key \
    --key-usage ENCRYPT_DECRYPT \
    --key-spec SYMMETRIC_DEFAULT \
    --origin EXTERNAL \
    --policy file://key-policy.json

# 然后通过 GetParametersForImport 获取包装公钥,再导入密钥材料(后续章节细讲)

3.3 CloudFormation 创建:基础设施即代码的优雅解法

我最喜欢用 CloudFormation 创建 CMK,因为它把整个生命周期都纳入了模板。想想看,一个 aws kms create-key 你跑完还要单独配别名、标签,而 CloudFormation 一个 YAML 全部搞定,还自动处理依赖和回滚。

下面是一个标准模板,你可以直接拿去用:

AWSTemplateFormatVersion: '2010-09-09'
Resources:
  MyCMK:
    Type: AWS::KMS::Key
    Properties:
      KeyUsage: ENCRYPT_DECRYPT
      KeySpec: SYMMETRIC_DEFAULT
      Description: "CloudFormation 创建的 CMK"
      Enabled: true
      EnableKeyRotation: true    # 自动轮换!每年一次
      KeyPolicy:
        Version: "2012-10-17"
        Statement:
          - Sid: "Enable IAM User Permissions"
            Effect: Allow
            Principal:
              AWS: !Sub "arn:aws:iam::${AWS::AccountId}:root"
            Action: "kms:*"
            Resource: "*"
          - Sid: "Allow S3 Service to Use Key"
            Effect: Allow
            Principal:
              Service: s3.amazonaws.com
            Action:
              - "kms:Encrypt"
              - "kms:Decrypt"
              - "kms:ReEncrypt*"
              - "kms:GenerateDataKey"
              - "kms:DescribeKey"
            Resource: "*"
      Tags:
        - Key: Environment
          Value: Production

  MyKeyAlias:
    Type: AWS::KMS::Alias
    Properties:
      AliasName: "alias/myapp-prod-key"
      TargetKeyId: !Ref MyCMK

关键点解读

参数/属性说明注意事项
EnableKeyRotation: true开启自动轮换(每年一次)仅对 AWS 托管密钥材料有效;外部导入的密钥不支持此属性
KeyPolicy必须至少包含 root 用户的完全权限,否则后续你无法管理写错策略会导致整个密钥不可用,部署后修改策略需要额外操作
TargetKeyId: !Ref MyCMK引用 CMK 资源,自动建立依赖别名是独立资源,不能直接在 CMK 内部设置 Alias

📌 实战建议:我建议把所有 CMK 和相关资源(别名、策略、权限)放在一个嵌套堆栈中,统一版本管理。每次改动都通过 CloudFormation ChangeSet 审查效果,避免直接修改策略导致权限错乱。

部署命令简单:

aws cloudformation deploy \
    --template-file cmk-template.yaml \
    --stack-name my-cmk-stack \
    --capabilities CAPABILITY_IAM

注意要加 CAPABILITY_IAM,因为密钥策略里定义了 IAM 权限,CloudFormation 需要你确认这是有意为之。

💡 小技巧:在 CloudFormation 中,如果你想从外部文件加载策略(比如 policy.json),可以用 AWS::Include 或直接 Fn::Sub 引用参数。但我个人更倾向把策略直接写在模板里,这样模板自己就是完整的,别人 review 也方便。

三种方式对比,选哪个?

我把常见场景列了个表,你参考一下:

场景推荐方式原因
首次学习、快速测试Console零门槛,随时调整
自动化部署、CI/CDCLI简单命令,可集成脚本
多账号、多环境、基础设施即代码CloudFormation声明式、可版本控制、可审计
需要外部密钥材料CLI 或 ConsoleCloudFormation 目前不直接支持导入密钥材料的过程

最后唠叨一句:不管用哪种方式,密钥策略千万不能出错。我建议创建一个 CMK 后,先用 aws kms describe-key 和 aws kms get-key-policy 验证策略是否如预期。别嫌麻烦,出过一次生产事故就知道它的价值了。