Ansible ff@home aufsetzen
Software
- Debian 12 (bookworm) oder Ubuntu 22.04
python3 und ansible
***** Es empfiehlt sich, eine python virtuelle Umgebung zu verwenden *****
Die folgenden Pakete mit Root-Rechten installieren, sofern noch nicht geschehen:sudo apt install python3-pip python3-venv
Die weiteren Befehle alle als normaler User ausführen.
Im Basisverzeichnis (bei mir /datadisk) die Testumgebung herunterladen mit
git clone https:/...
Für ein neues Projekt, welches noch nicht von einem git geklont werden kann, ein leeres Verzeichnis anlegen mit
mkdir ffhome
Dann in das neue Verzeichnis ffhome wechseln und das lokale git Repository initialisieren mit
git init
Wenn das Verzeichnis geklont wurde, den Schritt “git init” überspringen.
Nun im ffhome Verzeichnis (oder in geklonten Verzeichnis) (bei mir /datadisk/ffhome) die python virtuelle Umgebung einrichten:
python3 -m venv --prompt ffhome .venv
Hierdurch wird in ffhome ein Unterverzeichnis .venv angelegt.
Die virtuelle Umgebung wird in /datadisk/ffhome/.venv eingerichtet und kann aktiviert werden mit
source .venv/bin/activate
Dadurch ändert sich der prompt:
(ffhome) 18:16:41[frankb@berglap /datadisk/ffhome ]
Jetzt kann ansible in der ffhome Umgebung installiert werden:
pip3 install ansible
Damit ist ansible nur in der virtuellen Umgebung installiert und ausführbar.
Zum späteren Verlassen der Umgebung: deactivate oder Terminal Fenster schliessen
18:11:20[frankb@berglap /datadisk/ffhome 0] Die Verzeichnistruktur der Testumgebung
$ tree -L 4 /datadisk/ffhome
/datadisk/ffhome
├── ansible.cfg
├── inventory
│ ├── hosts.yaml
│ └── host_vars
| ├── bergdesk
│ │ ├── vars
│ │ └── vault
│ ├── berghofen
│ │ ├── vars
│ │ └── vault
│ ├── berglap
│ │ ├── vars
│ │ └── vault
│ └── luna
│ ├── vars
│ └── vault
├── playbooks
│ ├── resources
│ │ └── host
│ │ ├── tincbergdesk.gz
│ │ └── tincberghofen.gz
│ ├── templates
│ │ ├── tinc-up.lan.j2
│ │ └── tinc-up.wan.j2
│ ├── tincbuild.yaml
│ └── update.yaml
Bei den … sind Zeilen der Übersichtlichkeit halber weggelassen.
Weiter sind auch die versteckten Verzeichnisse .venv und evtl .git nicht aufgeführt.
Die verwendete ansible.cfg:
[defaults]
inventory=./inventory/
roles_path=./roles
playbook_dir=./playbooks/
interpreter_python=auto_silent
#vault_password_file=~/.vault-password
log_path=/tmp/ansible_ffhome.log
cow_selection=random
nocows=True
stdout_callback=yaml
display_args_to_stdout=True
[privilege_escalation]
become=True
[ssh_connection]
pipelining=True
Datei mit den beteiligten Hosts inventory/hosts.yaml
---
all:
vars:
ansible_port: 24
ansible_user: frankb
ansible_become: true
apus:
hosts:
berghofen:
ansible_host: 192.168.178.51
ansible_user: fb
ansible_become_password: "{{ berghofen_password }}"
desktops:
hosts:
bergdesk:
ansible_host: 192.168.178.201
ansible_become_pass: '{{ bergdesk_password }}'
berglap:
ansible_host: 192.168.178.52
ansible_become_pass: '{{ berglap_password }}'
luna:
ansible_host: 192.168.178.224
ansible_become_pass: '{{ luna_password }}'
altlast:
hosts:
hoerde:
ansible_host: 193.43.220.136
ansible_become: true
ansible_become_method: su
supernodes:
hosts:
31.172.33.20:
ansible_port: 22
snng-dus01.ffdo.de:
ansible_port: 22
snng-dtm01.ffdo.de:
ansible_port: 22
Die Gruppen apus und desktops enthalten die testhosts, die Gruppen altlast und supernodes sind nicht komplett einbezogen.
Im Verzeichnis inventory/host_vars sind Variablen für die einzelnen hosts, u.a. die passwords, in vars unverschlüsselt, in vault aes256 geschützt. Weiter sind Parameter für tinc enthalten, nur in vars, unverschlüsselt. Beispielhaft für berghofen
$ cat berghofen/vars
---
berghofen_password: "{{ vault_berghofen_password }}"
tinc_bindto: 192.168.178.51
wan_broadcast_ip: 193.43.220.191
wan_ip: 193.43.220.162/27
lan_broadcast_ip: 192.168.34.255
lan_ip: 192.168.34.1/24
$ cat berghofen/vault
$ANSIBLE_VAULT;1.2;AES256;xx
35656536383233636434636533613830303439316263636436363932333636626462616461636537
3838626266396332363236643361626134393238636133640a646333333866643161356333626564
32373735343033633666353763376230646137663639373438393537663031643562376365396337
3161646534666236350a303366373433373833373066353030363766616166666361376637393464
30613139313661643932373239333865616338653132613530393161656466326561633537383535
3631356664643139383037636565346630643036353364333866
In der vault Datei (hier Klartext)
---
vault_berghofen_password: hier das echte PW eintragen
dann die vault Datei verschlüsseln mit
$ ansible-vault encrypt vault --vault-id xxxxx@prompt
anzeigen kann man die Datei mit
$ ansible-vault view vault
und wieder entschlüsseln mit
$ ansible-vault decrypt vault
Es gibt z.Zt. zwei playbooks: update.yaml und tincbuild.yaml
$ cat playbooks/update.yaml
---
# name: update yaml
- hosts: [desktops,apus,altlast]
tasks:
- name: Testausgabe
debug: msg="Hallo von {{ ansible_hostname }} Ansible managed!"
- name: df -h Aufruf
command: df -h /
changed_when: false
register: df_cmd
- debug:
msg: '{{df_cmd.stdout_lines}} {{ansible_distribution }}'
- name: ping meine hosts
ansible.builtin.ping:
changed_when: false
# - name: Warte auf enter Taste
# ansible.builtin.pause:
- name: Ist flatpak installiert
stat:
path: /usr/bin/flatpak
register: flatpak_file
when: ansible_os_family == "Debian"
- name: Update flatpak Pakete falls snap vh
command: /usr/bin/flatpak update
when: ansible_os_family == "Debian" and flatpak_file.stat.exists
- name: Ist snap installiert
stat:
path: /usr/bin/snap
register: snap_file
when: ansible_os_family == "Debian"
- name: Update snap Pakete falls snap vh
command: /usr/bin/snap refresh
when: ansible_os_family == "Debian" and snap_file.stat.exists
- name: apt update mit upgrade und autoremove
ansible.builtin.apt:
update_cache: yes
cache_valid_time: 3600
autoremove: yes
upgrade: 'yes'
when: ansible_os_family == "Debian"
- stat:
path: /var/run/needrestart
register: needrestart_file
- name: reboot falls erforderlich
ansible.builtin.reboot:
when:
- ansible_os_family == "Debian" and
( needrestart_file.stat.exists or
rebootreq_file.stat.exists
)
- name: playbook hier beenden bei ! debian
meta: end_play
when: ansible_os_family != "Debian"
$ cat playbooks/tincbuild.yaml
---
# name: tincbuild yaml
- hosts: [desktops, apus, altlast]
vars:
TINC_VERSION: 1.1pre18
tinc_dev: /dev/net/tun
tinc_mode: switch
tinc_adr_family: ipv4
tinc_max_timeout: 30
tinc_port:
lan: 10001
wan: 661
tasks:
# - name: Show facts available on the system
# ansible.builtin.debug:
# var: ansible_facts
# das folgende klappt leider nicht {{tinc_port.{{ item }}}} syntaxfehler
# geschachtelte variablen gehen nicht.
# - name: willi
# debug: msg="var {{ tinc_port.{{lan}}}}"
- name: Testausgabe
debug: msg="Hallo von {{ ansible_hostname }} Ansible managed!"
- name: df -h Aufruf
command: df -h /
changed_when: false
register: df_cmd
- debug:
msg: '{{df_cmd.stdout_lines}} {{ansible_distribution }}'
# - name: ping meine hosts
# ansible.builtin.ping:
# changed_when: false
# - name: Warte auf enter Taste
# ansible.builtin.pause:
- name: playbook hier beenden bei ! debian
meta: end_play
when: ansible_os_family != "Debian"
- name: Ist tinc Konfigurationsverzeichnis vorhanden
stat:
path: /etc/tinc
register: tinckonf
- name: Gibt es Sicherung von tinc Konfiguration
# ueberlebt keinen reboot
stat:
path: /tmp/tinc{{ ansible_hostname }}.gz
register: tincgz
- name: Konfiguration packen wenn noetig
community.general.archive:
path: /etc/tinc
dest: /tmp/tinc{{ ansible_hostname }}.gz
when: tinckonf.stat.exists
- name: Gesicherte Konfiguration auf Controlnode kopieren
ansible.builtin.fetch:
src: /tmp/tinc{{ ansible_hostname }}.gz
dest: resources/host/
flat: true
when: tinckonf.stat.exists
# - name: Gesicherte Konfiguration auf targetnode loeschen
# file:
# name: /tmp/tinc{{ ansible_hostname }}.gz
# state: absent
# when: tincgz.stat.exists
- name: Abhängigkeiten fuer tinc installieren
apt:
pkg: "{{ item }}"
state: present
with_items:
- build-essential
- libncurses-dev
- libreadline-dev
- pkg-config
- zlib1g-dev
- liblzo2-dev
- libssl-dev
- texinfo
- name: create directory for tinc
file:
name: /opt/tinc
state: directory
- name: Download tinc source
get_url:
url: "https://www.tinc-vpn.org/packages/tinc-{{TINC_VERSION}}.tar.gz"
dest: /opt/tinc/tinc-{{TINC_VERSION}}.tar.gz
register: gettinc
- name: tinc-Quellen entpacken
unarchive:
src: /opt/tinc/tinc-{{TINC_VERSION}}.tar.gz
dest: /usr/src
remote_src: true
when:
- gettinc.changed
- name: Pruefen tinc programm vh
stat:
path: /usr/sbin/tinc
register: tinc_bin
- name: tinc kompilieren und installieren
shell: "cd /usr/src/tinc-{{TINC_VERSION}}
&& ./configure --prefix=/usr --sysconfdir=/etc --runstatedir=/run
--localstatedir=/var --with-systemd
&& make
&& make install"
when:
- tinc_bin.stat.exists == False or gettinc.changed
- name: Gibt es schon eine (alte) tinc Konfiguration
stat:
path: /etc/tinc
register: tinc_etc
- name: tinc Konfigurationsreste beseitigen
file:
path: /etc/tinc
state: absent
when:
- tinc_etc.stat.exists
- name: tinc lan/wan vorkonfigurieren in mehreren Schritten
shell: "tinc --net={{ item }} init {{ansible_hostname}}"
with_items:
- lan
- wan
# when:
# - tinc_bin.stat.exists == False or gettinc.changed
- name: 2048er priv und pub keys löschen
shell: "rm /etc/tinc/{{ item }}/*.priv
&& rm /etc/tinc/{{ item }}/hosts/*"
with_items:
- lan
- wan
# when:
# - tinc_bin.stat.exists == False or gettinc.changed
- name: 4096er keys generieren
shell: "tinc --net={{ item }} -b generate-keys 4096"
with_items:
- lan
- wan
# when:
# - tinc_bin.stat.exists == False or gettinc.changed
- name: tinc.conf einrichten
shell: "tinc --net={{ item }} set Device {{tinc_dev}}
&& tinc --net={{ item }} set Mode {{tinc_mode}}
&& tinc --net={{ item }} set AddressFamily {{tinc_adr_family}}
&& tinc --net={{ item }} set MaxTimeout {{tinc_max_timeout}}
&& tinc --net={{ item }} set BindToAddress {{tinc_bindto}}"
with_items:
- lan
- wan
# when:
# - tinc_bin.stat.exists == False or gettinc.changed
- name: lan/wan ports setzen
# das geht leider nicht in loop, da Variablen nicht geschachtelt
shell: "tinc --net=lan set Port {{ tinc_port.lan }}
&& tinc --net=wan set Port {{ tinc_port.wan }}"
- name: tinc-up anpassen
ansible.builtin.template:
src: templates/tinc-up.{{ item }}.j2
dest: /etc/tinc/{{ item }}/tinc-up
with_items:
- lan
- wan
# when:
# - tinc_bin.stat.exists == False or gettinc.changed
- meta: end_play
Für tinc-up werden folgende templates verwendet
$ cat playbooks/templates/tinc-up.lan.j2
#!/bin/sh
ip addr add {{ lan_ip }} brd {{ lan_broadcast_ip }} dev $INTERFACE
ip link set $INTERFACE mtu 1504 up
$ cat playbooks/templates/tinc-up.wan.j2
#!/bin/sh
ip addr add {{ wan_ip }} brd {{ wan_broadcast_ip }} dev $INTERFACE
ip link set $INTERFACE mtu 1504 up
Aufruf der beiden playbooks mit
$ ansible-playbook -b playbooks/update.yaml -i inventory/hosts.yaml --ask-vault-pass
$ ansible-playbook -b playbooks/tincbuild.yaml -i inventory/hosts.yaml --ask-vault-pass
Gekürzte Ausgabe:
(ffhome) 20:55:59[frankb@berglap /datadisk/ffhome 4] ansible-playbook -b playbooks/update.yaml -i inventory/hosts.yaml --ask-vault-pass
Vault password:
PLAY [desktops,apus,altlast] ***************************************************************
TASK [Gathering Facts] *********************************************************************
[WARNING]: Platform linux on host berglap is using the discovered Python interpreter at
/usr/bin/python3.10, but future installation of another Python interpreter could change the
meaning of that path. See https://docs.ansible.com/ansible-
core/2.17/reference_appendices/interpreter_discovery.html for more information.
ok: [berglap]
[WARNING]: Platform linux on host bergdesk is using the discovered Python interpreter at
/usr/bin/python3.11, but future installation of another Python interpreter could change the
meaning of that path. See https://docs.ansible.com/ansible-
core/2.17/reference_appendices/interpreter_discovery.html for more information.
ok: [bergdesk]
fatal: [luna]: UNREACHABLE! => changed=false
msg: 'Failed to connect to the host via ssh: ssh: connect to host 192.168.178.224 port 24: No route to host'
unreachable: true
[WARNING]: Platform linux on host berghofen is using the discovered Python interpreter at
/usr/bin/python3.11, but future installation of another Python interpreter could change the
meaning of that path. See https://docs.ansible.com/ansible-
core/2.17/reference_appendices/interpreter_discovery.html for more information.
ok: [berghofen]
[WARNING]: Platform freebsd on host hoerde is using the discovered Python interpreter at
/usr/local/bin/python3.9, but future installation of another Python interpreter could
change the meaning of that path. See https://docs.ansible.com/ansible-
core/2.17/reference_appendices/interpreter_discovery.html for more information.
ok: [hoerde]
TASK [Testausgabe] *************************************************************************
ok: [bergdesk] =>
msg: Hallo von bergdesk Ansible managed!
ok: [berglap] =>
msg: Hallo von berglap Ansible managed!
ok: [berghofen] =>
msg: Hallo von berghofen Ansible managed!
ok: [hoerde] =>
msg: Hallo von hoerde Ansible managed!
TASK [df -h Aufruf] ************************************************************************
ok: [berglap]
ok: [bergdesk]
ok: [berghofen]
ok: [hoerde]
TASK [debug] *******************************************************************************
ok: [bergdesk] =>
msg: '[''Dateisystem Größe Benutzt Verf. Verw% Eingehängt auf'', ''/dev/sdb1 439G 98G 319G 24% /''] Debian'
ok: [berglap] =>
msg: '[''Dateisystem Größe Benutzt Verf. Verw% Eingehängt auf'', ''/dev/mapper/system-root 444G 298G 124G 71% /''] Ubuntu'
ok: [berghofen] =>
msg: '[''Dateisystem Größe Benutzt Verf. Verw% Eingehängt auf'', ''/dev/sda6 18G 5,1G 12G 30% /''] Debian'
ok: [hoerde] =>
msg: '[''Filesystem Size Used Avail Capacity Mounted on'', ''s3pool25/jail/hoerde.ffdo.net 3.9G 891M 3.0G 22% /''] FreeBSD'
TASK [ping meine hosts] ********************************************************************
ok: [berglap]
ok: [bergdesk]
ok: [berghofen]
ok: [hoerde]
...
PLAY RECAP *********************************************************************************
bergdesk : ok=6 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
berghofen : ok=6 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
berglap : ok=6 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
hoerde : ok=5 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
luna : ok=0 changed=0 unreachable=1 failed=0 skipped=0 rescued=0 ignored=0