Implementing Secure CloudFormation Patterns

Implementing Secure CloudFormation Patterns

Parameterization and dynamic references eliminate hardcoded values while maintaining template flexibility. CloudFormation parameters allow users to provide values at stack creation time, while dynamic references retrieve values from AWS Systems Manager Parameter Store or AWS Secrets Manager. This approach keeps sensitive data out of templates while enabling secure, automated deployments.

# Secure CloudFormation template with proper patterns
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Secure template demonstrating best practices'

Parameters:
  Environment:
    Type: String
    AllowedValues: [development, staging, production]
    Description: Deployment environment
    
  VPCId:
    Type: AWS::EC2::VPC::Id
    Description: VPC for resource deployment
    
  SubnetIds:
    Type: List<AWS::EC2::Subnet::Id>
    Description: Private subnets for resources

Resources:
  # SECURE: S3 bucket with encryption and private access
  SecureBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub '${AWS::StackName}-secure-data-${AWS::AccountId}'
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      VersioningConfiguration:
        Status: Enabled
      LifecycleConfiguration:
        Rules:
          - Id: DeleteOldVersions
            NoncurrentVersionExpirationInDays: 30
            Status: Enabled
            
  # SECURE: RDS instance with proper security controls
  DatabaseInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceIdentifier: !Sub '${AWS::StackName}-db'
      Engine: mysql
      MasterUsername: !Sub '{{resolve:secretsmanager:${DatabaseSecret}:SecretString:username}}'
      MasterUserPassword: !Sub '{{resolve:secretsmanager:${DatabaseSecret}:SecretString:password}}'
      DBInstanceClass: db.t3.micro
      AllocatedStorage: 20
      StorageEncrypted: true
      KmsKeyId: !Ref DatabaseKMSKey
      PubliclyAccessible: false
      VPCSecurityGroups:
        - !Ref DatabaseSecurityGroup
      DBSubnetGroupName: !Ref DatabaseSubnetGroup
      BackupRetentionPeriod: 7
      PreferredBackupWindow: "03:00-04:00"
      PreferredMaintenanceWindow: "sun:04:00-sun:05:00"
      
  # SECURE: Properly configured security group
  DatabaseSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for RDS instance
      VpcId: !Ref VPCId
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 3306
          ToPort: 3306
          SourceSecurityGroupId: !Ref ApplicationSecurityGroup
      Tags:
        - Key: Name
          Value: !Sub '${AWS::StackName}-db-sg'
          
  # Secret storage for database credentials
  DatabaseSecret:
    Type: AWS::SecretsManager::Secret
    Properties:
      Description: RDS master credentials
      GenerateSecretString:
        SecretStringTemplate: '{"username": "admin"}'
        GenerateStringKey: password
        PasswordLength: 32
        RequireEachIncludedType: true
        
  # KMS key for encryption
  DatabaseKMSKey:
    Type: AWS::KMS::Key
    Properties:
      Description: Encryption key for RDS
      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 RDS to use the key
            Effect: Allow
            Principal:
              Service: rds.amazonaws.com
            Action:
              - 'kms:Decrypt'
              - 'kms:GenerateDataKey'
            Resource: '*'

Conditional resource creation based on environment parameters prevents accidental production changes and enforces environment-specific security controls. Development environments might allow more permissive configurations for testing, while production environments enforce strict security requirements. CloudFormation conditions enable single templates to support multiple environments safely.