Skip to main content

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

AspectYAMLJSON
Readability✅ Excellent⚠️ Average
Comments✅ Supported❌ Not supported
VerbosityConciseVerbose
Common errorsIndentationCommas, 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-parameterDescription
AWS::AccountIdAWS account ID
AWS::RegionCurrent region
AWS::StackNameStack name
AWS::StackIdStack ARN ID
AWS::URLSuffixURL suffix (amazonaws.com)
AWS::PartitionPartition (aws, aws-cn, aws-us-gov)
AWS::NoValueRemoves 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 Resources section is mandatory
  • Pseudo-parameters provide dynamic values
  • Always validate your templates before deployment

← Introduction | Resources →