Inhaltsverzeichnis

Ansible

---
- name: PlayBook Betriebssystemversion anzeigen
  hosts: all
  gather_facts: yes
  become: true
  tasks:
 
    - name: "jammy"
      ansible.builtin.debug:
        var: ansible_facts.lsb.codename
 
    - name: "Ubuntu 22.04.4 LTS"
      ansible.builtin.debug:
        var: ansible_facts.lsb.description
 
    - name: "Ubuntu"
      ansible.builtin.debug:
        var: ansible_facts.lsb.id
 
    - name: "22"
      ansible.builtin.debug:
        var: ansible_facts.lsb.major_release
 
    - name: "22.04"
      ansible.builtin.debug:
        var: ansible_facts.lsb.release
> ansible-playbook -i inventory.yml -l test01 playbook_update.yml
> ansible-playbook -i inventory.yml -l test02 playbook_update.yml
inventory.yml
---
servers:
  hosts:
    test01:
      ansible_host: 10.10.3.11
      become: true
    test02:
      ansible_host: 10.10.3.12
      become: true
include_variables.yml
---
ansible_python_interpreter: "/usr/bin/python3"
 
SSHDCFG: "/etc/ssh/sshd_config"
 
NTP_SERVER1: "192.168.20.5"
NTP_SERVER2: "10.10.11.1"
include_users.yml
---
#------------------------------------------------------------------------------#
# SFTP-Benutzer definieren
#------------------------------------------------------------------------------#
#
# Der User, bei dem Gruppenname und Benutzername sind gleich, ist ein "Master",
# alle weiteren User, die mit dieser gleichen Gruppe angelegt werden,
# sind "Kunden" unterhalb dieses Masters.
#
# Wenn bei einem User der Gruppenname und der Benutzername gleich sind,
# dann wird sein Home-Verzeichnis ganz normal unterhalb von /home angelegt.
# Sind diese Namen unterschiedlich, dann wird sein Home-Verzeichnis unterhalb
# dessen Home-Verzeichnis angelegt, dessen Benutzername dem eigenen Gruppennamen
# entspricht.
#
# Ein "Master" hat kein "datadir", ein "Kunde" braucht immer ein "datadir"!
#
#------------------------------------------------------------------------------#
    users:
      - name: "sftp"
        gruppe: "sftp"
        shell: "/bin/bash"
        ssh_key: "{{ lookup('file', 'ssh-keys/sftp.pub') }}"
        password: "!"
        comment: "Master-User"
 
      - name: "otto"
        gruppe: "sftp"
        shell: "/bin/bash"
        ssh_key: "{{ lookup('file', 'ssh-keys/otto.pub') }}"
        password: "!"
        comment: "Otto der Filmemacher"
        datadir: "DATEN"
 
      - name: "fritz"
        gruppe: "sftp"
        shell: "/bin/bash"
        ssh_key: "{{ lookup('file', 'ssh-keys/fritz.pub') }}"
        password: "!"
        comment: "Fritzchen klein ging allein"
        datadir: "DATEN"
playbook_update.yml
---
# -----------------------------------------------------------
# Upgrade
# -----------------------------------------------------------
- name: "Update"
  gather_facts: false
  become: true
  hosts: servers
  tasks:
    # -------------------------------------------------------
    #  IPv6 abschalten
    # -------------------------------------------------------
    - name: Deactivate ipv6 perm
      lineinfile:
        path: /etc/default/grub
        state: present
        regexp: '^GRUB_CMDLINE_LINUX='
        line: 'GRUB_CMDLINE_LINUX="ipv6.disable=1"'
 
    - name: Deactivate ipv6 temp
      ansible.builtin.shell: |
        sysctl -w net.ipv6.conf.all.disable_ipv6=1
        sysctl -w net.ipv6.conf.default.disable_ipv6=1
        update-grub
        exit 0
      args:
        executable: /bin/bash
 
    - name: Restart systemd-resolved
      service:
        name: systemd-resolved
        state: restarted
 
    # -------------------------------------------------------
    #  apt-get dist-upgrade
    # -------------------------------------------------------
    - name: Perform a dist-upgrade.
      ansible.builtin.apt:
        upgrade: dist
        update_cache: yes
 
    - name: Check if a reboot is required.
      ansible.builtin.stat:
        path: /var/run/reboot-required
        get_md5: no
      register: reboot_required_file
 
    - name: Reboot the server (if required).
      ansible.builtin.reboot:
      when: reboot_required_file.stat.exists == true
 
    - name: Remove dependencies that are no longer required.
      apt:
        autoremove: yes
 
    - name: Check the Uptime of the servers
      shell: "uptime"
      register: Uptime
 
    - debug: var=Uptime.stdout
 
    ### TASK install basic
    - name: Install Tools server
      apt:
        update_cache: yes
        name:
          - systemd-timesyncd
          - vim
          - screen
          - mc
        state: present
