Select Page

Variablen mergen mit Ansible

by | May 13, 2021 | Ansible

Ansible kann Variable standardmäßig nicht mergen (miteinander vereinen, ineinander übergeben), sondern nur an verschiedenen Stellen überschreiben. Dies ist  bei manchen Anwendungsfällen unpraktisch, unübersichtlich und fehleranfällig wie z. B. beim ausrollen von SSH-Keys, Usern oder Firewall-Regeln. Angenommen wir wollen sowohl allgemeine SSH-Keys auf alle Server ausrollen, als auch extra Schlüssel zu bestimmten Servern zuordnen. In diesem Fall können wir unter group_vars/all  die allgemeinen Keys in einem Array oder in einem Dictonary definieren und unter group_vars/group_name oder host_vars/hostname die vorherigen Keys plus die Extras eintragen. Eine andere Möglichkeit wäre, dass wir die SSH-Keys (allgemeine und spezifische) in unterschiedlichen Variablen packen, die jeweils mit einem Task behandelt werden können. Die oben erwähnte Möglichkeiten machen besonders bei großen Umgebungen kein Spaß und ergibt am Ende entweder unübersichtliche Variablen-Definition oder statische Rollen.

In diesem Zuge wäre hiera im Kombination mit dem hiera lookup plugin eine gute Lösung. hiera ist ein hierarchisch durchsuchbarer key => value Store. In diesem Blogpost werde ich anhand eines Beispiels demonstrieren, wie hiera mit Ansible eingesetzt werden kann. Dieses Beispiel befasst die Verteilung der Konfigurationen für Gruppen, Benutzers und SSH-Keys auf zwei Server.  Bei allen Linux-Distrubtionen gibt es in unserem Fall keine Unterschiede. Alle Schritte erfolgen auf dem Ansible Controller.  Ich fange mal mit der hiera Installation an.

# yum install ruby -y
# gem install hiera

Unter /etc/hiera.yaml liegt die hiera-Konfiguration.

:backends:
- yaml
:hierarchy:
- "%{groups}"
- "%{hosts}"
- common

:yaml:
:datadir: /etc/hieradata

:merge_behavior: deeper

Unter hierarchy definieren wir die Stufen aufsteigend/absteigend, bei denen hiera nach einem Schlüssel suchen soll. hiera fängt mit groups an zu suchen und endet mit common. common trifft immer zu und gilt in unserem Fall für alle Server. groups und hosts sind Facts, die wir später dem Ansible playbook übergeben wollen. Der Pfad zu suchenden Daten bzw. Schlüsseln kann man beliebig ändern. Außerdem kann man bei :merge_behavior: eine der drei folgenden Optionen einstellen: native, deep, deeper. Um die Unterschiede zu erfahren, könnt ihr das hier nachlesen.

In der Ansible-Inentory stehen zwei Hosts jweils unter einer Gruppe.

[webserver]
web1.shared
web2.shared
web3.shared

[monitoring]
icinga-master1.shared

Unter /etc/hieradata/common.yaml liegen die SSH-Keys, die auf alle Server ausgerollt werden müssen, da common.yaml als unser Default für alle Hosts gilt, wie schon vorher erwähnt wurde.

---
ssh_users:
  - name: 'sergio'
    comment: 'sergio@example.com'
    key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDjuyGPTdo17ATAu69v2Bqui/f38e1uqOLvObiMw+uS9+Raxy5sO12pagVJeN9BTQaL09Sp9Dw+ozozg67WXfgTo+yoC5wy5a3d3Ihl4XJ/68SFUmEO2qo8Zg3914teL+FQMw5BE52LyqJjjBulGQ+jloGaldqxBfvjrmGMnz3mafCLtix+/UO1W+51gkea925XAOQ+KR1u1WFbEM3E6TfAoMv5Ev41e3jIcS+O+dnBqiZLsSIF3h72ni4eGr6h6x51itoFGQhN1jRcK9J5QfJG4O8OciReUCU5gETLi8RgFuBlQqDztZT1jGPbpkH2/swt3WGBUGOv+GizQg8iK9F"
    authorize_to: 'root'
    state: present

  - name: 'david'
    key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDRsAZ3DKxisCchDBd1dqtM9kPEgq+8MXbkClYVAoAlidx6qLz8Z6zBeSZ8ob+ae0dEegoN31mXv9ITaFhIdgIUxP0s54Mb4kgc9FE4njNRlb7xkTwsU3C6G7JUN9pJ64ucEqLI2iJ1JLI+zh0u5sWZS0tMoyEy73ZaAE6O32XyywIw5X+Uw7ISwqeeFsnWc4faKoWVgjt/s1MsuEOGsD1ocUxVPG7PKMEy8LQtQ7WL+RybV/TYH56hxBMi5H4BfC61Wm6Fn7pck5pCMzZOwstYikHoTWhJ16UYoJ6MubddoAOq/JyTimC/559U3lYgdHBXGJyCyW2xcGF7blmh0U97"
    authorize_to: 'root'
    state: absent

