Archives de catégorie : Ansible

Raspberry et Ansible : gestion des clefs SSH et suppression du user par défaut

Précédemment, nous avions découvert comment créer nos users avec ansible. Mais nous avons quelques lacunes avec cette gestion minimaliste des users. En effet, d’une part la connexion ne se fait que par mot de passe (ce n’est pas pratique et très sécurisé). D’autre part, l’existence du user pi est une vraie faille de sécurité. Toute installation d’un raspbian dispose systématiquement de ce user et bien sûr avec le même mot de passe (pratique mais pas sécurisé tout ça).

Création de nos users

Pour cela nous allons industrialiser tout cela avec Ansible. Pour appel, nous avions nos mots de passe stockés sous les varaiables de group_vars/all/all.yml avec ceci :

users_password_xavki: "{{ vault_users_password_xavki }}"
users_password_xavier: "{{ vault_users_password_xavier }}"

Et ces variables faisaient appel à un fichier vault situé au même endroit dans group_vars/all/vault.yml mais chiffré par un mot de passe :

$ANSIBLE_VAULT;1.1;AES256
613362633865666266653364373533323263663137623536316431313933653331336239623437613232343965386434353761386436333663303533653862350a333939363463653663656563643966653035353666623165323434613434616334313163616663643763396635313636323666356437393665366339636561650a623032376634633634353132343539613962306132373230343232306234346664336231343866326532363930303566313262376264383231306664386462303461646432646433386535333432643337613138653365396132386261373362366463646564373830656265613239366334636361336462313039323064666432646161326463666635366663313539303136313965623430386435303466386634663161393438363134376138393137373033323565353065383465356638

Maintenant créons un répertoire dédié au stockage de nos clefs publiques (PUBLIQUES j’insiste) : files. Il s’agit des clefs que nous allons diffuser et installer dans la home de nos users. S’agissant de clefs publiques, un chiffrement n’est pas nécessaire, seule la clef privée est d’une importance capitale.

Maintenant modifions notre playbook de création des users :

- name: deploy users
  hosts: all
  become: yes
  vars:
    users_admin:
    - { name: "xavki", password: "{{ vault_users_password_xavki }}" }
    users_no_admin:
    - { name: "xavier", password: "{{ vault_users_password_xavier }}" }
  tasks:
  - name: create group admin
    group:
      name: "admin"
      state: present

  - name: create admin user accounts
    user:
      name: "{{ item.name }}"
      password: "{{ item.password | password_hash('sha512')}}"
      groups: "admin"
    with_items:
    - "{{ users_admin }}"
    no_log: true
 
  - name: create standard user accounts
    user:
      name: "{{ item.name }}"
      password: "{{ item.password | password_hash('sha512')}}"
    with_items:
    - "{{ users_no_admin }}"
    no_log: true

  - name: add authorized keys
    authorized_key:
      user: "{{ item.name }}"
      key: "{{ lookup('file', 'files/'+ item.name + '.key.pub') }}"
    with_items: 
    - "{{ users_admin }}"
    - "{{ users_no_admin }}"
 
  - name: "Allow admin users to sudo without a password"
    lineinfile:
      dest: "/etc/sudoers"
      state: "present"
      regexp: "^%sudo"
      line: "%admin ALL=(ALL) NOPASSWD: ALL"

La tâche « add authorized keys » nous permet donc de récupérer ces clefs et de les placer par défaut dans la hoem de chaque users et selon la bonne pratique avec un répertoire « .ssh ».

Voici donc pour le déploiement de nos clefs correspondantes pour chaque utilisateurs.

Retrouvez les fichiers ici.

Suppression du user PI

Pour supprimer un utilisateur, la démarche est très simple, il suffit d’ajouter la tâches suivante :

- name: remove pi user
  user:
    name: "pi"
    state: absent

Profitons-en pour faire un peu d’organisation et de bonnes pratiques ansible. Pour cela nous allons utliser le principe de rôle. Un rôle est une sorte de module/librairie/fonction qui peut être appelé autant que nécessaire.

Pour cela nous allon créer un répertoire « roles » à la racine de notre ansible et taper la commande :

mkdir roles && cd roles
ansible-galaxy init users

Cette commande créée toute la structure nécessaire pour créer le contenu d’un rôle. A l’heure actuelle ce qui nous intéresse c’est uniquement le répertoire task et son fichier main.yml. C’ets la première chose qui est appelé quand on lance un rôle. Donc dans ce fichier nous recopions le conteneur de notre users.yml.

Ensuite il nous faut modifier notre playbook pour appeler le rôle et non plus les tâches une à une :

- name: deploy users
  become: yes
  hosts: all
  roles:
  - users

Et voilà le tour est joué. il ne reste plus qu’à jouer le playbook :

