CloudFormation Template Basics
Structure of a template
A CloudFormation template is made up of several sections:
AWSTemplateFormatVersion: '2010-09-09'
Description: Description du template
Metadata:
# Informations additionnelles
Parameters:
# Paramètres d'entrée
Mappings:
# Correspondances clé-valeur
Conditions:
# Logique conditionnelle
Transform:
# Macros et transformations
Resources:
# OBLIGATOIRE - Ressources AWS
Outputs:
# Valeurs de sortie
Sections in detail
AWSTemplateFormatVersion
The template format version. Currently, only 2010-09-09 exists.
AWSTemplateFormatVersion: '2010-09-09'
Description
A textual description of the template (max 1024 characters).
Description: |
Ce template crée une infrastructure web complète
incluant VPC, EC2, et RDS.
Version: 1.0.0
Metadata
Additional information for the template.
Metadata:
# Interface pour la console AWS
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "Configuration Réseau"
Parameters:
- VPCCidr
- SubnetCidr
- Label:
default: "Configuration Instance"
Parameters:
- InstanceType
- KeyName
ParameterLabels:
VPCCidr:
default: "CIDR du VPC"
YAML vs JSON
CloudFormation supports both formats. YAML is recommended for its readability.
YAML
Resources:
MyBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: my-bucket
Tags:
- Key: Environment
Value: Production
Equivalent JSON
{
"Resources": {
"MyBucket": {
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName": "my-bucket",
"Tags": [
{
"Key": "Environment",
"Value": "Production"
}
]
}
}
}
}
Comparison
| Aspect | YAML | JSON |
|---|---|---|
| Readability | ✅ Excellent | ⚠️ Average |
| Comments | ✅ Supported | ❌ Not supported |
| Verbosity | Concise | Verbose |
| Common errors | Indentation | Commas, quotes |
YAML syntax for CloudFormation
Data types
# String
Name: "ma-valeur"
# Number
Port: 443
# Boolean
Enabled: true
# List
AvailabilityZones:
- eu-west-1a
- eu-west-1b
- eu-west-1c
# Map
Tags:
Environment: Production
Team: DevOps
# Multi-line string (literal)
UserData: |
#!/bin/bash
yum update -y
yum install -y httpd
# Multi-line string (folded)
Description: >
Ceci est une description
sur plusieurs lignes
qui sera jointe en une seule.
Anchors and aliases
# Définir une ancre
CommonTags: &common-tags
Environment: Production
ManagedBy: CloudFormation
Resources:
Bucket1:
Type: AWS::S3::Bucket
Properties:
Tags:
<<: *common-tags # Réutiliser l'ancre
Name: bucket-1
Bucket2:
Type: AWS::S3::Bucket
Properties:
Tags:
<<: *common-tags
Name: bucket-2
Pseudo-parameters
CloudFormation provides predefined pseudo-parameters:
Resources:
MyBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub 'app-${AWS::Region}-${AWS::AccountId}'
Tags:
- Key: StackName
Value: !Ref AWS::StackName
- Key: StackId
Value: !Ref AWS::StackId
| Pseudo-parameter | Description |
|---|---|
AWS::AccountId | AWS account ID |
AWS::Region | Current region |
AWS::StackName | Stack name |
AWS::StackId | Stack ARN ID |
AWS::URLSuffix | URL suffix (amazonaws.com) |
AWS::Partition | Partition (aws, aws-cn, aws-us-gov) |
AWS::NoValue | Removes a property |
Template validation
Via CLI
# Validation locale
aws cloudformation validate-template \
--template-body file://template.yaml
# Validation avec template S3
aws cloudformation validate-template \
--template-url https://s3.amazonaws.com/bucket/template.yaml
Via cfn-lint
# Installer cfn-lint
pip install cfn-lint
# Valider un template
cfn-lint template.yaml
# Avec règles spécifiques
cfn-lint -t template.yaml --ignore-checks W3002
Common errors
# ❌ ERREUR: Indentation incorrecte
Resources:
MyBucket:
Type: AWS::S3::Bucket
# ✅ CORRECT
Resources:
MyBucket:
Type: AWS::S3::Bucket
# ❌ ERREUR: Type invalide
Resources:
MyBucket:
Type: AWS::S3::Buckett # Typo!
# ✅ CORRECT
Resources:
MyBucket:
Type: AWS::S3::Bucket
Complete template example
AWSTemplateFormatVersion: '2010-09-09'
Description: Infrastructure web basique avec VPC, Subnet et EC2
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "Configuration Réseau"
Parameters:
- VPCCidr
- Label:
default: "Configuration Instance"
Parameters:
- InstanceType
Parameters:
VPCCidr:
Type: String
Default: '10.0.0.0/16'
Description: CIDR block pour le VPC
AllowedPattern: '(\d{1,3}\.){3}\d{1,3}/\d{1,2}'
InstanceType:
Type: String
Default: t3.micro
AllowedValues:
- t3.micro
- t3.small
- t3.medium
Description: Type d'instance EC2
Mappings:
RegionAMI:
eu-west-1:
AMI: ami-0c55b159cbfafe1f0
eu-west-2:
AMI: ami-0a669382ea0feb73a
us-east-1:
AMI: ami-0ff8a91507f77f867
Conditions:
IsProduction: !Equals
- !Ref AWS::StackName
- production
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VPCCidr
EnableDnsHostnames: true
EnableDnsSupport: true
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-vpc'
PublicSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Select
- 0
- !Cidr
- !Ref VPCCidr
- 4
- 8
MapPublicIpOnLaunch: true
AvailabilityZone: !Select
- 0
- !GetAZs ''
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-public-subnet'
WebServer:
Type: AWS::EC2::Instance
Properties:
InstanceType: !Ref InstanceType
ImageId: !FindInMap
- RegionAMI
- !Ref AWS::Region
- AMI
SubnetId: !Ref PublicSubnet
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-webserver'
Outputs:
VPCId:
Description: ID du VPC
Value: !Ref VPC
Export:
Name: !Sub '${AWS::StackName}-VPCId'
InstanceId:
Description: ID de l'instance EC2
Value: !Ref WebServer
PublicIP:
Description: IP publique de l'instance
Value: !GetAtt WebServer.PublicIp
Condition: IsProduction
Syntax best practices
1. Use descriptive names
# ❌ Mauvais
Resources:
R1:
Type: AWS::EC2::VPC
# ✅ Bon
Resources:
ProductionVPC:
Type: AWS::EC2::VPC
2. Comment the code
Resources:
# VPC principal pour l'environnement de production
# CIDR: 10.0.0.0/16 (65536 IPs)
MainVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: '10.0.0.0/16'
3. Organize resources logically
Resources:
# ========================================
# NETWORK
# ========================================
VPC:
Type: AWS::EC2::VPC
# ...
PublicSubnet:
Type: AWS::EC2::Subnet
# ...
# ========================================
# SECURITY
# ========================================
SecurityGroup:
Type: AWS::EC2::SecurityGroup
# ...
# ========================================
# COMPUTE
# ========================================
WebServer:
Type: AWS::EC2::Instance
# ...
Summary
- Templates are written in YAML or JSON
- YAML is recommended for its readability
- The
Resourcessection is mandatory - Pseudo-parameters provide dynamic values
- Always validate your templates before deployment