在 AWS CloudFormation 中自动实施密钥创建 - AWS Secrets Manager
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门

如果我们为英文版本指南提供翻译,那么如果存在任何冲突,将以英文版本指南为准。在提供翻译时使用机器翻译。

在 AWS CloudFormation 中自动实施密钥创建

通过使用 AWS CloudFormation 模板,您可以为您的 AWS 云基础设施中的数据库和服务资源自动创建密钥。

您可以使用 AWS CloudFormation 自动创建您的云基础设施。您可以使用 JSON 或 YAML 创建模板以定义项目所需的资源。然后,AWS CloudFormation 处理模板并构建定义的资源。这使您能够在需要时轻松地重新创建基础设施的新副本。例如,您可以复制测试基础设施来创建公有版本。您还可以轻松将基础设施作为简单的文本文件共享,从而使其他人无需手动干预即可复制资源。

您可以使用 CloudFormer 将现有资源集的所有详细信息捕获到 AWS CloudFormation 模板中。

Secrets Manager 提供了以下资源类型,以便您能够创建密钥作为 AWS CloudFormation 模板的一部分。有关在 AWS CloudFormation 模板中配置每种资源类型的详细信息,请选择资源类型名称以链接到 AWS CloudFormation 用户指南

  • AWS::SecretsManager::Secret – 创建密钥并将其存储在 Secrets Manager 中。您可以指定一个密码,或者让 Secrets Manager 为您生成一个密码。您还可以创建一个空密钥,并以后使用 SecretString. 参数更新该密钥。

  • AWS::SecretsManager::ResourcePolicy – 创建基于资源的策略并将其附加到指定密钥。基于资源的策略控制谁可以对密钥执行操作。

  • AWS::SecretsManager::RotationSchedule – 配置密钥以使用指定的 Lambda 轮换函数执行自动定期轮换。

  • AWS::SecretsManager::SecretTargetAttachment – 在创建密钥后,如果在创建服务或数据库时引用该密钥以访问凭证,该资源类型将返回并完成密钥配置。Secrets Manager 为密钥配置使轮换正常工作所需的服务或数据库详细信息。例如,对于 Amazon RDS 数据库实例,Secrets Manager 将连接详细信息和数据库引擎类型作为条目添加到密钥的 SecureString 属性中。

Examples

以下示例模板创建一个密钥,并将密钥中的凭证作为主用户和密码以创建一个 Amazon RDS MySQL 数据库实例。该密钥附加了基于资源的策略,以指定密钥的访问权限。该模板还创建 Lambda 轮换函数并将密钥配置为每 30 天自动轮换一次。

注意

JSON 规范不支持注释。有关注释,请参阅此页面上后面的 YAML 版本。

注意

如果部署 Aurora PostgreSQL 数据库,则必须创建除 admin 之外的用户名。admin" 是一个保留关键字,您无法使用该用户名创建数据库。

JSON

{ "Transform": "AWS::SecretsManager-2020-07-23", "Description": "This is an example template to demonstrate CloudFormation resources for Secrets Manager", "Resources": { "TestVPC": { "Type": "AWS::EC2::VPC", "Properties": { "CidrBlock": "10.0.0.0/16", "EnableDnsHostnames": true, "EnableDnsSupport": true } }, "TestSubnet01": { "Type": "AWS::EC2::Subnet", "Properties": { "CidrBlock": "10.0.96.0/19", "AvailabilityZone": { "Fn::Select": [ "0", { "Fn::GetAZs": { "Ref": "AWS::Region" } } ] }, "VpcId": { "Ref": "TestVPC" } } }, "TestSubnet02": { "Type": "AWS::EC2::Subnet", "Properties": { "CidrBlock": "10.0.128.0/19", "AvailabilityZone": { "Fn::Select": [ "1", { "Fn::GetAZs": { "Ref": "AWS::Region" } } ] }, "VpcId": { "Ref": "TestVPC" } } }, "SecretsManagerVPCEndpoint": { "Type": "AWS::EC2::VPCEndpoint", "Properties": { "SubnetIds": [ { "Ref": "TestSubnet01" }, { "Ref": "TestSubnet02" } ], "SecurityGroupIds": [ { "Fn::GetAtt": [ "TestVPC", "DefaultSecurityGroup" ] } ], "VpcEndpointType": "Interface", "ServiceName": { "Fn::Sub": "com.amazonaws.${AWS::Region}.secretsmanager" }, "PrivateDnsEnabled": true, "VpcId": { "Ref": "TestVPC" } } }, "MyRDSInstanceRotationSecret": { "Type": "AWS::SecretsManager::Secret", "Properties": { "Description": "This is my rds instance secret", "GenerateSecretString": { "SecretStringTemplate": "{\"username\": \"admin\"}", "GenerateStringKey": "password", "PasswordLength": 16, "ExcludeCharacters": "\"@/\\" }, "Tags": [ { "Key": "AppName", "Value": "MyApp" } ] } }, "MyDBInstance": { "Type": "AWS::RDS::DBInstance", "Properties": { "AllocatedStorage": 20, "DBInstanceClass": "db.t2.micro", "Engine": "mysql", "DBSubnetGroupName": { "Ref": "MyDBSubnetGroup" }, "MasterUsername": { "Fn::Sub": "{{resolve:secretsmanager:${MyRDSInstanceRotationSecret}::username}}" }, "MasterUserPassword": { "Fn::Sub": "{{resolve:secretsmanager:${MyRDSInstanceRotationSecret}::password}}" }, "BackupRetentionPeriod": 0, "VPCSecurityGroups": [ { "Fn::GetAtt": [ "TestVPC", "DefaultSecurityGroup" ] } ] } }, "MyDBSubnetGroup": { "Type": "AWS::RDS::DBSubnetGroup", "Properties": { "DBSubnetGroupDescription": "Test Group", "SubnetIds": [ { "Ref": "TestSubnet01" }, { "Ref": "TestSubnet02" } ] } }, "SecretRDSInstanceAttachment": { "Type": "AWS::SecretsManager::SecretTargetAttachment", "Properties": { "SecretId": { "Ref": "MyRDSInstanceRotationSecret" }, "TargetId": { "Ref": "MyDBInstance" }, "TargetType": "AWS::RDS::DBInstance" } }, "MySecretRotationSchedule": { "Type": "AWS::SecretsManager::RotationSchedule", "DependsOn": "SecretRDSInstanceAttachment", "Properties": { "SecretId": { "Ref": "MyRDSInstanceRotationSecret" }, "HostedRotationLambda": { "RotationType": "MySQLSingleUser", "RotationLambdaName": "SecretsManagerRotation", "VpcSecurityGroupIds": { "Fn::GetAtt": [ "TestVPC", "DefaultSecurityGroup" ] }, "VpcSubnetIds": { "Fn::Join": [ ",", [ { "Ref": "TestSubnet01" }, { "Ref": "TestSubnet02" } ] ] } }, "RotationRules": { "AutomaticallyAfterDays": 30 } } } } }

