Strukturen, Playbooks, Vaults - so habe ich es gemacht
Prolog
Ich möchte meine Erfahrungen mit Ansible mit euch teilen und werde hier mal aufführen wie ich Ansible auf meinem Lernweg aufbaue. Bedenkt aber stets, dass ich gerade erst mit Ansible anfange und vorher noch nie etwas mit zentralem Konfigurationsmanagement zu tun hatte. Ich zeige euch hier lediglich meine Überlegungen, die wahrscheinlich hier und da noch verbessert werden müssten. Ein Nachbauen macht ihr immer auf eigene Gefahr hin.
Vorraussetzungen - Ansible Eigenheiten
Was solltet ihr beachten bzw. vorausschauend planen, wenn ihr Ansible einsetzen wollt?
Benutzer für zentrale Verwaltungsaufgaben
Das Arbeiten mit Ansible wird euch viel einfacher fallen, wenn ihr einen einzigen Benutzer auf allen euren Hosts angelegt habt und dieser SUDO Rechte hat. Dann könnt ihr euer Ansible Management einheitlich aufbauen und habt nicht zig verschiedene User, die ihr berücksichtigen müsst.
Ja, das ist sicherlich Geschmackssache und in manchen Situationen im Bezug auf Sicherheit sollte man das abwandeln und auf mehrere spezifische Benutzer zurückgreifen.
Ordnerstruktur
Ansible Docs: https://docs.ansible.com/ansible/latest/user_guide/playbooks_best_practices.html#directory-layout
Von Ansible wird keine Struktur vorgegeben. Man hat also die freie Entscheidungsgewalt. So habe ich also das hier angefangen zu strukturieren:
root@server:/etc/ansible# tree
.
├── ansible.cfg
├── archive
│ ├── azure.bak
│ ├── configure-linuxserver-rsyslog-to-graylog.yml.alt
│ ├── hosts.bak
│ └── install-prometheus-node-exporter.yml.bak
├── azure
├── group_vars
│ ├── production
│ │ ├── vars
│ │ └── vault
│ ├── init-linuxserver
│ │ ├── vars
│ │ └── vault
│ └── linuxserver
│ ├── vars
│ └── vault
├── playbooks
│ ├── packages
│ │ ├── install-production-prometheus-node-exporter.yml
│ │ ├── install-prometheus-node-exporter.yml
│ │ └── install-systemtools.yml
│ ├── services
│ │ └── connect-graylog.yml
│ ├── systemsettings
│ │ ├── set-timezone-europe-berlin.yml
│ │ └── update-hosts-file.yml
│ └── users
│ └── create-user-webdata.yml
└── vault_pwd
Variablen
So sieht eine vars Datei für die Gruppe linuxserver aus:
root@server:/etc/ansible# cat group_vars/linuxserver/vars
---
ansible_connection: ssh
ansible_user: ansibleadmin
ansible_ssh_private_key_file: /home/ansibleadmin/.ssh/id_rsa
ansible_ssh_common_args: '-o StrictHostKeyChecking=no'
ansible_become: yes
ansible_become_method: sudo
ansible_become_user: root
ansible_become_pass: "{{ vault_ansible_become_pass }}"
Inventory
Ansible Docs: https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html
Meine Inventory Datei heißt azure, weil ich Ansible im Zuge einer Azure Evaluierung einsetze.
root@vm-azure-manager:/etc/ansible# cat azure
#Here i was experimenting where do set this option for being applied everywhere.
#ansible_ssh_common_args='-o StrictHostKeyChecking=no'
[prometheus]
prometheus-01
[grafana]
grafana-01
[graylog]
graylog-01
[es-nodes]
es-node-01
[init-linuxserver:children]
prometheus
grafana
graylog
es-nodes
[linuxserver:children]
prometheus
grafana
graylog
es-nodes
[graylogclients:children]
grafana
prometheus
es-nodes
Bisher habe ich folgendes gemeistert:
- Einstellungen in separate Unterverzeichnisse zu kapseln und Gruppen bezogen Einstellungen zu vergeben
- Hosts in Gruppen zu unterteilen
- Gruppen zu verschachteln
Durch die Verschachtelung von Gruppen kann ich meine Hosts kategorisieren und habe eine ähnliche Vorangehensweise wie beim Administrieren von Benutzerrechten, d.h. bei Änderungen den Aufwand zu minimieren, weil man z.B. einen neuen Host nur noch einer Gruppe zuweist oder einen alten aus einer Gruppe löschen muss.
Ansible Vault
Ansible Docs: https://docs.ansible.com/ansible/latest/user_guide/vault.html
Ich habe am Anfang die Passwörter für meine User, die Ansible benutzen sollte, klar lesbar in meine Konfig-Dateien geschrieben. Da ich davon aber absolut kein Freund bin, habe ich mich also zeitnah darum gekümmert und herausgefunden, dass es die sog. Ansible-Vault gibt. Vault heißt Tresor. Also ein verschlüsselter Container, der eure Passwörter und sonstige Einstellungen beinhalten kann. Ich habe aktuell nur ein Passwort darin gespeichert.
Wie ihr schon anhand meiner Ordnerstruktur gesehen habt, gibt es jeweils in jedem Unterordner einer Gruppe eine Datei namens "vault". Das sind meine geschützten Bereiche für die jeweilige Gruppe.
So hier habe ich es gemacht:
- Eine Schlüsseldatei "vault_pwd" erstellt und in Klartext den Schlüssel eingetragen, der global zum Ver- und Entschlüsseln benutzt werden soll.
Man muss keinen globalen Schlüssel verwenden. Das kann man so einstellen wie man es möchte.
root@server:# nano vault_pwd
- Schlüssel eintragen
- Globale Schlüsseldatei in der ansbile.cfg aktiviert
vault_password_file = /etc/ansible/vault_pwd
- zu verschlüsselnde Variablen mit einem Editor in die jeweilige vault Datei eintragen
- vault Datei verschlüsseln:
ansible-vault encrypt vault
-
Da wir einen globalen Schlüssel aktiviert haben, wird dieser automatisch zum Verschlüsseln benutzt, sodass ihr keinen Schlüssel an der Stelle eingeben müsst.
- So habe ich z.B. das Passwort hinterlegt, dass benutzt wird um SUDO Rechte zu aktivieren:
-
vault_ansible_become_pass: DAS-PASSWORT
- Ansible empfiehlt als Variablennamen der zu verschlüsselnden Variable ein "vault_" als Präfix zu verwenden. Ich finde das gut, da man so gleich den Bezug der Verwendung herstellen kann.
-
-
- Passwort in unverschlüsselter Variable aus verschlüsselter Variable aufrufen
- So sieht der Aufruf dann in meiner "vars" Datei aus:
ansible_become_pass: "{{ vault_ansible_become_pass }}"
- Die Syntax nennt sich jinja2
- So sieht der Aufruf dann in meiner "vars" Datei aus:
Alles was ich jetzt mit Ansible mache, funktioniert mit verschlüsselten Passwörtern.
Playbooks
Ansible Docs: https://docs.ansible.com/ansible/latest/user_guide/playbooks.html
Ansible-Systembenutzer bereitstellen
Funktionen
- User mit Home Verzeichnis anlegen
- SSH Key hinterlegen
- SUDO Rechte vergeben
Probleme
Man benötigt natürlich auf allen Hosts für das erstmalige Bereitstellen mit Ansible einen Systemuser mit SUDO Rechten. Da ich für Ansible Arbeiten einen eigenen Systemuser nutzen möchte, habe ich als erstes einen neuen user auf allen Hosts angelegt. Dafür habe ich den User benutzt, den man mit der Installation von Debian anlegen muss.
Playbook "create-user-ansibleadmin.yml
root@server:/etc/ansible# cat playbooks/users/create-user-ansibleadmin.yml
---
- hosts: init-linuxserver
remote_user: initial-user-from-fresh-install-with-sudo-rights
become: yes
become_method: sudo
become_user: root
tasks:
- name: Ansible create user ansibleadmin with home directory
user:
name: ansibleadmin
createhome: yes
- name: create directory .ssh
file:
path: /home/ansibleadmin/.ssh
state: directory
owner: ansibleadmin
group: ansibleadmin
mode: 0700
- name: Ansible copy the ssh public key of the user ansibleadmin to the remote host
copy:
src: "/home/ansibleadmin/.ssh/id_rsa.pub"
dest: "/home/ansibleadmin/.ssh/authorized_keys"
owner: ansibleadmin
group: ansibleadmin
- name: Add user ansibleadmin to sudo group and grant sudo rights
user:
name: ansibleadmin
groups: sudo
Debian Paket mit apt installieren
Playbook: "install-systemtools.yml"
root@server:/etc/ansible# cat playbooks/packages/install-systemtools.yml
---
- hosts: linuxserver
tasks:
- name: install lsb-release
apt: name=lsb-release state=present
- name: install lsof
apt: name=lsof state=present
Playbook: Azure CLI installieren
---
- hosts: azure-master
tasks:
- name: Install apt-transport-https
apt: name=apt-transport-https state=present
- name: Add Azure Repository to sources.list.d
apt_repository:
repo: deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ stretch main
state: present
filename: azure-cli
- name: Add Microsoft´s signature key
apt_key:
url: https://packages.microsoft.com/keys/microsoft.asc
state: present
- name: make an apt-update before be able to find azure-cli package
apt:
update_cache: yes
- name: Install Azure CLI
apt: name=azure-cli state=present
Playbook: Docker CE installieren
---
- hosts: docker-vm
tasks:
- name: Add Azure Repository to sources.list.d
apt_repository:
repo: deb [arch=amd64] https://download.docker.com/linux/debian stretch stable
state: present
filename: docker-ce
- name: Add Docker CE signature key
apt_key:
url: https://download.docker.com/linux/debian/gpg
state: present
- name: make an apt-update before be able to find azure-cli package
apt:
update_cache: yes
- name: Install Docker CE
apt: name=docker-ce state=present
Datei kopieren - hosts Datei bereitstellen
Playbook "update-hosts-file.yml"
root@server:/etc/ansible# cat playbooks/systemsettings/update-hosts-file.yml
---
- hosts: linuxserver
# steht alles in den "Vars" Dateien
# remote_user: ansibleadmin
# become: yes
# become_method: sudo
# become_user: root
tasks:
- name: copy the hosts file from host "server" to the group linuxserver
copy:
src: "/etc/hosts"
dest: "/etc/hosts"
owner: root
group: root
Hintergrund
Ich arbeite in meiner testumgebung mit den Hosts Dateien, weil ich auf die Schnelle kein DNS aufbauen konnte. Zum Einen bin ich kein Experte für DNS (erst einmal damit rumprobiert) und Zweitens wollte ich so schnell wie möglich alle Hosts mit Namen anstelle von IP Adressen ansprechen.
Zeitzone einstellen
Playbook "set-timezone-europe-berlin.yml"
root@server:/etc/ansible# cat playbooks/systemsettings/set-timezone-europe-berlin.yml
---
- hosts: linuxserver
tasks:
- name: set timezone to Europe/Berlin
timezone:
name: Europe/Berlin
Hintergrund
Da ich die Debian VMs in Azure über den RessourcenManager von Azure bereitstellen lassen habe, gab es nachträglich Einstellungen, die angepasst werden mussten. Dazu gehörte u.a. die Zeitzone.