ansible-playbook -i list_servers.yml -u xavki users.yml

Retrouvez les fichiers ici.

Ansible – Comment installer la stack haproxy, consul et consult template de manière orchestrée ?

Ansible est pratiquement inévitable à l’heure actuelle. Il faut dire que cet orchestrateur est surement l’un des plus simples à utiliser et à apprendre.

Pour apprendre à l’utiliser, je vous propose d’installer une stack très utile :

  • haproxy : reverse-proxy et load-balancer très réputé
  • consul : la registry de service dont je vous ai déjà parlé sur le blog et la chaine youtube
  • consul-template : un binaire qui va permettre de modifier automatiquement la conf de haproxy en cas de modification dans la composition et l’état des services de consul

En 9 courtes vidéos, vous allez pouvoir faire coup double :

  1. Installation de haproxy : rôle, apt
  2. Installation de consul : unarchive, wget
  3. Création du user consul : user, group
  4. Structurer ses tâches : include task
  5. Gestion des configurations : templates
  6. Création d’une application de test
  7. Mise en place d’un service système D
  8. Installation du binaire consul-template
  9. Finalisation de consul-template : utilisation de blockinfile, du jinja dans du jinja

Grâce à ces vidéos, vous allez pouvoir rendre dynamique votre configuration haproxy et réaliser un haproxy reload si nécessaire.

[Ansible] – comment utiliser les gather_facts et tenir à jour un début de cmdb ?

Ansible regorge d’astuces qu’il faut engranger pour pouvoir aller plus loin et ne pas simplement installer des paquets sur des machines distantes. Par exemple, nous allons voir aujourd’hui une valorisation des gather_facts de ansible. Sur puppet, je crois que la même chose est réalisable avec facter.

Gather_facts c’est la possibilité d’utiliser des variables d’environnement ansible. Ce sont principalement des caractéristiques de la machine (interface, os…). Ces données vous vous en doutez seraient bien utiles dans une cmdb (centralisation d’informations de votre parc de machine).

Pour commencer cette démos nous allons commencer par créer quelques machines à l’aide de mon script maison (vous pouvez aussi le découvrir en vidéo désormais). Dans mon cas, j’ai 2 vm debian qui fonctionnent avec du ssh (merci docker).

└─ $ ▶ ./deploy-centre-sans-proxy-v2.sh --infos
#### Récap des conteneurs de tests ####
=> /oki-deb-vmparc3 - 172.17.0.3 - Utilisteur : oki / mdp:password
=> /oki-deb-vmparc2 - 172.17.0.2 - Utilisteur : oki / mdp:password

Maintenant nous allons configurer notre inventory hosts.yml très simplement :

all:  hosts:    172.17.0.2:    172.17.0.3:

Objectif ?

Notre souhait c’est d’utiliser les gather_facts et faire en sorte que ansible centralise tout cela sous forme de fichiers.html. Ainsi nous pourrons faire de la datavisualisation avec un apache installé localement (attention c’est pour la démo, c’est très moyen d’installer un serveur web sur une machine qui a la main sur tout votre parc).

Enfin, grâce à notre apache on pourra afficher dans un navigateur web. Et vous verrez ce qui compte c’est le principe car derrière c’est assez facile d’avoir des idées pour compléter tout cela pour avoir un bon début de cmdb.

Comment lister les gather_facts à notre dispostion ?

Les gather_facts sont accessibles via le module setup de ansible. Donc pour consulter toutes ces variables voici la commande à réaliser :

ansible all - i hosts.yml -u oki -m "setup"

La liste est assez longue et c’est plutôt une bonne nouvelle.

Faisons nos courses et retenons les variables :

  • inventory_hostname
  • ansible_default_ipv4.alias
  • ansible_architecture
  • ansible_distribution
  • ansible_distribution_version

Et on met tout cela en forme dans un template jinja2 pour générer à terme un fichier html :

<h1>Machine : {{ inventory_hostname }}</h1>
<ul>
<li>Interfaces : {{ ansible_default_ipv4.alias }}</li>
<li>Architecture : {{ ansible_architecture }}</li>
<li>OS : {{ ansible_distribution }}</li>
<li>Version : {{ ansible_distribution_version }}</li>
</ul>

Maintenant le playbook !

Voici le contenu de notre répertoire :

.
├── hosts.yml
├── playbook-cmdb.yml
└── templates
└── listing_ipv4.html.j2

Editons donc le playbook-cmdb.yml de la manière suivante :

---
- name: "[IP v4 listing]"
  hosts: all
  gather_facts: yes
  tasks:
    - name: "[IP v4 listing] - generate html"
      template:
        src: listing_ipv4.html.j2
        dest: "/var/www/html/{{ inventory_hostname }}.html"
      connection: local