Unter /etc/hieradata/monitoring.yaml steht extra Konfiguration für die Hosts, die der monitoring-Gruppe zugeordnet sind.

user_groups:
  - name: 'nagios'
    state: 'present'

users:
  - name: 'icinga'
    shell: '/bin/bash'
    groups: 'nagios'
    append: yes
    state: 'present'

ssh_users:
  - name: 'alex'
    comment: 'sergio@example.com'
    key: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDCu5vAfoePg8Z5Tc3uOfua+RvxpA/WyDNKtHJze/pogssAtA+RZ6wdmvwuBGVFILgVKrpHItsUWZwWwsrNF0rjXV4MsPZzS8TbUNISoV7sETOk6pM1vg8ldy5XEszCokFsHmYLfovlqaICneKwiZ4SfQo21WjgzNXeVSND/1W5BZNAptobH6HC9oASRgeidwbDjDEux8//zvjjcIQlj9HXGmsKT5/r2+LR5Wo8rRkhdC+sbDJcDfN9OFg2Wo+PmwX6ArMfZ3oqh4xEGS3hN4Yo8lAVK8APPKNojtKv53qnFNTkfNrHRw9MbiXpPiYMFmKtGZztc9vPNKB6kBF1DFL/'
    authorize_to: 'icinga'
    state: present

Die Konfigurationen unter /etc/hieradata/web1.shared.yaml werden nur dem web1.shared angeordnet.

---
user_groups:
  - name: 'web-group'
    state: 'present'

  - name: 'admins'
    state: 'present'

users:
  - name: 'web-user'
    shell: '/bin/bash'
    groups: 'web-group, admins'
    append: yes
    state: 'present'

ssh_users:
  - name: 'mueller'
    comment: 'web-user@example.com'
    key: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCg6fvX0UIN22fPHHbSxPZQCyeqa8j2AEeqF7TlX3TSkJ17Q7Rz3g4B1RG8L+WfI+eb11bmESPTQ5Pym27qmNvfYl6dJynSdrRihnNj4Id1fKEzoW6J835rtRmaKD0V7KJ1JJvip0m24oIlFJIYSfShWSrOuvUgP3TpYUsU3KA2AQhoNtXWhgUM+wwFfCF3qZ4AX5zhQFy+bdqyYudmW99DasuZjaCq3djoMh9Ocm9lRPdDTpGS/Yb1yAqKU7rizrwlS3EmNcbQddRd2ZXFQnustfSX+ejo7PcEpimAPpcC2jbbS38pFbYdIvdm7BXsRMpsOXEuEZLrrbZMsPpEQ8FJ'
    authorize_to: 'web-user'
    state: present

Unser playbook kann so aussehen.

---
- hosts: all
  remote_user: root
  become: true
  tasks:
    - name: Set facts
      set_fact:
        ssh_users: "{{ lookup('hiera', 'ssh_users --array hosts={{ inventory_hostname }}  groups={{ item }} --format yaml')|from_yaml }}"
        user_groups: "{{ lookup('hiera', 'user_groups --array hosts={{ inventory_hostname }}  groups={{ item }} --format yaml')|from_yaml }}"
        users: "{{ lookup('hiera', 'users --array hosts={{ inventory_hostname }}  groups={{ item }} --format yaml')|from_yaml }}"
      loop: "{{ group_names }}"
 
    - name: Create groups
      group:
        name: "{{ item.name }}"
        state: "{{ item.state }}"
      loop: "{{ user_groups | default ([]) }}"
  - name: Create users
      user:
        name: "{{ item.name }}"
        shell: "{{ item.shell | default (omit) }}"
        state: "{{ item.state }}"
        append: "{{ item.append }}"
      loop: "{{ users | default ([]) }}"

    - name: Set ssh-keys
      authorized_key:
        user: "{{ item.authorize_to }}"
        state: "{{ item.state }}"
        key: "{{ item.key }}"
      loop: "{{ ssh_users | default ([]) }}"

