Stacks Imbriquées et StackSets
Introduction
Pour les infrastructures complexes, CloudFormation offre deux mécanismes d'organisation :
- Nested Stacks : Stacks enfants appelées depuis une stack parent
- StackSets : Déploiement sur plusieurs comptes/régions
Nested Stacks
Concept
Une nested stack est une stack créée comme ressource d'une autre stack.
# parent-stack.yaml
Resources:
NetworkStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.amazonaws.com/my-bucket/network.yaml
Parameters:
VPCCidr: 10.0.0.0/16
Structure type
infrastructure/
├── parent.yaml # Stack principale
├── templates/
│ ├── network.yaml # VPC, Subnets, IGW
│ ├── security.yaml # Security Groups, IAM
│ ├── database.yaml # RDS, ElastiCache
│ └── application.yaml # EC2, ALB, ASG
└── deploy.sh
Stack parent
AWSTemplateFormatVersion: '2010-09-09'
Description: Stack parent orchestrant toute l'infrastructure
Parameters:
Environment:
Type: String
AllowedValues: [dev, staging, prod]
Default: dev
TemplateBucket:
Type: String
Description: Bucket S3 contenant les templates
Resources:
# Stack réseau
NetworkStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: !Sub 'https://s3.amazonaws.com/${TemplateBucket}/network.yaml'
Parameters:
Environment: !Ref Environment
VPCCidr: '10.0.0.0/16'
Tags:
- Key: StackType
Value: Network
# Stack sécurité (dépend du réseau)
SecurityStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: !Sub 'https://s3.amazonaws.com/${TemplateBucket}/security.yaml'
Parameters:
Environment: !Ref Environment
VPCId: !GetAtt NetworkStack.Outputs.VPCId
Tags:
- Key: StackType
Value: Security
# Stack base de données
DatabaseStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: !Sub 'https://s3.amazonaws.com/${TemplateBucket}/database.yaml'
Parameters:
Environment: !Ref Environment
VPCId: !GetAtt NetworkStack.Outputs.VPCId
SubnetIds: !GetAtt NetworkStack.Outputs.PrivateSubnets
SecurityGroupId: !GetAtt SecurityStack.Outputs.DatabaseSecurityGroup
Tags:
- Key: StackType
Value: Database
# Stack application
ApplicationStack:
Type: AWS::CloudFormation::Stack
DependsOn: DatabaseStack
Properties:
TemplateURL: !Sub 'https://s3.amazonaws.com/${TemplateBucket}/application.yaml'
Parameters:
Environment: !Ref Environment
VPCId: !GetAtt NetworkStack.Outputs.VPCId
PublicSubnets: !GetAtt NetworkStack.Outputs.PublicSubnets
PrivateSubnets: !GetAtt NetworkStack.Outputs.PrivateSubnets
SecurityGroupId: !GetAtt SecurityStack.Outputs.AppSecurityGroup
DatabaseEndpoint: !GetAtt DatabaseStack.Outputs.DatabaseEndpoint
Tags:
- Key: StackType
Value: Application
Outputs:
VPCId:
Value: !GetAtt NetworkStack.Outputs.VPCId
ApplicationURL:
Value: !GetAtt ApplicationStack.Outputs.LoadBalancerDNS
DatabaseEndpoint:
Value: !GetAtt DatabaseStack.Outputs.DatabaseEndpoint
Stack enfant : network.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: Stack réseau
Parameters:
Environment:
Type: String
VPCCidr:
Type: String
Default: '10.0.0.0/16'
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VPCCidr
EnableDnsHostnames: true
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-vpc'
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Select [0, !Cidr [!Ref VPCCidr, 6, 8]]
AvailabilityZone: !Select [0, !GetAZs '']
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-public-1'
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Select [1, !Cidr [!Ref VPCCidr, 6, 8]]
AvailabilityZone: !Select [1, !GetAZs '']
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-public-2'
PrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Select [2, !Cidr [!Ref VPCCidr, 6, 8]]
AvailabilityZone: !Select [0, !GetAZs '']
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-private-1'
PrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Select [3, !Cidr [!Ref VPCCidr, 6, 8]]
AvailabilityZone: !Select [1, !GetAZs '']
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-private-2'
InternetGateway:
Type: AWS::EC2::InternetGateway
VPCGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
# ... routes, NAT, etc.
Outputs:
VPCId:
Description: VPC ID
Value: !Ref VPC
PublicSubnets:
Description: Public subnet IDs
Value: !Join [',', [!Ref PublicSubnet1, !Ref PublicSubnet2]]
PrivateSubnets:
Description: Private subnet IDs
Value: !Join [',', [!Ref PrivateSubnet1, !Ref PrivateSubnet2]]
VPCCidr:
Description: VPC CIDR
Value: !GetAtt VPC.CidrBlock
Accéder aux outputs des nested stacks
# Dans la stack parent
!GetAtt NestedStackName.Outputs.OutputName
# Exemple
DatabaseEndpoint: !GetAtt DatabaseStack.Outputs.Endpoint
VPCId: !GetAtt NetworkStack.Outputs.VPCId
Script de déploiement
#!/bin/bash
# deploy.sh
STACK_NAME="my-infrastructure"
BUCKET_NAME="my-cfn-templates"
ENVIRONMENT="prod"
REGION="eu-west-1"
# Upload des templates
echo "Uploading templates to S3..."
aws s3 sync ./templates s3://${BUCKET_NAME}/ --delete
# Déployer la stack parent
echo "Deploying parent stack..."
aws cloudformation deploy \
--template-file parent.yaml \
--stack-name ${STACK_NAME} \
--parameter-overrides \
Environment=${ENVIRONMENT} \
TemplateBucket=${BUCKET_NAME} \
--capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM CAPABILITY_AUTO_EXPAND \
--region ${REGION}
echo "Deployment complete!"
StackSets
Les StackSets permettent de déployer des stacks sur plusieurs comptes et régions.
Créer un StackSet
# Créer le StackSet
aws cloudformation create-stack-set \
--stack-set-name my-stackset \
--template-body file://template.yaml \
--parameters ParameterKey=Environment,ParameterValue=prod \
--permission-model SERVICE_MANAGED \
--auto-deployment Enabled=true,RetainStacksOnAccountRemoval=false
# Ajouter des instances (déploiements)
aws cloudformation create-stack-instances \
--stack-set-name my-stackset \
--deployment-targets OrganizationalUnitIds=ou-xxxxx \
--regions eu-west-1 us-east-1 ap-northeast-1 \
--operation-preferences FailureTolerancePercentage=10,MaxConcurrentPercentage=25
Template StackSet
AWSTemplateFormatVersion: '2010-09-09'
Description: Template pour déploiement multi-compte via StackSet
Parameters:
Environment:
Type: String
Default: production
Resources:
# Bucket S3 de logs (un par compte/région)
LogsBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub 'logs-${AWS::AccountId}-${AWS::Region}'
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
# Config Rule (même config partout)
RequireEncryptionRule:
Type: AWS::Config::ConfigRule
Properties:
ConfigRuleName: require-s3-encryption
Description: Vérifie que les buckets S3 sont chiffrés
Source:
Owner: AWS
SourceIdentifier: S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED
Outputs:
LogsBucketName:
Value: !Ref LogsBucket
Description: Nom du bucket de logs
Permissions StackSets
Pour les déploiements cross-account, vous avez besoin de rôles IAM :
# Dans le compte administrateur
AWSTemplateFormatVersion: '2010-09-09'
Description: Rôle administrateur pour StackSets
Resources:
AdministrationRole:
Type: AWS::IAM::Role
Properties:
RoleName: AWSCloudFormationStackSetAdministrationRole
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: cloudformation.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: StackSetAdministration
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: sts:AssumeRole
Resource: 'arn:aws:iam::*:role/AWSCloudFormationStackSetExecutionRole'
# Dans chaque compte cible
AWSTemplateFormatVersion: '2010-09-09'
Description: Rôle d'exécution pour StackSets
Parameters:
AdministratorAccountId:
Type: String
Description: ID du compte administrateur
Resources:
ExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: AWSCloudFormationStackSetExecutionRole
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
AWS: !Sub 'arn:aws:iam::${AdministratorAccountId}:root'
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AdministratorAccess
Nested Stacks vs Cross-Stack References vs StackSets
| Aspect | Nested Stacks | Cross-Stack (Export/Import) | StackSets |
|---|---|---|---|
| Scope | Même stack | Même région/compte | Multi-compte/région |
| Couplage | Fort | Moyen | Faible |
| Lifecycle | Ensemble | Indépendant | Indépendant |
| Use case | Modularité | Partage de ressources | Gouvernance |
Bonnes pratiques
1. Structure modulaire
infrastructure/
├── main.yaml # Stack parent
├── templates/
│ ├── network/
│ │ └── vpc.yaml