Première chose on spécifie l’utilisation des gather_acts. Ensuite on utilise le module template pour faire appel au fichier jinja2. Puis on indique comme destination le répertoire de notre apache /var/www/html/ (de la machine master host). C’est aussi pour cela que nous spécifions connection : local.

Maintenant lançons la commande ansible-playbook :

ansible-playbook -i hosts.yml -u oki playbook-cmdb.yml

Et bingo :

PLAY [[IP v4 listing]] *******************************

TASK [Gathering Facts] *******************************
ok: [172.17.0.3]
ok: [172.17.0.2]

TASK [[IP v4 listing] - generate html] ***************
changed: [172.17.0.3]
changed: [172.17.0.2]

PLAY RECAP *******************************************
172.17.0.2 : ok=2 changed=1 unreachable=0 failed=0 
172.17.0.3 : ok=2 changed=1 unreachable=0 failed=0

Supprimons l’index de notre apache local : rm -f /var/www/html/index.html

Remarque : j’ai confié les droits de ce réprtoire à oki pour cet exercice

Et voici le résultat, une fiche par machine :

fiche-arbre

Puis la fiche de la machine :

fiche-cmdb.png

C’est bon tout ça non ? On comprend mieux l’intérêt des facts avec ce genre d’outils d’orchestration. Et ne vous inquiétez pas vous pouvez aisément pousser les fichier vers une autre machine qui portera un service apache de manière isolée.

Ansible – installer un applicatif (ex. WordPress)

Poursuivons notre découverte de ansible avec l’installation d’un applicatif en l’occurence wordpress. Chaque applicatif possède toutefois des manières différentes de s’installer, il s’agit juste là de prendre un exemple pour se faire la main.

Vous pouvez retrouver cet article en vidéo :

 

La première chose à faire dans notre rôle est de vérifier si wordpress existe déjà :

- name: "[WORDPRESS] - check if exist"
  stat: 
    path: "/var/www/html/wordpress/"
  register: check_wordpress

Avec stat, nous vérifions si le répertoire wordpress est déjà là et nous alimentons l’état de ce répertoire dans une variable avec register. Notre variable s’appelle donc check_wordpress.

Utilisons maintenant cette variable pour conditonner à celle-ci le téléchargement de l’archive tar.gz.

- name: "[WORDPRESS] - download tar.gz"
  unarchive:
    src: "{{ wordpress_source }}"
    dest: "/var/www/html/"
    remote_src: yes
  when: check_wordpress.stat.exists == False

Avec unarchive, nous procédons au téléchargement en ligne car la variable wordpress_source est une url de téléchargement. Par ailleurs pour pouvoir télécharger une url on utilise remote_src. Et enfin notre condition avec le when.

Après nous procédons à la suppression de index.html que notre apache à installer par défaut.

- name: "[WORDPRESS] - index.html"
  file: 
    path: "/var/www/html/index.html"
    state: absent

Pour cela nous utilisons le module file avec un state à absent.

A la première installation, le fichier wp-config.php se nomme wp-config-sample.php. Nous vérifions donc si nous sommes dans ce cas.

- name: "[WORDPRESS] - exist wp-config-sample.php"
  stat:
    path: "/var/www/html/wordpress/wp-config-sample.php"
  register: check_sample

Nous procédons comme pour le répertoire wordpress en vérifiant la présence de wp-config-sample.php.

Si c’est le cas nous le renommons.

- name: "[WORDPRESS] - rename wp-config-sample.php"
  command: mv /var/www/html/wordpress/wp-config-sample.php /var/www/html/wordpress/wp-config.php 
  when: check_sample.stat.exists == True

Enfin nous procédons à  la modification de plusieurs ligne dans ce même fichier pour configurer celui-ci en fonction de notre serveur base de données.

- name: "[WORDPRESS] - config wp-config.php"
  lineinfile:
    dest: "/var/www/html/wordpress/wp-config.php"
    regexp: "{{ item.search }}"
    line: "{{ item.new }}"
    backrefs: yes
  with_items:
    - {'search': '^(.*)database_name_here(.*)$', 'new': '{{ mysql_db }}'}
    - {'search': '^(.*)username_here(.*)$', 'new': '{{ mysql_user }}'}
    - {'search': '^(.*)password_here(.*)$', 'new': '{{ mysql_password }}'}

Pour chaque ligne définie dans le with_items, nous recherchons un élément (ex : database_name_here) et compturons les éléments présents avant et après. Ensuite nous remplaçons cette ligne par une nouvelle ligne contenant le premier élément capturé puis notre variable puis le deuxième élément capturé.

Et voilà pour notre installation de wordpress. Vous pouvez retrouver tout le code sur mon github.