YAML

Transform: AWS::SecretsManager-2020-07-23 Description: "This is an example template to demonstrate CloudFormation resources for Secrets Manager" Resources: #This is the VPC that the rotation Lambda and the RDS instance will be placed in TestVPC: Type: AWS::EC2::VPC Properties: CidrBlock: 10.0.0.0/16 EnableDnsHostnames: true EnableDnsSupport: true # Subnet that the rotation Lambda and the RDS instance will be placed in TestSubnet01: Type: AWS::EC2::Subnet Properties: CidrBlock: 10.0.96.0/19 AvailabilityZone: Fn::Select: - '0' - Fn::GetAZs: {Ref: 'AWS::Region'} VpcId: Ref: TestVPC TestSubnet02: Type: AWS::EC2::Subnet Properties: CidrBlock: 10.0.128.0/19 AvailabilityZone: Fn::Select: - '1' - Fn::GetAZs: {Ref: 'AWS::Region'} VpcId: Ref: TestVPC #VPC endpoint that will enable the rotation Lambda to make api calls to Secrets Manager SecretsManagerVPCEndpoint: Type: AWS::EC2::VPCEndpoint Properties: SubnetIds: - Ref: TestSubnet01 - Ref: TestSubnet02 SecurityGroupIds: - !GetAtt TestVPC.DefaultSecurityGroup VpcEndpointType: 'Interface' ServiceName: !Sub "com.amazonaws.${AWS::Region}.secretsmanager" PrivateDnsEnabled: true VpcId: Ref: TestVPC #This is a Secret resource with a randomly generated password in its SecretString JSON. MyRDSInstanceRotationSecret: Type: AWS::SecretsManager::Secret Properties: Description: 'This is my rds instance secret' GenerateSecretString: SecretStringTemplate: '{"username": "admin"}' GenerateStringKey: 'password' PasswordLength: 16 ExcludeCharacters: '"@/\' Tags: - Key: AppName Value: MyApp #This is an RDS instance resource. Its master username and password use dynamic references to resolve values from #SecretsManager. The dynamic reference guarantees that CloudFormation will not log or persist the resolved value #We sub the Secret resource's logical id in order to construct the dynamic reference, since the Secret's name is being #generated by CloudFormation MyDBInstance: Type: AWS::RDS::DBInstance Properties: AllocatedStorage: 20 DBInstanceClass: db.t2.micro Engine: mysql DBSubnetGroupName: Ref: MyDBSubnetGroup MasterUsername: !Sub '{{resolve:secretsmanager:${MyRDSInstanceRotationSecret}::username}}' MasterUserPassword: !Sub '{{resolve:secretsmanager:${MyRDSInstanceRotationSecret}::password}}' BackupRetentionPeriod: 0 VPCSecurityGroups: - !GetAtt TestVPC.DefaultSecurityGroup #Database subnet group for the RDS instance MyDBSubnetGroup: Type: AWS::RDS::DBSubnetGroup Properties: DBSubnetGroupDescription: "Test Group" SubnetIds: - Ref: TestSubnet01 - Ref: TestSubnet02 #This is a SecretTargetAttachment resource which updates the referenced Secret resource with properties about #the referenced RDS instance SecretRDSInstanceAttachment: Type: AWS::SecretsManager::SecretTargetAttachment Properties: SecretId: !Ref MyRDSInstanceRotationSecret TargetId: !Ref MyDBInstance TargetType: AWS::RDS::DBInstance #This is a RotationSchedule resource. It configures rotation of password for the referenced secret using a rotation lambda #The first rotation happens at resource creation time, with subsequent rotations scheduled according to the rotation rules #We explicitly depend on the SecretTargetAttachment resource being created to ensure that the secret contains all the #information necessary for rotation to succeed MySecretRotationSchedule: Type: AWS::SecretsManager::RotationSchedule DependsOn: SecretRDSInstanceAttachment Properties: SecretId: !Ref MyRDSInstanceRotationSecret HostedRotationLambda: RotationType: MySQLSingleUser RotationLambdaName: SecretsManagerRotation VpcSecurityGroupIds: !GetAtt TestVPC.DefaultSecurityGroup VpcSubnetIds: Fn::Join: - "," - - Ref: TestSubnet01 - Ref: TestSubnet02 RotationRules: AutomaticallyAfterDays: 30