AWS CloudFormation
Le service Infrastructure as Code d'AWS qui permet de modéliser et provisionner vos ressources cloud de manière automatisée, cohérente et reproductible.
Qu'est-ce qu'AWS CloudFormation ?
Imaginez que vous construisez une ville complexe. Au lieu de construire chaque bâtiment un par un manuellement, vous pourriez dessiner un plan détaillé de la ville et laisser des machines construire tout automatiquement selon vos spécifications.
AWS CloudFormation fonctionne de manière similaire pour le cloud. C'est un service qui permet de définir toute votre infrastructure AWS (serveurs, bases de données, réseaux, etc.) sous forme de "plans" textuels (appelés templates) qui décrivent exactement ce que vous voulez construire.
Pourquoi est-ce important ?
Reproductibilité
Vous pouvez recréer exactement le même environnement dans différentes régions ou comptes AWS, garantissant cohérence et fiabilité.
Automatisation et Sécurité
Élimine les erreurs humaines lors de la configuration manuelle des ressources, tout en permettant de contrôler et vérifier les changements avant leur application.
En résumé, CloudFormation transforme la manière dont les entreprises gèrent leur infrastructure cloud, en passant de processus manuels sujets aux erreurs à une approche programmable, versionnable et automatisée.
Fonctionnement technique
AWS CloudFormation est un service qui utilise des templates pour décrire, provisionner et gérer des ressources AWS et tierces de façon ordonnée et prévisible. Ces templates peuvent être écrits en JSON ou YAML et sont traités comme du code, permettant la gestion de version, la revue et la réutilisation.
Les concepts fondamentaux
Structure d'un template
Un template CloudFormation comprend plusieurs sections principales:
- Format Version : Version du template (ex: "2010-09-09")
- Description : Description textuelle du template
- Parameters : Valeurs que l'utilisateur peut personnaliser lors du déploiement
- Mappings : Tables de mappage pour configurer des valeurs conditionnelles
- Conditions : Conditions pour la création conditionnelle de ressources
- Resources : Définition des ressources AWS à créer (section obligatoire)
- Outputs : Valeurs renvoyées après la création de la stack
Template de base
Exemple de template CloudFormation créant un bucket S3 et une
instance EC2 :
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Template basique pour créer un bucket S3 et une instance EC2'
Parameters:
InstanceType:
Description: Type d'instance EC2
Type: String
Default: t2.micro
AllowedValues:
- t2.micro
- t2.small
- t3.micro
ConstraintDescription: Doit être un type d'instance valide
BucketName:
Description: 'Nom du bucket S3 (unique globalement)'
Type: String
Default: my-unique-bucket-name
Environment:
Description: 'Environnement de déploiement'
Type: String
Default: dev
AllowedValues:
- dev
- staging
- prod
Resources:
# Instance EC2
WebServer:
Type: AWS::EC2::Instance
Properties:
InstanceType: !Ref InstanceType
ImageId: ami-01234567890abcdef # AMI Amazon Linux 2 (remplacer par l'AMI appropriée)
SecurityGroups:
- !Ref WebServerSecurityGroup
Tags:
- Key: Name
Value: !Sub 'WebServer-${Environment}'
- Key: Environment
Value: !Ref Environment
UserData:
Fn::Base64: |
#!/bin/bash -xe
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "<html><body><h1>Hello from CloudFormation!</h1></body></html>" > /var/www/html/index.html
# Groupe de sécurité pour l'instance EC2
WebServerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Enable HTTP and SSH access
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 0.0.0.0/0
Tags:
- Key: Environment
Value: !Ref Environment
# Bucket S3
S3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref BucketName
AccessControl: Private
VersioningConfiguration:
Status: Enabled
Tags:
- Key: Environment
Value: !Ref Environment
Outputs:
WebsiteURL:
Description: URL du serveur web
Value: !Sub 'http://${WebServer.PublicDnsName}'
BucketName:
Description: Nom du bucket S3 créé
Value: !Ref S3Bucket
BucketARN:
Description: ARN du bucket S3
Value: !GetAtt S3Bucket.Arn
Architecture Serverless
Exemple de template pour une API Serverless avec API Gateway,
Lambda et
DynamoDB :
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Template Serverless API avec API Gateway, Lambda et DynamoDB'
Parameters:
StageName:
Type: String
Default: dev
Description: Stage name for API Gateway deployment
TableReadCapacity:
Type: Number
Default: 5
Description: Read capacity units for DynamoDB table
TableWriteCapacity:
Type: Number
Default: 5
Description: Write capacity units for DynamoDB table
Resources:
# Fonction Lambda pour traiter les requêtes API
ApiFunction:
Type: AWS::Lambda::Function
Properties:
Handler: index.handler
Role: !GetAtt ApiFunctionRole.Arn
Code:
ZipFile: |
exports.handler = async (event) => {
const dynamoDb = new (require('aws-sdk')).DynamoDB.DocumentClient();
try {
if (event.httpMethod === 'GET') {
const params = {
TableName: process.env.TABLE_NAME,
};
const result = await dynamoDb.scan(params).promise();
return {
statusCode: 200,
body: JSON.stringify(result.Items)
};
} else if (event.httpMethod === 'POST') {
const data = JSON.parse(event.body);
const params = {
TableName: process.env.TABLE_NAME,
Item: {
id: Date.now().toString(),
content: data.content,
createdAt: new Date().toISOString()
}
};
await dynamoDb.put(params).promise();
return {
statusCode: 201,
body: JSON.stringify(params.Item)
};
}
return {
statusCode: 400,
body: JSON.stringify({ message: 'Unsupported method' })
};
} catch (error) {
console.error(error);
return {
statusCode: 500,
body: JSON.stringify({ message: 'Internal server error' })
};
}
}
Runtime: nodejs14.x
Timeout: 10
MemorySize: 128
Environment:
Variables:
TABLE_NAME: !Ref ItemsTable
# Rôle IAM pour la fonction Lambda
ApiFunctionRole:
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: DynamoDBAccess
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
- dynamodb:Scan
- dynamodb:Query
Resource: !GetAtt ItemsTable.Arn
# Table DynamoDB
ItemsTable:
Type: AWS::DynamoDB::Table
Properties:
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: !Ref TableReadCapacity
WriteCapacityUnits: !Ref TableWriteCapacity
# API Gateway REST API
ApiGateway:
Type: AWS::ApiGateway::RestApi
Properties:
Name: ServerlessAPI
Description: API pour accéder aux données DynamoDB via Lambda
# Ressource API Gateway
ApiResource:
Type: AWS::ApiGateway::Resource
Properties:
RestApiId: !Ref ApiGateway
ParentId: !GetAtt ApiGateway.RootResourceId
PathPart: items
# Méthode GET
ApiGatewayGetMethod:
Type: AWS::ApiGateway::Method
Properties:
RestApiId: !Ref ApiGateway
ResourceId: !Ref ApiResource
HttpMethod: GET
AuthorizationType: NONE
Integration:
Type: AWS_PROXY
IntegrationHttpMethod: POST
Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ApiFunction.Arn}/invocations
# Méthode POST
ApiGatewayPostMethod:
Type: AWS::ApiGateway::Method
Properties:
RestApiId: !Ref ApiGateway
ResourceId: !Ref ApiResource
HttpMethod: POST
AuthorizationType: NONE
Integration:
Type: AWS_PROXY
IntegrationHttpMethod: POST
Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ApiFunction.Arn}/invocations
# Déploiement API Gateway
ApiDeployment:
Type: AWS::ApiGateway::Deployment
DependsOn:
- ApiGatewayGetMethod
- ApiGatewayPostMethod
Properties:
RestApiId: !Ref ApiGateway
# Stage API Gateway
ApiStage:
Type: AWS::ApiGateway::Stage
Properties:
RestApiId: !Ref ApiGateway
DeploymentId: !Ref ApiDeployment
StageName: !Ref StageName
# Permission pour API Gateway d'invoquer Lambda
ApiGatewayPermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: !Ref ApiFunction
Principal: apigateway.amazonaws.com
SourceArn: !Sub arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ApiGateway}/*/*
Outputs:
ApiEndpoint:
Description: URL de l'API
Value: !Sub https://${ApiGateway}.execute-api.${AWS::Region}.amazonaws.com/${StageName}/items
TableName:
Description: Nom de la table DynamoDB
Value: !Ref ItemsTable
Stacks imbriqués
Les stacks imbriqués permettent de diviser l'infrastructure en modules réutilisables et de gérer des architectures complexes :
# Template principal (main-stack.yaml)
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Template principal avec stacks imbriqués'
Parameters:
Environment:
Type: String
Default: dev
AllowedValues:
- dev
- staging
- prod
Description: Environnement de déploiement
Resources:
# Stack imbriqué pour le réseau
NetworkStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.amazonaws.com/my-templates/network.yaml
Parameters:
Environment: !Ref Environment
VpcCidr: 10.0.0.0/16
# Stack imbriqué pour la base de données
DatabaseStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.amazonaws.com/my-templates/database.yaml
Parameters:
Environment: !Ref Environment
DbInstanceClass: db.t3.small
VpcId: !GetAtt NetworkStack.Outputs.VpcId
SubnetIds: !GetAtt NetworkStack.Outputs.PrivateSubnetIds
# Stack imbriqué pour l'application
ApplicationStack:
Type: AWS::CloudFormation::Stack
DependsOn:
- NetworkStack
- DatabaseStack
Properties:
TemplateURL: https://s3.amazonaws.com/my-templates/application.yaml
Parameters:
Environment: !Ref Environment
VpcId: !GetAtt NetworkStack.Outputs.VpcId
SubnetIds: !GetAtt NetworkStack.Outputs.PublicSubnetIds
DbEndpoint: !GetAtt DatabaseStack.Outputs.DbEndpoint
DbName: !GetAtt DatabaseStack.Outputs.DbName
Outputs:
WebsiteUrl:
Description: URL de l'application
Value: !GetAtt ApplicationStack.Outputs.WebsiteUrl
ApiEndpoint:
Description: URL de l'API
Value: !GetAtt ApplicationStack.Outputs.ApiEndpoint
# Template réseau (network.yaml)
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Template pour l''infrastructure réseau'
Parameters:
Environment:
Type: String
VpcCidr:
Type: String
Default: 10.0.0.0/16
Resources:
# VPC
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCidr
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: !Sub '${Environment}-vpc'
# Sous-réseaux publics
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 '${Environment}-public-subnet-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 '${Environment}-public-subnet-2'
# Sous-réseaux privés
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 '${Environment}-private-subnet-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 '${Environment}-private-subnet-2'
# Autres ressources réseau (Internet Gateway, NAT Gateway, Route Tables, etc.)
# ...
Outputs:
VpcId:
Description: ID du VPC
Value: !Ref VPC
PublicSubnetIds:
Description: Liste des IDs des sous-réseaux publics
Value: !Join [',', [!Ref PublicSubnet1, !Ref PublicSubnet2]]
PrivateSubnetIds:
Description: Liste des IDs des sous-réseaux privés
Value: !Join [',', [!Ref PrivateSubnet1, !Ref PrivateSubnet2]]
AWS CDK : CloudFormation en code
AWS CDK (Cloud Development Kit) permet de définir l'infrastructure en utilisant des langages comme TypeScript ou Python, qui génèrent ensuite des templates CloudFormation :
// Exemple AWS CDK en TypeScript pour créer un stack CloudFormation
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as iam from 'aws-cdk-lib/aws-iam';
export class InfrastructureStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Définir un VPC avec 2 sous-réseaux publics et 2 sous-réseaux privés
const vpc = new ec2.Vpc(this, 'MainVpc', {
maxAzs: 2,
natGateways: 1,
subnetConfiguration: [
{
name: 'public',
subnetType: ec2.SubnetType.PUBLIC,
cidrMask: 24,
},
{
name: 'private',
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
cidrMask: 24,
},
],
});
// Créer un groupe de sécurité pour les instances web
const webSG = new ec2.SecurityGroup(this, 'WebSecurityGroup', {
vpc,
description: 'Allow HTTP and SSH',
allowAllOutbound: true,
});
webSG.addIngressRule(
ec2.Peer.anyIpv4(),
ec2.Port.tcp(80),
'Allow HTTP traffic'
);
webSG.addIngressRule(
ec2.Peer.anyIpv4(),
ec2.Port.tcp(22),
'Allow SSH traffic'
);
// Créer un bucket S3 pour les assets statiques
const staticBucket = new s3.Bucket(this, 'StaticAssetsBucket', {
versioned: true,
removalPolicy: cdk.RemovalPolicy.RETAIN,
encryption: s3.BucketEncryption.S3_MANAGED,
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
});
// Créer un rôle IAM pour les instances EC2
const webServerRole = new iam.Role(this, 'WebServerRole', {
assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'),
managedPolicies: [
iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore'),
],
});
// Donner accès au bucket S3 aux instances EC2
staticBucket.grantRead(webServerRole);
// User data pour l'installation d'un serveur web
const userData = ec2.UserData.forLinux();
userData.addCommands(
'yum update -y',
'yum install -y httpd',
'systemctl start httpd',
'systemctl enable httpd',
'echo "<html><body><h1>Hello from CDK!</h1></body></html>" > /var/www/html/index.html'
);
// Créer une instance EC2
const webServer = new ec2.Instance(this, 'WebServer', {
vpc,
vpcSubnets: {
subnetType: ec2.SubnetType.PUBLIC,
},
securityGroup: webSG,
instanceType: ec2.InstanceType.of(
ec2.InstanceClass.T3,
ec2.InstanceSize.MICRO
),
machineImage: ec2.MachineImage.latestAmazonLinux({
generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2,
}),
role: webServerRole,
userData,
});
// Outputs
new cdk.CfnOutput(this, 'WebServerPublicIP', {
value: webServer.instancePublicIp,
description: 'The public IP address of the web server',
});
new cdk.CfnOutput(this, 'BucketName', {
value: staticBucket.bucketName,
description: 'The name of the S3 bucket',
});
new cdk.CfnOutput(this, 'WebServerURL', {
value: `http://${webServer.instancePublicDnsName}`,
description: 'URL of the web server',
});
}
}
Fonctionnalités avancées
- Change Sets : Prévisualisation des modifications avant leur application
- Drift Detection : Détection des modifications manuelles apportées aux ressources
- Stack Policies : Protection des ressources critiques contre les mises à jour accidentelles
- Custom Resources : Extension de CloudFormation pour gérer des ressources personnalisées
- Macros : Transformation dynamique des templates pour générer du contenu
- Provisioned Products : Intégration avec AWS Service Catalog pour une gestion standardisée
Bonnes pratiques
- Validation : Valider les templates avec
aws cloudformation validate-template
ou cfn-lint - Stacks modulaires : Utiliser des stacks imbriqués pour séparer les préoccupations (réseau, sécurité, applications)
- Gestion des paramètres : Utiliser AWS Systems Manager Parameter Store pour les paramètres sensibles
- Dépendances explicites : Utiliser DependsOn pour contrôler l'ordre de création des ressources
- Rollback sur échec : Configurer le rollback automatique en cas d'échec lors de la création ou mise à jour
- DeletionPolicy : Protéger les données importantes avec la politique de suppression Retain ou Snapshot
- Tests : Tester les templates dans des environnements de développement avant la production
Cas d'usage
Environnements multi-couches
Création d'environnements complets pour les applications, incluant le réseau, la sécurité, le calcul avec EC2, le stockage avec
S3 et les bases de données comme
DynamoDB, avec une cohérence totale entre les environnements.
Déploiement continu
Intégration avec les pipelines CI/CD comme AWS CodePipeline et
GitHub Actions pour automatiser le déploiement d'applications et d'infrastructures avec tests et validations automatisés.
Architectures standardisées
Création de templates standardisés pour les équipes afin d'assurer le respect des bonnes pratiques, des normes de sécurité et des processus de gouvernance de l'entreprise.
Infrastructure temporaire
Provisionnement rapide d'environnements de test ou de développement qui peuvent être facilement créés et détruits selon les besoins, optimisant les coûts et les ressources.
Industries et entreprises utilisant CloudFormation
CloudFormation est utilisé dans de nombreux secteurs pour automatiser et standardiser les infrastructures cloud :
Ressources complémentaires
Toutes les compétencesDocumentation officielle
La référence complète pour AWS CloudFormation avec guides et exemples
Bibliothèque de templates
Collection de templates CloudFormation prêts à l'emploi pour divers cas d'usage
AWS CDK
Cloud Development Kit pour définir l'infrastructure en TypeScript, Python, Java ou .NET