--- # # First run check # - name: regather facts setup: tags: always - name: check if this is a new instance shell: "echo 'bootstrapped' > /etc/pvc-install.base" args: creates: /etc/pvc-install.base register: newhost_check tags: always - name: set newhost fact set_fact: newhost: yes when: newhost_check.changed tags: always # Set this_node fact - set_fact: this_node: "{{ inventory_hostname.split('.')[0] }}" tags: always # Set coordinator state fact - set_fact: is_coordinator: "{% for node in pvc_nodes if node.hostname == this_node %}{{ node.is_coordinator }}{% endfor %}" tags: always # # Set Debian details # - name: set Debian details (with ansible_distribution_*) set_fact: debian_version: "{{ ansible_distribution_major_version }}" debian_codename: "{{ ansible_distribution_release }}" when: ansible_distribution_release is defined tags: always - name: set Debian details (with ansible_lsb) set_fact: debian_version: "{{ ansible_lsb.major_release }}" debian_codename: "{{ ansible_lsb.codename }}" when: ansible_lsb.codename is defined tags: always # # Remove obsolete issue-gen # - name: remove obsolete issue-gen script from PVC installer file: dest: /etc/network/if-up.d/issue-gen state: absent when: newhost is defined and newhost tags: always # # Install custom fact scripts # - name: create facts directory file: dest: "/etc/ansible/facts.d" state: directory recurse: yes tags: base-ansible - name: install custom facts template: src: "etc/ansible/facts.d/{{ item }}.fact.j2" dest: "/etc/ansible/facts.d/{{ item }}.fact" mode: 0755 register: installed_facts with_items: - host_id - host_group - dhcp_status tags: base-ansible - name: regather facts setup: tags: always - debug: var: ansible_local.host_group verbosity: 1 tags: always - debug: var: ansible_local.host_id verbosity: 1 tags: always - debug: var: ansible_local.dhcp_status verbosity: 1 tags: always # # Configure APT # - name: install apt config files template: src: "{{ item.src }}" dest: "{{ item.dest }}" with_items: - { src: "etc/apt/apt.conf.d/10norecommends.j2", dest: "/etc/apt/apt.conf.d/10norecommends" } - { src: "etc/apt/preferences.d/pins.j2", dest: "/etc/apt/preferences.d/pins" } - { src: "etc/apt/sources.list.{{ ansible_machine }}.{{ debian_codename }}.j2", dest: "/etc/apt/sources.list" } register: apt_config tags: base-apt - name: add key for PVC repo apt_key: url: "{{ debian_pvc_signing_key_path }}" id: "{{ debian_pvc_signing_key_id }}" state: present register: apt_key tags: base-apt # # Safe apt upgrades (on first install only) # - name: apt update apt: update-cache: yes when: (newhost is defined and newhost) or apt_config.changed or apt_key.changed register: apt_res retries: 5 until: apt_res is success tags: base-apt - name: apt safe upgrade with autoremove apt: update_cache: yes autoremove: yes upgrade: safe when: newhost is defined and newhost register: apt_res retries: 5 until: apt_res is success tags: base-apt - name: install dbus apt: name: - dbus state: latest when: newhost is defined and newhost register: apt_res retries: 5 until: apt_res is success tags: base-apt - name: clean out apt cache file: path: "/var/cache/apt/archives" state: absent when: newhost is defined and newhost tags: base-apt # # Purge unneeded packages # - name: remove unneeded packages apt: name: - exim4 - exim4-base - exim4-config - exim4-daemon-light - joe - aptitude state: absent purge: yes autoremove: yes register: apt_res retries: 5 until: apt_res is success tags: base-packages - name: set override debconf selections shell: 'echo "{{ item }}" | debconf-set-selections' with_items: - "wireshark-common wireshark-common/install-setuid boolean true" tags: base-packages - name: install common packages (buster) apt: name: - python when: debian_version|int <= 10 register: apt_res retries: 5 until: apt_res is success tags: base-packages - name: install common packages (bullseye+) apt: name: - python-is-python3 when: debian_version|int >= 11 register: apt_res retries: 5 until: apt_res is success tags: base-packages - name: install common packages (all versions) apt: name: - debconf-utils - iptables - locales - acpid - acpi-support-base - rsync - bash - bash-completion - net-tools - pciutils - usbutils - smartmontools - edac-utils - check-mk-agent - dns-root-data - bind9-host - dnsutils - whois - postfix - ntp - openssh-client - openssh-server - libpam-systemd - fail2ban - ca-certificates - openssl - sudo - rsyslog - logrotate - man - less - vim - nano - git - vlan - bridge-utils - ifenslave - nmap - traceroute - mtr - netcat-openbsd - htop - psmisc - dstat - iotop - lsof - jnettop - iperf - sysstat - binutils - deborphan - needrestart - wget - curl - gawk - uuid-runtime - mmv - pv - bc - reptyr - sharutils - tcptraceroute - nethogs - strace - tshark - acl - bzip2 - lzop - xz-utils - zstd - haveged - cpufrequtils - lm-sensors - ipmitool - grub-efi - efibootmgr - plymouth - plymouth-themes - linux-image-amd64 - linux-headers-amd64 register: apt_res retries: 5 until: apt_res is success tags: base-packages - name: install Prometheus node and process exporters if enabled apt: name: - prometheus-node-exporter - prometheus-process-exporter when: enable_prometheus_exporters is defined and enable_prometheus_exporters tags: base-packages - name: install Intel-specific microcode package apt: name: - intel-microcode when: "'GenuineIntel' in ansible_processor" tags: base-packages - name: install AMD-specific microcode package apt: name: - amd64-microcode when: "'AuthenticAMD' in ansible_processor" tags: base-packages - name: install cleanup scripts template: src: "{{ item.src }}" dest: "{{ item.dest }}" mode: 0755 with_items: - { src: "usr/local/sbin/kernel-cleanup.sh.j2", dest: "/usr/local/sbin/kernel-cleanup.sh" } - { src: "usr/local/sbin/dpkg-cleanup.sh.j2", dest: "/usr/local/sbin/dpkg-cleanup.sh" } tags: base-packages # # System configuration # # networking - name: install base interfaces file template: src: etc/network/interfaces.j2 dest: /etc/network/interfaces tags: base-network - name: install per-interface files template: src: etc/network/interfaces-perif.j2 dest: /etc/network/interfaces.d/{{ network.key }} with_dict: "{{ networks }}" loop_control: loop_var: network tags: base-network # locale - name: install locale config files template: src: "{{ item.src }}" dest: "{{ item.dest }}" with_items: - { src: "etc/default/locale.j2", dest: "/etc/default/locale" } - { src: "etc/locale.gen.j2", dest: "/etc/locale.gen" } tags: base-system - name: set timezone for /etc/localtime file: src: /usr/share/zoneinfo/{{ timezone_location }} dest: /etc/localtime state: link force: yes tags: base-system - name: set timezone for /etc/timezone copy: content: "{{ timezone_location }}" dest: /etc/timezone tags: base-system - name: generate locales command: locale-gen tags: base-system # sysctl - name: install sysctl tweaks template: src: "{{ item.src }}" dest: "{{ item.dest }}" with_items: - { src: "etc/sysctl.d/pvc.conf.j2", dest: "/etc/sysctl.d/pvc.conf" } tags: base-system - name: activate sysctl tweaks shell: "sysctl -p {{ item }}" with_items: - /etc/sysctl.d/pvc.conf tags: base-system # cpufreq - name: write the cpufrequtils governor template: src: etc/default/cpufrequtils.j2 dest: /etc/default/cpufrequtils register: cpufrequtils tags: base-system - name: activate cpufrequtils governor service: name: cpufrequtils state: restarted when: cpufrequtils.changed tags: base-system # sudo - name: write the sudoers file template: src: "etc/sudoers.j2" dest: "/etc/sudoers" mode: 0440 tags: base-system # needrestart - name: write the needrestart pvc blacklist file template: src: "etc/needrestart/conf.d/pvc.conf.j2" dest: "/etc/needrestart/conf.d/pvc.conf" mode: 0444 tags: base-system # dns - name: write the hosts config template: src: "{{ item.src }}" dest: "{{ item.dest }}" with_items: - { src: "etc/hosts.j2", dest: "/etc/hosts" } tags: base-dns - name: write the resolver configs template: src: "{{ item.src }}" dest: "{{ item.dest }}" with_items: - { src: "etc/resolv.conf.j2", dest: "/etc/resolv.conf" } - { src: "etc/dhcp/dhclient-enter-hooks.d/noresolv.j2", dest: "/etc/dhcp/dhclient-enter-hooks.d/noresolv" } tags: base-dns # GRUB bootloader - name: create PVC grub directory file: state: directory dest: "/usr/share/grub-pvc" tags: base-bootloader - name: install PVC grub style copy: src: "usr/share/grub-pvc/{{ item }}" dest: "/usr/share/grub-pvc/{{ item }}" with_items: - background.png - theme.txt tags: base-bootloader - name: install GRUB configuration template: src: etc/default/grub.j2 dest: /etc/default/grub notify: - update grub - regenerate uefi entries tags: base-bootloader # Plymouth theme - name: install PVC Plymouth theme archive unarchive: src: "usr/share/plymouth/themes/pvc.tar" dest: "/usr/share/plymouth/themes/" creates: "/usr/share/plymouth/themes/pvc" owner: root group: root tags: base-bootloader - name: install PVC Plymouth background file copy: src: "usr/share/grub-pvc/background.png" dest: "/usr/share/plymouth/themes/pvc/background-tile.png" tags: base-bootloader - name: set PVC Plymouth theme as the default command: plymouth-set-default-theme -R pvc tags: base-bootloader # syslog - name: install rsyslog and logrotate configs template: src: "{{ item.src }}" dest: "{{ item.dest }}" notify: - restart rsyslog with_items: - { src: "etc/rsyslog.conf.j2", dest: "/etc/rsyslog.conf" } - { src: "etc/logrotate.d/rsyslog.j2", dest: "/etc/logrotate.d/rsyslog" } tags: base-syslog - name: set journalctl persistence template: src: "{{ item.src }}" dest: "{{ item.dest }}" mode: 0644 with_items: - { src: "etc/systemd/journald.conf.j2", dest: "/etc/systemd/journald.conf" } tags: base-syslog # cron - name: install crontab template: src: "{{ item.src }}" dest: "{{ item.dest }}" mode: 0755 with_items: - { src: "etc/crontab.j2", dest: "/etc/crontab" } tags: base-cron # mta - name: install postfix generic config template: src: "etc/postfix/main.cf.j2" dest: "/etc/postfix/main.cf" notify: - restart postfix tags: base-mta - name: touch the postfix aliases file file: dest: /etc/postfix/aliases state: touch tags: base-mta - name: install local alias maps for various users lineinfile: dest: "/etc/aliases" regexp: "^{{ item }}:" line: "{{ item }}: {{ username_email_root }}" state: present with_items: - root - postmaster - amavis - clamav notify: - newaliases tags: base-mta # ntp - name: write the NTP config file on Debian < 12 template: src: "{{ item.src }}" dest: "{{ item.dest }}" notify: - restart ntp with_items: - { src: "etc/ntp.conf.j2", dest: "/etc/ntp.conf" } when: debian_version|int < 12 tags: base-time - name: write the NTP config file on Debian >= 12 template: src: "{{ item.src }}" dest: "{{ item.dest }}" notify: - restart ntp with_items: - { src: "etc/ntpsec/ntp.conf.j2", dest: "/etc/ntpsec/ntp.conf" } when: debian_version|int >= 12 tags: base-time - name: clean up old NTP config file on Debian >= 12 file: dest: /etc/ntp.conf state: absent notify: - restart ntp when: debian_version|int >= 12 tags: base-time # ssl - name: ensure haveged is running service: name: haveged state: started tags: base-ssl - name: generate diffie-hellman parameters command: openssl dhparam -out /etc/ssl/dhparams.pem 2048 args: creates: /etc/ssl/dhparams.pem tags: base-ssl - name: correct permissions on dhparams file: dest: /etc/ssl/dhparams.pem mode: 0440 tags: base-ssl # ssh - name: write the sshd_config files template: src: "{{ item.src }}" dest: "{{ item.dest }}" notify: - restart ssh with_items: - { src: 'etc/ssh/ssh_config.j2', dest: '/etc/ssh/ssh_config' } - { src: 'etc/ssh/sshd_config.j2', dest: '/etc/ssh/sshd_config' } - { src: 'etc/ssh/shosts.equiv.j2', dest: '/etc/ssh/shosts.equiv' } - { src: 'etc/ssh/ssh_known_hosts.j2', dest: '/etc/ssh/ssh_known_hosts' } tags: base-ssh - name: write sshd pam.d config template: src: "etc/pam.d/sshd.j2" dest: "/etc/pam.d/sshd" tags: base-ssh - name: remove unneeded SSH keys (leave only RSA and ED25519) file: name: "{{ item }}" state: "absent" with_items: - /etc/ssh/ssh_host_dsa_key - /etc/ssh/ssh_host_dsa_key.pub - /etc/ssh/ssh_host_ecdsa_key - /etc/ssh/ssh_host_ecdsa_key.pub notify: - restart ssh tags: base-ssh - name: set permissions on rsa and ed25519 host keys (just in case they're wrong) file: name: "/etc/ssh/{{ item.name }}" mode: "{{ item.mode }}" with_items: - { name: 'ssh_host_rsa_key', mode: '600' } - { name: 'ssh_host_rsa_key.pub', mode: '644' } - { name: 'ssh_host_ed25519_key', mode: '600' } - { name: 'ssh_host_ed25519_key.pub', mode: '644' } tags: base-ssh # bash - name: write the bash.bashrc config file template: src: "etc/bash.bashrc.j2" dest: "/etc/bash.bashrc" tags: base-shell # motd - name: ensure update-issue, update-motd and profile.d scripts are present template: src: "{{ item.src }}" dest: "{{ item.dest }}" mode: 0755 with_items: - { src: "usr/local/sbin/update-issue.sh.j2", dest: "/usr/local/sbin/update-issue.sh" } - { src: "usr/local/sbin/update-motd.sh.j2", dest: "/usr/local/sbin/update-motd.sh" } - { src: "etc/profile.d/w.sh.j2", dest: "/etc/profile.d/w.sh" } - { src: "etc/profile.d/pvc.sh.j2", dest: "/etc/profile.d/zzz_pvc.sh" } register: profile_scripts tags: base-shell - name: install banner update crontabs template: src: "{{ item.src }}" dest: "{{ item.dest }}" mode: 0644 with_items: - { src: "etc/cron.d/update-issue.j2", dest: "/etc/cron.d/update-issue" } - { src: "etc/cron.d/update-motd.j2", dest: "/etc/cron.d/update-motd" } tags: base-shell - name: ensure /etc/motd is absent file: dest: "/etc/motd" state: absent tags: base-shell - name: run update-motd on change command: /usr/local/sbin/update-motd.sh when: profile_scripts.changed and newhost is not defined and not newhost tags: base-shell - name: run update-issue on change command: /usr/local/sbin/update-issue.sh when: profile_scripts.changed and newhost is not defined and not newhost tags: base-shell # htop - name: install htop configuration template: src: "etc/htoprc.j2" dest: "/etc/htoprc" mode: 0644 tags: base-shell # fail2ban - name: install fail2ban configurations template: src: "{{ item.src }}" dest: "{{ item.dest }}" mode: 0644 notify: restart fail2ban with_items: - { src: "etc/fail2ban/action.d/route.conf.j2", dest: "/etc/fail2ban/action.d/route.conf" } - { src: "etc/fail2ban/filter.d/sshd.conf.j2", dest: "/etc/fail2ban/filter.d/sshd.conf" } - { src: "etc/fail2ban/jail.d/sshd.conf.j2", dest: "/etc/fail2ban/jail.d/sshd.conf" } - { src: "etc/fail2ban/jail.d/sshd.local.j2", dest: "/etc/fail2ban/jail.d/sshd.local" } tags: base-fail2ban # lm-sensors - name: run sensors-detect to update sensors configuration command: sensors-detect --auto tags: base-sensors # check-mk-agent - name: install check_mk agent plugins copy: src: "usr/lib/check_mk_agent/plugins/{{ item }}" dest: "/usr/lib/check_mk_agent/plugins/{{ item }}" mode: 0755 with_items: - backup - ceph - cephfsmounts - dpkg - entropy - freshness - ipmi - ownership tags: base-cmkagent # backups - name: create backup directory file: dest: /srv/backups state: directory tags: base-backups - name: install daily backup scripts template: src: "etc/cron.daily/{{ item }}.j2" dest: "/etc/cron.daily/{{ item }}" mode: 0755 with_items: - pvc-backup - mon-backup tags: base-backups - name: install IPMI network interfaces fragment template: src: etc/network/interfaces.d/ipmi.j2 dest: /etc/network/interfaces.d/ipmi tags: base-ipmi - name: configure IPMI username command: "ipmitool user set name {{ ipmi_user_configuration[cluster_hardware][item]['id'] }} {{ ipmi_user_configuration[cluster_hardware][item]['username'] }}" with_items: - "admin" - "pvc" ignore_errors: yes tags: base-ipmi - name: configure IPMI password command: "ipmitool user set password {{ ipmi_user_configuration[cluster_hardware][item]['id'] }} {{ ipmi_user_configuration[cluster_hardware][item]['password'] }}" with_items: - "admin" - "pvc" ignore_errors: yes tags: base-ipmi - name: configure IPMI role command: "ipmitool user priv {{ ipmi_user_configuration[cluster_hardware][item]['id'] }} {{ ipmi_user_configuration[cluster_hardware][item]['role'] }} {{ ipmi_user_configuration[cluster_hardware]['channel'] }}" with_items: - "admin" - "pvc" ignore_errors: yes tags: base-ipmi - name: enable IPMI user command: "ipmitool user enable {{ ipmi_user_configuration[cluster_hardware][item]['id'] }}" with_items: - "admin" - "pvc" ignore_errors: yes tags: base-ipmi # # Configure users # # common - name: ensure /var/home exists file: state: directory dest: /var/home tags: - users # root - name: generate Root password hash command: "mkpasswd --method=sha512crypt {{ root_password }}" no_log: true register: mkpasswd tags: - users - user-root - name: set Root password user: name: root password: "{{ mkpasswd.stdout }}" tags: - users - user-root ignore_errors: yes - name: remove Root known_hosts file: state: absent dest: /root/.ssh/known_hosts tags: - users - user-root - name: write vimrc to root homedir template: src: var/home/user/vimrc.j2 dest: /root/.vimrc mode: 0600 tags: - users - user-root - name: create vimdir file: state: directory dest: /root/.vim mode: 0700 tags: - users - user-root - name: remove root htoprc file: dest: "{{ item }}" state: absent loop: - /root/.htoprc - /root/.config/htop tags: - users - user-root # backup - name: ensure backup user has shell user: name: backup shell: /bin/sh tags: - users - user-backup ignore_errors: yes - name: create backup .ssh directory file: path: /var/backups/.ssh state: directory owner: backup group: root mode: 0700 tags: - users - user-backup - name: create backup authorized_keys file template: src: var/backups/ssh/authorized_keys.j2 dest: /var/backups/.ssh/authorized_keys owner: backup group: root mode: 0640 tags: - users - user-backup - name: write the sudoers file template: src: etc/sudoers.d/sudoers-backup.j2 dest: /etc/sudoers.d/backup tags: - users - user-backup - name: install the post-backup timestamp script template: src: var/backups/timestamp.sh.j2 dest: /var/backups/timestamp.sh mode: 0755 tags: - users - user-backup - name: touch shares file file: dest: /var/backups/shares state: touch owner: backup tags: - users - user-backup # deploy - name: ensure user deploy exists user: name: "{{ deploy_username }}" uid: 200 group: operator groups: operator shell: /bin/bash home: "/var/home/{{ deploy_username }}" createhome: yes move_home: yes state: present append: yes tags: - users - user-deploy ignore_errors: yes - name: ensure homedir has right permissions file: dest: "/var/home/{{ deploy_username }}" state: directory owner: "{{ deploy_username }}" group: operator mode: 0700 tags: - users - user-deploy - name: ensure .ssh directory exists file: dest: "/var/home/{{ deploy_username }}/.ssh" state: directory owner: "{{ deploy_username }}" group: operator mode: 0700 tags: - users - user-deploy - name: add authorized keys authorized_key: user: "{{ deploy_username }}" key: "{{ item.1 }}" state: present with_subelements: - "{{ admin_users }}" - keys tags: - users - user-deploy - name: remove authorized keys authorized_key: user: "{{ deploy_username }}" key: "{{ item.1 }}" state: absent with_subelements: - "{{ admin_users }}" - removed ignore_errors: yes tags: - users - user-deploy # admin_users - name: ensure user exists user: name: "{{ item.name }}" uid: "{{ item.uid }}" group: operator groups: sudo,adm,wireshark shell: /bin/bash home: "/var/home/{{ item.name }}" createhome: yes state: present append: yes with_items: "{{ admin_users }}" tags: - users - user-admin ignore_errors: yes - name: ensure homedir has right permissions file: dest: "/var/home/{{ item.name }}" state: directory owner: "{{ item.name }}" group: operator mode: 0700 with_items: "{{ admin_users }}" tags: - users - user-admin - name: ensure .ssh directory exists file: dest: "/var/home/{{ item.name }}/.ssh" state: directory owner: "{{ item.name }}" group: operator mode: 0700 with_items: "{{ admin_users }}" tags: - users - user-admin - name: add authorized keys authorized_key: user: "{{ item.0.name }}" key: "{{ item.1 }}" state: present with_subelements: - "{{ admin_users }}" - keys tags: - users - user-admin - name: remove authorized keys authorized_key: user: "{{ item.0.name }}" key: "{{ item.1 }}" state: absent with_subelements: - "{{ admin_users }}" - removed ignore_errors: yes tags: - users - user-deploy - name: write bashrc to homedir template: src: var/home/user/bashrc.j2 dest: "/var/home/{{ item.name }}/.bashrc" owner: "{{ item.name }}" group: operator mode: 0700 with_items: "{{ admin_users }}" tags: - users - user-admin - name: write bash_logout to homedir template: src: var/home/user/bash_logout.j2 dest: "/var/home/{{ item.name }}/.bash_logout" owner: "{{ item.name }}" group: operator mode: 0700 with_items: "{{ admin_users }}" tags: - users - user-admin - name: remove user htop configuration directory file: dest: "/var/home/{{ item.name }}/.config/htop" state: absent with_items: "{{ admin_users }}" tags: - users - user-admin - name: write profile to homedir template: src: var/home/user/profile.j2 dest: "/var/home/{{ item.name }}/.profile" owner: "{{ item.name }}" group: operator mode: 0700 with_items: "{{ admin_users }}" tags: - users - user-admin - name: write vimrc to homedir template: src: var/home/user/vimrc.j2 dest: "/var/home/{{ item.name }}/.vimrc" owner: "{{ item.name }}" group: operator mode: 0600 with_items: "{{ admin_users }}" tags: - users - user-admin - name: create vimdir file: state: directory dest: /var/home/{{ item.name }}/.vim owner: "{{ item.name }}" group: operator mode: 0700 with_items: "{{ admin_users }}" tags: - users - user-admin # # Verify and enable services # - name: verify and enable services service: name: "{{ item }}" state: started enabled: yes with_items: - acpid - cpufrequtils - ntp - postfix - rsyslog - ssh tags: base-services # # Cleanup # - name: run dpkg-cleanup.sh script command: /usr/local/sbin/dpkg-cleanup.sh - meta: flush_handlers