diff --git a/.github/workflows/ansible.yml b/.github/workflows/ansible.yml index 2302372..7a20203 100644 --- a/.github/workflows/ansible.yml +++ b/.github/workflows/ansible.yml @@ -16,6 +16,15 @@ on: required: true default: false type: boolean + runner: + description: "Runner Image" + required: true + type: choice + default: "ubuntu-latest" + options: + - ubuntu-latest + - ubuntu-22.04 + ansible_verbose: description: "Verbose mode" required: true @@ -34,7 +43,7 @@ jobs: python-version: ["3.13"] steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Set up Python ${{ matrix.python-version }} id: setup-python @@ -48,7 +57,7 @@ jobs: - name: Cache pipenv id: cache-pipenv - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ~/.local/share/virtualenvs key: ${{ runner.os }}-pipenv-${{ hashFiles('**/Pipfile.lock') }} @@ -81,7 +90,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up Python uses: actions/setup-python@v6 diff --git a/.github/workflows/powershell.yml b/.github/workflows/powershell.yml index b6a5caf..7c63776 100644 --- a/.github/workflows/powershell.yml +++ b/.github/workflows/powershell.yml @@ -27,10 +27,10 @@ jobs: name: PSScriptAnalyzer runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Run PSScriptAnalyzer - uses: microsoft/psscriptanalyzer-action@6b2948b1944407914a58661c49941824d149734f + uses: microsoft/psscriptanalyzer-action@v1.1 with: # Check https://github.com/microsoft/action-psscriptanalyzer for more info about the options. # The below set up runs PSScriptAnalyzer to your entire repository and runs some basic security rules. diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml index d3813a4..ca13036 100644 --- a/.github/workflows/shellcheck.yml +++ b/.github/workflows/shellcheck.yml @@ -14,6 +14,6 @@ jobs: name: Shellcheck runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Run ShellCheck uses: ludeeus/action-shellcheck@master diff --git a/README.md b/README.md index d98ac9d..2d15632 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,15 @@ -# cloud-init_ubuntu -[![Ansible](https://github.com/Kipjr/cloud-init_ubuntu/actions/workflows/ansible.yml/badge.svg)](https://github.com/Kipjr/cloud-init_ubuntu/actions/workflows/ansible.yml) +# cloud-init_linux +[![Ansible](https://github.com/Kipjr/cloud-init_linux/actions/workflows/ansible.yml/badge.svg)](https://github.com/Kipjr/cloud-init_linux/actions/workflows/ansible.yml) -Cloud-Init for Ubuntu Server +Cloud-Init for + +`Ubuntu 24.04 LTS Noble Numbat (trixie 13)` + +`Ubuntu 22.04 LTS Jammy Jellyfish (bookworm 12)` + +`Debian 12 (bookworm)` + +_~Debian 13 (trixie)~ - When available on ansible-lockdown.._ # Usage @@ -12,18 +20,40 @@ Cloud-Init for Ubuntu Server { "ansible_become_user": "root", "ansible_become_method": "sudo", + "docker_type": "rootless", + "portainer_agent": true, + "portainer_host": true, + "ubtu22_vm": true, "ubtu22_run_task_disk": true, "ubtu22_run_task_packages": true, "ubtu22_pkg_webmin": true, "ubtu22_pkg_snmp": true, - "ubtu22_run_task_docker": true - "ubtu22_docker_type": "rootless", - "ubtu22_portainer_agent": true, - "ubtu22_portainer_host": true, + "ubtu22_run_task_docker": true, "ubtu22_run_task_configuration": true, "ubtu22_run_task_security": true, - "ubtu22_runcis": false + "ubtu22_runcis": false, + + "ubtu24_vm": true, + "ubtu24_run_task_disk": true, + "ubtu24_run_task_packages": true, + "ubtu24_pkg_webmin": true, + "ubtu24_pkg_snmp": true, + "ubtu24_run_task_docker": true + "ubtu24_run_task_configuration": true, + "ubtu24_run_task_security": true, + "ubtu24_runcis": false, + + "deb12_vm": true, + "deb12_run_task_disk": true, + "deb12_run_task_packages": true, + "deb12_pkg_webmin": true, + "deb12_pkg_snmp": true, + "deb12_run_task_docker": true + "deb12_run_task_configuration": true, + "deb12_run_task_security": true, + "deb12_runcis": false + } ``` ### Use standalone (Installs Ansible and executes playbook) @@ -33,8 +63,12 @@ Cloud-Init for Ubuntu Server ### Use with Proxmox Cloud-Init: - Build template - Do stuff.. - - Use `https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img` as base image. - - Resize image`qemu-img resize jammy-server-cloudimg-amd64.img 8G` + - Use as base image: + - `https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img` + - `https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img` + - Resize image: + - `qemu-img resize jammy-server-cloudimg-amd64.img 8G` + - `qemu-img resize noble-server-cloudimg-amd64.img 8G` - Execute somewhere `./proxmox/new_ci-config.sh` - Store 'ci-config-userdata.yaml' in Proxmox Snippets - Store 'ci-config-vendor.yaml' in Proxmox Snippets @@ -43,6 +77,17 @@ Cloud-Init for Ubuntu Server - `qm set --cicustom "vendor=local:snippets/ci-config-vendor.yaml"` ### Use Raw: -- `https://raw.githubusercontent.com/Kipjr/cloud-init_ubuntu/master/site.yml` +- `https://raw.githubusercontent.com/Kipjr/cloud-init_linux/master/site.yml` +# Recommended partition layout +| Mount Point | Size | Filesystem (Recommended) | Remarks | +| ---------------- | ------------------ | ------------------------ | -------------------------------------------------------------------------------------------------------- | +| `/` | 32 GB | ext4 | Root filesystem. Sufficient for base OS, packages, updates. | +| `/home` | 8 GB | ext4 | User data isolation. | +| `/var` | 8 GB | ext4 | Variable state data. Logs excluded. Monitor space usage. | +| `/var/log` | 8 GB | ext4 | Log isolation to prevent root exhaustion. | +| `/var/log/audit` | 4 GB | ext4 | Dedicated audit trail partition (auditd). Prevents log flooding impact. | +| `/var/tmp` | 1 GB | ext4 | Persistent temp storage across reboots. | +| `/tmp` | 1 GB | ext4 or tmpfs | Ephemeral temp storage. Prefer `tmpfs` if RAM allows. | +| `/opt/data` | x GB + remainder | ext4 or XFS | Primary persistent data storage. | diff --git a/defaults/main.yml b/defaults/main.yml index 56bc8c5..781d999 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -1,11 +1,27 @@ -ubtu22_vm: true -ubtu22_pkg_webmin: true -ubtu22_pkg_snmp: false -ubtu22_portainer_host: true -ubtu22_portainer_agent: true -ubtu22_docker_type: "rootless" -# ubtu22_docker_type: "rootfull" -ubtu22_docker_rootless_user: "docker" +portainer_host: true +portainer_agent: true +docker_type: "rootless" +# docker_type: "rootfull" +docker_rootless_user: "docker" + +vm: true +pkg_webmin: true +pkg_snmp: false + +deb12_run_task_configuration: true +deb12_run_task_disk: true +deb12_run_task_docker: true +deb12_run_task_packages: true +deb12_run_task_security: true +deb12_runcis: false + +deb13_run_task_configuration: true +deb13_run_task_disk: false +deb13_run_task_docker: false +deb13_run_task_packages: true +deb13_run_task_security: true +deb13_runcis: false + ubtu22_run_task_configuration: true ubtu22_run_task_disk: true ubtu22_run_task_docker: true @@ -13,6 +29,13 @@ ubtu22_run_task_packages: true ubtu22_run_task_security: true ubtu22_runcis: false +ubtu24_run_task_configuration: true +ubtu24_run_task_disk: true +ubtu24_run_task_docker: true +ubtu24_run_task_packages: true +ubtu24_run_task_security: true +ubtu24_runcis: false + ### ### ubtu22cis variables ### diff --git a/proxmox/ci-config-userdata.template.yaml b/proxmox/ci-config-userdata.template.yaml index ebd4125..09896c7 100644 --- a/proxmox/ci-config-userdata.template.yaml +++ b/proxmox/ci-config-userdata.template.yaml @@ -26,7 +26,7 @@ packages: - git #runcmd: # - sudo -u ${CI_USER} curl https://bootstrap.pypa.io/get-pip.py -o /tmp/get-pip.py && sudo -u ${CI_USER} python3 /tmp/get-pip.py --user -# - wget -O /run/cloud-init/tmp/script.sh https://raw.githubusercontent.com/Kipjr/cloud-init_ubuntu/master/standalone_ansible_playbook.sh +# - wget -O /run/cloud-init/tmp/script.sh https://raw.githubusercontent.com/Kipjr/cloud-init_linux/master/standalone_ansible_playbook.sh # - chmod +x /run/cloud-init/tmp/script.sh # - sudo -iu ${CI_USER} -- /run/cloud-init/tmp/script.sh ansible: diff --git a/roles/requirements.yml b/roles/requirements.yml index d7cc8fc..9be560b 100644 --- a/roles/requirements.yml +++ b/roles/requirements.yml @@ -4,3 +4,11 @@ roles: src: https://github.com/ansible-lockdown/UBUNTU22-CIS.git version: main scm: git + - name: ansible-lockdown.ubuntu24-cis + src: https://github.com/ansible-lockdown/UBUNTU24-CIS.git + version: main + scm: git + - name: ansible-lockdown.debian12-cis + src: https://github.com/ansible-lockdown/DEBIAN12-CIS + version: main + scm: git diff --git a/site.yml b/site.yml index bac030c..adf156f 100644 --- a/site.yml +++ b/site.yml @@ -1,6 +1,6 @@ --- -- name: Ubuntu Installer +- name: Linux Installer hosts: all gather_facts: true environment: diff --git a/standalone_ansible_playbook.ps1 b/standalone_ansible_playbook.ps1 index d75303d..06f3d3c 100755 --- a/standalone_ansible_playbook.ps1 +++ b/standalone_ansible_playbook.ps1 @@ -1,7 +1,7 @@ #!/usr/bin/env pwsh param ( - [Parameter(Position=0)][string]$GitHubRepoUrl = "https://github.com/Kipjr/cloud-init_ubuntu", + [Parameter(Position=0)][string]$GitHubRepoUrl = "https://github.com/Kipjr/cloud-init_linux", [Parameter(Position=1)][string]$PlaybookName = "site.yml", [Parameter(Position=2)][string]$WorkingDir = "/tmp", [Parameter(Position=3)][string]$AnsibleArg diff --git a/standalone_ansible_playbook.sh b/standalone_ansible_playbook.sh index 7d05538..c59297a 100755 --- a/standalone_ansible_playbook.sh +++ b/standalone_ansible_playbook.sh @@ -8,7 +8,7 @@ if [ "$UUID" -eq 0 ]; then exit 1 fi -GITHUB_REPO_URL="${1:-https://github.com/Kipjr/cloud-init_ubuntu}" +GITHUB_REPO_URL="${1:-https://github.com/Kipjr/cloud-init_linux}" PLAYBOOK_NAME="${2:-site.yml}" WORKING_DIR="${3:-/tmp}" ANSIBLE_ARG="${4}" diff --git a/tasks/configuration/main.yml b/tasks/configuration/main.yml index 8788bc0..9fb54a6 100644 --- a/tasks/configuration/main.yml +++ b/tasks/configuration/main.yml @@ -4,7 +4,7 @@ when: ansible_fqdn is defined and ansible_fqdn | length <= 32 become: true ansible.builtin.hostname: - name: "{{ ansible_fqdn }}" + name: "{{ ansible_facts['fqdn'] }}" - name: Set timezone to Europe/Amsterdam become: true @@ -28,29 +28,39 @@ - name: Create ~/.ssh if not exist ansible.builtin.file: - path: /home/{{ ansible_user_id }}/.ssh - owner: "{{ ansible_user_id }}" + path: /home/{{ ansible_facts['user_id'] }}/.ssh + owner: "{{ ansible_facts['user_id'] }}" state: directory mode: "0700" - name: Check if SSH private key already exists - ansible.builtin.stat: - path: /home/{{ ansible_user_id }}/.ssh/id_rsa + ansible.builtin.find: + paths: "/home/{{ ansible_facts.user_id }}/.ssh" + file_type: file + patterns: + - "id_*" + - "*.key" + excludes: + - "*.pub" + - "known_hosts" + - "authorized_keys" + - "config" register: file_private_key + failed_when: false - name: Generate SSH private and public keys when: not file_private_key.stat.exists community.crypto.openssh_keypair: - path: /home/{{ ansible_user_id }}/.ssh/id_rsa + path: /home/{{ ansible_facts['user_id'] }}/.ssh/id_rsa type: ed25519 - owner: "{{ ansible_user_id }}" + owner: "{{ ansible_facts['user_id'] }}" mode: '0600' register: ssh_keypair - name: Add SSH public key to authorized_keys when: not file_private_key.stat.exists ansible.posix.authorized_key: - user: "{{ ansible_user_id }}" + user: "{{ ansible_facts['user_id'] }}" key: "{{ ssh_keypair.public_key }}" - name: Disable SSH password authentication diff --git a/tasks/debian12.yml b/tasks/debian12.yml new file mode 100644 index 0000000..f53effa --- /dev/null +++ b/tasks/debian12.yml @@ -0,0 +1,34 @@ +--- +- name: Debian 12 specific task + ansible.builtin.debug: + msg: "Running tasks for Debian 12" + +- name: Disk Configuration + when: deb12_run_task_disk + ansible.builtin.import_tasks: packages/main.yml + tags: + - packages + +- name: Packages + when: deb12_run_task_packages + ansible.builtin.import_tasks: packages/main.yml + tags: + - packages + +- name: Docker + when: deb12_run_task_docker + ansible.builtin.import_tasks: docker/main.yml + tags: + - docker + +- name: Configuration + when: deb12_run_task_configuration + ansible.builtin.import_tasks: configuration/main.yml + tags: + - configure + +- name: Security + when: deb12_run_task_security + ansible.builtin.import_tasks: security/main.yml + tags: + - security diff --git a/tasks/debian13.yml b/tasks/debian13.yml new file mode 100644 index 0000000..cc3dbb9 --- /dev/null +++ b/tasks/debian13.yml @@ -0,0 +1,34 @@ +--- +- name: Debian 13 specific task + ansible.builtin.debug: + msg: "Running tasks for Debian 13" + +- name: Disk Configuration + when: deb13_run_task_disk + ansible.builtin.import_tasks: disk/main.yml + tags: + - packages + +- name: Packages + when: deb13_run_task_packages + ansible.builtin.import_tasks: packages/main.yml + tags: + - packages + +- name: Docker + when: deb13_run_task_docker + ansible.builtin.import_tasks: docker/main.yml + tags: + - docker + +- name: Configuration + when: deb13_run_task_configuration + ansible.builtin.import_tasks: configuration/main.yml + tags: + - configure + +- name: Security + when: deb13_run_task_security + ansible.builtin.import_tasks: security/main.yml + tags: + - security diff --git a/tasks/disk/main.yml b/tasks/disk/main.yml index b4a3e89..beef9ad 100644 --- a/tasks/disk/main.yml +++ b/tasks/disk/main.yml @@ -13,35 +13,144 @@ - quota state: present -# sudo modprobe -v xfs +- name: Detect candidate block devices + ansible.legacy.set_fact: + candidate_disks: >- + {{ + ansible_facts.devices + | dict2items + | rejectattr('key', 'search', '^(loop|ram|sr|dm-)') + | selectattr('value.removable', 'equalto', '0') + | selectattr('value.size', 'defined') + | map(attribute='key') + | list + }} -# fdisk -l -# Disk /dev/xvda: 40 GiB, 42949672960 bytes, 83886080 sectors -# Disk /dev/xvdf: 400 GiB, 429496729600 bytes, 838860800 sectors +- name: Build disk size map (GB numeric) + ansible.legacy.set_fact: + disk_sizes: >- + {{ + dict(candidate_disks | zip( + candidate_disks + | map('extract', ansible_facts.devices) + | map(attribute='size') + | map('regex_replace','[^0-9.]','') + | map('float') + )) + }} -# mkfs.xfs [options] /dev/device +- name: Sort disks by size + ansible.legacy.set_fact: + sorted_disks: "{{ disk_sizes | dict2items | sort(attribute='value') | map(attribute='key') | list }}" + disk_count: "{{ sorted_disks | length }}" -# read info and reuse it in subsequent task -- name: Read device info (always use unit when probing) - community.general.parted: - device: /dev/sdb - unit: MiB - register: sdb_info +- name: Detect root source device + ansible.legacy.set_fact: + root_device: "{{ ansible_facts.mounts | selectattr('mount', 'equalto', '/') | map(attribute='device') | first }}" + root_online: "{{ (ansible_facts.mounts | selectattr('mount','equalto','/') | list | length) > 0 }}" + +######################################################### +# CASE 1: Single disk + online root → SKIP +######################################################### + +- name: Skip disk changes (single disk with active root) + ansible.legacy.meta: end_play + when: + - disk_count == 1 + - root_online | bool + +######################################################### +# Disk role assignment +######################################################### + +- name: Assign disk roles + ansible.builtin.set_fact: + smallest_disk: "{{ sorted_disks[0] }}" + largest_disk: "{{ sorted_disks[-1] }}" + when: disk_count >= 2 -- name: Create a new XFS data partition +######################################################### +# Helper: partition suffix handling +######################################################### + +- name: Set partition suffix rule + ansible.builtin.set_fact: + part_suffix: >- + {{ + 'p' if largest_disk is search('^nvme|^mmcblk') else '' + }} + when: disk_count >= 2 + +######################################################### +# 2 DISKS → DATA ONLY +######################################################### + +- name: Ensure GPT label on largest disk community.general.parted: - device: /dev/sdb + device: "/dev/{{ largest_disk }}" label: gpt - name: data + when: disk_count >= 2 + +- name: Create data partition (64G at start) + community.general.parted: + device: "/dev/{{ largest_disk }}" number: 1 state: present - fs_type: xfs + part_start: 1MiB + part_end: 64G + when: disk_count >= 2 + +- name: Create XFS filesystem for data + community.general.filesystem: + fstype: xfs + dev: "/dev/{{ largest_disk }}{{ part_suffix }}1" + when: disk_count >= 2 + +- name: Mount data + ansible.posix.mount: + path: /mnt/data + src: "/dev/{{ largest_disk }}{{ part_suffix }}1" + fstype: xfs + state: mounted + when: disk_count >= 2 + +######################################################### +# 3 DISKS → ADDITIONAL LOG DISK +######################################################### + +- name: Set log partition suffix + ansible.builtin.set_fact: + log_suffix: >- + {{ + 'p' if smallest_disk is search('^nvme|^mmcblk') else '' + }} + when: disk_count == 3 -- name: Create a new log partition +- name: Ensure GPT label on smallest disk community.general.parted: - device: /dev/sdc + device: "/dev/{{ smallest_disk }}" label: gpt - name: log + when: disk_count == 3 + +- name: Create log partition (8G) + community.general.parted: + device: "/dev/{{ smallest_disk }}" number: 1 state: present - fs_type: ext4 + part_start: 1MiB + part_end: 8G + when: disk_count == 3 + +- name: Create ext4 for /var/log + community.general.filesystem: + fstype: ext4 + dev: "/dev/{{ smallest_disk }}{{ log_suffix }}1" + when: disk_count == 3 + +- name: Mount /var/log + ansible.posix.mount: + path: /var/log + src: "/dev/{{ smallest_disk }}{{ log_suffix }}1" + fstype: ext4 + state: mounted + when: disk_count == 3 diff --git a/tasks/docker/main.yml b/tasks/docker/main.yml index ce4b15e..d3d4f61 100644 --- a/tasks/docker/main.yml +++ b/tasks/docker/main.yml @@ -1,17 +1,59 @@ --- -- name: Add Docker official GPG key + +- name: Ensure supported distribution + ansible.builtin.assert: + that: + - ansible_facts['distribution'] in ['Debian', 'Ubuntu'] + +- name: Set Docker repo variables + ansible.builtin.set_fact: + docker_repo_base: "https://download.docker.com/linux/{{ ansible_facts['distribution'] | lower }}" + docker_gpg_url: "https://download.docker.com/linux/{{ ansible_facts['distribution'] | lower }}/gpg" + docker_codename: >- + {{ + ansible_facts['distribution_release'] + }} + +- name: Update apt cache become: true - ansible.builtin.apt_key: - url: https://download.docker.com/linux/ubuntu/gpg - state: present + ansible.builtin.apt: + update_cache: true -- name: Add Docker repository +- name: Install required packages become: true - ansible.builtin.apt_repository: - repo: "deb https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable" - filename: docker + ansible.builtin.apt: + name: + - ca-certificates + - curl state: present +- name: Ensure keyring directory exists + become: true + ansible.builtin.file: + path: /etc/apt/keyrings + state: directory + mode: "0755" + +- name: Download Docker GPG key + become: true + ansible.builtin.get_url: + url: "{{ docker_gpg_url }}" + dest: /etc/apt/keyrings/docker.asc + mode: "0644" + force: true + +- name: Configure Docker apt source + become: true + ansible.builtin.copy: + dest: /etc/apt/sources.list.d/docker.sources + mode: "0644" + content: | + Types: deb + URIs: {{ docker_repo_base }} + Suites: {{ docker_codename }} + Components: stable + Signed-By: /etc/apt/keyrings/docker.asc + - name: Ensure all packages are up to date become: true ansible.builtin.apt: @@ -62,7 +104,7 @@ exit 0 - name: Rootfull Docker - when: ubtu22_docker_type == "rootfull" + when: docker_type == "rootfull" block: - name: Set variables ansible.builtin.set_fact: @@ -71,23 +113,23 @@ docker_daemon_conf: /etc/docker/daemon.json - name: Rootless Docker - when: ubtu22_docker_type == "rootless" + when: docker_type == "rootless" block: - name: Set variables ansible.builtin.set_fact: - docker_host: /run/user/{{ ansible_user_uid }}/docker.sock - docker_volumes: /home/{{ ansible_user_id }}/.local/share/docker/volumes - docker_daemon_conf: /home/{{ ansible_user_id }}/.config/docker/daemon.json + docker_host: /run/user/{{ ansible_facts['user_uid'] }}/docker.sock + docker_volumes: /home/{{ ansible_facts['user_id'] }}/.local/share/docker/volumes + docker_daemon_conf: /home/{{ ansible_facts['user_id'] }}/.config/docker/daemon.json - name: Create ~/.config/docker if not exist ansible.builtin.file: - path: /home/{{ ansible_user_id }}/.config/docker + path: /home/{{ ansible_facts['user_id'] }}/.config/docker state: directory mode: "0755" - name: Check if Docker Rootless is installed ansible.builtin.stat: - path: /run/user/{{ ansible_user_uid }}/docker.sock + path: /run/user/{{ ansible_facts['user_uid'] }}/docker.sock register: file_check_docker_rootless - name: Disable Docker.service @@ -111,25 +153,25 @@ state: absent - name: Install Docker (rootless, using systemd) - when: not file_check_docker_rootless.stat.exists and ubtu22_docker_type == "rootless" + when: not file_check_docker_rootless.stat.exists and docker_type == "rootless" environment: - XDG_RUNTIME_DIR: "/run/user/{{ ansible_user_uid }}" - DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ ansible_user_uid }}/bus" - HOME: "/home/{{ ansible_user_id }}" + XDG_RUNTIME_DIR: "/run/user/{{ ansible_facts['user_uid'] }}" + DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ ansible_facts['user_uid'] }}/bus" + HOME: "/home/{{ ansible_facts['user_id'] }}" args: - creates: "/home/{{ ansible_user_id }}/.docker/config.json" + creates: "/home/{{ ansible_facts['user_id'] }}/.docker/config.json" ansible.builtin.shell: | dockerd-rootless-setuptool.sh install - name: Check if /usr/bin is in PATH in .bashrc - ansible.builtin.command: grep -q 'export PATH=/usr/bin:$PATH' /home/{{ ansible_user_id }}/.bashrc + ansible.builtin.command: grep -q 'export PATH=/usr/bin:$PATH' /home/{{ ansible_facts['user_id'] }}/.bashrc register: bashrc_path_usr_bin_check ignore_errors: true changed_when: false - name: Ensure /usr/bin is in PATH in .bashrc ansible.builtin.lineinfile: - path: /home/{{ ansible_user_id }}/.bashrc + path: /home/{{ ansible_facts['user_id'] }}/.bashrc line: 'export PATH=/usr/bin:$PATH' state: present create: true @@ -137,41 +179,52 @@ when: bashrc_path_usr_bin_check.rc != 0 - name: Check if DOCKER_HOST is set in .bashrc - when: ubtu22_docker_type == "rootless" - ansible.builtin.command: grep -q 'export DOCKER_HOST=unix:///run/user/{{ ansible_user_uid }}/docker.sock' /home/{{ ansible_user_id }}/.bashrc + when: docker_type == "rootless" + ansible.builtin.lineinfile: + path: "/home/{{ ansible_facts['user_id'] }}/.bashrc" + line: "export DOCKER_HOST=unix:///run/user/{{ ansible_facts['user_uid'] }}/docker.sock" + state: present register: bashrc_docker_host_check ignore_errors: true changed_when: false +# - name: Check if DOCKER_HOST is set in .bashrc +# when: docker_type == "rootless" +# ansible.builtin.command: | +# grep -q 'export DOCKER_HOST=unix:///run/user/{{ ansible_facts['user_uid'] }}/docker.sock' /home/{{ ansible_facts['user_id'] }}/.bashrc +# register: bashrc_docker_host_check +# ignore_errors: true +# changed_when: false + - name: Ensure DOCKER_HOST is set in .bashrc ansible.builtin.lineinfile: - path: /home/{{ ansible_user_id }}/.bashrc - line: "export DOCKER_HOST=unix:///run/user/{{ ansible_user_uid }}/docker.sock" + path: /home/{{ ansible_facts['user_id'] }}/.bashrc + line: "export DOCKER_HOST=unix:///run/user/{{ ansible_facts['user_uid'] }}/docker.sock" state: present create: true mode: "0644" when: bashrc_docker_host_check.rc != 0 - name: Check if lingering is enabled for the user - ansible.builtin.command: loginctl show-user {{ ansible_user_id }} --property=Linger + ansible.builtin.command: loginctl show-user {{ ansible_facts['user_id'] }} --property=Linger register: linger_status ignore_errors: true changed_when: false - name: Enable lingering for the user - ansible.builtin.command: loginctl enable-linger {{ ansible_user_id }} + ansible.builtin.command: loginctl enable-linger {{ ansible_facts['user_id'] }} when: linger_status.stdout != 'Linger=yes' changed_when: linger_status.stdout != 'Linger=yes' - name: Ensure the user directory docker service exists ansible.builtin.file: - path: /home/{{ ansible_user_id }}/.config/systemd/user/docker.service.d + path: /home/{{ ansible_facts['user_id'] }}/.config/systemd/user/docker.service.d state: directory mode: "0755" - name: Configure systemd override for user ansible.builtin.copy: - dest: /home/{{ ansible_user_id }}/.config/systemd/user/docker.service.d/override.conf + dest: /home/{{ ansible_facts['user_id'] }}/.config/systemd/user/docker.service.d/override.conf mode: "0644" content: | [Service] @@ -181,7 +234,7 @@ - name: Refresh env changed_when: true ansible.builtin.shell: | - . /home/{{ ansible_user_id }}/.bashrc + . /home/{{ ansible_facts['user_id'] }}/.bashrc exit 0 - name: General (post) Docker @@ -201,7 +254,7 @@ } - name: Ensure the directory for Portainer exists ansible.builtin.file: - path: /home/{{ ansible_user_id }}/docker/portainer + path: /home/{{ ansible_facts['user_id'] }}/docker/portainer state: directory mode: "0750" @@ -210,10 +263,10 @@ append_newline: true prepend_newline: true create: true - path: /home/{{ ansible_user_id }}/docker/portainer/docker-compose.yml + path: /home/{{ ansible_facts['user_id'] }}/docker/portainer/docker-compose.yml mode: "0640" - owner: "{{ ansible_user_uid }}" - group: "{{ ansible_user_gid }}" + owner: "{{ ansible_facts['user_uid'] }}" + group: "{{ ansible_facts['user_gid'] }}" content: | volumes: data: @@ -245,9 +298,9 @@ - "9443:9443" - name: Update Portainer EE - when: not ubtu22_portainer_host + when: not portainer_host ansible.builtin.blockinfile: - path: /home/{{ ansible_user_id }}/docker/portainer/docker-compose.yml + path: /home/{{ ansible_facts['user_id'] }}/docker/portainer/docker-compose.yml marker: "" prepend_newline: true insertafter: "portainer:" @@ -256,9 +309,9 @@ - host - name: Update Portainer Agent - when: not ubtu22_portainer_agent + when: not portainer_agent ansible.builtin.blockinfile: - path: /home/{{ ansible_user_id }}/docker/portainer/docker-compose.yml + path: /home/{{ ansible_facts['user_id'] }}/docker/portainer/docker-compose.yml marker: "" prepend_newline: true insertafter: "agent:" @@ -270,7 +323,7 @@ when: not in_pipeline block: - name: Run the Docker service - when: ubtu22_docker_type == "rootless" + when: docker_type == "rootless" ansible.builtin.systemd: name: docker enabled: true @@ -278,7 +331,7 @@ scope: user - name: Run the Docker service - when: ubtu22_docker_type == "rootfull" and not in_pipeline + when: docker_type == "rootfull" and not in_pipeline ansible.builtin.systemd: name: docker enabled: true @@ -304,8 +357,8 @@ gateway: 192.168.224.129 - name: Start Docker Portainer - when: ubtu22_docker_type == "rootless" and (ubtu22_portainer_agent or ubtu22_portainer_host) and not in_pipeline + when: docker_type == "rootless" and (portainer_agent or portainer_host) and not in_pipeline community.docker.docker_compose_v2: docker_host: unix://{{ docker_host }} - project_src: /home/{{ ansible_user_id }}/docker/portainer + project_src: /home/{{ ansible_facts['user_id'] }}/docker/portainer state: present diff --git a/tasks/main.yml b/tasks/main.yml index 2d7edca..69a1a89 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -13,32 +13,26 @@ ansible.builtin.debug: msg: "Running in pipeline: {{ in_pipeline }}" -- name: Disk Configuration - when: ubtu22_run_task_disk - ansible.builtin.import_tasks: packages/main.yml - tags: - - packages +- name: Include Debian 12 tasks + ansible.builtin.include_tasks: debian12.yml + when: + - ansible_facts['distribution'] == "Debian" + - ansible_facts['distribution_version'] is version("12", "==") -- name: Packages - when: ubtu22_run_task_packages - ansible.builtin.import_tasks: packages/main.yml - tags: - - packages +- name: Include Debian 13 tasks + ansible.builtin.include_tasks: debian13.yml + when: + - ansible_facts['distribution'] == "Debian" + - ansible_facts['distribution_version'] is version("13.3", "==") -- name: Docker - when: ubtu22_run_task_docker - ansible.builtin.import_tasks: docker/main.yml - tags: - - docker +- name: Include Ubuntu 22.04 tasks + ansible.builtin.include_tasks: ubuntu2204.yml + when: + - ansible_facts['distribution'] == "Ubuntu" + - ansible_facts['distribution_version'] is version("22.04", "==") -- name: Configuration - when: ubtu22_run_task_configuration - ansible.builtin.import_tasks: configuration/main.yml - tags: - - configure - -- name: Security - when: ubtu22_run_task_security - ansible.builtin.import_tasks: security/main.yml - tags: - - security +- name: Include Ubuntu 24.04 tasks + ansible.builtin.include_tasks: ubuntu2404.yml + when: + - ansible_facts['distribution'] == "Ubuntu" + - ansible_facts['distribution_version'] is version("24.04", "==") diff --git a/tasks/packages/main.yml b/tasks/packages/main.yml index 4330ab4..5968d77 100644 --- a/tasks/packages/main.yml +++ b/tasks/packages/main.yml @@ -1,9 +1,26 @@ --- +- name: Set Microsoft repo variables (Debian / Ubuntu only) + ansible.builtin.set_fact: + ms_base: "https://packages.microsoft.com/config" + ms_deb: "packages-microsoft-prod.deb" + ms_repo_path: >- + {% if ansible_facts.distribution == "Debian" %} + debian/{{ ansible_facts['distribution_major_version'] }} + {% elif ansible_facts.distribution == "Ubuntu" %} + ubuntu/{{ ansible_facts['distribution_major_version'] }} + {% else %} + unsupported + {% endif %} +- name: Download the Microsoft repository package + ansible.builtin.get_url: + url: "{{ ms_base }}/{{ ms_repo_path }}" + dest: "/tmp/{{ ms_deb }}" + mode: "0644" - name: Download the Microsoft repository key file ansible.builtin.get_url: - url: "https://packages.microsoft.com/config/ubuntu/{{ ansible_lsb.release }}/packages-microsoft-prod.deb" - dest: "/tmp/packages-microsoft-prod.deb" + url: "{{ ms_base }}/{{ ms_repo_path }}/{{ ms_deb }}" + dest: "/tmp/{{ ms_deb }}" mode: "0644" - name: Task name @@ -34,7 +51,7 @@ register: webmin_repo_download ignore_errors: true when: - - ubtu22_pkg_webmin + - pkg_webmin ansible.builtin.get_url: url: https://raw.githubusercontent.com/webmin/webmin/master/setup-repos.sh dest: /tmp/setup-repos.sh @@ -42,7 +59,7 @@ - name: Configure Webmin Repo when: - - ubtu22_pkg_webmin + - pkg_webmin - webmin_repo_download.state == "file" become: true args: @@ -74,17 +91,15 @@ - apt-transport-https - ca-certificates - libssl-dev - - software-properties-common - openssh-server - uidmap - dbus-user-session - unattended-upgrades - pkg-config - - powershell state: present - name: Install PWSH - when: msprod.stat.exists + when: msprod.stat.exists and ansible_facts['architecture'] == "amd64" become: true ansible.builtin.apt: name: @@ -93,7 +108,7 @@ - name: Install Webmin when: - - ubtu22_pkg_webmin + - pkg_webmin become: true ansible.builtin.apt: name: @@ -102,7 +117,7 @@ - name: Install hardware packages when: - - not ubtu22_vm + - not vm become: true ansible.builtin.apt: name: @@ -112,7 +127,7 @@ - name: Install SNMP when: - - ubtu22_pkg_snmp + - pkg_snmp become: true ansible.builtin.apt: name: diff --git a/tasks/security/main.yml b/tasks/security/main.yml index 97643b5..1c80c80 100644 --- a/tasks/security/main.yml +++ b/tasks/security/main.yml @@ -51,4 +51,167 @@ ubtu22cis_nfs_server: false ubtu22cis_nfs_client: false ubtu22cis_remote_log_server: "127.0.0.1" - ubtu22cis_sshd_allow_users: "{{ ansible_user_id }}" + ubtu22cis_sshd_allow_users: "{{ ansible_facts['user_id'] }}" + +- name: Apply CIS-remediation for Ubuntu 24.04 + when: ubtu24_runcis + ansible.builtin.include_role: + name: ansible-lockdown.ubuntu24-cis + apply: + vars: + ansible_become: true + ansible_become_user: "root" + ansible_become_method: "sudo" + ### Auditing + setup_audit: true + run_audit: true + audit_only: false + ubtu24cis_level_2: false + + # Do not use boot password + ubtu24cis_ask_passwd_to_boot: false + # ubtu24cis_rule_1_4_3: false + # Do not patch UFW to do default deny + # ubtu24cis_rule_3_5_1_7: false + # Takes alot of time: Ensure no unowned files or directories exist | Set unowned files/directories to configured owner + # ubtu24cis_rule_6_1_10: false + # Takes alot of time: Ensure no ungrouped files or directories exist | Get ungrouped files or directories + # ubtu24cis_rule_6_1_11: false + # Takes alot of time: Audit SUID executables | Find SUID executables + # ubtu24cis_rule_6_1_12: false + # Takes alot of time: Audit SGID executables | Find SGID executables + # ubtu24cis_rule_6_1_13: false + + ### + ### CIS Level 2 + ### + # keep squashfs + # ubtu24cis_rule_1_1_1_2: false + # Disable AppArmor enforcement + # ubtu24cis_rule_1_6_1_4: false + ubtu24cis_apparmor_disable: true + ubtu24cis_apparmor_mode: "complain" + # enable audit logs auto delete" + # ubtu24cis_rule_4_1_2_2: false + # disable system disabling when audit logs are full" + # ubtu24cis_rule_4_1_2_3: false + # breaks sudo during remediation: Ensure users must provide password for escalation + # ubtu24cis_rule_5_3_4: false + + ### + ### Generic + ### + ubtu24cis_snmp_server: true + ubtu24cis_nfs_server: false + ubtu24cis_nfs_client: false + ubtu24cis_remote_log_server: "127.0.0.1" + ubtu24cis_sshd_allow_users: "{{ ansible_facts['user_id'] }}" + +- name: Apply CIS-remediation for Debian 12 + when: deb12_runcis + ansible.builtin.include_role: + name: ansible-lockdown.deb12-cis + apply: + vars: + ansible_become: true + ansible_become_user: "root" + ansible_become_method: "sudo" + ### Auditing + setup_audit: true + run_audit: true + audit_only: false + deb12cis_level_2: false + + # Do not use boot password + deb12cis_ask_passwd_to_boot: false + # deb12cis_rule_1_4_3: false + # Do not patch UFW to do default deny + # deb12cis_rule_3_5_1_7: false + # Takes alot of time: Ensure no unowned files or directories exist | Set unowned files/directories to configured owner + # deb12cis_rule_6_1_10: false + # Takes alot of time: Ensure no ungrouped files or directories exist | Get ungrouped files or directories + # deb12cis_rule_6_1_11: false + # Takes alot of time: Audit SUID executables | Find SUID executables + # deb12cis_rule_6_1_12: false + # Takes alot of time: Audit SGID executables | Find SGID executables + # deb12cis_rule_6_1_13: false + + ### + ### CIS Level 2 + ### + # keep squashfs + # deb12cis_rule_1_1_1_2: false + # Disable AppArmor enforcement + # deb12cis_rule_1_6_1_4: false + deb12cis_apparmor_disable: true + deb12cis_apparmor_mode: "complain" + # enable audit logs auto delete" + # deb12cis_rule_4_1_2_2: false + # disable system disabling when audit logs are full" + # deb12cis_rule_4_1_2_3: false + # breaks sudo during remediation: Ensure users must provide password for escalation + # deb12cis_rule_5_3_4: false + + ### + ### Generic + ### + deb12cis_snmp_server: true + deb12cis_nfs_server: false + deb12cis_nfs_client: false + deb12cis_remote_log_server: "127.0.0.1" + deb12cis_sshd_allow_users: "{{ ansible_facts['user_id'] }}" + + +- name: Apply CIS-remediation for Debian 13 + when: deb13_runcis + ansible.builtin.include_role: + name: ansible-lockdown.deb13-cis + apply: + vars: + ansible_become: true + ansible_become_user: "root" + ansible_become_method: "sudo" + ### Auditing + setup_audit: true + run_audit: true + audit_only: false + deb13cis_level_2: false + + # Do not use boot password + deb13cis_ask_passwd_to_boot: false + # deb13cis_rule_1_4_3: false + # Do not patch UFW to do default deny + # deb13cis_rule_3_5_1_7: false + # Takes alot of time: Ensure no unowned files or directories exist | Set unowned files/directories to configured owner + # deb13cis_rule_6_1_10: false + # Takes alot of time: Ensure no ungrouped files or directories exist | Get ungrouped files or directories + # deb13cis_rule_6_1_11: false + # Takes alot of time: Audit SUID executables | Find SUID executables + # deb13cis_rule_6_1_12: false + # Takes alot of time: Audit SGID executables | Find SGID executables + # deb13cis_rule_6_1_13: false + + ### + ### CIS Level 2 + ### + # keep squashfs + # deb13cis_rule_1_1_1_2: false + # Disable AppArmor enforcement + # deb13cis_rule_1_6_1_4: false + deb13cis_apparmor_disable: true + deb13cis_apparmor_mode: "complain" + # enable audit logs auto delete" + # deb13cis_rule_4_1_2_2: false + # disable system disabling when audit logs are full" + # deb13cis_rule_4_1_2_3: false + # breaks sudo during remediation: Ensure users must provide password for escalation + # deb13cis_rule_5_3_4: false + + ### + ### Generic + ### + deb13cis_snmp_server: true + deb13cis_nfs_server: false + deb13cis_nfs_client: false + deb13cis_remote_log_server: "127.0.0.1" + deb13cis_sshd_allow_users: "{{ ansible_facts['user_id'] }}" diff --git a/tasks/ubuntu2204.yml b/tasks/ubuntu2204.yml new file mode 100644 index 0000000..6b7edab --- /dev/null +++ b/tasks/ubuntu2204.yml @@ -0,0 +1,34 @@ +--- +- name: Ubuntu 22.04 specific task + ansible.builtin.debug: + msg: "Running tasks for Ubuntu 22.04" + +- name: Disk Configuration + when: ubtu22_run_task_disk + ansible.builtin.import_tasks: packages/main.yml + tags: + - packages + +- name: Packages + when: ubtu22_run_task_packages + ansible.builtin.import_tasks: packages/main.yml + tags: + - packages + +- name: Docker + when: ubtu22_run_task_docker + ansible.builtin.import_tasks: docker/main.yml + tags: + - docker + +- name: Configuration + when: ubtu22_run_task_configuration + ansible.builtin.import_tasks: configuration/main.yml + tags: + - configure + +- name: Security + when: ubtu22_run_task_security + ansible.builtin.import_tasks: security/main.yml + tags: + - security diff --git a/tasks/ubuntu2404.yml b/tasks/ubuntu2404.yml new file mode 100644 index 0000000..42161a0 --- /dev/null +++ b/tasks/ubuntu2404.yml @@ -0,0 +1,34 @@ +--- +- name: Ubuntu 24.04 specific task + ansible.builtin.debug: + msg: "Running tasks for Ubuntu 24.04" + +- name: Disk Configuration + when: ubtu24_run_task_disk + ansible.builtin.import_tasks: packages/main.yml + tags: + - packages + +- name: Packages + when: ubtu24_run_task_packages + ansible.builtin.import_tasks: packages/main.yml + tags: + - packages + +- name: Docker + when: ubtu24_run_task_docker + ansible.builtin.import_tasks: docker/main.yml + tags: + - docker + +- name: Configuration + when: ubtu24_run_task_configuration + ansible.builtin.import_tasks: configuration/main.yml + tags: + - configure + +- name: Security + when: ubtu24_run_task_security + ansible.builtin.import_tasks: security/main.yml + tags: + - security