cytopia.cloudformation

Rôle Ansible : Créer des piles CloudFormation

Motivation | Installation | Fonctionnalités | Variables | Utilisation | Modèles | Diff | Dépendances | Exigences | Licence

Statut de construction Ansible Galaxy Version

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.

  1. 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.
  2. 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.
  3. 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

Licence MIT

Copyright (c) 2017 cytopia

À propos du projet

Ansible role to render an arbitrary number of Jinja2 templates into cloudformation files and create any number of stacks.

Installer
ansible-galaxy install cytopia.cloudformation
Licence
mit
Téléchargements
5.2k
Propriétaire
DevOps Engineer