A practical guide to implementing security contact automation using CloudFormation StackSets
The Challenge
Organizations with multiple AWS accounts need accurate security contact information to ensure AWS Security can reach appropriate teams during incidents. Manual configuration across hundreds of accounts becomes impractical and error-prone. Organizations need automated deployment that scales with their AWS footprint.
This best practice is supported by CIS AWS Foundations Benchmark v3.0.0 Account.1 control, which requires security contact information for each AWS account.
AWS Organizations Integration
AWS Account Management service integrates with AWS Organizations for centralized alternate contact management. The management account can programmatically set security contact information across all member accounts using APIs for billing, operations, and security contacts.
Implementation Approach
CloudFormation StackSets provide scalable deployment using Lambda-backed custom resources to call the AWS Account Management API. The solution deploys consistently across all accounts and automatically applies to new accounts when configured with automatic deployment.
CloudFormation Template
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
SecurityContactName:
Type: String
Description: Name of the security contact
Default: "Security Team"
SecurityContactEmail:
Type: String
Description: Email address of the security contact
AllowedPattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
SecurityContactPhone:
Type: String
Description: Phone number of the security contact
Default: "+1-555-0123"
Resources:
SecurityContact:
Type: AWS::CloudFormation::CustomResource
Properties:
ServiceToken: !GetAtt SecurityContactFunction.Arn
ContactName: !Ref SecurityContactName
ContactEmail: !Ref SecurityContactEmail
ContactPhone: !Ref SecurityContactPhone
SecurityContactFunction:
Type: AWS::Lambda::Function
Properties:
Runtime: python3.12
Handler: index.handler
Role: !GetAtt LambdaExecutionRole.Arn
Code:
ZipFile: |
import boto3
import cfnresponse
def handler(event, context):
try:
account_client = boto3.client('account')
if event['RequestType'] == 'Create' or event['RequestType'] == 'Update':
account_client.put_alternate_contact(
AlternateContactType='SECURITY',
Name=event['ResourceProperties']['ContactName'],
EmailAddress=event['ResourceProperties']['ContactEmail'],
PhoneNumber=event['ResourceProperties']['ContactPhone'],
Title='Security Operations'
)
cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
except Exception as e:
print(f"Error: {str(e)}")
cfnresponse.send(event, context, cfnresponse.FAILED, {})
LambdaExecutionRole:
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: AccountManagementPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- account:PutAlternateContact
- account:GetAlternateContact
Resource: '*'
Deployment Strategy
Deploy using CloudFormation StackSets from the management account or delegated administrator. Target organizational units based on governance requirements and enable automatic deployment for new accounts.
# Create StackSet
aws cloudformation create-stack-set \
--stack-set-name security-contact-stackset \
--template-body file://security-contact.yaml \
--capabilities CAPABILITY_IAM \
--parameters ParameterKey=SecurityContactEmail,ParameterValue=security@company.com
# Deploy to organization
aws cloudformation create-stack-instances \
--stack-set-name security-contact-stackset \
--deployment-targets OrganizationalUnitIds=r-[placeholder org id] \
--regions us-east-1 \
--operation-preferences MaxConcurrentPercentage=100
Operations and Maintenance
Use centralized security email addresses or distribution lists to ensure notifications reach appropriate teams regardless of personnel changes. Periodically verify contact information using the get-alternate-contact API.
AWS Security Hub provides built-in detective controls to monitor accounts without configured security contacts through CIS compliance checks.
Limitations and Alternatives
This approach creates Lambda functions in each account, which may be unnecessary overhead for one-time configuration.
For one-time setup, AWS CLI provides simpler deployment without per-account resources. See Programmatically managing alternate contacts on member accounts with AWS Organizations for CLI implementation.
CloudFormation StackSets provide ongoing management and automatic application to new accounts, while CLI offers simpler one-time deployment.