playbook_add_user.yml
---
- hosts: servers
  gather_facts: true
  become_user: root
  become: true
  tasks:
 
#==============================================================================#
### SSHD/SFTP-Konfiguration - Anfang
#------------------------------------------------------------------------------#
### die letzte Sektion wird entfernt, weil sie immer am Ende bleiben muss
### und hier aber noch etwas hinzugefühgt (bzw. eingeschoben) werden soll
 
    # 330 # Sicherheitssektion entfernen
    - name: Textblock aus der Datei entfernen
      ansible.builtin.blockinfile:
        path: "{{SSHDCFG}}"
        marker: "# {mark} Sicherheitssektion"
        block: ""
        state: absent
 
#----------------------------------------------------------------------#
### Das SFTP-Sub-System mus umgestellt werden
 
    - name: SFTP-User umask 0002
      ansible.builtin.lineinfile:
        path: "{{SSHDCFG}}"
        line: Subsystem sftp internal-sftp -u 002 -l VERBOSE
        create: yes
 
    #--------------------------------------------------------------------------#
    # SFTP-Log
    #--------------------------------------------------------------------------#
    # 350 # SSHD/SFTP - überprüfen und ggf. konfigurieren
    - name: SFTP - logadmin einrichten
      ansible.builtin.lineinfile:
        path: "{{SSHDCFG}}"
        line: "{{ item }}"
        create: yes
      with_items:
        - '# Log internal-sftp in a separate file'
        - ':programname, isequal, "internal-sftp" -/var/log/sftp.log'
        - ':programname, isequal, "internal-sftp" ~'
 
    #--------------------------------------------------------------------------#
    # 365 # spezieller Benutzer zum lesen von Logs
    - name: SFTP - SSHD-CFG für logadmin
      ansible.builtin.lineinfile:
        path: "{{SSHDCFG}}"
        line: "{{ item }}"
        create: yes
      with_items:
        - '# Create an additional socket for some of the sshd chrooted users.'
        - '$AddUnixListenSocket /home/logadmin/dev/log'
        - '#========================================================================#'
        - 'Match user logadmin'
        - '        ChrootDirectory %h'
        - '        X11Forwarding no'
        - '        AllowTcpForwarding no'
        - '        ForceCommand internal-sftp -l VERBOSE'
 
#==============================================================================#
### SSHD/SFTP-Konfiguration - Mitte
 
#------------------------------------------------------------------------------#
### Master: item['name'] == item['gruppe']
 
    - name: Master-Gruppe anlegen
      ansible.builtin.group:
        name: "{{ item['gruppe'] }}"
        state: present
        local: false
        non_unique: false
      when: item['name'] == item['gruppe']
      with_items:
        - "{{ users }}"
 
    - name: Master-Benutzer anlegen
      ansible.builtin.user:
        name: "{{ item['name'] }}"
        group: "{{ item['gruppe'] }}"
        home: "/home/{{ item['name'] }}"
        comment: "{{ item['comment'] }}"
        password: "{{ item.password | default('!') }}"
        state: present
        umask: 0002
        append: false
        create_home: true
        generate_ssh_key: false
        local: false
        non_unique: false
      when: item['name'] == item['gruppe']
      with_items:
        - "{{ users }}"
 
    - name: Rechte vom Master-Home-Verzeichnis setzen
      ansible.builtin.file:
        path: "/home/{{ item['name'] }}"
        owner: root
        group: root
        mode: '0755'
        recurse: false
        state: directory
      when: item['name'] == item['gruppe']
      with_items:
        - "{{ users }}"
 
    - name: Rechte vom Master-DEV-Verzeichnis setzen
      ansible.builtin.file:
        path: "/home/{{ item['name'] }}/dev"
        owner: root
        group: root
        mode: '0755'
        recurse: false
        state: directory
      when: item['name'] == item['gruppe']
      with_items:
        - "{{ users }}"
 
    - name: Rechte vom Master-SSH-Verzeichnis setzen
      ansible.builtin.file:
        path: "/home/{{ item['name'] }}/.ssh"
        owner: "{{ item['name'] }}"
        group: root
        mode: '0755'
        recurse: false
        state: directory
      when: item['name'] == item['gruppe']
      with_items:
        - "{{ users }}"
 
