# Initial server setup # --- - hosts: all become: yes vars: my_client_ip: 192.168.1.75 tmzone: America/Vancouver sudo_timeout: 60 # Set ufw logging: on | off | low | medium | high | full ufw_log: off # SSH socket config used for 22.10 and later. # Disable any existing listen steam and enable the new stream. ssh_socket_cfg: | [Socket] ListenStream= ListenStream={{ ssh_port }} resolved_cfg: | [Resolve] DNSStubListener=no DNS=127.0.0.1 f2b_jail_local: | [DEFAULT] ignoreip = 127.0.0.1/8 ::1 {{ my_client_ip }} findtime = 15m bantime = 2h maxretry = 5 [sshd] enabled = true maxretry = 3 port = {{ ssh_port }} tasks: - name: Get datestamp from the system shell: date +"%Y%m%d" register: dstamp - name: Set current date stamp variable set_fact: cur_date: "{{ dstamp.stdout }}" # Update and install the base software - name: Update apt package cache apt: update_cache: yes cache_valid_time: 3600 - name: Upgrade installed apt packages apt: upgrade: dist register: upgrade retries: 15 delay: 5 until: upgrade is success - name: Ensure that a base set of software packages are installed apt: pkg: - apt-transport-https - build-essential - fail2ban - pwgen - unbound - unzip - docker - docker-compose - net-tools - traceroute - python3-pip - git # state: latest - name: Create a local systemd-resolved configuration directory. file: path: /etc/systemd/resolved.conf.d state: directory owner: root group: root mode: 0755 - name: Create a local systemd-resolved configuration that works with unbound. copy: dest: /etc/systemd/resolved.conf.d/local.conf content: "{{ resolved_cfg }}" owner: root group: root mode: 0644 - name: Update the systemd-resolved /etc/resolv.conf symbolic link. file: src: /run/systemd/resolve/resolv.conf dest: /etc/resolv.conf state: link owner: root group: root - name: Restart systemd-resolved service: name: systemd-resolved state: restarted - name: Check if a reboot is needed for Debian-based systems stat: path: /var/run/reboot-required register: reboot_required # Host Setup - name: Set static hostname hostname: name: "{{ inventory_hostname_short }}" - name: Add FQDN to /etc/hosts lineinfile: dest: /etc/hosts regexp: '^127\.0\.1\.1' line: '127.0.1.1 {{ inventory_hostname }} {{ inventory_hostname_short }}' state: present - name: Check if cloud init is installed. stat: path="/etc/cloud/templates/hosts.debian.tmpl" register: cloud_installed - name: Add FQDN to /etc/cloud/templates/hosts.debian.tmpl lineinfile: dest: /etc/cloud/templates/hosts.debian.tmpl regexp: '^127\.0\.1\.1' line: "127.0.1.1 {{ inventory_hostname }} {{ inventory_hostname_short }}" state: present when: cloud_installed.stat.exists - name: set timezone timezone: name: "{{ tmzone }}" # Set sudo password timeout (default is 15 minutes) - name: Set sudo password timeout. lineinfile: path: /etc/sudoers state: present regexp: '^Defaults\tenv_reset' line: 'Defaults env_reset, timestamp_timeout={{ sudo_timeout }}' validate: '/usr/sbin/visudo -cf %s' - name: Create/update regular user with sudo privileges user: name: "{{ user }}" password: "{{ user_passwd | password_hash('sha512') }}" # password: ELqZ9L70SSOTjnE0Jq state: present groups: sudo append: true shell: /bin/bash - name: Install requests python package ansible.builtin.pip: name: requests - name: Install gitpython python package ansible.builtin.pip: name: gitpython - name: Run clone all repos ansible.builtin.script: ./clone_all_repos.py args: executable: python3 - name: Change site name in all repos ansible.builtin.shell: cmd: grep -rli 'franv.site' * | xargs -i@ sed -i 's/franv.site/new.site/g' @ chdir: /home/user_this/ - name: Change back ownership to user_this ansible.builtin.shell: cmd: chown -R user_this:user_this fossilfranv chdir: /home/user_this/ - name: Ensure ansible_sudo_passwd matches the [new] user password set_fact: ansible_sudo_passwd: "{{ user_passwd }}" - name: Ensure authorized keys for remote user is installed authorized_key: user: "{{ user }}" state: present key: "{{ ssh_pub_key }}" - name: Ensure authorized key for root user is installed authorized_key: user: root state: present key: "{{ ssh_pub_key }}" - name: Update root user password. user: name: root password: "{{ root_passwd | password_hash('sha512') }}" - name: Disable password authentication for root lineinfile: path: /etc/ssh/sshd_config state: present regexp: '^#?PermitRootLogin' line: 'PermitRootLogin prohibit-password' - name: Disable tunneled clear-text passwords lineinfile: path: /etc/ssh/sshd_config state: present regexp: '^PasswordAuthentication yes' line: 'PasswordAuthentication no' - name: Set user PS1 to a two-line prompt lineinfile: dest: "/home/{{ user }}/.bashrc" insertafter: EOF line: "PS1='${debian_chroot:+($debian_chroot)}\\[\\033[01;32m\\]\\u@\\h\\[\\033[00m\\]:\\[\\033[01;34m\\]\\w\\[\\033[00m\\]\\n\\$ '" state: present - name: Set root PS1 to a two-line prompt lineinfile: path: '/root/.bashrc' state: present insertafter: EOF line: PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\n\$ ' # Configure the UFW firewall - name: Disable and reset ufw firewall to installation defaults. ufw: state: reset - name: Find backup rules to delete find: paths: /etc/ufw patterns: "*.{{ cur_date }}_*" use_regex: no register: files_to_delete - name: Delete ufw backup rules file: path: "{{ item.path }}" state: absent with_items: "{{ files_to_delete.files }}" - name: Set the ssh '{{ ssh_port }}' port number in sshd_config (ver < 22.10). lineinfile: dest: /etc/ssh/sshd_config regexp: '^#Port ' line: 'Port {{ ssh_port }}' state: present when: ansible_facts['distribution_version'] < '22.10' - name: Create a ssh.socket.d configuration directory (ver >= 22.10). file: path: /etc/systemd/system/ssh.socket.d state: directory owner: root group: root mode: 0755 when: ansible_facts['distribution_version'] >= '22.10' - name: Create a local SSH socket stream configuration (ver >= 22.10). copy: dest: /etc/systemd/system/ssh.socket.d/listen.conf content: "{{ ssh_socket_cfg }}" owner: root group: root mode: 0644 when: ansible_facts['distribution_version'] >= '22.10' - name: daemon-reload (ver >= 22.10) systemd: daemon_reload: yes when: ansible_facts['distribution_version'] >= '22.10' - name: Restart the ssh service after updating the SSH port number (ver < 22.10). service: name: ssh state: restarted when: ansible_facts['distribution_version'] < '22.10' - name: Restart the ssh socket unit after updating the SSH port number (ver >= 22.10). systemd: name: ssh.socket state: restarted when: ansible_facts['distribution_version'] >= '22.10' - name: Change the ansible ssh port to '{{ ssh_port }}' set_fact: ansible_port: '{{ ssh_port }}' - name: Allow ssh port '{{ ssh_port }}'. ufw: rule: allow proto: tcp port: '{{ ssh_port }}' state: enabled - name: Set the UFW log level. ufw: logging: '{{ ufw_log }}' - name: configure fail2ban for ssh copy: dest: /etc/fail2ban/jail.local content: "{{ f2b_jail_local }}" owner: root group: root mode: 0644 notify: - restart fail2ban - name: enable fail2ban service on boot service: name: fail2ban enabled: true state: started # simple shell script to display fail2ban-client status info; usage: # f2bst # f2bst sshd - name: Configure f2bst copy: dest: /usr/local/bin/f2bst content: | #!/bin/sh fail2ban-client status $* owner: root group: root mode: 0750 - name: run needrestart command: needrestart -r a when: not reboot_required.stat.exists and upgrade.changed - name: Configure static networking copy: src: etc/netplan/50-cloud-init.yaml dest: /etc/netplan/50-cloud-init.yaml owner: root group: root mode: 0644 notify: - netplan apply when: cfg_static_network == true - name: Report if reboot is needed. debug: msg: Rebooting the server, please wait. when: reboot_required.stat.exists - name: Reboot the server if needed reboot: msg: "Reboot initiated by Ansible because of reboot required file." connect_timeout: 5 reboot_timeout: 600 pre_reboot_delay: 0 post_reboot_delay: 30 test_command: whoami when: reboot_required.stat.exists - name: Remove old packages from the cache apt: autoclean: yes - name: Remove dependencies that are no longer needed apt: autoremove: yes purge: yes handlers: - name: restart fail2ban service: name: fail2ban state: restarted when: reboot_required.stat.exists == false - name: netplan apply command: netplan apply when: cfg_static_network == true