Das lookup-Plugin nutzt hiera um auf Daten bzw. Schlüssel zugreifen zu können. Wir geben die zu suchenden Schlüssel mit, z. B. ssh-users. Wir übermitteln auch die Facts die hiera erwartet, nämlich hosts und groups. Man kann anstatt “inventory_hostname” “ansible_hostname” oder “ansible_fqdn” verwenden. Allerdings muss man die Datein unter /etc/hieradata entsprechend benennen. Groupe-Fact geben wir durch einen Loop über den Ansible-Fact group_names an die hiera weiter, in dem alle Gruppen der Inventory aufgelistet sind. Die Rückgabe ist in unserem Fall ein array, man kann auch einen hash auswählen. Die standardmäßige Format bei hiera is ruby, allerdings stellen wir das auf yaml um, damit Ansible die Format verarbeiten kann.

# ansible-playbook hiera-playbook.yml -i inventory

PLAY [all] ****************************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************************************************************************************************************************
ok: [web1.shared]
ok: [icinga-master1.shared]

TASK [Set facts] **********************************************************************************************************************************************************************************************************************
ok: [icinga-master1.shared] => (item=monitoring)
ok: [web1.shared] => (item=webserver)

TASK [Create groups] ******************************************************************************************************************************************************************************************************************
ok: [icinga-master1.shared] => (item={u'state': u'present', u'name': u'nagios'})
ok: [web1.shared] => (item={u'state': u'present', u'name': u'web-group'})
ok: [web1.shared] => (item={u'state': u'present', u'name': u'admins'})

TASK [Create users] *******************************************************************************************************************************************************************************************************************
ok: [web1.shared] => (item={u'groups': u'web-group, admins', u'state': u'present', u'shell': u'/bin/bash', u'name': u'web-user', u'append': True})
ok: [icinga-master1.shared] => (item={u'groups': u'nagios', u'state': u'present', u'shell': u'/bin/bash', u'name': u'icinga', u'append': True})

TASK [Set ssh-keys] *******************************************************************************************************************************************************************************************************************
ok: [icinga-master1.shared] => (item={u'comment': u'sergio@example.com', u'state': u'present', u'authorize_to': u'icinga', u'name': u'alex', u'key': u'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDCu5vAfoePg8Z5Tc3uOfua+RvxpA/WyDNKtHJze/pogssAtA+RZ6wdmvwuBGVFILgVKrpHItsUWZwWwsrNF0rjXV4MsPZzS8TbUNISoV7sETOk6pM1vg8ldy5XEszCokFsHmYLfovlqaICneKwiZ4SfQo21WjgzNXeVSND/1W5BZNAptobH6HC9oASRgeidwbDjDEux8//zvjjcIQlj9HXGmsKT5/r2+LR5Wo8rRkhdC+sbDJcDfN9OFg2Wo+PmwX6ArMfZ3oqh4xEGS3hN4Yo8lAVK8APPKNojtKv53qnFNTkfNrHRw9MbiXpPiYMFmKtGZztc9vPNKB6kBF1DFL/'})
ok: [web1.shared] => (item={u'comment': u'web-user@example.com', u'state': u'present', u'authorize_to': u'web-user', u'name': u'mueller', u'key': u'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCg6fvX0UIN22fPHHbSxPZQCyeqa8j2AEeqF7TlX3TSkJ17Q7Rz3g4B1RG8L+WfI+eb11bmESPTQ5Pym27qmNvfYl6dJynSdrRihnNj4Id1fKEzoW6J835rtRmaKD0V7KJ1JJvip0m24oIlFJIYSfShWSrOuvUgP3TpYUsU3KA2AQhoNtXWhgUM+wwFfCF3qZ4AX5zhQFy+bdqyYudmW99DasuZjaCq3djoMh9Ocm9lRPdDTpGS/Yb1yAqKU7rizrwlS3EmNcbQddRd2ZXFQnustfSX+ejo7PcEpimAPpcC2jbbS38pFbYdIvdm7BXsRMpsOXEuEZLrrbZMsPpEQ8FJ'})
ok: [web1.shared] => (item={u'comment': u'sergio@example.com', u'state': u'present', u'authorize_to': u'root', u'name': u'sergio', u'key': u'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDjuyGPTdo17ATAu69v2Bqui/f38e1uqOLvObiMw+uS9+Raxy5sO12pagVJeN9BTQaL09Sp9Dw+ozozg67WXfgTo+yoC5wy5a3d3Ihl4XJ/68SFUmEO2qo8Zg3914teL+FQMw5BE52LyqJjjBulGQ+jloGaldqxBfvjrmGMnz3mafCLtix+/UO1W+51gkea925XAOQ+KR1u1WFbEM3E6TfAoMv5Ev41e3jIcS+O+dnBqiZLsSIF3h72ni4eGr6h6x51itoFGQhN1jRcK9J5QfJG4O8OciReUCU5gETLi8RgFuBlQqDztZT1jGPbpkH2/swt3WGBUGOv+GizQg8iK9F'})
ok: [icinga-master1.shared] => (item={u'comment': u'sergio@example.com', u'state': u'present', u'authorize_to': u'root', u'name': u'sergio', u'key': u'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDjuyGPTdo17ATAu69v2Bqui/f38e1uqOLvObiMw+uS9+Raxy5sO12pagVJeN9BTQaL09Sp9Dw+ozozg67WXfgTo+yoC5wy5a3d3Ihl4XJ/68SFUmEO2qo8Zg3914teL+FQMw5BE52LyqJjjBulGQ+jloGaldqxBfvjrmGMnz3mafCLtix+/UO1W+51gkea925XAOQ+KR1u1WFbEM3E6TfAoMv5Ev41e3jIcS+O+dnBqiZLsSIF3h72ni4eGr6h6x51itoFGQhN1jRcK9J5QfJG4O8OciReUCU5gETLi8RgFuBlQqDztZT1jGPbpkH2/swt3WGBUGOv+GizQg8iK9F'})
ok: [icinga-master1.shared] => (item={u'state': u'absent', u'authorize_to': u'root', u'name': u'david', u'key': u'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDRsAZ3DKxisCchDBd1dqtM9kPEgq+8MXbkClYVAoAlidx6qLz8Z6zBeSZ8ob+ae0dEegoN31mXv9ITaFhIdgIUxP0s54Mb4kgc9FE4njNRlb7xkTwsU3C6G7JUN9pJ64ucEqLI2iJ1JLI+zh0u5sWZS0tMoyEy73ZaAE6O32XyywIw5X+Uw7ISwqeeFsnWc4faKoWVgjt/s1MsuEOGsD1ocUxVPG7PKMEy8LQtQ7WL+RybV/TYH56hxBMi5H4BfC61Wm6Fn7pck5pCMzZOwstYikHoTWhJ16UYoJ6MubddoAOq/JyTimC/559U3lYgdHBXGJyCyW2xcGF7blmh0U97'})
ok: [web1.shared] => (item={u'state': u'absent', u'authorize_to': u'root', u'name': u'david', u'key': u'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDRsAZ3DKxisCchDBd1dqtM9kPEgq+8MXbkClYVAoAlidx6qLz8Z6zBeSZ8ob+ae0dEegoN31mXv9ITaFhIdgIUxP0s54Mb4kgc9FE4njNRlb7xkTwsU3C6G7JUN9pJ64ucEqLI2iJ1JLI+zh0u5sWZS0tMoyEy73ZaAE6O32XyywIw5X+Uw7ISwqeeFsnWc4faKoWVgjt/s1MsuEOGsD1ocUxVPG7PKMEy8LQtQ7WL+RybV/TYH56hxBMi5H4BfC61Wm6Fn7pck5pCMzZOwstYikHoTWhJ16UYoJ6MubddoAOq/JyTimC/559U3lYgdHBXGJyCyW2xcGF7blmh0U97'})