#------------------------------------------------------------------------------#
### Kunden: item['name'] != item['gruppe']
 
    - name: Kunde-Benutzer anlegen
      ansible.builtin.user:
        name: "{{ item['name'] }}"
        group: "{{ item['gruppe'] }}"
        home: "/home/{{ item['gruppe'] }}/{{ item['name'] }}"
        comment: "{{ item['comment'] }}"
        password: "{{ item.password | default('!') }}"
        state: present
        umask: 0002
        append: false
        create_home: true
        generate_ssh_key: false
        local: false
        non_unique: false
      when: item['name'] != item['gruppe']
      with_items:
        - "{{ users }}"
 
    - name: Rechte vom Kunden-Home-Verzeichnis setzen
      ansible.builtin.file:
        path: "/home/{{ item['gruppe'] }}/{{ item['name'] }}"
        owner: root
        group: root
        mode: '0755'
        recurse: false
        state: directory
      when: item['name'] != item['gruppe']
      with_items:
        - "{{ users }}"
 
    - name: Rechte vom Kunden-DEV-Verzeichnis setzen
      ansible.builtin.file:
        path: "/home/{{ item['gruppe'] }}/{{ item['name'] }}/dev"
        owner: root
        group: root
        mode: '0755'
        recurse: false
        state: directory
      when: item['name'] != item['gruppe']
      with_items:
        - "{{ users }}"
 
    - name: Rechte vom Kunden-SSH-Verzeichnis setzen
      ansible.builtin.file:
        path: "/home/{{ item['gruppe'] }}/{{ item['name'] }}/.ssh"
        owner: "{{ item['name'] }}"
        group: root
        mode: '0755'
        recurse: false
        state: directory
      when: item['name'] != item['gruppe']
      with_items:
        - "{{ users }}"
 
    - name: Rechte vom Kunden-DATADIR-Verzeichnis setzen
      ansible.builtin.file:
        path: "/home/{{ item['gruppe'] }}/{{ item['name'] }}/{{ item['datadir'] }}"
        owner: "{{ item['name'] }}"
        group: "{{ item['gruppe'] }}"
        mode: '0755'
        recurse: false
        state: directory
      when: item['name'] != item['gruppe']
      with_items:
        - "{{ users }}"
 
#------------------------------------------------------------------------------#
### Alle Benutzer
 
    - name: SSH-Schlüssel ablegen
      authorized_key:
        user: "{{ item['name'] }}"
        key: "{{ item['ssh_key'] }}"
        state: present
      with_items:
        - "{{ users }}"
 
#==============================================================================#
### SSHD/SFTP-Konfiguration - Ende
#------------------------------------------------------------------------------#
    #--------------------------------------------------------------------------#
    # Sicherheitssektion
 
    - name: "Textblock an die Datei anhängen / der muß immer ganz unten in der Datei sein"
      ansible.builtin.blockinfile:
        path: "{{SSHDCFG}}"
        marker: "# {mark} Sicherheitssektion"
        block: "#------------------------------------------------------------------------------#\nMatch group !root,!admin,*\n\t
                ChrootDirectory /tmp\n\t
                X11Forwarding no\n\t
                AllowTcpForwarding no\n\t
                ForceCommand internal-sftp -l VERBOSE\n#------------------------------------------------------------------------------#"
        state: present
 
    #--------------------------------------------------------------------------#
    - name: Restart sshd
        service:
          name: sshd
          state: restarted
          enabled: true

File

---
- name: Dateien und Verzeichnisse löschen
  file:
    path:  "{{ item }}"
    state: absent
  with_items:
    - /eine/datei.txt
    - /ein/verzeichnis/
---
# Inhalte von einem Verzeichnis löschen; z.B. von einem Mount-Point
- block:
  - name: Dateien im Verzeichnis einlesen
    find:
      paths: "/etc/nginx/modules-enabled"
      hidden: True
      recurse: True
    register: collected_files
 
  - name: Sym-Links im Verzeichnis einlesen
    find:
      paths: "/etc/nginx/modules-enabled"
      hidden: True
      recurse: True
      file_type: link
    register: collected_link
 
  - name: Unterverzeichnisse einlesen
    find:
      paths: "/etc/nginx/modules-enabled"
      hidden: True
      recurse: True
      file_type: directory
    register: collected_directories
 
  - name: entferne Dateien und Unterverzeichnisse aus dem Verzeichnis
    file:
      path: "{{ item.path }}"
      state: absent
    with_items: >
      {{
        collected_files.files
        + collected_link.files
        + collected_directories.files
      }}

LineInFile

---
# -----------------------------------------------------------
# Tests
# -----------------------------------------------------------
- name: "Install Squid on remote hosts"
  gather_facts: false
  become: true
  hosts: servers
  vars_files:
    - include_variables.yml
 
  # https://docs.ansible.com/ansible/latest/collections/ansible/builtin/lineinfile_module.html#examples
  tasks:
    - name: Add a line to a file if the file does not exist, without passing regexp
      ansible.builtin.lineinfile:
        path: /tmp/testfile
        line: 192.168.1.99 foo.lab.net foo
        create: yes

