Exercices et Projets
Exercice 1 : Bucket S3 sécurisé
Objectif : Créer un bucket S3 avec toutes les bonnes pratiques de sécurité.
Exigences
- Chiffrement SSE-S3
- Versioning activé
- Bloquer tout accès public
- Lifecycle : transition vers IA après 30 jours, Glacier après 90 jours
- Bucket policy pour forcer HTTPS
- Tags
Solution
AWSTemplateFormatVersion: '2010-09-09'
Description: Exercice 1 - Bucket S3 sécurisé
Parameters:
BucketNamePrefix:
Type: String
Default: secure-data
Environment:
Type: String
AllowedValues: [dev, staging, prod]
Default: dev
Resources:
SecureBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub '${BucketNamePrefix}-${AWS::AccountId}-${AWS::Region}'
# Chiffrement
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
# Versioning
VersioningConfiguration:
Status: Enabled
# Bloquer accès public
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
# Lifecycle
LifecycleConfiguration:
Rules:
- Id: TransitionToIA
Status: Enabled
Transitions:
- StorageClass: STANDARD_IA
TransitionInDays: 30
- StorageClass: GLACIER
TransitionInDays: 90
- Id: DeleteOldVersions
Status: Enabled
NoncurrentVersionExpiration:
NoncurrentDays: 90
# Tags
Tags:
- Key: Environment
Value: !Ref Environment
- Key: Purpose
Value: SecureDataStorage
BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref SecureBucket
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: EnforceHTTPS
Effect: Deny
Principal: '*'
Action: 's3:*'
Resource:
- !GetAtt SecureBucket.Arn
- !Sub '${SecureBucket.Arn}/*'
Condition:
Bool:
'aws:SecureTransport': 'false'
Outputs:
BucketName:
Description: Nom du bucket
Value: !Ref SecureBucket
BucketArn:
Description: ARN du bucket
Value: !GetAtt SecureBucket.Arn
Exercice 2 : VPC complet
Objectif : Créer un VPC avec subnets publics/privés, NAT Gateway et routes.
Architecture
Template
AWSTemplateFormatVersion: '2010-09-09'
Description: Exercice 2 - VPC complet
Parameters:
VPCCidr:
Type: String
Default: '10.0.0.0/16'
Environment:
Type: String
Default: dev
Resources:
# VPC
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VPCCidr
EnableDnsHostnames: true
EnableDnsSupport: true
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-vpc'
# Internet Gateway
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-igw'
VPCGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
# Public Subnets
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Select [0, !Cidr [!Ref VPCCidr, 16, 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, 16, 8]]
AvailabilityZone: !Select [1, !GetAZs '']
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-public-2'
# Private Subnets
PrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Select [10, !Cidr [!Ref VPCCidr, 16, 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 [11, !Cidr [!Ref VPCCidr, 16, 8]]
AvailabilityZone: !Select [1, !GetAZs '']
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-private-2'
# NAT Gateway
NATGatewayEIP:
Type: AWS::EC2::EIP
DependsOn: VPCGatewayAttachment
Properties:
Domain: vpc
NATGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt NATGatewayEIP.AllocationId
SubnetId: !Ref PublicSubnet1
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-nat'
# Route Tables
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-public-rt'
PublicRoute:
Type: AWS::EC2::Route
DependsOn: VPCGatewayAttachment
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet1
RouteTableId: !Ref PublicRouteTable
PublicSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet2
RouteTableId: !Ref PublicRouteTable
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-private-rt'
PrivateRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTable
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NATGateway
PrivateSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnet1
RouteTableId: !Ref PrivateRouteTable
PrivateSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnet2
RouteTableId: !Ref PrivateRouteTable
Outputs:
VPCId:
Description: VPC ID
Value: !Ref VPC
Export:
Name: !Sub '${AWS::StackName}-VPCId'
PublicSubnets:
Description: Public subnet IDs
Value: !Join [',', [!Ref PublicSubnet1, !Ref PublicSubnet2]]
Export:
Name: !Sub '${AWS::StackName}-PublicSubnets'
PrivateSubnets:
Description: Private subnet IDs
Value: !Join [',', [!Ref PrivateSubnet1, !Ref PrivateSubnet2]]
Export:
Name: !Sub '${AWS::StackName}-PrivateSubnets'
Exercice 3 : Application Web avec ALB
Objectif : Déployer une application web avec Auto Scaling et Load Balancer.
Exigences
- ALB avec HTTPS (certificat ACM)
- Auto Scaling Group (2-10 instances)
- Launch Template avec UserData
- Security Groups appropriés
- Health checks
Template (extrait)
AWSTemplateFormatVersion: '2010-09-09'
Description: Exercice 3 - Application Web avec ALB
Parameters:
VPCStackName:
Type: String
Description: Nom de la stack VPC (exercice 2)
InstanceType:
Type: String
Default: t3.micro
MinSize:
Type: Number
Default: 2
MaxSize:
Type: Number
Default: 10
Resources:
# Security Groups
ALBSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: ALB Security Group
VpcId: !ImportValue
!Sub '${VPCStackName}-VPCId'
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
AppSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Application Security Group
VpcId: !ImportValue
!Sub '${VPCStackName}-VPCId'
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
SourceSecurityGroupId: !Ref ALBSecurityGroup
# Application Load Balancer
ApplicationLoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: !Sub '${AWS::StackName}-alb'
Type: application
Scheme: internet-facing
SecurityGroups:
- !Ref ALBSecurityGroup
Subnets: !Split
- ','
- !ImportValue
!Sub '${VPCStackName}-PublicSubnets'
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: !Sub '${AWS::StackName}-tg'
Port: 80
Protocol: HTTP
VpcId: !ImportValue
!Sub '${VPCStackName}-VPCId'
HealthCheckPath: /health
HealthCheckIntervalSeconds: 30
HealthyThresholdCount: 2
UnhealthyThresholdCount: 3
TargetType: instance
HTTPListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
LoadBalancerArn: !Ref ApplicationLoadBalancer
Port: 80
Protocol: HTTP
DefaultActions:
- Type: forward
TargetGroupArn: !Ref TargetGroup
# Launch Template
LaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateName: !Sub '${AWS::StackName}-lt'
LaunchTemplateData:
ImageId: !Sub '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}'
InstanceType: !Ref InstanceType
SecurityGroupIds:
- !Ref AppSecurityGroup
UserData:
Fn::Base64: !Sub |
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
cat > /var/www/html/index.html <<EOF
<!DOCTYPE html>
<html>
<head><title>CloudFormation Demo</title></head>
<body>
<h1>Hello from CloudFormation!</h1>
<p>Instance: $INSTANCE_ID</p>
<p>Stack: ${AWS::StackName}</p>
<p>Region: ${AWS::Region}</p>
</body>
</html>
EOF
echo "OK" > /var/www/html/health
# Auto Scaling Group
AutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
AutoScalingGroupName: !Sub '${AWS::StackName}-asg'
LaunchTemplate:
LaunchTemplateId: !Ref LaunchTemplate
Version: !GetAtt LaunchTemplate.LatestVersionNumber
MinSize: !Ref MinSize
MaxSize: !Ref MaxSize
DesiredCapacity: !Ref MinSize
VPCZoneIdentifier: !Split
- ','
- !ImportValue
!Sub '${VPCStackName}-PrivateSubnets'
TargetGroupARNs:
- !Ref TargetGroup
HealthCheckType: ELB
HealthCheckGracePeriod: 300
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-instance'
PropagateAtLaunch: true
# Scaling Policies
ScaleUpPolicy:
Type: AWS::AutoScaling::ScalingPolicy
Properties:
AutoScalingGroupName: !Ref AutoScalingGroup
PolicyType: TargetTrackingScaling
TargetTrackingConfiguration:
PredefinedMetricSpecification:
PredefinedMetricType: ASGAverageCPUUtilization
TargetValue: 70
Outputs:
LoadBalancerDNS:
Description: URL de l'application
Value: !Sub 'http://${ApplicationLoadBalancer.DNSName}'
Projet final : Infrastructure complète
Objectif : Créer une infrastructure de production complète avec nested stacks.
Architecture
Structure
project/
├── main.yaml
├── templates/
│ ├── network.yaml
│ ├── security.yaml
│ ├── database.yaml
│ └── application.yaml
├── parameters/
│ ├── dev.json
│ └── prod.json
└── deploy.sh
Déploiement
#!/bin/bash
# deploy.sh
STACK_NAME="production-infra"
ENVIRONMENT="prod"
REGION="eu-west-1"
BUCKET="my-cfn-templates-bucket"
# Upload templates
aws s3 sync ./templates s3://${BUCKET}/templates/
# Deploy
aws cloudformation deploy \
--template-file main.yaml \
--stack-name ${STACK_NAME} \
--parameter-overrides \
Environment=${ENVIRONMENT} \
TemplateBucket=${BUCKET} \
--capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM \
--region ${REGION}
# Get outputs
aws cloudformation describe-stacks \
--stack-name ${STACK_NAME} \
--query 'Stacks[0].Outputs' \
--region ${REGION}
Récapitulatif du cours
Félicitations ! Vous avez complété le cours AWS CloudFormation.
Ce que vous avez appris
- ✅ Concepts et workflow CloudFormation
- ✅ Structure des templates YAML/JSON
- ✅ Ressources AWS
- ✅ Paramètres et validation
- ✅ Mappings et conditions
- ✅ Outputs et exports cross-stack
- ✅ Fonctions intrinsèques
- ✅ Nested stacks et StackSets
- ✅ Bonnes pratiques et sécurité
- ✅ Projets pratiques
Prochaines étapes
- Pratiquez avec les exercices
- Explorez AWS SAM pour les applications serverless
- Découvrez CDK pour l'IaC en code