Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Provides AWS CloudFormation patterns for security infrastructure including KMS encryption, Secrets Manager, IAM security, VPC security, ACM certificates, parameter security, outputs, and secure cross-stack references. Use when implementing security best practices, encrypting data, managing secrets, applying least privilege IAM policies, securing VPC configurations, managing TLS/SSL certificates, and implementing defense in depth strategies.
.claude/skills/giuseppe-trisciuoglio-aws-cloudformation-security/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-07 | ✗→✓ | ▲ Improved | 42% | 0% |
| case-04 | ✓→✗ | ▼ Worse | 188% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 176% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 208% | 0% |
| case-20 | ✓→✓ | = Same ✓ | 179% | 0% |
Create production-ready security infrastructure using AWS CloudFormation templates. This skill covers KMS encryption, Secrets Manager, IAM security with least privilege, VPC security configurations, ACM certificates, parameter security, secure outputs, cross-stack references, CloudWatch Logs encryption, defense in depth strategies, and security best practices.
Follow these steps to create security infrastructure with CloudFormation:
Create customer-managed keys for encryption:
yamlResources: EncryptionKey: Type: AWS::KMS::Key Properties: Description: Customer-managed key for data encryption KeyPolicy: Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: - kms:Decrypt - kms:GenerateDataKey Resource: "*" - Effect: Allow Principal: AWS: !Sub "arn:aws:iam::${AWS::AccountId}:root" Action: - kms:* Resource: "*" KeyAlias: Type: AWS::KMS::Alias Properties: AliasName: !Sub "${AWS::StackName}/encryption-key" TargetKeyId: !Ref EncryptionKey
Validate: aws kms get-key-policy --key-id <key-id> --output text
Store and retrieve sensitive data securely:
yamlResources: DatabaseSecret: Type: AWS::SecretsManager::Secret Properties: Name: !Sub "${AWS::StackName}/database" Description: Database credentials SecretString: !Sub | { "username": "admin", "password": "${DatabasePassword}", "engine": "mysql", "host": "${DatabaseEndpoint}", "port": 3306 } KmsKeyId: !Ref EncryptionKey SecretRotationSchedule: Type: AWS::SecretsManager::RotationSchedule Properties: SecretId: !Ref DatabaseSecret RotationLambdaARN: !Ref RotationLambda.Arn RotationRules: AutomaticallyAfterDays: 30
Validate: aws secretsmanager describe-secret --secret-id <secret-name>
Create roles and policies with minimal required permissions:
yamlResources: ExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Policies: - PolicyName: SpecificPermissions PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - s3:GetObject Resource: !Sub "${DataBucket.Arn}/*"
Validate: aws iam simulate-principal-policy --policy-source-arn <role-arn> --action-names s3:GetObject --resource-arns <bucket-arn>
Implement network security with security groups and NACLs:
yamlResources: ApplicationSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Application security group VpcId: !Ref VPC SecurityGroupIngress: - IpProtocol: tcp FromPort: 443 ToPort: 443 SourceSecurityGroupId: !Ref LoadBalancerSecurityGroup SecurityGroupEgress: - IpProtocol: -1 CidrIp: 0.0.0.0/0 ApplicationNACL: Type: AWS::EC2::NetworkAcl Properties: VpcId: !Ref VPC NACLEntry: Type: AWS::EC2::NetworkAclEntry Properties: NetworkAclId: !Ref ApplicationNACL RuleNumber: 100 Protocol: "6" RuleAction: allow Egress: false CidrBlock: 0.0.0.0/0 PortRange: From: 443 To: 443
Validate: aws ec2 describe-security-groups --group-ids <sg-id> --query 'SecurityGroups[0].IpPermissions'
Manage TLS/SSL certificates for secure communication:
yamlResources: Certificate: Type: AWS::ACM::Certificate Properties: DomainName: !Ref DomainName SubjectAlternativeNames: - !Sub "www.${DomainName}" - !Sub "api.${DomainName}" DomainValidationOptions: - DomainName: !Ref DomainName ValidationDomain: !Ref DomainName Tags: - Key: Environment Value: !Ref Environment # DNS validation record DnsValidationRecord: Type: AWS::Route53::RecordSet Properties: HostedZoneName: !Ref HostedZone Name: !Sub "_${DomainName}." Type: CNAME TTL: 300 ResourceRecords: - !Ref Certificate
Validate: aws acm describe-certificate --certificate-arn <arn> --query 'Certificate.Status'
Use SecureString for sensitive parameter values:
yamlResources: DatabasePasswordParameter: Type: AWS::SSM::Parameter Properties: Name: !Sub "/${AWS::StackName}/database/password" Type: SecureString Value: !Ref DatabasePassword Description: Database master password KmsKeyId: !Ref EncryptionKey # Reference in other resources DatabaseInstance: Type: AWS::RDS::DBInstance Properties: MasterUsername: admin MasterUserPassword: !Ref DatabasePasswordParameter
Validate: aws ssm get-parameter --name <param-name> --with-decryption --query 'Parameter.Type'
Export only non-sensitive values from stacks:
yamlOutputs: # Safe to export KMSKeyArn: Description: KMS Key ARN for encryption Value: !GetAtt EncryptionKey.Arn Export: Name: !Sub "${AWS::StackName}-KMSKeyArn" SecretArn: Description: Secret ARN (not the secret value) Value: !Ref DatabaseSecret Export: Name: !Sub "${AWS::StackName}-SecretArn" # DO NOT export sensitive data # Incorrect: # SecretValue: # Value: !GetAtt DatabaseSecret.SecretString
Validate: aws cloudformation list-exports --query "Exports[?Name=='<stack-name>-KMSKeyArn']"
Enable encryption for log groups:
yamlResources: EncryptedLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub "/aws/applications/${ApplicationName}" RetentionInDays: 30 KmsKeyId: !Ref EncryptionKey
Validate: aws logs describe-log-groups --log-group-name-prefix <prefix> --query 'logGroups[0].kmsKeyId'
yamlResources: # KMS Key with proper policy AppKey: Type: AWS::KMS::Key Properties: KeyPolicy: Statement: - Effect: Allow Principal: AWS: !Sub "arn:aws:iam::${AWS::AccountId}:root" Action: kms:* Resource: "*" - Effect: Allow Principal: Service: lambda.amazonaws.com Action: - kms:Decrypt - kms:GenerateDataKey Resource: "*" # Secrets Manager with rotation DbSecret: Type: AWS::SecretsManager::Secret Properties: SecretString: !Sub '{"password":"${DbPassword}"}' KmsKeyId: !Ref AppKey RotationRules: AutomaticallyAfterDays: 30
yamlResources: LambdaRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: sts:AssumeRole Policies: - PolicyName: AccessPolicy PolicyDocument: Statement: - Effect: Allow Action: s3:GetObject Resource: !Sub "${Bucket.Arn}/*"
For comprehensive examples with VPC security groups, ACM certificates, and complete encrypted infrastructure stacks, see examples.md.
For detailed constraints including cost considerations and quota management, see constraints.md.
For detailed implementation guidance, see:
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | pass→pass | 7,350 | 7,316 | -0% | 1 | 1 | 0% | 1,415 | 3,910 | +176% | 0 | 0 | — |
case-02 | pass→pass | 7,311 | 7,603 | +4% | 1 | 1 | 0% | 1,300 | 4,007 | +208% | 0 | 0 | — |
case-20 | pass→pass | 6,391 | 5,970 | -7% | 1 | 1 | 0% | 1,366 | 3,815 | +179% | 0 | 0 | — |
case-03 | pass→pass | 6,937 | 6,786 | -2% | 1 | 1 | 0% | 1,279 | 3,825 | +199% | 0 | 0 | — |
case-04 | pass→fail | 8,522 | 9,105 | +7% | 1 | 1 | 0% | 1,507 | 4,333 | +188% | 0 | 0 | — |
case-05 | pass→pass | 6,000 | 4,744 | -21% | 1 | 1 | 0% | 1,009 | 3,466 | +244% | 0 | 0 | — |
case-06 | pass→pass | 6,169 | 12,335 | +100% | 1 | 1 | 0% | 1,092 | 3,781 | +246% | 0 | 0 | — |
case-07 | fail→pass | 16,472 | 7,406 | -55% | 1 | 1 | 0% | 2,806 | 3,991 | +42% | 0 | 0 | — |
case-08 | pass→pass | 7,218 | 10,819 | +50% | 1 | 1 | 0% | 1,183 | 4,654 | +293% | 0 | 0 | — |
case-09 | fail→fail | 7,218 | 6,669 | -8% | 1 | 1 | 0% | 1,219 | 3,839 | +215% | 0 | 0 | — |
case-10 | pass→pass | 9,954 | 7,384 | -26% | 1 | 1 | 0% | 1,791 | 3,947 | +120% | 0 | 0 | — |
case-11 | pass→pass | 8,389 | 5,443 | -35% | 1 | 1 | 0% | 809 | 3,495 | +332% | 0 | 0 | — |
case-12 | pass→pass | 20,173 | 8,125 | -60% | 1 | 1 | 0% | 1,764 | 3,949 | +124% | 0 | 0 | — |
case-13 | pass→pass | 6,043 | 4,158 | -31% | 1 | 1 | 0% | 1,039 | 3,245 | +212% | 0 | 0 | — |
case-14 | pass→pass | 7,979 | 9,013 | +13% | 1 | 1 | 0% | 1,419 | 4,298 | +203% | 0 | 0 | — |
case-15 | pass→pass | 3,690 | 3,184 | -14% | 1 | 1 | 0% | 730 | 3,261 | +347% | 0 | 0 | — |
case-16 | pass→pass | 9,020 | 4,594 | -49% | 1 | 1 | 0% | 1,415 | 3,294 | +133% | 0 | 0 | — |
case-17 | pass→pass | 7,114 | 3,843 | -46% | 1 | 1 | 0% | 1,248 | 3,064 | +146% | 0 | 0 | — |
case-18 | pass→pass | 8,538 | 7,124 | -17% | 1 | 1 | 0% | 1,507 | 3,779 | +151% | 0 | 0 | — |
case-19 | pass→pass | 5,235 | 3,969 | -24% | 1 | 1 | 0% | 955 | 3,308 | +246% | 0 | 0 | — |
case-21 | pass→pass | 3,615 | 3,397 | -6% | 1 | 1 | 0% | 625 | 3,130 | +401% | 0 | 0 | — |
case-22 | pass→pass | 3,846 | 2,437 | -37% | 1 | 1 | 0% | 725 | 2,992 | +313% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of 0 percentage points is the difference between those two pass rates over the 22 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.