aws-cloudformation-security
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAWS CloudFormation Security
AWS CloudFormation 安全
Overview
概述
Create secure AWS infrastructure using CloudFormation templates with security best practices. This skill covers encryption with AWS KMS, secrets management with Secrets Manager, secure parameters, IAM least privilege, security groups, TLS/SSL certificates, and defense-in-depth strategies.
遵循安全最佳实践,使用CloudFormation模板创建安全的AWS基础设施。本内容涵盖通过AWS KMS实现加密、通过Secrets Manager管理密钥、安全参数、IAM最小权限原则、安全组、TLS/SSL证书以及纵深防御策略。
When to Use
适用场景
Use this skill when:
- Creating CloudFormation templates with encryption at-rest and in-transit
- Managing secrets and credentials with AWS Secrets Manager
- Configuring AWS KMS for encryption keys
- Implementing secure parameters with SSM Parameter Store
- Creating IAM policies with least privilege
- Configuring security groups and network security
- Implementing secure cross-stack references
- Configuring TLS/SSL for AWS services
- Applying defense-in-depth for infrastructure
在以下场景中使用本内容:
- 创建支持静态和传输中加密的CloudFormation模板
- 使用AWS Secrets Manager管理密钥和凭证
- 为加密密钥配置AWS KMS
- 通过SSM Parameter Store实现安全参数
- 创建遵循最小权限原则的IAM策略
- 配置安全组和网络安全
- 实现安全的跨栈引用
- 为AWS服务配置TLS/SSL
- 为基础设施应用纵深防御策略
CloudFormation Template Structure
CloudFormation模板结构
Base Template with Security Section
包含安全章节的基础模板
yaml
AWSTemplateFormatVersion: 2010-09-09
Description: Secure infrastructure template with encryption and secrets management
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Encryption Settings
Parameters:
- EncryptionKeyArn
- SecretsKmsKeyId
- Label:
default: Security Configuration
Parameters:
- SecurityLevel
- EnableVPCPeering
Parameters:
Environment:
Type: String
Default: dev
AllowedValues:
- dev
- staging
- production
EncryptionKeyArn:
Type: AWS::KMS::Key::Arn
Description: KMS key ARN for encryption
SecretsKmsKeyId:
Type: String
Description: KMS key ID for secrets encryption
Mappings:
SecurityConfig:
dev:
EnableDetailedMonitoring: false
RequireMultiAZ: false
staging:
EnableDetailedMonitoring: true
RequireMultiAZ: false
production:
EnableDetailedMonitoring: true
RequireMultiAZ: true
Conditions:
IsProduction: !Equals [!Ref Environment, production]
EnableEnhancedMonitoring: !Equals [!Ref Environment, production]
Resources:
# Resources will be defined here
Outputs:
SecurityConfigurationOutput:
Description: Security configuration applied
Value: !Ref Environmentyaml
AWSTemplateFormatVersion: 2010-09-09
Description: Secure infrastructure template with encryption and secrets management
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Encryption Settings
Parameters:
- EncryptionKeyArn
- SecretsKmsKeyId
- Label:
default: Security Configuration
Parameters:
- SecurityLevel
- EnableVPCPeering
Parameters:
Environment:
Type: String
Default: dev
AllowedValues:
- dev
- staging
- production
EncryptionKeyArn:
Type: AWS::KMS::Key::Arn
Description: KMS key ARN for encryption
SecretsKmsKeyId:
Type: String
Description: KMS key ID for secrets encryption
Mappings:
SecurityConfig:
dev:
EnableDetailedMonitoring: false
RequireMultiAZ: false
staging:
EnableDetailedMonitoring: true
RequireMultiAZ: false
production:
EnableDetailedMonitoring: true
RequireMultiAZ: true
Conditions:
IsProduction: !Equals [!Ref Environment, production]
EnableEnhancedMonitoring: !Equals [!Ref Environment, production]
Resources:
# Resources will be defined here
Outputs:
SecurityConfigurationOutput:
Description: Security configuration applied
Value: !Ref EnvironmentAWS KMS - Encryption
AWS KMS - 加密
Complete KMS Key with Full Policy
包含完整策略的KMS密钥
yaml
Resources:
# Master KMS Key for application
ApplicationKmsKey:
Type: AWS::KMS::Key
Properties:
Description: "KMS Key for application encryption"
KeyPolicy:
Version: "2012-10-17"
Id: "application-key-policy"
Statement:
# Allow key management to administrators
- Sid: "EnableIAMPolicies"
Effect: Allow
Principal:
AWS: !Sub "arn:aws:iam::${AWS::AccountId}:role/AdminRole"
Action:
- kms:Create*
- kms:Describe*
- kms:Enable*
- kms:List*
- kms:Put*
- kms:Update*
- kms:Revoke*
- kms:Disable*
- kms:Get*
- kms:Delete*
- kms:TagResource
- kms:UntagResource
Resource: "*"
Condition:
StringEquals:
aws:PrincipalOrgID: !Ref OrganizationId
# Allow encryption/decryption for application roles
- Sid: "AllowCryptographicOperations"
Effect: Allow
Principal:
AWS:
- !Sub "arn:aws:iam::${AWS::AccountId}:role/LambdaExecutionRole"
- !Sub "arn:aws:iam::${AWS::AccountId}:role/ECSTaskRole"
Action:
- kms:Encrypt
- kms:Decrypt
- kms:GenerateDataKey*
- kms:ReEncrypt*
Resource: "*"
# Allow key usage for specific services
- Sid: "AllowKeyUsageForSpecificServices"
Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
- ecs.amazonaws.com
- rds.amazonaws.com
Action:
- kms:Encrypt
- kms:Decrypt
- kms:GenerateDataKey*
Resource: "*"
KeyUsage: ENCRYPT_DECRYPT
EnableKeyRotation: true
PendingWindowInDays: 30
# Alias for the key
ApplicationKmsKeyAlias:
Type: AWS::KMS::Alias
Properties:
AliasName: !Sub "alias/application-${Environment}"
TargetKeyId: !Ref ApplicationKmsKey
# KMS Key for S3 bucket encryption
S3KmsKey:
Type: AWS::KMS::Key
Properties:
Description: "KMS Key for S3 bucket encryption"
KeyPolicy:
Version: "2012-10-17"
Statement:
- Sid: "AllowS3Encryption"
Effect: Allow
Principal:
Service: s3.amazonaws.com
Action:
- kms:Encrypt
- kms:Decrypt
- kms:GenerateDataKey*
Resource: "*"
Condition:
StringEquals:
aws:SourceAccount: !Ref AWS::AccountId
# KMS Key for RDS encryption
RdsKmsKey:
Type: AWS::KMS::Key
Properties:
Description: "KMS Key for RDS database encryption"
KeyPolicy:
Version: "2012-10-17"
Statement:
- Sid: "AllowRDSEncryption"
Effect: Allow
Principal:
Service: rds.amazonaws.com
Action:
- kms:Encrypt
- kms:Decrypt
- kms:GenerateDataKey*
Resource: "*"yaml
Resources:
# Master KMS Key for application
ApplicationKmsKey:
Type: AWS::KMS::Key
Properties:
Description: "KMS Key for application encryption"
KeyPolicy:
Version: "2012-10-17"
Id: "application-key-policy"
Statement:
# Allow key management to administrators
- Sid: "EnableIAMPolicies"
Effect: Allow
Principal:
AWS: !Sub "arn:aws:iam::${AWS::AccountId}:role/AdminRole"
Action:
- kms:Create*
- kms:Describe*
- kms:Enable*
- kms:List*
- kms:Put*
- kms:Update*
- kms:Revoke*
- kms:Disable*
- kms:Get*
- kms:Delete*
- kms:TagResource
- kms:UntagResource
Resource: "*"
Condition:
StringEquals:
aws:PrincipalOrgID: !Ref OrganizationId
# Allow encryption/decryption for application roles
- Sid: "AllowCryptographicOperations"
Effect: Allow
Principal:
AWS:
- !Sub "arn:aws:iam::${AWS::AccountId}:role/LambdaExecutionRole"
- !Sub "arn:aws:iam::${AWS::AccountId}:role/ECSTaskRole"
Action:
- kms:Encrypt
- kms:Decrypt
- kms:GenerateDataKey*
- kms:ReEncrypt*
Resource: "*"
# Allow key usage for specific services
- Sid: "AllowKeyUsageForSpecificServices"
Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
- ecs.amazonaws.com
- rds.amazonaws.com
Action:
- kms:Encrypt
- kms:Decrypt
- kms:GenerateDataKey*
Resource: "*"
KeyUsage: ENCRYPT_DECRYPT
EnableKeyRotation: true
PendingWindowInDays: 30
# Alias for the key
ApplicationKmsKeyAlias:
Type: AWS::KMS::Alias
Properties:
AliasName: !Sub "alias/application-${Environment}"
TargetKeyId: !Ref ApplicationKmsKey
# KMS Key for S3 bucket encryption
S3KmsKey:
Type: AWS::KMS::Key
Properties:
Description: "KMS Key for S3 bucket encryption"
KeyPolicy:
Version: "2012-10-17"
Statement:
- Sid: "AllowS3Encryption"
Effect: Allow
Principal:
Service: s3.amazonaws.com
Action:
- kms:Encrypt
- kms:Decrypt
- kms:GenerateDataKey*
Resource: "*"
Condition:
StringEquals:
aws:SourceAccount: !Ref AWS::AccountId
# KMS Key for RDS encryption
RdsKmsKey:
Type: AWS::KMS::Key
Properties:
Description: "KMS Key for RDS database encryption"
KeyPolicy:
Version: "2012-10-17"
Statement:
- Sid: "AllowRDSEncryption"
Effect: Allow
Principal:
Service: rds.amazonaws.com
Action:
- kms:Encrypt
- kms:Decrypt
- kms:GenerateDataKey*
Resource: "*"S3 Bucket with KMS Encryption
启用KMS加密的S3存储桶
yaml
Resources:
EncryptedS3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub "secure-bucket-${AWS::AccountId}-${AWS::Region}"
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: aws:kms
KMSMasterKeyID: !Ref S3KmsKey
BucketKeyEnabled: true
VersioningConfiguration:
Status: Enabled
LifecycleConfiguration:
Rules:
- Id: ArchiveOldVersions
Status: Enabled
NoncurrentVersionExpiration:
NoncurrentDays: 90
Tags:
- Key: Environment
Value: !Ref Environment
- Key: Encrypted
Value: "true"yaml
Resources:
EncryptedS3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub "secure-bucket-${AWS::AccountId}-${AWS::Region}"
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: aws:kms
KMSMasterKeyID: !Ref S3KmsKey
BucketKeyEnabled: true
VersioningConfiguration:
Status: Enabled
LifecycleConfiguration:
Rules:
- Id: ArchiveOldVersions
Status: Enabled
NoncurrentVersionExpiration:
NoncurrentDays: 90
Tags:
- Key: Environment
Value: !Ref Environment
- Key: Encrypted
Value: "true"AWS Secrets Manager
AWS Secrets Manager
Secrets Manager with Automatic Rotation
启用自动轮转的Secrets Manager
yaml
Resources:
# Database credentials secret
DatabaseSecret:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Sub "${AWS::StackName}/database/credentials"
Description: "Database credentials with automatic rotation"
SecretString: !Sub |
{
"username": "${DBUsername}",
"password": "${DBPassword}",
"host": "${DBHost}",
"port": "${DBPort}",
"dbname": "${DBName}",
"engine": "postgresql"
}
KmsKeyId: !Ref SecretsKmsKeyId
# Enable automatic rotation
RotationRules:
AutomaticallyAfterDays: 30
# Rotation Lambda configuration
RotationLambdaARN: !GetAtt SecretRotationFunction.Arn
Tags:
- Key: Environment
Value: !Ref Environment
- Key: ManagedBy
Value: CloudFormation
- Key: RotationEnabled
Value: "true"
# Secret with resource-based policy
ApiSecret:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Sub "${AWS::StackName}/api/keys"
Description: "API keys for external service authentication"
SecretString: !Sub |
{
"api_key": "${ExternalApiKey}",
"api_secret": "${ExternalApiSecret}",
"endpoint": "https://api.example.com"
}
KmsKeyId: !Ref SecretsKmsKeyId
# Resource-based policy for access control
ResourcePolicy:
Version: "2012-10-17"
Statement:
- Sid: "AllowLambdaAccess"
Effect: Allow
Principal:
AWS: !Sub "arn:aws:iam::${AWS::AccountId}:role/LambdaExecutionRole"
Action:
- secretsmanager:GetSecretValue
- secretsmanager:DescribeSecret
Resource: "*"
Condition:
StringEquals:
aws:ResourceTag/Environment: !Ref Environment
- Sid: "DenyUnencryptedAccess"
Effect: Deny
Principal: "*"
Action:
- secretsmanager:GetSecretValue
Resource: "*"
Condition:
StringEquals:
kms:ViaService: !Sub "secretsmanager.${AWS::Region}.amazonaws.com"
StringNotEquals:
kms:EncryptContext: !Sub "secretsmanager:${AWS::StackName}"
# Secret with cross-account access
SharedSecret:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Sub "${AWS::StackName}/shared/credentials"
Description: "Secret shared across accounts"
SecretString: !Sub |
{
"shared_key": "${SharedKey}",
"shared_value": "${SharedValue}"
}
KmsKeyId: !Ref SecretsKmsKeyId
# Cross-account access policy
ResourcePolicy:
Version: "2012-10-17"
Statement:
- Sid: "AllowCrossAccountRead"
Effect: Allow
Principal:
AWS:
- !Sub "arn:aws:iam::${ProductionAccountId}:role/SharedSecretReader"
Action:
- secretsmanager:GetSecretValue
- secretsmanager:DescribeSecret
Resource: "*"yaml
Resources:
# Database credentials secret
DatabaseSecret:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Sub "${AWS::StackName}/database/credentials"
Description: "Database credentials with automatic rotation"
SecretString: !Sub |
{
"username": "${DBUsername}",
"password": "${DBPassword}",
"host": "${DBHost}",
"port": "${DBPort}",
"dbname": "${DBName}",
"engine": "postgresql"
}
KmsKeyId: !Ref SecretsKmsKeyId
# Enable automatic rotation
RotationRules:
AutomaticallyAfterDays: 30
# Rotation Lambda configuration
RotationLambdaARN: !GetAtt SecretRotationFunction.Arn
Tags:
- Key: Environment
Value: !Ref Environment
- Key: ManagedBy
Value: CloudFormation
- Key: RotationEnabled
Value: "true"
# Secret with resource-based policy
ApiSecret:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Sub "${AWS::StackName}/api/keys"
Description: "API keys for external service authentication"
SecretString: !Sub |
{
"api_key": "${ExternalApiKey}",
"api_secret": "${ExternalApiSecret}",
"endpoint": "https://api.example.com"
}
KmsKeyId: !Ref SecretsKmsKeyId
# Resource-based policy for access control
ResourcePolicy:
Version: "2012-10-17"
Statement:
- Sid: "AllowLambdaAccess"
Effect: Allow
Principal:
AWS: !Sub "arn:aws:iam::${AWS::AccountId}:role/LambdaExecutionRole"
Action:
- secretsmanager:GetSecretValue
- secretsmanager:DescribeSecret
Resource: "*"
Condition:
StringEquals:
aws:ResourceTag/Environment: !Ref Environment
- Sid: "DenyUnencryptedAccess"
Effect: Deny
Principal: "*"
Action:
- secretsmanager:GetSecretValue
Resource: "*"
Condition:
StringEquals:
kms:ViaService: !Sub "secretsmanager.${AWS::Region}.amazonaws.com"
StringNotEquals:
kms:EncryptContext: !Sub "secretsmanager:${AWS::StackName}"
# Secret with cross-account access
SharedSecret:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Sub "${AWS::StackName}/shared/credentials"
Description: "Secret shared across accounts"
SecretString: !Sub |
{
"shared_key": "${SharedKey}",
"shared_value": "${SharedValue}"
}
KmsKeyId: !Ref SecretsKmsKeyId
# Cross-account access policy
ResourcePolicy:
Version: "2012-10-17"
Statement:
- Sid: "AllowCrossAccountRead"
Effect: Allow
Principal:
AWS:
- !Sub "arn:aws:iam::${ProductionAccountId}:role/SharedSecretReader"
Action:
- secretsmanager:GetSecretValue
- secretsmanager:DescribeSecret
Resource: "*"SSM Parameter Store with SecureString
使用SecureString的SSM Parameter Store
yaml
Parameters:
# SSM Parameter for database connection
DBCredentialsParam:
Type: AWS::SSM::Parameter::Value<SecureString>
NoEcho: true
Description: Database credentials from SSM Parameter Store
Value: !Sub "/${Environment}/database/credentials"
# SSM Parameter with specific path
ApiKeyParam:
Type: AWS::SSM::Parameter::Value<SecureString>
NoEcho: true
Description: API key for external service
Value: !Sub "/${Environment}/external-api/key"
Resources:
# Lambda function using SSM parameters
SecureLambdaFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: !Sub "${AWS::StackName}-secure-function"
Runtime: python3.11
Handler: handler.handler
Code:
S3Bucket: !Ref CodeBucket
S3Key: lambda/secure-function.zip
Role: !GetAtt LambdaExecutionRole.Arn
Environment:
Variables:
DB_CREDENTIALS_SSM_PATH: !Sub "/${Environment}/database/credentials"
API_KEY_SSM_PATH: !Sub "/${Environment}/external-api/key"yaml
Parameters:
# SSM Parameter for database connection
DBCredentialsParam:
Type: AWS::SSM::Parameter::Value<SecureString>
NoEcho: true
Description: Database credentials from SSM Parameter Store
Value: !Sub "/${Environment}/database/credentials"
# SSM Parameter with specific path
ApiKeyParam:
Type: AWS::SSM::Parameter::Value<SecureString>
NoEcho: true
Description: API key for external service
Value: !Sub "/${Environment}/external-api/key"
Resources:
# Lambda function using SSM parameters
SecureLambdaFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: !Sub "${AWS::StackName}-secure-function"
Runtime: python3.11
Handler: handler.handler
Code:
S3Bucket: !Ref CodeBucket
S3Key: lambda/secure-function.zip
Role: !GetAtt LambdaExecutionRole.Arn
Environment:
Variables:
DB_CREDENTIALS_SSM_PATH: !Sub "/${Environment}/database/credentials"
API_KEY_SSM_PATH: !Sub "/${Environment}/external-api/key"IAM Security - Least Privilege
IAM安全 - 最小权限原则
IAM Role with Granular Policies
包含细粒度策略的IAM角色
yaml
Resources:
# Lambda Execution Role with minimal permissions
LambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${AWS::StackName}-lambda-role"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
Condition:
StringEquals:
aws:SourceAccount: !Ref AWS::AccountId
lambda:SourceFunctionArn: !Ref SecureLambdaFunctionArn
# Permissions boundary for enhanced security
PermissionsBoundary: !Ref PermissionsBoundaryPolicy
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
# Policy for specific secrets access
- PolicyName: SecretsAccessPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- secretsmanager:GetSecretValue
- secretsmanager:DescribeSecret
Resource: !Ref DatabaseSecretArn
Condition:
StringEquals:
secretsmanager:SecretTarget: !Sub "${DatabaseSecretArn}:${DatabaseSecret}"
- Effect: Allow
Action:
- secretsmanager:GetSecretValue
Resource: !Ref ApiSecretArn
# Policy for specific S3 access
- PolicyName: S3AccessPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- s3:GetObject
- s3:PutObject
Resource:
- !Sub "${DataBucket.Arn}/*"
- !Sub "${DataBucket.Arn}"
Condition:
StringEquals:
s3:ResourceAccount: !Ref AWS::AccountId
- Effect: Deny
Action:
- s3:DeleteObject*
Resource:
- !Sub "${DataBucket.Arn}/*"
Condition:
Bool:
aws:MultiFactorAuthPresent: true
# Policy for CloudWatch Logs
- PolicyName: CloudWatchLogsPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: !Sub "${LogGroup.Arn}:*"
Tags:
- Key: Environment
Value: !Ref Environment
- Key: LeastPrivilege
Value: "true"
# Permissions Boundary Policy
PermissionsBoundaryPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
Description: "Permissions boundary for Lambda execution role"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Sid: "DenyAccessToAllExceptSpecified"
Effect: Deny
Action:
- "*"
Resource: "*"
Condition:
StringNotEqualsIfExists:
aws:RequestedRegion:
- !Ref AWS::Region
ArnNotEqualsIfExists:
aws:SourceArn: !Ref AllowedResourceArnsyaml
Resources:
# Lambda Execution Role with minimal permissions
LambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${AWS::StackName}-lambda-role"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
Condition:
StringEquals:
aws:SourceAccount: !Ref AWS::AccountId
lambda:SourceFunctionArn: !Ref SecureLambdaFunctionArn
# Permissions boundary for enhanced security
PermissionsBoundary: !Ref PermissionsBoundaryPolicy
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
# Policy for specific secrets access
- PolicyName: SecretsAccessPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- secretsmanager:GetSecretValue
- secretsmanager:DescribeSecret
Resource: !Ref DatabaseSecretArn
Condition:
StringEquals:
secretsmanager:SecretTarget: !Sub "${DatabaseSecretArn}:${DatabaseSecret}"
- Effect: Allow
Action:
- secretsmanager:GetSecretValue
Resource: !Ref ApiSecretArn
# Policy for specific S3 access
- PolicyName: S3AccessPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- s3:GetObject
- s3:PutObject
Resource:
- !Sub "${DataBucket.Arn}/*"
- !Sub "${DataBucket.Arn}"
Condition:
StringEquals:
s3:ResourceAccount: !Ref AWS::AccountId
- Effect: Deny
Action:
- s3:DeleteObject*
Resource:
- !Sub "${DataBucket.Arn}/*"
Condition:
Bool:
aws:MultiFactorAuthPresent: true
# Policy for CloudWatch Logs
- PolicyName: CloudWatchLogsPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: !Sub "${LogGroup.Arn}:*"
Tags:
- Key: Environment
Value: !Ref Environment
- Key: LeastPrivilege
Value: "true"
# Permissions Boundary Policy
PermissionsBoundaryPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
Description: "Permissions boundary for Lambda execution role"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Sid: "DenyAccessToAllExceptSpecified"
Effect: Deny
Action:
- "*"
Resource: "*"
Condition:
StringNotEqualsIfExists:
aws:RequestedRegion:
- !Ref AWS::Region
ArnNotEqualsIfExists:
aws:SourceArn: !Ref AllowedResourceArnsIAM Policy for Cross-Account Access
用于跨账户访问的IAM策略
yaml
Resources:
# Role for cross-account access
CrossAccountRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${AWS::StackName}-cross-account-role"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
AWS:
- !Sub "arn:aws:iam::${ProductionAccountId}:root"
- !Sub "arn:aws:iam::${StagingAccountId}:role/CrossAccountAccessRole"
Action: sts:AssumeRole
Condition:
StringEquals:
aws:PrincipalAccount: !Ref ProductionAccountId
Bool:
aws:MultiFactorAuthPresent: true
Policies:
- PolicyName: CrossAccountReadOnlyPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- s3:GetObject*
- s3:List*
Resource:
- !Sub "${SharedBucket.Arn}"
- !Sub "${SharedBucket.Arn}/*"
- Effect: Allow
Action:
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
Resource:
- !Sub "${SharedTable.Arn}"
- !Sub "${SharedTable.Arn}/index/*"
- Effect: Deny
Action:
- s3:DeleteObject*
- s3:PutObject*
Resource:
- !Sub "${SharedBucket.Arn}/*"yaml
Resources:
# Role for cross-account access
CrossAccountRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${AWS::StackName}-cross-account-role"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
AWS:
- !Sub "arn:aws:iam::${ProductionAccountId}:root"
- !Sub "arn:aws:iam::${StagingAccountId}:role/CrossAccountAccessRole"
Action: sts:AssumeRole
Condition:
StringEquals:
aws:PrincipalAccount: !Ref ProductionAccountId
Bool:
aws:MultiFactorAuthPresent: true
Policies:
- PolicyName: CrossAccountReadOnlyPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- s3:GetObject*
- s3:List*
Resource:
- !Sub "${SharedBucket.Arn}"
- !Sub "${SharedBucket.Arn}/*"
- Effect: Allow
Action:
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
Resource:
- !Sub "${SharedTable.Arn}"
- !Sub "${SharedTable.Arn}/index/*"
- Effect: Deny
Action:
- s3:DeleteObject*
- s3:PutObject*
Resource:
- !Sub "${SharedBucket.Arn}/*"VPC Security
VPC安全
Security Groups with Restrictive Rules
包含限制性规则的安全组
yaml
Resources:
# Security Group for application
ApplicationSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub "${AWS::StackName}-app-sg"
GroupDescription: "Security group for application tier"
VpcId: !Ref VPCId
Tags:
- Key: Name
Value: !Sub "${AWS::StackName}-app-sg"
- Key: Environment
Value: !Ref Environment
# Inbound rules - only necessary traffic
SecurityGroupIngress:
# HTTP from ALB
- IpProtocol: tcp
FromPort: 80
ToPort: 80
SourceSecurityGroupId: !Ref ALBSecurityGroup
Description: "HTTP from ALB"
# HTTPS from ALB
- IpProtocol: tcp
FromPort: 443
ToPort: 443
SourceSecurityGroupId: !Ref ALBSecurityGroup
Description: "HTTPS from ALB"
# SSH from bastion only (if needed)
- IpProtocol: tcp
FromPort: 22
ToPort: 22
SourceSecurityGroupId: !Ref BastionSecurityGroup
Description: "SSH access from bastion"
# Custom TCP for internal services
- IpProtocol: tcp
FromPort: 8080
ToPort: 8080
SourceSecurityGroupId: !Ref InternalSecurityGroup
Description: "Internal service communication"
# Outbound rules - limited
SecurityGroupEgress:
# HTTPS outbound for API calls
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
Description: "HTTPS outbound"
# DNS outbound
- IpProtocol: udp
FromPort: 53
ToPort: 53
CidrIp: 10.0.0.0/16
Description: "DNS outbound for VPC"
# Security Group for database
DatabaseSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub "${AWS::StackName}-db-sg"
GroupDescription: "Security group for database tier"
VpcId: !Ref VPCId
Tags:
- Key: Name
Value: !Sub "${AWS::StackName}-db-sg"
# Inbound - only from application security group
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 5432
ToPort: 5432
SourceSecurityGroupId: !Ref ApplicationSecurityGroup
Description: "PostgreSQL from application tier"
# Outbound - minimum required
SecurityGroupEgress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
Description: "HTTPS for updates and patches"
# Security Group for ALB
ALBSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub "${AWS::StackName}-alb-sg"
GroupDescription: "Security group for ALB"
VpcId: !Ref VPCId
SecurityGroupIngress:
# HTTP from internet
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
Description: "HTTP from internet"
# HTTPS from internet
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
Description: "HTTPS from internet"
SecurityGroupEgress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
SourceSecurityGroupId: !Ref ApplicationSecurityGroup
Description: "Forward to application"
# VPC Endpoint for Secrets Manager
SecretsManagerVPCEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcId: !Ref VPCId
ServiceName: !Sub "com.amazonaws.${AWS::Region}.secretsmanager"
VpcEndpointType: Interface
Subnets:
- !Ref PrivateSubnet1
- !Ref PrivateSubnet2
SecurityGroups:
- !Ref ApplicationSecurityGroup
PrivateDnsEnabled: trueyaml
Resources:
# Security Group for application
ApplicationSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub "${AWS::StackName}-app-sg"
GroupDescription: "Security group for application tier"
VpcId: !Ref VPCId
Tags:
- Key: Name
Value: !Sub "${AWS::StackName}-app-sg"
- Key: Environment
Value: !Ref Environment
# Inbound rules - only necessary traffic
SecurityGroupIngress:
# HTTP from ALB
- IpProtocol: tcp
FromPort: 80
ToPort: 80
SourceSecurityGroupId: !Ref ALBSecurityGroup
Description: "HTTP from ALB"
# HTTPS from ALB
- IpProtocol: tcp
FromPort: 443
ToPort: 443
SourceSecurityGroupId: !Ref ALBSecurityGroup
Description: "HTTPS from ALB"
# SSH from bastion only (if needed)
- IpProtocol: tcp
FromPort: 22
ToPort: 22
SourceSecurityGroupId: !Ref BastionSecurityGroup
Description: "SSH access from bastion"
# Custom TCP for internal services
- IpProtocol: tcp
FromPort: 8080
ToPort: 8080
SourceSecurityGroupId: !Ref InternalSecurityGroup
Description: "Internal service communication"
# Outbound rules - limited
SecurityGroupEgress:
# HTTPS outbound for API calls
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
Description: "HTTPS outbound"
# DNS outbound
- IpProtocol: udp
FromPort: 53
ToPort: 53
CidrIp: 10.0.0.0/16
Description: "DNS outbound for VPC"
# Security Group for database
DatabaseSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub "${AWS::StackName}-db-sg"
GroupDescription: "Security group for database tier"
VpcId: !Ref VPCId
Tags:
- Key: Name
Value: !Sub "${AWS::StackName}-db-sg"
# Inbound - only from application security group
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 5432
ToPort: 5432
SourceSecurityGroupId: !Ref ApplicationSecurityGroup
Description: "PostgreSQL from application tier"
# Outbound - minimum required
SecurityGroupEgress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
Description: "HTTPS for updates and patches"
# Security Group for ALB
ALBSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub "${AWS::StackName}-alb-sg"
GroupDescription: "Security group for ALB"
VpcId: !Ref VPCId
SecurityGroupIngress:
# HTTP from internet
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
Description: "HTTP from internet"
# HTTPS from internet
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
Description: "HTTPS from internet"
SecurityGroupEgress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
SourceSecurityGroupId: !Ref ApplicationSecurityGroup
Description: "Forward to application"
# VPC Endpoint for Secrets Manager
SecretsManagerVPCEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcId: !Ref VPCId
ServiceName: !Sub "com.amazonaws.${AWS::Region}.secretsmanager"
VpcEndpointType: Interface
Subnets:
- !Ref PrivateSubnet1
- !Ref PrivateSubnet2
SecurityGroups:
- !Ref ApplicationSecurityGroup
PrivateDnsEnabled: trueTLS/SSL Certificates with ACM
使用ACM的TLS/SSL证书
Certificate Manager for API Gateway
用于API Gateway的证书管理器
yaml
Resources:
# SSL Certificate for domain
SSLCertificate:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Ref DomainName
SubjectAlternativeNames:
- !Sub "*.${DomainName}"
- !Ref AdditionalDomainName
ValidationMethod: DNS
DomainValidationOptions:
- DomainName: !Ref DomainName
Route53HostedZoneId: !Ref HostedZoneId
Options:
CertificateTransparencyLoggingPreference: ENABLED
Tags:
- Key: Environment
Value: !Ref Environment
- Key: ManagedBy
Value: CloudFormation
# Certificate for regional API Gateway
RegionalCertificate:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Sub "${Environment}.${DomainName}"
ValidationMethod: DNS
DomainValidationOptions:
- DomainName: !Sub "${Environment}.${DomainName}"
Route53HostedZoneId: !Ref HostedZoneId
# API Gateway with TLS 1.2+
SecureApiGateway:
Type: AWS::ApiGateway::RestApi
Properties:
Name: !Sub "${AWS::StackName}-secure-api"
Description: "Secure REST API with TLS enforcement"
EndpointConfiguration:
Types:
- REGIONAL
MinimumCompressionSize: 1024
# Policy to enforce HTTPS
Policy:
Version: "2012-10-17"
Statement:
- Effect: Deny
Principal: "*"
Action: execute-api:Invoke
Resource: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${SecureApiGateway}/*"
Condition:
Bool:
aws:SecureTransport: "false"
# Custom Domain per API Gateway
ApiGatewayDomain:
Type: AWS::ApiGateway::DomainName
Properties:
DomainName: !Sub "api.${DomainName}"
RegionalCertificateArn: !Ref RegionalCertificate
EndpointConfiguration:
Types:
- REGIONAL
# Route 53 record per dominio API
ApiGatewayDNSRecord:
Type: AWS::Route53::RecordSet
Properties:
Name: !Sub "api.${DomainName}."
Type: A
AliasTarget:
DNSName: !GetAtt ApiGatewayRegionalHostname.RegionalHostname
HostedZoneId: !GetAtt ApiGatewayRegionalHostname.RegionalHostedZoneId
EvaluateTargetHealth: false
HostedZoneId: !Ref HostedZoneId
# Lambda Function URL con AuthType AWS_IAM
SecureLambdaUrl:
Type: AWS::Lambda::Url
Properties:
AuthType: AWS_IAM
TargetFunctionArn: !GetAtt SecureLambdaFunction.Arn
Cors:
AllowCredentials: true
AllowHeaders:
- Authorization
- Content-Type
AllowMethods:
- GET
- POST
AllowOrigins:
- !Ref AllowedOrigin
MaxAge: 86400
InvokeMode: BUFFEREDyaml
Resources:
# SSL Certificate for domain
SSLCertificate:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Ref DomainName
SubjectAlternativeNames:
- !Sub "*.${DomainName}"
- !Ref AdditionalDomainName
ValidationMethod: DNS
DomainValidationOptions:
- DomainName: !Ref DomainName
Route53HostedZoneId: !Ref HostedZoneId
Options:
CertificateTransparencyLoggingPreference: ENABLED
Tags:
- Key: Environment
Value: !Ref Environment
- Key: ManagedBy
Value: CloudFormation
# Certificate for regional API Gateway
RegionalCertificate:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Sub "${Environment}.${DomainName}"
ValidationMethod: DNS
DomainValidationOptions:
- DomainName: !Sub "${Environment}.${DomainName}"
Route53HostedZoneId: !Ref HostedZoneId
# API Gateway with TLS 1.2+
SecureApiGateway:
Type: AWS::ApiGateway::RestApi
Properties:
Name: !Sub "${AWS::StackName}-secure-api"
Description: "Secure REST API with TLS enforcement"
EndpointConfiguration:
Types:
- REGIONAL
MinimumCompressionSize: 1024
# Policy to enforce HTTPS
Policy:
Version: "2012-10-17"
Statement:
- Effect: Deny
Principal: "*"
Action: execute-api:Invoke
Resource: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${SecureApiGateway}/*"
Condition:
Bool:
aws:SecureTransport: "false"
# Custom Domain per API Gateway
ApiGatewayDomain:
Type: AWS::ApiGateway::DomainName
Properties:
DomainName: !Sub "api.${DomainName}"
RegionalCertificateArn: !Ref RegionalCertificate
EndpointConfiguration:
Types:
- REGIONAL
# Route 53 record per dominio API
ApiGatewayDNSRecord:
Type: AWS::Route53::RecordSet
Properties:
Name: !Sub "api.${DomainName}."
Type: A
AliasTarget:
DNSName: !GetAtt ApiGatewayRegionalHostname.RegionalHostname
HostedZoneId: !GetAtt ApiGatewayRegionalHostname.RegionalHostedZoneId
EvaluateTargetHealth: false
HostedZoneId: !Ref HostedZoneId
# Lambda Function URL con AuthType AWS_IAM
SecureLambdaUrl:
Type: AWS::Lambda::Url
Properties:
AuthType: AWS_IAM
TargetFunctionArn: !GetAtt SecureLambdaFunction.Arn
Cors:
AllowCredentials: true
AllowHeaders:
- Authorization
- Content-Type
AllowMethods:
- GET
- POST
AllowOrigins:
- !Ref AllowedOrigin
MaxAge: 86400
InvokeMode: BUFFEREDParameter Security Best Practices
参数安全最佳实践
AWS-Specific Parameter Types with Validation
带验证的AWS特定参数类型
yaml
Parameters:
# AWS-specific types for automatic validation
VPCId:
Type: AWS::EC2::VPC::Id
Description: VPC ID for deployment
SubnetIds:
Type: List<AWS::EC2::Subnet::Id>
Description: Subnet IDs for private subnets
SecurityGroupIds:
Type: List<AWS::EC2::SecurityGroup::Id>
Description: Security group IDs
DatabaseInstanceIdentifier:
Type: AWS::RDS::DBInstance::Identifier
Description: RDS instance identifier
KMSKeyArn:
Type: AWS::KMS::Key::Arn
Description: KMS key ARN for encryption
SecretArn:
Type: AWS::SecretsManager::Secret::Arn
Description: Secrets Manager secret ARN
LambdaFunctionArn:
Type: AWS::Lambda::Function::Arn
Description: Lambda function ARN
# SSM Parameter with secure string
DatabasePassword:
Type: AWS::SSM::Parameter::Value<SecureString>
NoEcho: true
Description: Database password from SSM
# Custom parameters with constraints
DBUsername:
Type: String
Description: Database username
Default: appuser
MinLength: 1
MaxLength: 63
AllowedPattern: "[a-zA-Z][a-zA-Z0-9_]*"
ConstraintDescription: Must start with letter, alphanumeric and underscores only
DBPort:
Type: Number
Description: Database port
Default: 5432
MinValue: 1024
MaxValue: 65535
MaxConnections:
Type: Number
Description: Maximum database connections
Default: 100
MinValue: 10
MaxValue: 65535
EnvironmentName:
Type: String
Description: Deployment environment
Default: dev
AllowedValues:
- dev
- staging
- production
ConstraintDescription: Must be dev, staging, or productionyaml
Parameters:
# AWS-specific types for automatic validation
VPCId:
Type: AWS::EC2::VPC::Id
Description: VPC ID for deployment
SubnetIds:
Type: List<AWS::EC2::Subnet::Id>
Description: Subnet IDs for private subnets
SecurityGroupIds:
Type: List<AWS::EC2::SecurityGroup::Id>
Description: Security group IDs
DatabaseInstanceIdentifier:
Type: AWS::RDS::DBInstance::Identifier
Description: RDS instance identifier
KMSKeyArn:
Type: AWS::KMS::Key::Arn
Description: KMS key ARN for encryption
SecretArn:
Type: AWS::SecretsManager::Secret::Arn
Description: Secrets Manager secret ARN
LambdaFunctionArn:
Type: AWS::Lambda::Function::Arn
Description: Lambda function ARN
# SSM Parameter with secure string
DatabasePassword:
Type: AWS::SSM::Parameter::Value<SecureString>
NoEcho: true
Description: Database password from SSM
# Custom parameters with constraints
DBUsername:
Type: String
Description: Database username
Default: appuser
MinLength: 1
MaxLength: 63
AllowedPattern: "[a-zA-Z][a-zA-Z0-9_]*"
ConstraintDescription: Must start with letter, alphanumeric and underscores only
DBPort:
Type: Number
Description: Database port
Default: 5432
MinValue: 1024
MaxValue: 65535
MaxConnections:
Type: Number
Description: Maximum database connections
Default: 100
MinValue: 10
MaxValue: 65535
EnvironmentName:
Type: String
Description: Deployment environment
Default: dev
AllowedValues:
- dev
- staging
- production
ConstraintDescription: Must be dev, staging, or productionOutputs and Secure Cross-Stack References
输出与安全跨栈引用
Export with Naming Convention
带命名规范的导出
yaml
Outputs:
# Export for cross-stack references
VPCIdExport:
Description: VPC ID for network stack
Value: !Ref VPC
Export:
Name: !Sub "${AWS::StackName}-VPCId"
ApplicationSecurityGroupIdExport:
Description: Application security group ID
Value: !Ref ApplicationSecurityGroup
Export:
Name: !Sub "${AWS::StackName}-AppSecurityGroupId"
DatabaseSecurityGroupIdExport:
Description: Database security group ID
Value: !Ref DatabaseSecurityGroup
Export:
Name: !Sub "${AWS::StackName}-DBSecurityGroupId"
KMSKeyArnExport:
Description: KMS key ARN for encryption
Value: !GetAtt ApplicationKmsKey.Arn
Export:
Name: !Sub "${AWS::StackName}-KMSKeyArn"
DatabaseSecretArnExport:
Description: Database secret ARN
Value: !Ref DatabaseSecret
Export:
Name: !Sub "${AWS::StackName}-DatabaseSecretArn"
SSLCertificateArnExport:
Description: SSL certificate ARN
Value: !Ref SSLCertificate
Export:
Name: !Sub "${AWS::StackName}-SSLCertificateArn"yaml
Outputs:
# Export for cross-stack references
VPCIdExport:
Description: VPC ID for network stack
Value: !Ref VPC
Export:
Name: !Sub "${AWS::StackName}-VPCId"
ApplicationSecurityGroupIdExport:
Description: Application security group ID
Value: !Ref ApplicationSecurityGroup
Export:
Name: !Sub "${AWS::StackName}-AppSecurityGroupId"
DatabaseSecurityGroupIdExport:
Description: Database security group ID
Value: !Ref DatabaseSecurityGroup
Export:
Name: !Sub "${AWS::StackName}-DBSecurityGroupId"
KMSKeyArnExport:
Description: KMS key ARN for encryption
Value: !GetAtt ApplicationKmsKey.Arn
Export:
Name: !Sub "${AWS::StackName}-KMSKeyArn"
DatabaseSecretArnExport:
Description: Database secret ARN
Value: !Ref DatabaseSecret
Export:
Name: !Sub "${AWS::StackName}-DatabaseSecretArn"
SSLCertificateArnExport:
Description: SSL certificate ARN
Value: !Ref SSLCertificate
Export:
Name: !Sub "${AWS::StackName}-SSLCertificateArn"Import from Network Stack
从网络栈导入
yaml
Parameters:
NetworkStackName:
Type: String
Description: Name of the network stack
Resources:
# Import values from network stack
VPCId:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Select [0, !Split [",", !ImportValue !Sub "${NetworkStackName}-VPCcidrs"]]
ApplicationSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub "${AWS::StackName}-app-sg"
VpcId: !ImportValue !Sub "${NetworkStackName}-VPCId"
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
SourceSecurityGroupId: !ImportValue !Sub "${NetworkStackName}-ALBSecurityGroupId"yaml
Parameters:
NetworkStackName:
Type: String
Description: Name of the network stack
Resources:
# Import values from network stack
VPCId:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Select [0, !Split [",", !ImportValue !Sub "${NetworkStackName}-VPCcidrs"]]
ApplicationSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub "${AWS::StackName}-app-sg"
VpcId: !ImportValue !Sub "${NetworkStackName}-VPCId"
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
SourceSecurityGroupId: !ImportValue !Sub "${NetworkStackName}-ALBSecurityGroupId"CloudWatch Logs Encryption
CloudWatch日志加密
Log Group with KMS Encryption
启用KMS加密的日志组
yaml
Resources:
# Encrypted CloudWatch Log Group
EncryptedLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub "/aws/lambda/${AWS::StackName}-function"
RetentionInDays: 30
KmsKeyId: !Ref ApplicationKmsKey
# Data protection policy
LogGroupClass: STANDARD
Tags:
- Key: Environment
Value: !Ref Environment
- Key: Encrypted
Value: "true"
# Metric Filter for security events
SecurityEventMetricFilter:
Type: AWS::Logs::MetricFilter
Properties:
LogGroupName: !Ref EncryptedLogGroup
FilterPattern: '[ERROR, WARNING, "Access Denied", "Unauthorized"]'
MetricTransformations:
- MetricValue: "1"
MetricNamespace: !Sub "${AWS::StackName}/Security"
MetricName: SecurityEvents
# Alarm for security errors
SecurityAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName: !Sub "${AWS::StackName}-security-errors"
AlarmDescription: Alert on security-related errors
MetricName: SecurityEvents
Namespace: !Sub "${AWS::StackName}/Security"
Statistic: Sum
Period: 60
EvaluationPeriods: 5
Threshold: 1
ComparisonOperator: GreaterThanThreshold
AlarmActions:
- !Ref SecurityAlertTopic
# SNS Topic for security alerts
SecurityAlertTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: !Sub "${AWS::StackName}-security-alerts"yaml
Resources:
# Encrypted CloudWatch Log Group
EncryptedLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub "/aws/lambda/${AWS::StackName}-function"
RetentionInDays: 30
KmsKeyId: !Ref ApplicationKmsKey
# Data protection policy
LogGroupClass: STANDARD
Tags:
- Key: Environment
Value: !Ref Environment
- Key: Encrypted
Value: "true"
# Metric Filter for security events
SecurityEventMetricFilter:
Type: AWS::Logs::MetricFilter
Properties:
LogGroupName: !Ref EncryptedLogGroup
FilterPattern: '[ERROR, WARNING, "Access Denied", "Unauthorized"]'
MetricTransformations:
- MetricValue: "1"
MetricNamespace: !Sub "${AWS::StackName}/Security"
MetricName: SecurityEvents
# Alarm for security errors
SecurityAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName: !Sub "${AWS::StackName}-security-errors"
AlarmDescription: Alert on security-related errors
MetricName: SecurityEvents
Namespace: !Sub "${AWS::StackName}/Security"
Statistic: Sum
Period: 60
EvaluationPeriods: 5
Threshold: 1
ComparisonOperator: GreaterThanThreshold
AlarmActions:
- !Ref SecurityAlertTopic
# SNS Topic for security alerts
SecurityAlertTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: !Sub "${AWS::StackName}-security-alerts"Defense in Depth
纵深防御
Stack with Multiple Security Layers
包含多层安全防护的栈
yaml
AWSTemplateFormatVersion: 2010-09-09
Description: Defense in depth security architecture
Resources:
# Layer 1: Network Security - Security Groups
WebTierSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: "Web tier security group"
VpcId: !Ref VPCId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
Description: "HTTPS from internet"
AppTierSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: "App tier security group"
VpcId: !Ref VPCId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 8080
ToPort: 8080
SourceSecurityGroupId: !Ref WebTierSecurityGroup
# Layer 2: Encryption - KMS
DataEncryptionKey:
Type: AWS::KMS::Key
Properties:
Description: "Data encryption key"
KeyPolicy:
Version: "2012-10-17"
Statement:
- Sid: "EnableIAMPoliciesForKeyManagement"
Effect: Allow
Principal:
AWS: !Sub "arn:aws:iam::${AWS::AccountId}:role/AdminRole"
Action: kms:*
Resource: "*"
- Sid: "AllowEncryptionOperations"
Effect: Allow
Principal:
AWS: !Sub "arn:aws:iam::${AWS::AccountId}:role/AppRole"
Action:
- kms:Encrypt
- kms:Decrypt
Resource: "*"
# Layer 3: Secrets Management
ApplicationSecret:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Sub "${AWS::StackName}/application/credentials"
SecretString: "{}"
KmsKeyId: !Ref DataEncryptionKey
# Layer 4: IAM Least Privilege
ApplicationRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${AWS::StackName}-app-role"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: ecs.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: MinimalSecretsAccess
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- secretsmanager:GetSecretValue
Resource: !Ref ApplicationSecret
# Layer 5: Logging and Monitoring
AuditLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub "/aws/${AWS::StackName}/audit"
RetentionInDays: 365
KmsKeyId: !Ref DataEncryptionKey
# Layer 6: WAF for API protection
WebACL:
Type: AWS::WAFv2::WebACL
Properties:
Name: !Sub "${AWS::StackName}-waf"
Scope: REGIONAL
DefaultAction:
Allow:
CustomRequestHandling:
InsertHeaders:
- Name: X-Frame-Options
Value: DENY
Rules:
- Name: BlockSQLInjection
Priority: 1
Statement:
SqliMatchStatement:
FieldToMatch:
Body:
OversizeHandling: CONTINUE
SensitivityLevel: HIGH
Action:
Block:
CustomResponse:
ResponseCode: 403
ResponseBody: "Request blocked due to SQL injection"
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: BlockSQLInjection
- Name: BlockXSS
Priority: 2
Statement:
XssMatchStatement:
FieldToMatch:
QueryString:
OversizeHandling: CONTINUE
Action:
Block:
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: BlockXSS
- Name: RateLimit
Priority: 3
Statement:
RateBasedStatement:
Limit: 2000
EvaluationWindowSec: 60
Action:
Block:
CustomResponse:
ResponseCode: 429
ResponseBody: "Too many requests"
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: RateLimit
VisibilityConfig:
CloudWatchMetricsEnabled: true
MetricName: !Sub "${AWS::StackName}-WebACL"
SampledRequestsEnabled: trueyaml
AWSTemplateFormatVersion: 2010-09-09
Description: Defense in depth security architecture
Resources:
# Layer 1: Network Security - Security Groups
WebTierSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: "Web tier security group"
VpcId: !Ref VPCId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
Description: "HTTPS from internet"
AppTierSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: "App tier security group"
VpcId: !Ref VPCId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 8080
ToPort: 8080
SourceSecurityGroupId: !Ref WebTierSecurityGroup
# Layer 2: Encryption - KMS
DataEncryptionKey:
Type: AWS::KMS::Key
Properties:
Description: "Data encryption key"
KeyPolicy:
Version: "2012-10-17"
Statement:
- Sid: "EnableIAMPoliciesForKeyManagement"
Effect: Allow
Principal:
AWS: !Sub "arn:aws:iam::${AWS::AccountId}:role/AdminRole"
Action: kms:*
Resource: "*"
- Sid: "AllowEncryptionOperations"
Effect: Allow
Principal:
AWS: !Sub "arn:aws:iam::${AWS::AccountId}:role/AppRole"
Action:
- kms:Encrypt
- kms:Decrypt
Resource: "*"
# Layer 3: Secrets Management
ApplicationSecret:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Sub "${AWS::StackName}/application/credentials"
SecretString: "{}"
KmsKeyId: !Ref DataEncryptionKey
# Layer 4: IAM Least Privilege
ApplicationRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${AWS::StackName}-app-role"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: ecs.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: MinimalSecretsAccess
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- secretsmanager:GetSecretValue
Resource: !Ref ApplicationSecret
# Layer 5: Logging and Monitoring
AuditLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub "/aws/${AWS::StackName}/audit"
RetentionInDays: 365
KmsKeyId: !Ref DataEncryptionKey
# Layer 6: WAF for API protection
WebACL:
Type: AWS::WAFv2::WebACL
Properties:
Name: !Sub "${AWS::StackName}-waf"
Scope: REGIONAL
DefaultAction:
Allow:
CustomRequestHandling:
InsertHeaders:
- Name: X-Frame-Options
Value: DENY
Rules:
- Name: BlockSQLInjection
Priority: 1
Statement:
SqliMatchStatement:
FieldToMatch:
Body:
OversizeHandling: CONTINUE
SensitivityLevel: HIGH
Action:
Block:
CustomResponse:
ResponseCode: 403
ResponseBody: "Request blocked due to SQL injection"
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: BlockSQLInjection
- Name: BlockXSS
Priority: 2
Statement:
XssMatchStatement:
FieldToMatch:
QueryString:
OversizeHandling: CONTINUE
Action:
Block:
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: BlockXSS
- Name: RateLimit
Priority: 3
Statement:
RateBasedStatement:
Limit: 2000
EvaluationWindowSec: 60
Action:
Block:
CustomResponse:
ResponseCode: 429
ResponseBody: "Too many requests"
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: RateLimit
VisibilityConfig:
CloudWatchMetricsEnabled: true
MetricName: !Sub "${AWS::StackName}-WebACL"
SampledRequestsEnabled: trueBest Practices
最佳实践
Encryption
加密
- Always use KMS with customer-managed keys for sensitive data
- Enable automatic key rotation (max 365 days)
- Use S3 bucket keys to reduce KMS costs
- Encrypt CloudWatch Logs with KMS
- Implement envelope encryption for large data
- 对于敏感数据,始终使用带客户管理密钥的KMS
- 启用自动密钥轮转(最长365天)
- 使用S3存储桶密钥降低KMS成本
- 使用KMS加密CloudWatch日志
- 对大型数据实施信封加密
Secrets Management
密钥管理
- Use Secrets Manager for automatic rotation
- Reference secrets via ARN, not hard-coded
- Use resource-based policies for granular access
- Implement encryption context for auditing
- Limit access with IAM conditions
- 使用Secrets Manager实现自动轮转
- 通过ARN引用密钥,而非硬编码
- 使用基于资源的策略实现细粒度访问控制
- 为审计实现加密上下文
- 使用IAM条件限制访问
IAM Security
IAM安全
- Apply least privilege in all policies
- Use permissions boundaries to limit escalation
- Enable MFA for administrative roles
- Implement condition keys for region/endpoint
- Regular audit with IAM Access Analyzer
- 在所有策略中应用最小权限原则
- 使用权限边界限制权限提升
- 为管理员角色启用MFA
- 基于区域/端点实现条件键
- 使用IAM Access Analyzer定期审计
Network Security
网络安全
- Security groups with minimal rules
- Deny default outbound where possible
- Use VPC endpoints for AWS services
- Implement private subnets for backend tiers
- Use Network ACLs as additional layer
- 安全组使用最小规则
- 尽可能拒绝默认出站流量
- 为AWS服务使用VPC端点
- 为后端层使用私有子网
- 使用网络ACL作为额外防护层
TLS/SSL
TLS/SSL
- Use ACM for managed certificates
- Enforce HTTPS with resource policies
- Configure minimum TLS 1.2
- Use HSTS headers
- Renew certificates before expiration
- 使用ACM管理证书
- 通过资源策略强制使用HTTPS
- 配置最低TLS 1.2版本
- 使用HSTS头部
- 在证书过期前进行续订
Monitoring
监控
- Enable CloudTrail for audit trail
- Create metrics for security events
- Configure alarms for suspicious activity
- Appropriate log retention (min 90 days)
- Use GuardDuty for threat detection
- 启用CloudTrail以生成审计日志
- 为安全事件创建指标
- 为可疑活动配置告警
- 设置合适的日志保留期限(最少90天)
- 使用GuardDuty进行威胁检测
Related Resources
相关资源
Additional Files
附加文件
For complete details on resources and their properties, see:
- REFERENCE.md - Detailed reference guide for all CloudFormation security resources
- EXAMPLES.md - Complete production-ready examples for security scenarios
如需了解资源及其属性的完整详情,请查看:
- REFERENCE.md - 所有CloudFormation安全资源的详细参考指南
- EXAMPLES.md - 适用于安全场景的完整生产级示例
CloudFormation Stack Management Best Practices
CloudFormation栈管理最佳实践
Stack Policies
栈策略
Stack Policies prevent accidental updates to critical infrastructure resources. Use them to protect production resources from unintended modifications.
yaml
Resources:
ProductionStackPolicy:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: !Sub "https://${BucketName}.s3.amazonaws.com/production-stack.yaml"
StackPolicyBody:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action: Update:*
Principal: "*"
Resource: "*"
- Effect: Deny
Action:
- Update:Replace
- Update:Delete
Principal: "*"
Resource:
- LogicalResourceId/ProductionDatabase
- LogicalResourceId/ProductionKmsKey
Condition:
StringEquals:
aws:RequestedRegion:
- us-east-1
- us-west-2
# Inline stack policy for sensitive resources
SensitiveResourcesPolicy:
Type: AWS::CloudFormation::StackPolicy
Properties:
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Deny
Action: Update:*
Principal: "*"
Resource: "*"
Condition:
StringEquals:
aws:ResourceTag/Environment: production
Not:
StringEquals:
aws:username: security-admin栈策略可防止对关键基础设施资源进行意外更新。使用它们保护生产资源免受非预期修改。
yaml
Resources:
ProductionStackPolicy:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: !Sub "https://${BucketName}.s3.amazonaws.com/production-stack.yaml"
StackPolicyBody:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action: Update:*
Principal: "*"
Resource: "*"
- Effect: Deny
Action:
- Update:Replace
- Update:Delete
Principal: "*"
Resource:
- LogicalResourceId/ProductionDatabase
- LogicalResourceId/ProductionKmsKey
Condition:
StringEquals:
aws:RequestedRegion:
- us-east-1
- us-west-2
# Inline stack policy for sensitive resources
SensitiveResourcesPolicy:
Type: AWS::CloudFormation::StackPolicy
Properties:
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Deny
Action: Update:*
Principal: "*"
Resource: "*"
Condition:
StringEquals:
aws:ResourceTag/Environment: production
Not:
StringEquals:
aws:username: security-adminTermination Protection
终止保护
Enable termination protection to prevent accidental deletion of production stacks. This adds a safety layer for critical infrastructure.
yaml
Resources:
# Production stack with termination protection
ProductionDatabaseStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: !Sub "https://${BucketName}.s3.amazonaws.com/database.yaml"
TerminationProtection: true
Parameters:
Environment: production
InstanceClass: db.r6g.xlarge
MultiAZ: true
# Stack with conditional termination protection
ApplicationStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: !Sub "https://${BucketName}.s3.amazonaws.com/application.yaml"
TerminationProtection: !If [IsProduction, true, false]
Parameters:
Environment: !Ref Environment启用终止保护以防止意外删除生产栈。这为关键基础设施添加了一层安全防护。
yaml
Resources:
# Production stack with termination protection
ProductionDatabaseStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: !Sub "https://${BucketName}.s3.amazonaws.com/database.yaml"
TerminationProtection: true
Parameters:
Environment: production
InstanceClass: db.r6g.xlarge
MultiAZ: true
# Stack with conditional termination protection
ApplicationStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: !Sub "https://${BucketName}.s3.amazonaws.com/application.yaml"
TerminationProtection: !If [IsProduction, true, false]
Parameters:
Environment: !Ref EnvironmentDrift Detection
漂移检测
Detect configuration drift in your CloudFormation stacks to identify unauthorized or unexpected changes.
yaml
Resources:
# Custom resource for drift detection
DriftDetectionFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: !Sub "${AWS::StackName}-drift-detector"
Runtime: python3.11
Handler: drift_detector.handler
Role: !GetAtt DriftDetectionRole.Arn
Code:
S3Bucket: !Ref CodeBucket
S3Key: lambda/drift-detector.zip
Environment:
Variables:
STACK_NAME: !Ref StackName
SNS_TOPIC_ARN: !Ref DriftAlertTopic
Timeout: 300
# Scheduled drift detection
DriftDetectionSchedule:
Type: AWS::Events::Rule
Properties:
Name: !Sub "${AWS::StackName}-drift-schedule"
ScheduleExpression: rate(1 day)
State: ENABLED
Targets:
- Arn: !GetAtt DriftDetectionFunction.Arn
Id: DriftDetectionFunction
# Permission for EventBridge to invoke Lambda
DriftDetectionPermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !Ref DriftDetectionFunction
Action: lambda:InvokeFunction
Principal: events.amazonaws.com
SourceArn: !GetAtt DriftDetectionSchedule.Arn
# SNS topic for drift alerts
DriftAlertTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: !Sub "${AWS::StackName}-drift-alerts"检测CloudFormation栈中的配置漂移,以识别未授权或意外变更。
yaml
Resources:
# Custom resource for drift detection
DriftDetectionFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: !Sub "${AWS::StackName}-drift-detector"
Runtime: python3.11
Handler: drift_detector.handler
Role: !GetAtt DriftDetectionRole.Arn
Code:
S3Bucket: !Ref CodeBucket
S3Key: lambda/drift-detector.zip
Environment:
Variables:
STACK_NAME: !Ref StackName
SNS_TOPIC_ARN: !Ref DriftAlertTopic
Timeout: 300
# Scheduled drift detection
DriftDetectionSchedule:
Type: AWS::Events::Rule
Properties:
Name: !Sub "${AWS::StackName}-drift-schedule"
ScheduleExpression: rate(1 day)
State: ENABLED
Targets:
- Arn: !GetAtt DriftDetectionFunction.Arn
Id: DriftDetectionFunction
# Permission for EventBridge to invoke Lambda
DriftDetectionPermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !Ref DriftDetectionFunction
Action: lambda:InvokeFunction
Principal: events.amazonaws.com
SourceArn: !GetAtt DriftDetectionSchedule.Arn
# SNS topic for drift alerts
DriftAlertTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: !Sub "${AWS::StackName}-drift-alerts"Drift Detection Python Handler
漂移检测Python处理程序
python
import boto3
import json
def handler(event, context):
cloudformation = boto3.client('cloudformation')
sns = boto3.client('sns')
stack_name = event.get('STACK_NAME', 'my-production-stack')
topic_arn = event.get('SNS_TOPIC_ARN')
# Detect drift
response = cloudformation.detect_stack_drift(StackName=stack_name)
# Wait for drift detection to complete
import time
time.sleep(60)
# Get drift status
drift_status = cloudformation.describe_stack-drift-detection-status(
StackName=stack_name,
DetectionId=response['StackDriftDetectionId']
)
# Get resources with drift
resources = []
paginator = cloudformation.get_paginator('list_stack_resources')
for page in paginator.paginate(StackName=stack_name):
for resource in page['StackResourceSummaries']:
if resource['DriftStatus'] != 'IN_SYNC':
resources.append({
'LogicalId': resource['LogicalResourceId'],
'PhysicalId': resource['PhysicalResourceId'],
'DriftStatus': resource['DriftStatus'],
'Expected': resource.get('ExpectedResourceType'),
'Actual': resource.get('ActualResourceType')
})
# Send alert if drift detected
if resources:
message = f"Drift detected on stack {stack_name}:\n"
for r in resources:
message += f"- {r['LogicalId']}: {r['DriftStatus']}\n"
sns.publish(
TopicArn=topic_arn,
Subject=f"CloudFormation Drift Alert: {stack_name}",
Message=message
)
return {
'statusCode': 200,
'body': json.dumps({
'drift_status': drift_status['StackDriftStatus'],
'resources_with_drift': len(resources)
})
}python
import boto3
import json
def handler(event, context):
cloudformation = boto3.client('cloudformation')
sns = boto3.client('sns')
stack_name = event.get('STACK_NAME', 'my-production-stack')
topic_arn = event.get('SNS_TOPIC_ARN')
# Detect drift
response = cloudformation.detect_stack_drift(StackName=stack_name)
# Wait for drift detection to complete
import time
time.sleep(60)
# Get drift status
drift_status = cloudformation.describe_stack-drift-detection-status(
StackName=stack_name,
DetectionId=response['StackDriftDetectionId']
)
# Get resources with drift
resources = []
paginator = cloudformation.get_paginator('list_stack_resources')
for page in paginator.paginate(StackName=stack_name):
for resource in page['StackResourceSummaries']:
if resource['DriftStatus'] != 'IN_SYNC':
resources.append({
'LogicalId': resource['LogicalResourceId'],
'PhysicalId': resource['PhysicalResourceId'],
'DriftStatus': resource['DriftStatus'],
'Expected': resource.get('ExpectedResourceType'),
'Actual': resource.get('ActualResourceType')
})
# Send alert if drift detected
if resources:
message = f"Drift detected on stack {stack_name}:\n"
for r in resources:
message += f"- {r['LogicalId']}: {r['DriftStatus']}\n"
sns.publish(
TopicArn=topic_arn,
Subject=f"CloudFormation Drift Alert: {stack_name}",
Message=message
)
return {
'statusCode': 200,
'body': json.dumps({
'drift_status': drift_status['StackDriftStatus'],
'resources_with_drift': len(resources)
})
}Change Sets Usage
变更集使用
Use Change Sets to preview and review changes before applying them to production stacks.
yaml
Resources:
# Change set for stack update
ChangeSet:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: !Sub "https://${BucketName}.s3.amazonaws.com/updated-template.yaml"
ChangeSetName: !Sub "${AWS::StackName}-update-changeset"
ChangeSetType: UPDATE
Parameters:
Environment: !Ref Environment
InstanceType: !Ref NewInstanceType
Capabilities:
- CAPABILITY_IAM
- CAPABILITY_NAMED_IAM
# Nested change set for review
ReviewChangeSet:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: !Sub "https://${BucketName}.s3.amazonaws.com/review-template.yaml"
ChangeSetName: !Sub "${AWS::StackName}-review-changeset"
ChangeSetType: UPDATE
Parameters:
Environment: !Ref Environment
Tags:
- Key: ChangeSetType
Value: review
- Key: CreatedBy
Value: CloudFormation使用变更集在将变更应用到生产栈之前预览和审查变更。
yaml
Resources:
# Change set for stack update
ChangeSet:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: !Sub "https://${BucketName}.s3.amazonaws.com/updated-template.yaml"
ChangeSetName: !Sub "${AWS::StackName}-update-changeset"
ChangeSetType: UPDATE
Parameters:
Environment: !Ref Environment
InstanceType: !Ref NewInstanceType
Capabilities:
- CAPABILITY_IAM
- CAPABILITY_NAMED_IAM
# Nested change set for review
ReviewChangeSet:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: !Sub "https://${BucketName}.s3.amazonaws.com/review-template.yaml"
ChangeSetName: !Sub "${AWS::StackName}-review-changeset"
ChangeSetType: UPDATE
Parameters:
Environment: !Ref Environment
Tags:
- Key: ChangeSetType
Value: review
- Key: CreatedBy
Value: CloudFormationChange Set Generation Script
变更集生成脚本
bash
#!/bin/bashbash
#!/bin/bashCreate a change set for review
Create a change set for review
aws cloudformation create-change-set
--stack-name my-production-stack
--change-set-name production-update-changeset
--template-url https://my-bucket.s3.amazonaws.com/updated-template.yaml
--parameters ParameterKey=Environment,ParameterValue=production
--capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM
--stack-name my-production-stack
--change-set-name production-update-changeset
--template-url https://my-bucket.s3.amazonaws.com/updated-template.yaml
--parameters ParameterKey=Environment,ParameterValue=production
--capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM
aws cloudformation create-change-set
--stack-name my-production-stack
--change-set-name production-update-changeset
--template-url https://my-bucket.s3.amazonaws.com/updated-template.yaml
--parameters ParameterKey=Environment,ParameterValue=production
--capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM
--stack-name my-production-stack
--change-set-name production-update-changeset
--template-url https://my-bucket.s3.amazonaws.com/updated-template.yaml
--parameters ParameterKey=Environment,ParameterValue=production
--capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM
Wait for change set creation
Wait for change set creation
aws cloudformation wait change-set-create-complete
--stack-name my-production-stack
--change-set-name production-update-changeset
--stack-name my-production-stack
--change-set-name production-update-changeset
aws cloudformation wait change-set-create-complete
--stack-name my-production-stack
--change-set-name production-update-changeset
--stack-name my-production-stack
--change-set-name production-update-changeset
Describe change set to see what will change
Describe change set to see what will change
aws cloudformation describe-change-set
--stack-name my-production-stack
--change-set-name production-update-changeset
--stack-name my-production-stack
--change-set-name production-update-changeset
aws cloudformation describe-change-set
--stack-name my-production-stack
--change-set-name production-update-changeset
--stack-name my-production-stack
--change-set-name production-update-changeset
Execute change set if changes look good
Execute change set if changes look good
aws cloudformation execute-change-set
--stack-name my-production-stack
--change-set-name production-update-changeset
--stack-name my-production-stack
--change-set-name production-update-changeset
undefinedaws cloudformation execute-change-set
--stack-name my-production-stack
--change-set-name production-update-changeset
--stack-name my-production-stack
--change-set-name production-update-changeset
undefinedStack Update with Rollback Triggers
带回滚触发器的栈更新
yaml
Resources:
# Production stack with rollback configuration
ProductionStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: !Sub "https://${BucketName}.s3.amazonaws.com/production.yaml"
TimeoutInMinutes: 60
RollbackConfiguration:
RollbackTriggers:
- Arn: !Sub "arn:aws:cloudwatch:${AWS::Region}:${AWS::AccountId}:alarm:ProductionCPUHigh"
Type: AWS::CloudWatch::Alarm
- Arn: !Sub "arn:aws:cloudwatch:${AWS::Region}:${AWS::AccountId}:alarm:ProductionLatencyHigh"
Type: AWS::CloudWatch::Alarm
MonitoringTimeInMinutes: 15
NotificationARNs:
- !Ref UpdateNotificationTopic
# CloudWatch alarms for rollback
ProductionCPUHigh:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName: !Sub "${AWS::StackName}-CPU-High"
AlarmDescription: Trigger rollback if CPU exceeds 80%
MetricName: CPUUtilization
Namespace: AWS/EC2
Statistic: Average
Period: 60
EvaluationPeriods: 5
Threshold: 80
ComparisonOperator: GreaterThanThreshold
AlarmActions:
- !Ref UpdateNotificationTopic
# SNS topic for notifications
UpdateNotificationTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: !Sub "${AWS::StackName}-update-notifications"yaml
Resources:
# Production stack with rollback configuration
ProductionStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: !Sub "https://${BucketName}.s3.amazonaws.com/production.yaml"
TimeoutInMinutes: 60
RollbackConfiguration:
RollbackTriggers:
- Arn: !Sub "arn:aws:cloudwatch:${AWS::Region}:${AWS::AccountId}:alarm:ProductionCPUHigh"
Type: AWS::CloudWatch::Alarm
- Arn: !Sub "arn:aws:cloudwatch:${AWS::Region}:${AWS::AccountId}:alarm:ProductionLatencyHigh"
Type: AWS::CloudWatch::Alarm
MonitoringTimeInMinutes: 15
NotificationARNs:
- !Ref UpdateNotificationTopic
# CloudWatch alarms for rollback
ProductionCPUHigh:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName: !Sub "${AWS::StackName}-CPU-High"
AlarmDescription: Trigger rollback if CPU exceeds 80%
MetricName: CPUUtilization
Namespace: AWS/EC2
Statistic: Average
Period: 60
EvaluationPeriods: 5
Threshold: 80
ComparisonOperator: GreaterThanThreshold
AlarmActions:
- !Ref UpdateNotificationTopic
# SNS topic for notifications
UpdateNotificationTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: !Sub "${AWS::StackName}-update-notifications"Best Practices for Stack Management
栈管理最佳实践
-
Enable Termination Protection
- Always enable for production stacks
- Use as a safety mechanism against accidental deletion
- Requires manual disabling before deletion
-
Use Stack Policies
- Protect critical resources from unintended updates
- Use Deny statements for production databases, KMS keys, and IAM roles
- Apply conditions based on region, user, or tags
-
Implement Drift Detection
- Run drift detection regularly (daily for production)
- Alert on any drift detection
- Investigate and remediate drift immediately
-
Use Change Sets
- Always use Change Sets for production updates
- Review changes before execution
- Use descriptive change set names
-
Configure Rollback Triggers
- Set up CloudWatch alarms for critical metrics
- Configure monitoring time to allow stabilization
- Test rollback triggers in non-production first
-
Implement Change Management
- Require approval for production changes
- Use CodePipeline with manual approval gates
- Document all changes in change log
-
Use Stack Sets for Multi-Account
- Deploy infrastructure consistently across accounts
- Use StackSets for organization-wide policies
- Implement drift detection at organization level
-
启用终止保护
- 始终为生产栈启用
- 作为防止意外删除的安全机制
- 删除前需要手动禁用
-
使用栈策略
- 保护关键资源免受非预期更新
- 对生产数据库、KMS密钥和IAM角色使用Deny语句
- 基于区域、用户或标签应用条件
-
实施漂移检测
- 定期运行漂移检测(生产环境每日一次)
- 检测到任何漂移时触发告警
- 立即调查并修复漂移
-
使用变更集
- 生产环境更新始终使用变更集
- 执行前审查变更
- 使用描述性的变更集名称
-
配置回滚触发器
- 为关键指标设置CloudWatch告警
- 配置监控时间以允许系统稳定
- 先在非生产环境测试回滚触发器
-
实施变更管理
- 生产环境变更需要审批
- 使用带手动审批门的CodePipeline
- 在变更日志中记录所有变更
-
对多账户使用栈集
- 在多个账户中一致地部署基础设施
- 使用StackSets部署组织级策略
- 在组织层面实施漂移检测