BlockInFile

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/blockinfile_module.html

- name: Insert/Update HTML surrounded by custom markers after <body> line
  ansible.builtin.blockinfile:
    path: /var/www/html/index.html
    marker: "<!-- {mark} ANSIBLE MANAGED BLOCK -->"
    insertafter: "<body>"
    block: |
      <h1>Welcome to {{ ansible_hostname }}</h1>
      <p>Last updated on {{ ansible_date_time.iso8601 }}</p>
- name: Remove HTML as well as surrounding markers
  ansible.builtin.blockinfile:
    path: /var/www/html/index.html
    marker: "<!-- {mark} ANSIBLE MANAGED BLOCK -->"
    block: ""
    - name: Textblock aus der Datei entfernen
      ansible.builtin.blockinfile:
        path: /tmp/test.txt
        marker: "# {mark} Sicherheitssektion"
        block: ""
        state: absent
/tmp/test.txt
aaa
bbb
ccc
# BEGIN Sicherheitssektion
ddd
eee
fff
# END Sicherheitssektion

Wenn-Sonst

Wenn die Major-Versionsnummer eine "22" (von "Ubuntu 22.04") ist, dann bleibt der Wert in der Variable php_version auf "8.1", sonst wird er mit "7.2" überschrieben:

### OS-Schalter

- name: Ubuntu 22.04 LTS

set_fact:
  php_version: "8.1"
  percona_repo_version: "80"
when:
  ansible_facts.lsb.major_release == "22"

cut / split

https://www.middlewareinventory.com/blog/ansible-split-examples/

### ein einfaches Beispiel, hier wird die Zeichenkette einer E-Mail beim ''@'' getrennt
---
- name: Ansible Split Example 1
  hosts: localhost
  tasks:
    - name: Split Simple String Example
      debug: msg={{ 'sarav@gritfy.com'|split('@')}}
### in diesem Beispiel wird eine Zeichenkette bei bestimmten Zeichen (-) getrennt
---
- name: Ansible Split Example 2
  hosts: localhost
  vars:
    var1: dos-e1-south-209334567829102380
  tasks:
    - set_fact:
        var2: "{{ var1.split('-') }}"
    - debug:
        msg: "{{ var2.0 }}-{{ var2.1 }}-{{ var2.2 }}"
### in diesem Beispiel wird alles nach dem letzten Trennzeichen (-), einschließlich des Trennzeiches selbst, per RegEx entfernt
---
- name: Ansible Split Example 3
  hosts: localhost
  vars:
    var: dos-e1-south-209334567829102380
  tasks:
    - debug:
        msg: '{{ var | regex_replace("^(.*)-[^-]+$", "\\1") }}'

Die Ausgaben von Beispiel 2 und 3 sind identisch und lauten: "msg": "dos-e1-south"

Erklärung der im 3. Beispiel verwendeten RegEx:

^(.*)
behalte alles vom Beginn im Zwischenspeicher (1. Zwischenspeicher)

-[^-]+$
finde das "-", welches von einer Zeichenkette gefolgt wird, die kein "-" enthält (kurz gesagt: finde das letzte "-") samt der Zeichen bis zum Zeilenende

\\1
ersetze die Zeichenkette durch den Inhalt aus dem 1. Zwischenspeicher
### man kann auch mehrere Zeichenketten mit einem Spaltentrenner (-) wieder zu einer einzigen Zeichenkette zusammensetzen
    - debug:
        msg: "{{ var2[0:3] | join('-') }}"
### in diesem Beispiel wird eine Datei eingelesen, zeilenweise bearbeitet und die einzelnen Zeilen werden beim '':'' getrennt und der Inhalt der ersten Spalte wird ausgegeben
---
- name: Ansible Split Example 4
  hosts: localhost
  vars: 
    - usernames : []
  tasks:
    - name: print only domain names from Email IDs with Split
      set_fact:        
        usernames: '{{ usernames + [ item | split(":") | first ] }}'
      loop: "{{ lookup('file', '/etc/passwd').splitlines() | select('match','^(?!#)')}}"
      
    - debug: var=usernames

SED / regex_replace

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/replace_module.html

    - name: Replace old hostname with new hostname (requires Ansible >= 2.4)
      ansible.builtin.replace:
        path: /etc/hosts
        regexp: '(\s+)old\.host\.name(\s+.*)?$'
        replace: '\1new.host.name\2'
    - name: Supports a validate command
      ansible.builtin.replace:
        path: /etc/apache/ports
        regexp: '^(NameVirtualHost|Listen)\s+80\s*$'
        replace: '\1 127.0.0.1:8080'
        validate: '/usr/sbin/apache2ctl -f %s -t'