--- # Base packages, the Ansible root key and sshd basics for every Ubuntu/Rocky # guest. Run it once after a container is created (and adopted, see # discover_guests.yml). ssh_harden.yml then tightens sshd further through # /etc/ssh/sshd_config.d/00-ansible.conf. - name: Bootstrap - Install packages on Ubuntu hosts: ubuntu become: true tasks: - name: Install packages via apt ansible.builtin.apt: name: - vim - htop - nmap - curl - wget - iperf3 - fail2ban - net-tools - lsof - unzip - zip - git - sudo - tmux - tree - bash-completion - traceroute - dnsutils - ca-certificates - python3 - python3-pip - software-properties-common - rsync - sysstat - screen - mtr-tiny # plain "mtr" pulls in GTK on Ubuntu - tar state: present update_cache: true cache_valid_time: 3600 - name: Bootstrap - Install packages on Rocky Linux hosts: rocky become: true tasks: # epel-release ships in the "extras" repo on Rocky/Alma/CentOS Stream. # dnf-plugins-core provides "dnf config-manager" for the next task. - name: Ensure EPEL release package and dnf plugins are installed ansible.builtin.dnf: name: - epel-release - dnf-plugins-core state: present # EPEL packages may depend on CRB (CodeReady Builder). EPEL's install # guide enables it together with epel-release. - name: Enable the CRB repo community.general.dnf_config_manager: name: crb state: enabled - name: Install packages via dnf ansible.builtin.dnf: name: # BaseOS / AppStream - tar - vim-enhanced # "vim" is only a virtual provide on RHEL - nmap - curl - mtr - wget - iperf3 - net-tools - lsof - unzip - zip - git - sudo - tmux - tree - bash-completion - traceroute - bind-utils - ca-certificates - python3 - python3-pip - rsync - sysstat # EPEL - htop - fail2ban - screen state: present update_cache: true - name: Bootstrap - Configure SSH access hosts: ubuntu:rocky become: true gather_facts: false vars: bootstrap_ssh_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINegitHaQG8i+s412h3wTWf/KvpeX1CEpYFva9MhHR+7 ansible-key" sshd_service: "{{ 'ssh' if inventory_hostname in groups['ubuntu'] else 'sshd' }}" tasks: - name: Add the Ansible key to root's authorized_keys ansible.posix.authorized_key: user: root key: "{{ bootstrap_ssh_key }}" state: present # PasswordAuthentication stays on so a fresh container is still reachable # by password; ssh_harden.yml turns it off once keys are in place. - name: Allow key-based root login ansible.builtin.lineinfile: path: /etc/ssh/sshd_config regexp: '^#?{{ item.option }}\s' line: "{{ item.option }} {{ item.value }}" validate: /usr/sbin/sshd -t -f %s backup: true loop: - { option: PermitRootLogin, value: prohibit-password } - { option: PubkeyAuthentication, value: "yes" } - { option: PasswordAuthentication, value: "yes" } loop_control: label: "{{ item.option }} {{ item.value }}" notify: Restart sshd handlers: - name: Restart sshd ansible.builtin.service: name: "{{ sshd_service }}" state: restarted