cytopia.cloudformation
Rôle Ansible : Créer des piles CloudFormation
Motivation | Installation | Fonctionnalités | Variables | Utilisation | Modèles | Diff | Dépendances | Exigences | Licence
Rôle Ansible pour générer un nombre arbitraire de modèles Jinja2 en fichiers CloudFormation et déployer n'importe quel nombre de piles.
Motivation
Ce rôle surmonte les limites des modèles CloudFormation eux-mêmes tout en utilisant beaucoup de fonctionnalités d'Ansible.
- Limitations de CloudFormation - La syntaxe CloudFormation est très limitée en ce qui concerne la logique de programmation, comme les conditions, les boucles et les variables complexes comme les tableaux ou les dictionnaires. En intégrant votre modèle CloudFormation dans Ansible, vous pourrez utiliser des directives Jinja2 à l'intérieur du modèle CloudFormation, alliée à la puissance d'Ansible pour déployer des piles CloudFormation.
- Indépendant de l'environnement - Grâce à la possibilité de rendre des modèles CloudFormation avec des variables de boucle personnalisées, vous pouvez enfin créer des modèles entièrement indépendants de l'environnement et les réutiliser pour la production, les tests, la mise en scène et d'autres environnements.
- Exécution à blanc - Un autre avantage d'utiliser Ansible pour déployer vos modèles CloudFormation est qu'Ansible prend en charge un mode d'exécution à blanc (
--check
) pour les déploiements CloudFormation (depuis Ansible 2.4). En mode vérification, il créera des ensembles de changements et vous informera de ce qui changerait si vous le déployez réellement. Cela vous permet de tester vos piles en toute sécurité avant de les appliquer.
Ce rôle peut être utilisé uniquement pour générer vos modèles via cloudformation_generate_only
ou aussi pour déployer vos modèles rendus. Si votre infrastructure de déploiement est déjà en place, vous pouvez simplement rendre les modèles et les transmettre ensuite à votre infrastructure existante.
Lorsque les modèles sont rendus, un répertoire temporaire build/
est créé dans le répertoire du rôle. Ce répertoire peut soit persister, soit être recréé à chaque exécution du rôle. Spécifiez le comportement avec cloudformation_clean_build_env
.
Installation
Utilisez soit Ansible Galaxy pour installer le rôle :
$ ansible-galaxy install cytopia.cloudformation
Ou clonez-le avec git dans votre répertoire de rôles :
$ git clone https://github.com/cytopia/ansible-role-cloudformation /chemin/vers/ansible/roles
Fonctionnalités
- Déployer un nombre arbitraire de modèles CloudFormation
- Créer des modèles CloudFormation avec le moteur de modèle Jinja2
- Rendre des modèles uniquement et utiliser votre infrastructure actuelle pour déployer
- Exécution à blanc via le mode
--check
d'Ansible, qui générera des ensembles de changements temporaires (ex : vous indique si une ressource doit être recréée) - Avoir un diff ligne par ligne entre les modèles locaux et déployés via le module cloudformation_diff
- Utiliser Ansible Vault pour stocker des informations sensibles de manière sécurisée
Variables
Vue d'ensemble
Les variables suivantes sont disponibles dans defaults/main.yml
et peuvent être utilisées pour configurer votre infrastructure.
Variable | Type | Par défaut | Description |
---|---|---|---|
cloudformation_clean_build_env |
bool | False |
Nettoyer le répertoire build/ des modèles CloudFormation rendus par Jinja2 à chaque exécution. |
cloudformation_generate_only |
bool | False |
Au lieu de déployer vos modèles CloudFormation, vous pouvez aussi simplement les rendre et les rendre disponibles dans le répertoire build/ pour que vous puissiez utiliser votre infrastructure actuelle pour déployer ces modèles.Astuce : Spécifiez cette variable via les arguments en ligne de commande Ansible |
cloudformation_run_diff |
bool | False |
Ce rôle comprend un module CloudFormation personnalisé d'Ansible cloudformation_diff. Ce module génère un output diff basé sur du texte entre votre modèle CloudFormation local prêt à être déployé et le modèle actuellement déployé sur AWS CloudFormation. Pourquoi vouloir cela ? Le module CloudFormation actuel ne liste que les ensembles de changements en mode --check, indiquant quel type changera (ex : groupes de sécurité), mais pas exactement ce qui changera (quels groupes de sécurité et leurs valeurs) Pour voir les changements exacts, activez le module cloudformation_diff ici. |
cloudformation_diff_output |
string | json |
Lorsque cloudformation_run_diff est activé, quel type de diff de sortie doit être spécifié ? Si vous écrivez vos modèles CloudFormation en json, utilisez json ici ou si vous les écrivez en yaml, utilisez yaml . |
cloudformation_required |
list | [] |
Tableau des clés de pile CloudFormation disponibles que vous souhaitez rendre obligatoires plutôt qu'optionnelles. Chaque élément de la pile CloudFormation sera vérifié par rapport aux clés requises. Si un élément de la pile ne contient aucune de ces clés, une erreur sera signalée avant tout déploiement. |
cloudformation_defaults |
dict | {} |
Dictionnaire de valeurs par défaut à appliquer à chaque pile CloudFormation. Notez que ces valeurs peuvent toujours être écrasées pour chaque définition de pile. |
cloudformation_stacks |
list | [] |
Tableau des piles CloudFormation à déployer. |
Détails
Cette section contient une description plus détaillée des clés des dictionnaires ou tableaux disponibles.
cloudformation_defaults
Clé | Type | Requis | Description |
---|---|---|---|
aws_access_key |
string | optionnel | Clé d'accès AWS à utiliser |
aws_secret_key |
string | optionnel | Clé secrète AWS à utiliser |
security_token |
string | optionnel | Jeton de sécurité AWS à utiliser |
profile |
string | optionnel | Profil AWS boto à utiliser |
notification_arns |
string | optionnel | Publier les notifications de la pile vers ces ARN |
termination_protection |
bool | optionnel | Activer ou désactiver la protection contre la suppression de la pile. Fonctionne uniquement avec botocore >= 1.7.18 |
region |
string | optionnel | Région AWS pour déployer la pile |
cloudformation_stacks
Clé | Type | Requis | Description |
---|---|---|---|
stack_name |
string | requis | Nom de la pile CloudFormation |
template |
string | requis | Chemin vers le modèle CloudFormation à rendre et déployer (n’a pas besoin d’être rendu) |
aws_access_key |
string | optionnel | Clé d'accès AWS à utiliser (écrase la valeur par défaut) |
aws_secret_key |
string | optionnel | Clé d'accès AWS à utiliser (écrase la valeur par défaut) |
security_token |
string | optionnel | Jeton de sécurité AWS à utiliser (écrase la valeur par défaut) |
profile |
string | optionnel | Profil AWS boto à utiliser (écrase la valeur par défaut) |
notification_arns |
string | optionnel | Publier les notifications de la pile vers ces ARN (écrase la valeur par défaut) |
termination_protection |
bool | optionnel | Activer ou désactiver la protection contre la suppression de la pile. Fonctionne uniquement avec botocore >= 1.7.18 |
region |
string | optionnel | Région AWS pour déployer la pile (écrase la valeur par défaut) |
template_parameters |
dict | optionnel | Paramètres requis pour la pile CloudFormation |
tags |
dict | optionnel | Tags associés à la pile CloudFormation |
Exemples
Définir des valeurs par défaut à appliquer à toutes les piles (si elles ne sont pas écrasées pour chaque définition de pile)
# Exiger que 'profile' doit être défini pour chaque élément de la pile CloudFormation
cloudformation_required:
- profile
cloudformation_defaults:
region: eu-central-1
Définir les piles CloudFormation à rendre et déployer
cloudformation_stacks:
- stack_name: stack-s3
template: files/cloudformation/s3.yml.j2
profile: production
template_parameters:
bucketName: my-bucket
tags:
env: production
- stack_name: stack-lambda
template: files/cloudformation/lambda.yml.j2
profile: production
termination_protection: True
template_parameters:
lambdaFunctionName: lambda
handler: lambda.run_handler
runtime: python2.7
s3Bucket: my-bucket
s3Key: lambda.py.zip
tags:
env: production
Rendre uniquement vos modèles Jinja2, mais ne pas les déployer sur AWS. Les fichiers CloudFormation rendus seront dans le répertoire build/
de ce rôle.
$ ansible-playbook play.yml -e cloudformation_generate_only=True
Utilisation
Simple
Exemple d'utilisation de base :
playbook.yml
- hosts: localhost
connection: local
roles:
- cloudformation
group_vars/all.yml
# Définir les piles CloudFormation
cloudformation_stacks:
# Première pile
- stack_name: stack-s3
profile: testing
region: eu-central-1
template: files/cloudformation/s3.yml.j2
template_parameters:
bucketName: my-bucket
tags:
env: testing
# Deuxième pile
- stack_name: stack-lambda
profile: testing
termination_protection: True
region: eu-central-1
template: files/cloudformation/lambda.yml.j2
template_parameters:
lambdaFunctionName: lambda
handler: lambda.run_handler
runtime: python2.7
s3Bucket: my-bucket
s3Key: lambda.py.zip
tags:
env: testing
Avancé
Exemple d'utilisation avancée appelant le rôle indépendamment sur différents hôtes virtuels.
inventory
[my-group]
infrastructure ansible_connection=local
application ansible_connection=local
playbook.yml
# Partie Infrastructure
- hosts: infrastructure
roles:
- cloudformation
tags:
- infrastructure
# Partie Application
- hosts: application
roles:
- some-role
tags:
- some-role
- application
- hosts: application
roles:
- cloudformation
tags:
- application
group_vars/my-group.yml
stack_prefix: testing
boto_profile: testing
s3_bucket: awesome-lambda
cloudformation_defaults:
profile: "{{ boto_profile }}"
region: eu-central-1
host_vars/infrastructure.yml
cloudformation_stacks:
- stack_name: "{{ stack_prefix }}-s3"
template: files/cloudformation/s3.yml.j2
template_parameters:
bucketName: "{{ s3_bucket }}"
tags:
env: "{{ stack_prefix }}"
host_vars/application.yml
cloudformation_stacks:
- stack_name: "{{ stack_prefix }}-lambda"
template: files/cloudformation/lambda.yml.j2
template_parameters:
lambdaFunctionName: lambda
handler: lambda.run_handler
runtime: python2.7
s3Bucket: "{{ s3_bucket }}"
s3Key: lambda.py.zip
tags:
env: "{{ stack_prefix }}"
Modèles
Cette section donne un aperçu de ce qui peut être fait avec des modèles CloudFormation utilisant des directives Jinja2.
Exemple : Définitions de sous-réseaux
Le modèle suivant peut être déployé dans différents environnements de mise en scène et est capable d'inclure un nombre différent de sous-réseaux.
Variables Ansible
---
# fichier : staging.yml
vpc_subnets:
- directive: subnetA
az: a
cidr: 10.0.10.0/24
tags:
- name: Name
value: staging-subnet-a
- name: env
value: staging
- directive: subnetB
az: b
cidr: 10.0.20.0/24
tags:
- name: Name
value: staging-subnet-b
- name: env
value: staging
---
# fichier : production.yml
vpc_subnets:
- directive: subnetA
az: a
cidr: 10.0.10.0/24
tags:
- name: Name
value: prod-subnet-a
- name: env
value: production
- directive: subnetB
az: b
cidr: 10.0.20.0/24
tags:
- name: Name
value: prod-subnet-b
- name: env
value: production
- directive: subnetC
az: b
cidr: 10.0.30.0/24
tags:
- name: Name
value: prod-subnet-c
- name: env
value: production
Modèle CloudFormation
AWSTemplateFormatVersion: '2010-09-09'
Description: Modèle VPC
Resources:
vpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: {{ vpc_cidr_block }}
EnableDnsSupport: true
EnableDnsHostnames: true
{% if vpc_tags %}
Tags:
{% for tag in vpc_tags %}
- Key: {{ tag.name }}
Value: {{ tag.value }}
{% endfor %}
{% endif %}
{% for subnet in vpc_subnets %}
{{ subnet.directive }}:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: {{ subnet.az }}
CidrBlock: {{ subnet.cidr }}
VpcId: !Ref vpc
{% if subnet.tags %}
Tags:
{% for tag in subnet.tags %}
- Key: {{ tag.name }}
Value: {{ tag.value }}
{% endfor %}
{% endif %}
Exemple : Groupes de sécurité
Définir des groupes de sécurité avec des règles spécifiques IP est très difficile lorsque vous souhaitez conserver l'indépendance environnementale et utiliser le même modèle CloudFormation pour tous les environnements. Cela peut cependant être facilement contourné en fournissant des définitions de tableau spécifiques à l'environnement via Jinja2.
Variables Ansible
---
# fichier : staging.yml
# La mise en scène est largement ouverte, permettant aux développeurs de
# se connecter depuis les VPN associés
security_groups:
- protocol: tcp
from_port: 3306
to_port: 3306
cidr_ip: 10.0.0.1/32
- protocol: tcp
from_port: 3306
to_port: 3306
cidr_ip: 192.168.0.15/32
- protocol: tcp
from_port: 3306
to_port: 3306
cidr_ip: 172.16.0.0/16
---
# fichier : production.yml
# L'environnement de production a beaucoup moins de règles ainsi que d'autres
# plages IP.
security_groups:
- protocol: tcp
from_port: 3306
to_port: 3306
cidr_ip: 10.0.15.1/32
Modèle CloudFormation
AWSTemplateFormatVersion: '2010-09-09'
Description: Modèle VPC
Resources:
rdsSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Groupe de sécurité RDS
{% if security_groups %}
SecurityGroupIngress:
{% for rule in security_groups %}
- IpProtocol: "{{ rule.protocol }}"
FromPort: "{{ rule.from_port }}"
ToPort: "{{ rule.to_port }}"
CidrIp: "{{ rule.cidr_ip }}"
{% endfor %}
{% endif %}
Diff
Lorsque vous activez cloudformation_run_diff
, vous pourrez voir un output diff ligne par ligne entre votre modèle local (rendu par jinja2) et celui qui est actuellement déployé sur AWS. Pour vous donner une idée de ce à quoi cela ressemble, voici un exemple de sortie :
Assurez-vous d'exécuter Ansible avec --diff
pour que cela fonctionne :
$ ansible-playbook play.yml --diff
Diff Json
Pour avoir une sortie en mode diff json, réglez cloudformation_diff_output
sur json
.
TÂCHE [cloudformation : diff du fichier modèle cloudformation] *********************************************
--- avant
+++ après
@@ -38,7 +38,6 @@
"Type": "AWS::S3::BucketPolicy"
},
"s3Bucket": {
- "DeletionPolicy": "Retain",
"Properties": {
"BucketName": {
"Ref": "bucketName"
Diff Yaml
Pour avoir une sortie en mode diff yaml, réglez cloudformation_diff_output
sur yaml
.
TÂCHE [cloudformation : diff du fichier modèle cloudformation] *********************************************
--- avant
+++ après
@@ -14,7 +14,6 @@
Service: !Sub 'logs.${AWS::Region}.amazonaws.com'
Bucket: !Ref 's3Bucket'
s3Bucket:
- DeletionPolicy: Retain
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref 'bucketName'
Dépendances
Ce rôle ne dépend d'aucun autre rôle.
Exigences
Utilisez au moins Ansible 2.5 pour bénéficier également du mode --check
pour CloudFormation.
Le module python cfn_flip
est requis lors de l'utilisation de la diff ligne par ligne entre les modèles CloudFormation locaux et distants (cloudformation_run_diff=True
). Cela peut être facilement installé localement :
$ pip install cfn_flip
Licence
Copyright (c) 2017 cytopia
Ansible role to render an arbitrary number of Jinja2 templates into cloudformation files and create any number of stacks.
ansible-galaxy install cytopia.cloudformation