PLAY RECAP ****************************************************************************************************************************************************************************************************************************
icinga-master1.shared      : ok=5    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
web1.shared                : ok=5    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

 

Wenn Du mehr über Ansible lernen und Dein wissen vertiefen willst, wäre eine Teilnahme an einer Ansible Schulung nicht verkehrt.

 

Afeef Ghannam
Afeef Ghannam
Systems Engineer

Afeef hat seine Ausbildung Als Fachinformatiker in Richtung Systemintegration im Juli 2020 bei NETWAYS absolviert, seitdem unterstützt er die Kolleg:innen im Operations Team der NETWAYS Professional Services bei der Betriebsunterstützung. Nach der Arbeit macht er gerne Sport, trifft Freunde oder mag es Filme zu schauen.

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *

More posts on the topic Ansible

Was ist Ansible Semaphore?

Als Open Source Consultants müssen meine Kolleg:innen und ich uns regelmäßig mit neuen Technologien, Tools oder anderen Neuerungen auseinandersetzen. Dabei testen wir besonders neue Software die uns und unseren Kund:innen das Leben potenziell leichter machen können...

Automate Icinga for Windows with Ansible

This article will cover how to automate the monitoring of your windows infrastructure with Ansible and Icinga for Windows. For that, I developed a new Ansible role which you can find here: https://github.com/DanOPT/ansible-role-ifw The role will allow you to manage...

Ansible Continuous Deployment without AWX/Tower/AAP

Why Ansible? Ansible is a configuration management tool to automate tasks in your IT infrastructure. It offers a rather low barrier of entry, when compared to other tools. A local Ansible installation (i.e. on your machine) with SSH access to the infrastructure you...