Compare commits
9 Commits
378d9a88c2
...
d0b26a57ef
| Author | SHA1 | Date | |
|---|---|---|---|
| d0b26a57ef | |||
| f73982d502 | |||
| d92b89b001 | |||
| 3362aad149 | |||
| 2e59d7d27c | |||
| d0bcbb95d8 | |||
| 0181f9104a | |||
| 4de84a7312 | |||
| 04d5e99e56 |
2
.ansible-lint
Normal file
2
.ansible-lint
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
skip_list:
|
||||||
|
- run-once
|
||||||
163
README.md
163
README.md
@@ -1,6 +1,6 @@
|
|||||||
# Ansible-Bootstrap
|
# Ansible-Bootstrap
|
||||||
|
|
||||||
An Ansible playbook for automating system bootstrap processes in an Infrastructure-as-Code manner, utilizing ArchISO as the foundational tool.
|
An Ansible playbook for automating system bootstrap processes in an Infrastructure-as-Code manner.
|
||||||
|
|
||||||
# Info
|
# Info
|
||||||
|
|
||||||
@@ -8,13 +8,15 @@ Most of the roles are adaptable for use with systems beyond ArchLinux, requiring
|
|||||||
|
|
||||||
**NOTE**:
|
**NOTE**:
|
||||||
|
|
||||||
- For RHEL 8 and RHEL 9, repository access requires the `rhel_iso` variable. This variable specifies a local ISO or proxy repository.
|
- For RHEL 8, RHEL 9, and RHEL 10, repository access requires the `rhel_iso` variable. This variable specifies a local ISO or proxy repository.
|
||||||
- RHEL systems do not support `btrfs`. Use `ext4` or `xfs` as alternatives.
|
- RHEL systems do not support `btrfs`. Use `ext4` or `xfs` as alternatives.
|
||||||
- For RHEL 8, `xfs` may cause installation issues; `ext4` is recommended.
|
- For RHEL 8, `xfs` may cause installation issues; `ext4` is recommended.
|
||||||
|
- `custom_iso: true` skips ArchISO validation and pacman setup, your installer ISO must provide the tools required by the selected roles.
|
||||||
|
|
||||||
# Supported Distributions
|
# Supported Distributions
|
||||||
|
|
||||||
This playbook supports multiple Linux distributions with specific versions tailored to each. Below is a list of supported distributions:
|
This playbook supports multiple Linux distributions with specific versions tailored to each.
|
||||||
|
Below is a list of supported distributions:
|
||||||
|
|
||||||
| `os` | Distribution |
|
| `os` | Distribution |
|
||||||
| ---------- | ---------------------------------- |
|
| ---------- | ---------------------------------- |
|
||||||
@@ -51,22 +53,70 @@ The playbook uses the ArchLinux ISO as a foundational tool to provides an effici
|
|||||||
|
|
||||||
Global variables apply across your Ansible project and are loaded from `vars.yml` by default. These variables define common settings such as hypervisor connection details and the boot ISO path. They can be overridden by inventory variables for specific hosts or VMs if needed.
|
Global variables apply across your Ansible project and are loaded from `vars.yml` by default. These variables define common settings such as hypervisor connection details and the boot ISO path. They can be overridden by inventory variables for specific hosts or VMs if needed.
|
||||||
|
|
||||||
|
### 2.1 Core Provisioning
|
||||||
|
|
||||||
| Variable | Description | Example Value |
|
| Variable | Description | Example Value |
|
||||||
| ----------------------- | ---------------------------------------------------------- | ----------------------------------------- |
|
| ----------------------- | ---------------------------------------------------------- | ----------------------------------------- |
|
||||||
| `boot_iso` | Path to the boot ISO image. | `local-btrfs:iso/archlinux-x86_64.iso` |
|
|
||||||
| `rhel_iso` | Path to the RHEL ISO file, required for RHEL 8 and RHEL 9. | `local-btrfs:iso/rhel-9.4-x86_64-dvd.iso` |
|
|
||||||
| `hypervisor` | Type of hypervisor. | `libvirt`, `proxmox`, `vmware`, `none` |
|
|
||||||
| `vmware_ssh` | If Ansible should use SSH after base VM setup on VMware. | `true`, `false (default)` |
|
|
||||||
| `hypervisor_datacenter` | Name of the hypervisor datacenter. | `default-datacenter` |
|
|
||||||
| `hypervisor_cluster` | Name of the hypervisor cluster. | `default-cluster` |
|
|
||||||
| `hypervisor_node` | Hypervisor node name. | `node01` |
|
|
||||||
| `hypervisor_password` | Password for hypervisor authentication. | `123456` |
|
|
||||||
| `hypervisor_storage` | Storage identifier for VM disks. | `local-btrfs` |
|
|
||||||
| `hypervisor_url` | URL/IP address for the hypervisor interface. | `192.168.0.2` |
|
|
||||||
| `hypervisor_username` | Username for hypervisor authentication. | `root@pam` |
|
|
||||||
| `install_drive` | Drive where the system will be installed. | `/dev/sda` |
|
|
||||||
| `install_type` | Type of installation. | `virtual`, `physical` |
|
| `install_type` | Type of installation. | `virtual`, `physical` |
|
||||||
| `vlan_name` (optional) | VLAN for the VM's network interface. | `vlan100` |
|
| `hypervisor` | Type of hypervisor. | `libvirt`, `proxmox`, `vmware`, `none` |
|
||||||
|
| `install_drive` | Drive where the system will be installed. | `/dev/sda` |
|
||||||
|
| `boot_iso` | Path to the boot ISO image. | `local-btrfs:iso/archlinux-x86_64.iso` |
|
||||||
|
| `rhel_iso` | Path to the RHEL ISO file, required for RHEL 8/9/10. | `local-btrfs:iso/rhel-9.4-x86_64-dvd.iso` |
|
||||||
|
| `custom_iso` (optional) | Skip ArchISO checks and pacman setup on installer media. | `true`, `false (default)` |
|
||||||
|
| `cis` (optional) | Adjusts the installation to be CIS level 3 conformant. | `true`, `false` |
|
||||||
|
| `selinux` (optional) | Toggle SELinux where supported. | `true`, `false` |
|
||||||
|
|
||||||
|
### 2.2 Hypervisor Access (virtual installs)
|
||||||
|
|
||||||
|
| Variable | Description | Example Value |
|
||||||
|
| ----------------------- | ---------------------------------------------------------- | -------------------- |
|
||||||
|
| `hypervisor_url` | URL/IP address for the hypervisor interface. | `192.168.0.2` |
|
||||||
|
| `hypervisor_username` | Username for hypervisor authentication. | `root@pam` |
|
||||||
|
| `hypervisor_password` | Password for hypervisor authentication. | `123456` |
|
||||||
|
| `hypervisor_datacenter` | Name of the hypervisor datacenter. | `default-datacenter` |
|
||||||
|
| `hypervisor_cluster` | Name of the hypervisor cluster. | `default-cluster` |
|
||||||
|
| `hypervisor_node` | Hypervisor node name. | `node01` |
|
||||||
|
| `hypervisor_storage` | Storage identifier for VM disks. | `local-btrfs` |
|
||||||
|
| `vm_path` (optional) | Libvirt image dir or VMware folder path. | `/var/lib/libvirt/images` |
|
||||||
|
| `vmware_ssh` | If Ansible should use SSH after base VMware setup. | `true`, `false` |
|
||||||
|
| `vlan_name` (optional) | VLAN for the VM's network interface. | `vlan100` |
|
||||||
|
| `note` (optional) | VMware VM annotation. | `Provisioned by Ansible` |
|
||||||
|
|
||||||
|
### 2.3 VMware Tools connection (VMware installs)
|
||||||
|
|
||||||
|
These are required when `hypervisor: vmware` uses the `vmware_tools` connection.
|
||||||
|
|
||||||
|
| Variable | Description | Example Value |
|
||||||
|
| ------------------------------- | ------------------------------------------ | -------------------------------------- |
|
||||||
|
| `ansible_vmware_tools_user` | Guest OS user for guest operations. | `root` |
|
||||||
|
| `ansible_vmware_tools_password` | Guest OS password for guest operations. | `""` |
|
||||||
|
| `ansible_vmware_guest_path` | VM inventory path (datacenter + folder). | `/dc01/vm/Folder/vm01.example.com` |
|
||||||
|
| `ansible_vmware_host` | vCenter/ESXi hostname. | `vcenter01.example.com` |
|
||||||
|
| `ansible_vmware_user` | vCenter/ESXi username. | `administrator@vsphere.local` |
|
||||||
|
| `ansible_vmware_password` | vCenter/ESXi password. | `********` |
|
||||||
|
| `ansible_vmware_validate_certs` | Validate vCenter/ESXi TLS certs. | `false` |
|
||||||
|
|
||||||
|
### 2.4 Disk Encryption (optional)
|
||||||
|
|
||||||
|
| Variable | Description | Example Value |
|
||||||
|
| -------------------------- | ----------------------------------------------- | ------------------ |
|
||||||
|
| `luks_enabled` | Enable LUKS encryption for the root volume. | `true`, `false` |
|
||||||
|
| `luks_passphrase` | Passphrase used for initial LUKS format/unlock. | `1234` |
|
||||||
|
| `luks_mapper_name` | Decrypted mapper name. | `SYSTEM_DECRYPTED` |
|
||||||
|
| `luks_auto_decrypt` | Enable automatic unlock on boot. | `true`, `false` |
|
||||||
|
| `luks_auto_decrypt_method` | Auto-unlock method. | `tpm2`, `keyfile` |
|
||||||
|
| `luks_tpm2_device` | TPM2 device for enrollment. | `auto` |
|
||||||
|
| `luks_tpm2_pcrs` | TPM2 PCR list (systemd-cryptenroll). | `7` |
|
||||||
|
| `luks_keyfile_size` | Keyfile size in bytes for initramfs. | `64` |
|
||||||
|
| `luks_options` | LUKS options passed to crypttab/kernel. | `discard,tries=3` |
|
||||||
|
| `luks_type` | LUKS format type. | `luks2` |
|
||||||
|
| `luks_cipher` | LUKS cipher. | `aes-xts-plain64` |
|
||||||
|
| `luks_hash` | LUKS hash. | `sha512` |
|
||||||
|
| `luks_iter_time` | LUKS iter time in milliseconds. | `4000` |
|
||||||
|
| `luks_key_size` | LUKS key size in bits. | `512` |
|
||||||
|
| `luks_pbkdf` | LUKS PBKDF algorithm. | `argon2id` |
|
||||||
|
| `luks_use_urandom` | Reserved; module uses cryptsetup defaults. | `true` |
|
||||||
|
| `luks_verify_passphrase` | Reserved; module uses cryptsetup defaults. | `true` |
|
||||||
|
|
||||||
To protect sensitive information, such as passwords, API keys, and other confidential variables (e.g., `hypervisor_password`), **it is recommended to use Ansible Vault**.
|
To protect sensitive information, such as passwords, API keys, and other confidential variables (e.g., `hypervisor_password`), **it is recommended to use Ansible Vault**.
|
||||||
|
|
||||||
@@ -74,30 +124,51 @@ To protect sensitive information, such as passwords, API keys, and other confide
|
|||||||
|
|
||||||
Inventory variables are defined for individual hosts or VMs in the inventory file, allowing customization of settings such as the operating system, filesystem, and compliance with CIS benchmarks. These variables can be set globally and overridden for specific hosts or VMs.
|
Inventory variables are defined for individual hosts or VMs in the inventory file, allowing customization of settings such as the operating system, filesystem, and compliance with CIS benchmarks. These variables can be set globally and overridden for specific hosts or VMs.
|
||||||
|
|
||||||
| Variable | Description | Example Value |
|
### 3.1 System Identity and OS
|
||||||
| --------------------- | -------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
|
|
||||||
| `cis` (optional) | Adjusts the installation to be CIS level 3 conformant. | `true`, `false` |
|
| Variable | Description | Example Value |
|
||||||
| `selinux` (optional) | Toggle SELinux, `false` means it should be disabled.` | `true`, `false` |
|
| ------------ | -------------------------------------- | ---------------------- |
|
||||||
| `filesystem` | Filesystem type for the VM's primary storage. | `btrfs`, `ext4`, `xfs` |
|
| `os` | Operating system to be installed. | `ubuntu-lts` |
|
||||||
| `hostname` | The hostname assigned to the virtual machine or system. | `vm01` |
|
| `filesystem` | Filesystem type for the root volume. | `btrfs`, `ext4`, `xfs` |
|
||||||
| `os` | Operating system to be installed on the VM. | `archlinux`, `almalinux`, `debian11`, `debian12`, `fedora`, `rhel8`, `rhel9`, `rhel10`, `rocky`, `ubuntu`, `ubuntu-lts` |
|
| `hostname` | The hostname assigned to the system. | `vm01` |
|
||||||
| `root_password` | Root password for the VM or system, used for initial setup or secure access. | `SecurePass123` |
|
|
||||||
| `user_name` | Username for a user account within the VM, often used with cloud-init. | `adminuser` |
|
### 3.2 Credentials and Access
|
||||||
| `user_password` | Password for the user account within the VM. | `UserPass123` |
|
|
||||||
| `user_public_key` | SSH Key for the user account within the VM. | `ssh-ed25519 AAAAC` |
|
These are prompted by default via `vars_prompt` in `main.yml`, but can be supplied via inventory/vars/`-e` for non-interactive runs.
|
||||||
| `vm_ballo` (optional) | Ballooning memory size for the VM, used to adjust memory allocation dynamically. | `2048` |
|
|
||||||
| `vm_cpus` | Number of CPU cores assigned to the virtual machine. | `4` |
|
| Variable | Description | Example Value |
|
||||||
| `vm_dns` | DNS server IP address(es) for the virtual machine's network configuration. | `1.0.0.1`, `1.1.1.1` |
|
| ----------------- | ---------------------------------- | ----------------- |
|
||||||
| `vm_dns_search` | DNS search zone for the virtual machine's network configuration. | `example.com` |
|
| `root_password` | Root password (vault recommended). | `SecurePass123` |
|
||||||
| `vm_gw` | Default gateway IP address for the virtual machine's network configuration. | `192.168.0.1` |
|
| `user_name` | Username for a user account. | `adminuser` |
|
||||||
| `vm_id` | Unique identifier for the virtual machine. | `101` |
|
| `user_password` | Password for the user account. | `UserPass123` |
|
||||||
| `vm_ip` | IP address assigned to the virtual machine. | `192.168.0.10` |
|
| `user_public_key` | SSH Key for the user account. | `ssh-ed25519 AAAA` |
|
||||||
| `vm_nm` (optional) | IP address netmask assigned to the virtual machine. | `255.255.255.0` |
|
|
||||||
| `vm_nms` (optional) | IP address netmask assigned to the virtual machine. | `24` |
|
### 3.3 Networking
|
||||||
| `vm_memory` | Amount of memory (in MB) allocated to the virtual machine. | `2048` |
|
|
||||||
| `vm_nif` | Network interface type or identifier for the VM's network connection. | `vmbr0` |
|
| Variable | Description | Example Value |
|
||||||
| `vm_path (optional)` | Path or folder where the VM configuration or related files will be stored. | `/var/lib/libvirt/images/` |
|
| --------------- | -------------------------------------------------------------- | ----------------- |
|
||||||
| `vm_size` | Disk size allocated for the VM's primary storage (in GB). | `20` |
|
| `vm_ip` | IP address assigned to the system (omit to use DHCP). | `192.168.0.10` |
|
||||||
|
| `vm_nms` | Netmask bits for static addressing. | `24` |
|
||||||
|
| `vm_gw` | Default gateway IP address (static only). | `192.168.0.1` |
|
||||||
|
| `vm_dns` | DNS server IP address(es). | `1.0.0.1,1.1.1.1` |
|
||||||
|
| `vm_dns_search` | DNS search zone(s) for the network configuration. | `example.com` |
|
||||||
|
| `vm_nif` | Network interface/bridge for the VM's network connection. | `vmbr0` |
|
||||||
|
|
||||||
|
### 3.4 VM Sizing (virtual installs)
|
||||||
|
|
||||||
|
| Variable | Description | Example Value |
|
||||||
|
| ----------- | --------------------------------- | ------------- |
|
||||||
|
| `vm_id` | Unique identifier for the VM. | `101` |
|
||||||
|
| `vm_size` | Disk size allocated in GB. | `20` |
|
||||||
|
| `vm_memory` | Amount of memory in MB. | `2048` |
|
||||||
|
| `vm_cpus` | Number of CPU cores. | `4` |
|
||||||
|
| `vm_ballo` | Ballooning memory size (optional).| `2048` |
|
||||||
|
|
||||||
|
### 3.5 Post-install Packages
|
||||||
|
|
||||||
|
| Variable | Description | Example Value |
|
||||||
|
| ------------------------ | --------------------------------------------------------------------- | ------------------ |
|
||||||
|
| `extra_packages` (optional) | Additional packages installed after the first boot into the installed OS. | `["git", "jq"]` |
|
||||||
|
|
||||||
## 4. How to Use the Playbook
|
## 4. How to Use the Playbook
|
||||||
|
|
||||||
@@ -118,3 +189,15 @@ ansible-playbook -i inventory.yml -e @vars.yml main.yml
|
|||||||
```
|
```
|
||||||
|
|
||||||
This command prompts Ansible to execute the `main.yml` playbook, applying configurations defined in both `vars.yml` and the inventory file.
|
This command prompts Ansible to execute the `main.yml` playbook, applying configurations defined in both `vars.yml` and the inventory file.
|
||||||
|
|
||||||
|
Use `inventory_example.yml`, `vars_example.yml`, and the bare-metal examples as starting points for new inventories.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- `vm_size`/`vm_memory` are required for virtual installs only, physical installs use the full disk.
|
||||||
|
- `vm_dns` and `vm_dns_search` accept comma-separated strings or YAML lists.
|
||||||
|
- `hypervisor` determines which backend-specific roles run.
|
||||||
|
- Guest tools are installed based on `hypervisor`: `qemu-guest-agent` for `libvirt`/`proxmox`, `open-vm-tools` for `vmware`, otherwise none.
|
||||||
|
- With `luks_auto_decrypt_method: tpm2` on virtual installs, the virtualization role enables a TPM2 device (libvirt/proxmox/vmware).
|
||||||
|
- For VMware, `vmware_ssh: true` enables SSH on the guest and switches the connection to SSH for the remaining tasks.
|
||||||
|
- For physical installs, set `ansible_user`/`ansible_password` for the installer environment when it differs from the prompted user credentials.
|
||||||
|
|||||||
9
collections/requirements.yml
Normal file
9
collections/requirements.yml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
collections:
|
||||||
|
- name: ansible.posix
|
||||||
|
- name: community.general
|
||||||
|
- name: community.libvirt
|
||||||
|
- name: community.crypto
|
||||||
|
- name: community.proxmox
|
||||||
|
- name: community.vmware
|
||||||
|
- name: vmware.vmware
|
||||||
9
inventory_baremetal_example.yml
Normal file
9
inventory_baremetal_example.yml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
all:
|
||||||
|
hosts:
|
||||||
|
baremetal01.example.com:
|
||||||
|
ansible_host: 10.0.0.162
|
||||||
|
ansible_user: root
|
||||||
|
ansible_password: "1234"
|
||||||
|
ansible_become_password: "1234"
|
||||||
|
hostname: "baremetal01.example.com"
|
||||||
@@ -1,35 +1,40 @@
|
|||||||
|
---
|
||||||
all:
|
all:
|
||||||
vars:
|
vars:
|
||||||
hypervisor: 'proxmox'
|
hypervisor: "proxmox"
|
||||||
install_drive: '/dev/sda'
|
install_type: "virtual"
|
||||||
cis: true
|
install_drive: "/dev/sda"
|
||||||
boot_iso: "local-btrfs:iso/archlinux-x86_64.iso"
|
boot_iso: "local:iso/archlinux-x86_64.iso"
|
||||||
|
vm_nif: "vmbr0"
|
||||||
|
vm_gw: "10.0.0.1"
|
||||||
|
vm_dns:
|
||||||
|
- 1.1.1.1
|
||||||
|
- 1.0.0.1
|
||||||
|
vm_dns_search:
|
||||||
|
- example.com
|
||||||
children:
|
children:
|
||||||
promox-kvm:
|
proxmox:
|
||||||
hosts:
|
hosts:
|
||||||
192.168.122.10:
|
proxy01.example.com:
|
||||||
hostname: proxy
|
ansible_host: 10.0.0.10
|
||||||
vm_id: 100
|
hostname: "proxy01.example.com"
|
||||||
os: archlinux
|
vm_id: 100
|
||||||
filesystem: btrfs
|
os: "archlinux"
|
||||||
vm_memory: "2048"
|
filesystem: "btrfs"
|
||||||
vm_ballo: "1024"
|
vm_memory: 4096
|
||||||
vm_cpus: "2"
|
vm_ballo: 2048
|
||||||
vm_size: "5"
|
vm_cpus: 2
|
||||||
vm_nif: vmbr1
|
vm_size: 40
|
||||||
vm_gw: 192.168.122.1
|
vm_ip: 10.0.0.10
|
||||||
vm_dns: 1.1.1.1
|
database01.example.com:
|
||||||
vm_dns_search: "example.com"
|
ansible_host: 10.0.0.11
|
||||||
192.168.122.11:
|
hostname: "database01.example.com"
|
||||||
hostname: database
|
vm_id: 101
|
||||||
vm_id: 101
|
os: "rhel9"
|
||||||
os: rhel9
|
filesystem: "xfs"
|
||||||
filesystem: xfs
|
vm_memory: 4096
|
||||||
vm_memory: "6144"
|
vm_ballo: 2048
|
||||||
vm_ballo: "3072"
|
vm_cpus: 4
|
||||||
vm_cpus: "4"
|
vm_size: 60
|
||||||
vm_size: "40"
|
vm_ip: 10.0.0.11
|
||||||
vm_nif: vmbr1
|
rhel_iso: "local:iso/rhel-9.4-x86_64-dvd.iso"
|
||||||
vm_gw: 192.168.122.1
|
|
||||||
vm_dns: 1.1.1.1
|
|
||||||
rhel_iso: "local-btrfs:iso/rhel-9.4-x86_64-dvd.iso"
|
|
||||||
|
|||||||
133
main.yml
133
main.yml
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
- name: Create and configure VMs
|
- name: Create and configure VMs
|
||||||
hosts: all
|
hosts: all
|
||||||
strategy: free
|
strategy: free # noqa: run-once[play]
|
||||||
gather_facts: false
|
gather_facts: false
|
||||||
become: true
|
become: true
|
||||||
vars_prompt:
|
vars_prompt:
|
||||||
@@ -26,36 +26,65 @@
|
|||||||
confirm: true
|
confirm: true
|
||||||
vars_files: vars.yml
|
vars_files: vars.yml
|
||||||
pre_tasks:
|
pre_tasks:
|
||||||
- name: Set ansible_python_interpreter
|
- name: Validate variables
|
||||||
when: os | lower in ["almalinux", "rhel8", "rhel9", "rhel10", "rocky"]
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- install_type in ["virtual", "physical"]
|
||||||
|
- hypervisor in ["libvirt", "proxmox", "vmware", "none"]
|
||||||
|
- filesystem in ["btrfs", "ext4", "xfs"]
|
||||||
|
- install_drive is defined
|
||||||
|
- install_type == "physical" or vm_size is defined
|
||||||
|
- install_type == "physical" or vm_memory is defined
|
||||||
|
- os in ["archlinux", "almalinux", "debian11", "debian12", "debian13", "fedora", "rhel8", "rhel9", "rhel10", "rocky", "ubuntu", "ubuntu-lts"]
|
||||||
|
- os not in ["rhel8", "rhel9", "rhel10"] or rhel_iso is defined
|
||||||
|
- >-
|
||||||
|
install_type == "physical"
|
||||||
|
or (
|
||||||
|
(filesystem == "btrfs" and (vm_size | default(0) | int) >= 10)
|
||||||
|
or (filesystem != "btrfs" and (vm_size | default(0) | int) >= 20)
|
||||||
|
)
|
||||||
|
- >-
|
||||||
|
install_type == "physical"
|
||||||
|
or (
|
||||||
|
(vm_size | default(0) | float)
|
||||||
|
>= (
|
||||||
|
(vm_memory | default(0) | float / 1024 >= 16.0)
|
||||||
|
| ternary(
|
||||||
|
(vm_memory | default(0) | float / 2048),
|
||||||
|
[vm_memory | default(0) | float / 1024, 4.0] | max
|
||||||
|
)
|
||||||
|
+ 16
|
||||||
|
)
|
||||||
|
)
|
||||||
|
fail_msg: Invalid input specified, please try again.
|
||||||
|
|
||||||
|
- name: Normalize optional flags
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
cis: "{{ cis | default(false) | bool }}"
|
||||||
|
custom_iso: "{{ custom_iso | default(false) | bool }}"
|
||||||
|
is_rhel: "{{ os | default('') | lower in ['almalinux', 'fedora', 'rhel8', 'rhel9', 'rhel10', 'rocky'] }}"
|
||||||
|
is_debian: "{{ os | default('') | lower in ['debian11', 'debian12', 'debian13', 'ubuntu', 'ubuntu-lts'] }}"
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Set Python interpreter for RHEL-based installers
|
||||||
|
when:
|
||||||
|
- ansible_python_interpreter is not defined
|
||||||
|
- os | lower in ["almalinux", "rhel8", "rhel9", "rhel10", "rocky"]
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
ansible_python_interpreter: /usr/bin/python3
|
ansible_python_interpreter: /usr/bin/python3
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
- name: Set default variables
|
- name: Set SSH access
|
||||||
ansible.builtin.set_fact:
|
when:
|
||||||
cis: false
|
- install_type == "virtual"
|
||||||
|
- hypervisor != "vmware"
|
||||||
- name: Set SSH Access
|
|
||||||
when: hypervisor != "vmware"
|
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
ansible_user: "{{ user_name }}"
|
ansible_user: "{{ user_name }}"
|
||||||
ansible_password: "{{ user_password }}"
|
ansible_password: "{{ user_password }}"
|
||||||
ansible_become_password: "{{ user_password }}"
|
ansible_become_password: "{{ user_password }}"
|
||||||
ansible_ssh_extra_args: "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
ansible_ssh_extra_args: "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
||||||
|
|
||||||
- name: Validate variables
|
- name: Set connection for VMware
|
||||||
ansible.builtin.assert:
|
|
||||||
that:
|
|
||||||
- hypervisor in ["libvirt", "proxmox", "vmware", "none"]
|
|
||||||
- filesystem in ["btrfs", "ext4", "xfs"]
|
|
||||||
- install_drive is defined
|
|
||||||
- os in ["archlinux", "almalinux", "debian11", "debian12", "debian13", "fedora", "rhel8", "rhel9", "rhel10", "rocky", "ubuntu", "ubuntu-lts"]
|
|
||||||
- os not in ["rhel8", "rhel9", "rhel10"] or rhel_iso is defined
|
|
||||||
- (filesystem == "btrfs" and (vm_size | int) >= 10) or (filesystem != "btrfs" and (vm_size | int) >= 20)
|
|
||||||
- (vm_size | float) >= ((vm_memory | float / 1024 >= 16.0) | ternary((vm_memory | float / 2048), [vm_memory | float / 1024, 4.0] | max) + 16)
|
|
||||||
fail_msg: Invalid input specified, please try again.
|
|
||||||
|
|
||||||
- name: Set connection
|
|
||||||
when: hypervisor == "vmware"
|
when: hypervisor == "vmware"
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
ansible_connection: vmware_tools
|
ansible_connection: vmware_tools
|
||||||
@@ -73,31 +102,65 @@
|
|||||||
|
|
||||||
- role: partitioning
|
- role: partitioning
|
||||||
vars:
|
vars:
|
||||||
boot_partition_suffix: 1
|
partitioning_boot_partition_suffix: 1
|
||||||
main_partition_suffix: 2
|
partitioning_main_partition_suffix: 2
|
||||||
|
|
||||||
- role: bootstrap
|
- role: bootstrap
|
||||||
|
|
||||||
- role: configuration
|
- role: configuration
|
||||||
|
|
||||||
- role: cis
|
- role: cis
|
||||||
when: cis | bool
|
when: cis | default(false) | bool
|
||||||
|
|
||||||
- role: cleanup
|
- role: cleanup
|
||||||
when: install_type == "virtual"
|
when: install_type in ["virtual", "physical"]
|
||||||
vars:
|
become: false
|
||||||
ansible_connection: local
|
|
||||||
|
|
||||||
tasks:
|
post_tasks:
|
||||||
- name: Set final SSH Credentials
|
- name: Set post-reboot connection flags
|
||||||
when: hypervisor != 'vmware' or (hypervisor == 'vmware' and vmware_ssh | bool)
|
ansible.builtin.set_fact:
|
||||||
|
post_reboot_can_connect: >-
|
||||||
|
{{
|
||||||
|
(ansible_connection | default('ssh')) != 'ssh'
|
||||||
|
or ((vm_ip | default('') | string | length) > 0)
|
||||||
|
or (
|
||||||
|
install_type == 'physical'
|
||||||
|
and (ansible_host | default('') | string | length) > 0
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Set final SSH credentials for post-reboot tasks
|
||||||
|
when:
|
||||||
|
- post_reboot_can_connect | default(false) | bool
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
ansible_user: "{{ user_name }}"
|
ansible_user: "{{ user_name }}"
|
||||||
ansible_password: "{{ user_password }}"
|
ansible_password: "{{ user_password }}"
|
||||||
ansible_become_password: "{{ user_password }}"
|
ansible_become_password: "{{ user_password }}"
|
||||||
ansible_ssh_extra_args: "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
ansible_ssh_extra_args: "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
||||||
|
|
||||||
- name: Check if VM is back and running
|
- name: Install post-reboot extra packages
|
||||||
when: not (hypervisor == 'vmware' and cis | bool)
|
when:
|
||||||
ansible.builtin.wait_for_connection:
|
- extra_packages is defined
|
||||||
timeout: 300
|
- post_reboot_can_connect | default(false) | bool
|
||||||
|
block:
|
||||||
|
- name: Normalize extra package list
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
post_install_extra_packages: >-
|
||||||
|
{{
|
||||||
|
(
|
||||||
|
extra_packages
|
||||||
|
if (extra_packages is iterable and extra_packages is not string)
|
||||||
|
else (extra_packages | default('') | string).split(',')
|
||||||
|
)
|
||||||
|
| map('trim')
|
||||||
|
| reject('equalto', '')
|
||||||
|
| list
|
||||||
|
}}
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Install extra packages
|
||||||
|
when: post_install_extra_packages | length > 0
|
||||||
|
ansible.builtin.package:
|
||||||
|
name: "{{ post_install_extra_packages }}"
|
||||||
|
state: present
|
||||||
|
|||||||
25
roles/bootstrap/tasks/almalinux.yml
Normal file
25
roles/bootstrap/tasks/almalinux.yml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
- name: Bootstrap AlmaLinux 9
|
||||||
|
vars:
|
||||||
|
bootstrap_alma_extra: >-
|
||||||
|
{{
|
||||||
|
(
|
||||||
|
(
|
||||||
|
lookup('vars', bootstrap_var_key)
|
||||||
|
| difference(bootstrap_guest_agent_remove_packages)
|
||||||
|
)
|
||||||
|
+ bootstrap_guest_agent_packages
|
||||||
|
)
|
||||||
|
| join(' ')
|
||||||
|
}}
|
||||||
|
ansible.builtin.command: "{{ item }}"
|
||||||
|
loop:
|
||||||
|
- >-
|
||||||
|
dnf --releasever=9 --best --repo=alma-baseos --installroot=/mnt
|
||||||
|
--setopt=install_weak_deps=False groupinstall -y base core
|
||||||
|
- ln -sf /run/NetworkManager/resolv.conf /mnt/etc/resolv.conf
|
||||||
|
- >-
|
||||||
|
arch-chroot /mnt dnf --releasever=9 --setopt=install_weak_deps=False
|
||||||
|
install -y {{ bootstrap_alma_extra }}
|
||||||
|
register: bootstrap_result
|
||||||
|
changed_when: bootstrap_result.rc == 0
|
||||||
15
roles/bootstrap/tasks/archlinux.yml
Normal file
15
roles/bootstrap/tasks/archlinux.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
- name: Bootstrap ArchLinux
|
||||||
|
vars:
|
||||||
|
bootstrap_archlinux_packages: >-
|
||||||
|
{{
|
||||||
|
(
|
||||||
|
lookup('vars', bootstrap_var_key)
|
||||||
|
| difference(bootstrap_guest_agent_remove_packages)
|
||||||
|
)
|
||||||
|
+ bootstrap_guest_agent_packages
|
||||||
|
}}
|
||||||
|
ansible.builtin.command: >-
|
||||||
|
pacstrap /mnt {{ bootstrap_archlinux_packages | join(' ') }} --asexplicit
|
||||||
|
register: bootstrap_result
|
||||||
|
changed_when: bootstrap_result.rc == 0
|
||||||
29
roles/bootstrap/tasks/debian.yml
Normal file
29
roles/bootstrap/tasks/debian.yml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
- name: Bootstrap Debian System
|
||||||
|
vars:
|
||||||
|
bootstrap_debian_release: >-
|
||||||
|
{{
|
||||||
|
'bullseye' if bootstrap_os_key == 'debian11'
|
||||||
|
else 'bookworm' if bootstrap_os_key == 'debian12'
|
||||||
|
else 'trixie'
|
||||||
|
}}
|
||||||
|
bootstrap_debian_base_list: "{{ lookup('vars', bootstrap_var_key).base | default([]) }}"
|
||||||
|
bootstrap_debian_extra_list: "{{ lookup('vars', bootstrap_var_key).extra | default([]) }}"
|
||||||
|
bootstrap_debian_base: "{{ (bootstrap_debian_base_list | difference(bootstrap_guest_agent_remove_packages)) | join(',') }}"
|
||||||
|
bootstrap_debian_extra: >-
|
||||||
|
{{
|
||||||
|
(
|
||||||
|
(bootstrap_debian_extra_list | difference(bootstrap_guest_agent_remove_packages))
|
||||||
|
+ bootstrap_guest_agent_packages
|
||||||
|
)
|
||||||
|
| join(' ')
|
||||||
|
}}
|
||||||
|
ansible.builtin.command: "{{ item }}"
|
||||||
|
loop:
|
||||||
|
- >-
|
||||||
|
debootstrap --include={{ bootstrap_debian_base }}
|
||||||
|
{{ bootstrap_debian_release }} /mnt http://deb.debian.org/debian/
|
||||||
|
- "arch-chroot /mnt apt install -y {{ bootstrap_debian_extra }}"
|
||||||
|
- arch-chroot /mnt apt remove -y libcups2 libavahi-common3 libavahi-common-data
|
||||||
|
register: bootstrap_result
|
||||||
|
changed_when: bootstrap_result.rc == 0
|
||||||
27
roles/bootstrap/tasks/fedora.yml
Normal file
27
roles/bootstrap/tasks/fedora.yml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
- name: Bootstrap Fedora 42
|
||||||
|
vars:
|
||||||
|
bootstrap_fedora_extra: >-
|
||||||
|
{{
|
||||||
|
(
|
||||||
|
(
|
||||||
|
lookup('vars', bootstrap_var_key)
|
||||||
|
| difference(bootstrap_guest_agent_remove_packages)
|
||||||
|
)
|
||||||
|
+ bootstrap_guest_agent_packages
|
||||||
|
)
|
||||||
|
| join(' ')
|
||||||
|
}}
|
||||||
|
ansible.builtin.command: "{{ item }}"
|
||||||
|
loop:
|
||||||
|
- >-
|
||||||
|
dnf --releasever=42 --best --repo=fedora --repo=fedora-updates
|
||||||
|
--installroot=/mnt --setopt=install_weak_deps=False
|
||||||
|
groupinstall -y critical-path-base core
|
||||||
|
- ln -sf /run/NetworkManager/resolv.conf /mnt/etc/resolv.conf
|
||||||
|
- >-
|
||||||
|
arch-chroot /mnt dnf --releasever=42 --setopt=install_weak_deps=False
|
||||||
|
install -y {{ bootstrap_fedora_extra }}
|
||||||
|
- arch-chroot /mnt dnf reinstall -y kernel-core
|
||||||
|
register: bootstrap_result
|
||||||
|
changed_when: bootstrap_result.rc == 0
|
||||||
@@ -1,101 +1,43 @@
|
|||||||
---
|
---
|
||||||
- name: Run OS-specific bootstrap process
|
- name: Run OS-specific bootstrap process
|
||||||
|
vars:
|
||||||
|
bootstrap_os_key: "{{ os | lower }}"
|
||||||
|
bootstrap_var_key: "{{ 'bootstrap_' + (os | lower | replace('-', '_')) }}"
|
||||||
|
bootstrap_hypervisor_key: "{{ hypervisor | default('none') | lower }}"
|
||||||
|
bootstrap_guest_agent_packages: >-
|
||||||
|
{{
|
||||||
|
['qemu-guest-agent'] if bootstrap_hypervisor_key in ['libvirt', 'proxmox']
|
||||||
|
else ['open-vm-tools'] if bootstrap_hypervisor_key == 'vmware'
|
||||||
|
else []
|
||||||
|
}}
|
||||||
|
bootstrap_guest_agent_remove_packages:
|
||||||
|
- open-vm-tools
|
||||||
|
- qemu-guest-agent
|
||||||
block:
|
block:
|
||||||
- name: Bootstrap ArchLinux
|
- name: Include AlmaLinux bootstrap tasks
|
||||||
when: os | lower == 'archlinux'
|
when: bootstrap_os_key == 'almalinux'
|
||||||
ansible.builtin.command: pacstrap /mnt {{ archlinux | join(' ') }} --asexplicit
|
ansible.builtin.include_tasks: almalinux.yml
|
||||||
changed_when: result.rc == 0
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Bootstrap Debian System
|
- name: Include ArchLinux bootstrap tasks
|
||||||
when: os | lower in ['debian11', 'debian12', 'debian13']
|
when: bootstrap_os_key == 'archlinux'
|
||||||
ansible.builtin.command: "{{ item }}"
|
ansible.builtin.include_tasks: archlinux.yml
|
||||||
changed_when: result.rc == 0
|
|
||||||
register: result
|
|
||||||
with_items:
|
|
||||||
- debootstrap --include={{ vars[os].base | join(',') }} {{ 'bullseye' if os == 'debian11' else 'bookworm' if os == 'debian12' else 'trixie' }}
|
|
||||||
/mnt http://deb.debian.org/debian/
|
|
||||||
- arch-chroot /mnt apt install -y {{ vars[os].extra | join(' ') }}
|
|
||||||
- arch-chroot /mnt apt remove -y libcups2 libavahi-common3 libavahi-common-data
|
|
||||||
|
|
||||||
- name: Bootstrap Ubuntu System
|
- name: Include Debian bootstrap tasks
|
||||||
when: os | lower in ['ubuntu', 'ubuntu-lts']
|
when: bootstrap_os_key in ['debian11', 'debian12', 'debian13']
|
||||||
ansible.builtin.command: "{{ item }}"
|
ansible.builtin.include_tasks: debian.yml
|
||||||
changed_when: result.rc == 0
|
|
||||||
register: result
|
|
||||||
with_items:
|
|
||||||
- debootstrap --include={{ vars[os].base | join(',') }} {{ 'plucky' if os == 'ubuntu' else 'noble' }}
|
|
||||||
/mnt http://archive.ubuntu.com/ubuntu/
|
|
||||||
- ln -sf /run/NetworkManager/resolv.conf /mnt/etc/resolv.conf
|
|
||||||
- arch-chroot /mnt sed -i '1s|$| universe|' /etc/apt/sources.list
|
|
||||||
- arch-chroot /mnt apt update -y
|
|
||||||
- arch-chroot /mnt apt install -y {{ vars[os].extra | join(' ') }}
|
|
||||||
|
|
||||||
- name: Bootstrap AlmaLinux 9
|
- name: Include Fedora bootstrap tasks
|
||||||
when: os | lower == 'almalinux'
|
when: bootstrap_os_key == 'fedora'
|
||||||
ansible.builtin.command: "{{ item }}"
|
ansible.builtin.include_tasks: fedora.yml
|
||||||
changed_when: result.rc == 0
|
|
||||||
register: result
|
|
||||||
with_items:
|
|
||||||
- dnf --releasever=9 --best --repo=alma-baseos --installroot=/mnt --setopt=install_weak_deps=False groupinstall -y base core
|
|
||||||
- ln -sf /run/NetworkManager/resolv.conf /mnt/etc/resolv.conf
|
|
||||||
- arch-chroot /mnt dnf --releasever=9 --setopt=install_weak_deps=False install -y {{ almalinux | join(' ') }}
|
|
||||||
|
|
||||||
- name: Bootstrap Fedora 42
|
- name: Include Rocky bootstrap tasks
|
||||||
when: os | lower == 'fedora'
|
when: bootstrap_os_key == 'rocky'
|
||||||
ansible.builtin.command: "{{ item }}"
|
ansible.builtin.include_tasks: rocky.yml
|
||||||
changed_when: result.rc == 0
|
|
||||||
register: result
|
|
||||||
with_items:
|
|
||||||
- dnf --releasever=42 --best --repo=fedora --repo=fedora-updates
|
|
||||||
--installroot=/mnt --setopt=install_weak_deps=False groupinstall -y critical-path-base core
|
|
||||||
- ln -sf /run/NetworkManager/resolv.conf /mnt/etc/resolv.conf
|
|
||||||
- arch-chroot /mnt dnf --releasever=42 --setopt=install_weak_deps=False install -y {{ fedora | join(' ') }}
|
|
||||||
- arch-chroot /mnt dnf reinstall -y kernel-core
|
|
||||||
|
|
||||||
- name: Bootstrap RockyLinux 9
|
- name: Include RHEL bootstrap tasks
|
||||||
when: os | lower == 'rocky'
|
when: bootstrap_os_key in ['rhel8', 'rhel9', 'rhel10']
|
||||||
ansible.builtin.command: "{{ item }}"
|
ansible.builtin.include_tasks: rhel.yml
|
||||||
changed_when: result.rc == 0
|
|
||||||
register: result
|
|
||||||
with_items:
|
|
||||||
- dnf --releasever=9 --best --repo=rocky-baseos --installroot=/mnt
|
|
||||||
--setopt=install_weak_deps=False --setopt=optional_metadata_types=filelists
|
|
||||||
groupinstall -y base core
|
|
||||||
- ln -sf /run/NetworkManager/resolv.conf /mnt/etc/resolv.conf
|
|
||||||
- arch-chroot /mnt dnf --releasever=9 --setopt=install_weak_deps=False install -y {{ rocky | join(' ') }}
|
|
||||||
|
|
||||||
- name: Bootstrap RHEL System
|
- name: Include Ubuntu bootstrap tasks
|
||||||
when: os | lower in ['rhel8', 'rhel9', 'rhel10']
|
when: bootstrap_os_key in ['ubuntu', 'ubuntu-lts']
|
||||||
block:
|
ansible.builtin.include_tasks: ubuntu.yml
|
||||||
- name: Install base packages in chroot environment
|
|
||||||
ansible.builtin.command: >-
|
|
||||||
dnf --releasever={{ os | lower | replace('rhel', '') }} --repo={{ os | lower }}-baseos
|
|
||||||
--installroot=/mnt
|
|
||||||
--setopt=install_weak_deps=False --setopt=optional_metadata_types=filelists
|
|
||||||
groupinstall -y core base standard
|
|
||||||
changed_when: result.rc == 0
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Prepare chroot environment
|
|
||||||
ansible.builtin.shell: |
|
|
||||||
ln -sf /run/NetworkManager/resolv.conf /mnt/etc/resolv.conf
|
|
||||||
mkdir -p /mnt/usr/local/install/redhat/dvd
|
|
||||||
mount --bind /usr/local/install/redhat/dvd /mnt/usr/local/install/redhat/dvd
|
|
||||||
arch-chroot /mnt rpm --rebuilddb
|
|
||||||
changed_when: result.rc == 0
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Copy RHEL repo file into chroot environment
|
|
||||||
ansible.builtin.copy:
|
|
||||||
src: /etc/yum.repos.d/{{ os | lower }}.repo
|
|
||||||
dest: /mnt/etc/yum.repos.d/redhat.repo
|
|
||||||
mode: "0644"
|
|
||||||
remote_src: true
|
|
||||||
|
|
||||||
- name: Install additional packages in chroot
|
|
||||||
ansible.builtin.command: >-
|
|
||||||
arch-chroot /mnt dnf --releasever={{ os | lower | replace('rhel', '') }}
|
|
||||||
--setopt=install_weak_deps=False install -y {{ vars[os] | join(' ') }}
|
|
||||||
changed_when: result.rc == 0
|
|
||||||
register: result
|
|
||||||
|
|||||||
71
roles/bootstrap/tasks/rhel.yml
Normal file
71
roles/bootstrap/tasks/rhel.yml
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
---
|
||||||
|
- name: Bootstrap RHEL System
|
||||||
|
block:
|
||||||
|
- name: Install base packages in chroot environment
|
||||||
|
vars:
|
||||||
|
bootstrap_rhel_release: "{{ bootstrap_os_key | replace('rhel', '') }}"
|
||||||
|
ansible.builtin.command: >-
|
||||||
|
dnf --releasever={{ bootstrap_rhel_release }} --repo={{ bootstrap_os_key }}-baseos
|
||||||
|
--installroot=/mnt
|
||||||
|
--setopt=install_weak_deps=False --setopt=optional_metadata_types=filelists
|
||||||
|
groupinstall -y core base standard
|
||||||
|
register: bootstrap_result
|
||||||
|
changed_when: bootstrap_result.rc == 0
|
||||||
|
|
||||||
|
- name: Ensure chroot has resolv.conf
|
||||||
|
ansible.builtin.file:
|
||||||
|
src: /run/NetworkManager/resolv.conf
|
||||||
|
dest: /mnt/etc/resolv.conf
|
||||||
|
state: link
|
||||||
|
force: true
|
||||||
|
|
||||||
|
- name: Ensure chroot RHEL DVD directory exists
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /mnt/usr/local/install/redhat/dvd
|
||||||
|
state: directory
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Bind mount RHEL DVD into chroot
|
||||||
|
ansible.posix.mount:
|
||||||
|
src: /usr/local/install/redhat/dvd
|
||||||
|
path: /mnt/usr/local/install/redhat/dvd
|
||||||
|
fstype: none
|
||||||
|
opts: bind
|
||||||
|
state: mounted
|
||||||
|
|
||||||
|
- name: Rebuild RPM database inside chroot
|
||||||
|
ansible.builtin.command:
|
||||||
|
argv:
|
||||||
|
- arch-chroot
|
||||||
|
- /mnt
|
||||||
|
- rpm
|
||||||
|
- --rebuilddb
|
||||||
|
register: bootstrap_rpm_rebuild_result
|
||||||
|
changed_when: bootstrap_rpm_rebuild_result.rc == 0
|
||||||
|
|
||||||
|
- name: Copy RHEL repo file into chroot environment
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: /etc/yum.repos.d/{{ bootstrap_os_key }}.repo
|
||||||
|
dest: /mnt/etc/yum.repos.d/redhat.repo
|
||||||
|
mode: "0644"
|
||||||
|
remote_src: true
|
||||||
|
|
||||||
|
- name: Install additional packages in chroot
|
||||||
|
vars:
|
||||||
|
bootstrap_rhel_release: "{{ bootstrap_os_key | replace('rhel', '') }}"
|
||||||
|
bootstrap_rhel_extra: >-
|
||||||
|
{{
|
||||||
|
(
|
||||||
|
(
|
||||||
|
lookup('vars', bootstrap_var_key)
|
||||||
|
| difference(bootstrap_guest_agent_remove_packages)
|
||||||
|
)
|
||||||
|
+ bootstrap_guest_agent_packages
|
||||||
|
)
|
||||||
|
| join(' ')
|
||||||
|
}}
|
||||||
|
ansible.builtin.command: >-
|
||||||
|
arch-chroot /mnt dnf --releasever={{ bootstrap_rhel_release }}
|
||||||
|
--setopt=install_weak_deps=False install -y {{ bootstrap_rhel_extra }}
|
||||||
|
register: bootstrap_result
|
||||||
|
changed_when: bootstrap_result.rc == 0
|
||||||
26
roles/bootstrap/tasks/rocky.yml
Normal file
26
roles/bootstrap/tasks/rocky.yml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
- name: Bootstrap RockyLinux 9
|
||||||
|
vars:
|
||||||
|
bootstrap_rocky_extra: >-
|
||||||
|
{{
|
||||||
|
(
|
||||||
|
(
|
||||||
|
lookup('vars', bootstrap_var_key)
|
||||||
|
| difference(bootstrap_guest_agent_remove_packages)
|
||||||
|
)
|
||||||
|
+ bootstrap_guest_agent_packages
|
||||||
|
)
|
||||||
|
| join(' ')
|
||||||
|
}}
|
||||||
|
ansible.builtin.command: "{{ item }}"
|
||||||
|
loop:
|
||||||
|
- >-
|
||||||
|
dnf --releasever=9 --best --repo=rocky-baseos --installroot=/mnt
|
||||||
|
--setopt=install_weak_deps=False --setopt=optional_metadata_types=filelists
|
||||||
|
groupinstall -y base core
|
||||||
|
- ln -sf /run/NetworkManager/resolv.conf /mnt/etc/resolv.conf
|
||||||
|
- >-
|
||||||
|
arch-chroot /mnt dnf --releasever=9 --setopt=install_weak_deps=False
|
||||||
|
install -y {{ bootstrap_rocky_extra }}
|
||||||
|
register: bootstrap_result
|
||||||
|
changed_when: bootstrap_result.rc == 0
|
||||||
27
roles/bootstrap/tasks/ubuntu.yml
Normal file
27
roles/bootstrap/tasks/ubuntu.yml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
- name: Bootstrap Ubuntu System
|
||||||
|
vars:
|
||||||
|
bootstrap_ubuntu_release: >-
|
||||||
|
{{ 'plucky' if bootstrap_os_key == 'ubuntu' else 'noble' }}
|
||||||
|
bootstrap_ubuntu_base_list: "{{ lookup('vars', bootstrap_var_key).base | default([]) }}"
|
||||||
|
bootstrap_ubuntu_extra_list: "{{ lookup('vars', bootstrap_var_key).extra | default([]) }}"
|
||||||
|
bootstrap_ubuntu_base: "{{ (bootstrap_ubuntu_base_list | difference(bootstrap_guest_agent_remove_packages)) | join(',') }}"
|
||||||
|
bootstrap_ubuntu_extra: >-
|
||||||
|
{{
|
||||||
|
(
|
||||||
|
(bootstrap_ubuntu_extra_list | difference(bootstrap_guest_agent_remove_packages))
|
||||||
|
+ bootstrap_guest_agent_packages
|
||||||
|
)
|
||||||
|
| join(' ')
|
||||||
|
}}
|
||||||
|
ansible.builtin.command: "{{ item }}"
|
||||||
|
loop:
|
||||||
|
- >-
|
||||||
|
debootstrap --include={{ bootstrap_ubuntu_base }}
|
||||||
|
{{ bootstrap_ubuntu_release }} /mnt http://archive.ubuntu.com/ubuntu/
|
||||||
|
- ln -sf /run/NetworkManager/resolv.conf /mnt/etc/resolv.conf
|
||||||
|
- arch-chroot /mnt sed -i '1s|$| universe|' /etc/apt/sources.list
|
||||||
|
- arch-chroot /mnt apt update
|
||||||
|
- "arch-chroot /mnt apt install -y {{ bootstrap_ubuntu_extra }}"
|
||||||
|
register: bootstrap_result
|
||||||
|
changed_when: bootstrap_result.rc == 0
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
almalinux:
|
---
|
||||||
|
bootstrap_almalinux:
|
||||||
- bind-utils
|
- bind-utils
|
||||||
|
- cryptsetup
|
||||||
- dbus-daemon
|
- dbus-daemon
|
||||||
- dhcp-client
|
- dhcp-client
|
||||||
- efibootmgr
|
- efibootmgr
|
||||||
@@ -13,19 +15,20 @@ almalinux:
|
|||||||
- nfs-utils
|
- nfs-utils
|
||||||
- nfsv4-client-utils
|
- nfsv4-client-utils
|
||||||
- mtr
|
- mtr
|
||||||
- open-vm-tools
|
|
||||||
- ppp
|
- ppp
|
||||||
- shim
|
- shim
|
||||||
- tmux
|
- tmux
|
||||||
|
- tpm2-tools
|
||||||
- vim
|
- vim
|
||||||
- wget
|
- wget
|
||||||
- zram-generator
|
- zram-generator
|
||||||
- zstd
|
- zstd
|
||||||
|
|
||||||
archlinux:
|
bootstrap_archlinux:
|
||||||
- base
|
- base
|
||||||
- btrfs-progs
|
- btrfs-progs
|
||||||
- cronie
|
- cronie
|
||||||
|
- cryptsetup
|
||||||
- dhcpcd
|
- dhcpcd
|
||||||
- efibootmgr
|
- efibootmgr
|
||||||
- fastfetch
|
- fastfetch
|
||||||
@@ -43,27 +46,28 @@ archlinux:
|
|||||||
- ncdu
|
- ncdu
|
||||||
- networkmanager
|
- networkmanager
|
||||||
- nfs-utils
|
- nfs-utils
|
||||||
- open-vm-tools
|
|
||||||
- openssh
|
- openssh
|
||||||
- ppp
|
- ppp
|
||||||
- prometheus-node-exporter
|
- prometheus-node-exporter
|
||||||
- python-psycopg2
|
- python-psycopg2
|
||||||
- qemu-guest-agent
|
|
||||||
- reflector
|
- reflector
|
||||||
- rsync
|
- rsync
|
||||||
- sudo
|
- sudo
|
||||||
- tldr
|
- tldr
|
||||||
- tmux
|
- tmux
|
||||||
|
- tpm2-tools
|
||||||
- vim
|
- vim
|
||||||
- wireguard-tools
|
- wireguard-tools
|
||||||
- zram-generator
|
- zram-generator
|
||||||
|
|
||||||
debian11:
|
bootstrap_debian11:
|
||||||
base:
|
base:
|
||||||
- apparmor-utils
|
- apparmor-utils
|
||||||
- btrfs-progs
|
- btrfs-progs
|
||||||
- chrony
|
- chrony
|
||||||
- cron
|
- cron
|
||||||
|
- cryptsetup
|
||||||
|
- cryptsetup-initramfs
|
||||||
- gnupg
|
- gnupg
|
||||||
- grub-efi
|
- grub-efi
|
||||||
- grub-efi-amd64-signed
|
- grub-efi-amd64-signed
|
||||||
@@ -93,7 +97,6 @@ debian11:
|
|||||||
- ncdu
|
- ncdu
|
||||||
- neofetch
|
- neofetch
|
||||||
- network-manager
|
- network-manager
|
||||||
- open-vm-tools
|
|
||||||
- python-is-python3
|
- python-is-python3
|
||||||
- ripgrep
|
- ripgrep
|
||||||
- rsync
|
- rsync
|
||||||
@@ -102,14 +105,17 @@ debian11:
|
|||||||
- syslog-ng
|
- syslog-ng
|
||||||
- tcpd
|
- tcpd
|
||||||
- tldr
|
- tldr
|
||||||
|
- tpm2-tools
|
||||||
- vim
|
- vim
|
||||||
- wget
|
- wget
|
||||||
- zstd
|
- zstd
|
||||||
|
|
||||||
debian12:
|
bootstrap_debian12:
|
||||||
base:
|
base:
|
||||||
- btrfs-progs
|
- btrfs-progs
|
||||||
- cron
|
- cron
|
||||||
|
- cryptsetup
|
||||||
|
- cryptsetup-initramfs
|
||||||
- gnupg
|
- gnupg
|
||||||
- grub-efi
|
- grub-efi
|
||||||
- grub-efi-amd64-signed
|
- grub-efi-amd64-signed
|
||||||
@@ -140,7 +146,6 @@ debian12:
|
|||||||
- neofetch
|
- neofetch
|
||||||
- net-tools
|
- net-tools
|
||||||
- network-manager
|
- network-manager
|
||||||
- open-vm-tools
|
|
||||||
- openssh-server
|
- openssh-server
|
||||||
- python-is-python3
|
- python-is-python3
|
||||||
- python3
|
- python3
|
||||||
@@ -153,14 +158,17 @@ debian12:
|
|||||||
- systemd-zram-generator
|
- systemd-zram-generator
|
||||||
- tcpd
|
- tcpd
|
||||||
- tldr
|
- tldr
|
||||||
|
- tpm2-tools
|
||||||
- vim
|
- vim
|
||||||
- wget
|
- wget
|
||||||
- zstd
|
- zstd
|
||||||
|
|
||||||
debian13:
|
bootstrap_debian13:
|
||||||
base:
|
base:
|
||||||
- btrfs-progs
|
- btrfs-progs
|
||||||
- cron
|
- cron
|
||||||
|
- cryptsetup
|
||||||
|
- cryptsetup-initramfs
|
||||||
- gnupg
|
- gnupg
|
||||||
- grub-efi
|
- grub-efi
|
||||||
- grub-efi-amd64-signed
|
- grub-efi-amd64-signed
|
||||||
@@ -191,7 +199,6 @@ debian13:
|
|||||||
- ncdu
|
- ncdu
|
||||||
- net-tools
|
- net-tools
|
||||||
- network-manager
|
- network-manager
|
||||||
- open-vm-tools
|
|
||||||
- openssh-server
|
- openssh-server
|
||||||
- python-is-python3
|
- python-is-python3
|
||||||
- python3
|
- python3
|
||||||
@@ -202,15 +209,17 @@ debian13:
|
|||||||
- syslog-ng
|
- syslog-ng
|
||||||
- systemd-zram-generator
|
- systemd-zram-generator
|
||||||
- tcpd
|
- tcpd
|
||||||
|
- tpm2-tools
|
||||||
- vim
|
- vim
|
||||||
- wget
|
- wget
|
||||||
- zstd
|
- zstd
|
||||||
|
|
||||||
fedora:
|
bootstrap_fedora:
|
||||||
- bat
|
- bat
|
||||||
- bind-utils
|
- bind-utils
|
||||||
- btrfs-progs
|
- btrfs-progs
|
||||||
- cronie
|
- cronie
|
||||||
|
- cryptsetup
|
||||||
- dhcp-client
|
- dhcp-client
|
||||||
- duf
|
- duf
|
||||||
- efibootmgr
|
- efibootmgr
|
||||||
@@ -229,20 +238,21 @@ fedora:
|
|||||||
- nc
|
- nc
|
||||||
- nfs-utils
|
- nfs-utils
|
||||||
- nfsv4-client-utils
|
- nfsv4-client-utils
|
||||||
- open-vm-tools
|
|
||||||
- polkit
|
- polkit
|
||||||
- ppp
|
- ppp
|
||||||
- ripgrep
|
- ripgrep
|
||||||
- shim
|
- shim
|
||||||
- tmux
|
- tmux
|
||||||
|
- tpm2-tools
|
||||||
- vim-default-editor
|
- vim-default-editor
|
||||||
- wget
|
- wget
|
||||||
- zoxide
|
- zoxide
|
||||||
- zram-generator
|
- zram-generator
|
||||||
- zstd
|
- zstd
|
||||||
|
|
||||||
rhel8:
|
bootstrap_rhel8:
|
||||||
- bind-utils
|
- bind-utils
|
||||||
|
- cryptsetup
|
||||||
- dhcp-client
|
- dhcp-client
|
||||||
- efibootmgr
|
- efibootmgr
|
||||||
- glibc-langpack-de
|
- glibc-langpack-de
|
||||||
@@ -255,16 +265,17 @@ rhel8:
|
|||||||
- mtr
|
- mtr
|
||||||
- ncurses-term
|
- ncurses-term
|
||||||
- nfs-utils
|
- nfs-utils
|
||||||
- open-vm-tools
|
|
||||||
- policycoreutils-python-utils
|
- policycoreutils-python-utils
|
||||||
- python39
|
- python39
|
||||||
- shim
|
- shim
|
||||||
- tmux
|
- tmux
|
||||||
|
- tpm2-tools
|
||||||
- vim
|
- vim
|
||||||
- zstd
|
- zstd
|
||||||
|
|
||||||
rhel9:
|
bootstrap_rhel9:
|
||||||
- bind-utils
|
- bind-utils
|
||||||
|
- cryptsetup
|
||||||
- dhcp-client
|
- dhcp-client
|
||||||
- efibootmgr
|
- efibootmgr
|
||||||
- glibc-langpack-de
|
- glibc-langpack-de
|
||||||
@@ -277,17 +288,18 @@ rhel9:
|
|||||||
- mtr
|
- mtr
|
||||||
- ncurses-term
|
- ncurses-term
|
||||||
- nfs-utils
|
- nfs-utils
|
||||||
- open-vm-tools
|
|
||||||
- policycoreutils-python-utils
|
- policycoreutils-python-utils
|
||||||
- python
|
- python
|
||||||
- shim
|
- shim
|
||||||
- tmux
|
- tmux
|
||||||
|
- tpm2-tools
|
||||||
- vim
|
- vim
|
||||||
- zram-generator
|
- zram-generator
|
||||||
- zstd
|
- zstd
|
||||||
|
|
||||||
rhel10:
|
bootstrap_rhel10:
|
||||||
- bind-utils
|
- bind-utils
|
||||||
|
- cryptsetup
|
||||||
- efibootmgr
|
- efibootmgr
|
||||||
- glibc-langpack-de
|
- glibc-langpack-de
|
||||||
- glibc-langpack-en
|
- glibc-langpack-en
|
||||||
@@ -299,17 +311,18 @@ rhel10:
|
|||||||
- mtr
|
- mtr
|
||||||
- ncurses-term
|
- ncurses-term
|
||||||
- nfs-utils
|
- nfs-utils
|
||||||
- open-vm-tools
|
|
||||||
- policycoreutils-python-utils
|
- policycoreutils-python-utils
|
||||||
- python
|
- python
|
||||||
- shim
|
- shim
|
||||||
- tmux
|
- tmux
|
||||||
|
- tpm2-tools
|
||||||
- vim
|
- vim
|
||||||
- zram-generator
|
- zram-generator
|
||||||
- zstd
|
- zstd
|
||||||
|
|
||||||
rocky:
|
bootstrap_rocky:
|
||||||
- bind-utils
|
- bind-utils
|
||||||
|
- cryptsetup
|
||||||
- dbus-daemon
|
- dbus-daemon
|
||||||
- dhcp-client
|
- dhcp-client
|
||||||
- efibootmgr
|
- efibootmgr
|
||||||
@@ -323,21 +336,23 @@ rocky:
|
|||||||
- nc
|
- nc
|
||||||
- nfs-utils
|
- nfs-utils
|
||||||
- nfsv4-client-utils
|
- nfsv4-client-utils
|
||||||
- open-vm-tools
|
|
||||||
- ppp
|
- ppp
|
||||||
- shim
|
- shim
|
||||||
- telnet
|
- telnet
|
||||||
- tmux
|
- tmux
|
||||||
|
- tpm2-tools
|
||||||
- util-linux-core
|
- util-linux-core
|
||||||
- vim
|
- vim
|
||||||
- wget
|
- wget
|
||||||
- zram-generator
|
- zram-generator
|
||||||
- zstd
|
- zstd
|
||||||
|
|
||||||
ubuntu:
|
bootstrap_ubuntu:
|
||||||
base:
|
base:
|
||||||
- btrfs-progs
|
- btrfs-progs
|
||||||
- cron
|
- cron
|
||||||
|
- cryptsetup
|
||||||
|
- cryptsetup-initramfs
|
||||||
- gnupg
|
- gnupg
|
||||||
- grub-efi
|
- grub-efi
|
||||||
- grub-efi-amd64-signed
|
- grub-efi-amd64-signed
|
||||||
@@ -372,7 +387,6 @@ ubuntu:
|
|||||||
- ncurses-term
|
- ncurses-term
|
||||||
- net-tools
|
- net-tools
|
||||||
- network-manager
|
- network-manager
|
||||||
- open-vm-tools
|
|
||||||
- openssh-server
|
- openssh-server
|
||||||
- python-is-python3
|
- python-is-python3
|
||||||
- python3
|
- python3
|
||||||
@@ -386,6 +400,7 @@ ubuntu:
|
|||||||
- tcpd
|
- tcpd
|
||||||
- tldr
|
- tldr
|
||||||
- tmux
|
- tmux
|
||||||
|
- tpm2-tools
|
||||||
- traceroute
|
- traceroute
|
||||||
- util-linux-extra
|
- util-linux-extra
|
||||||
- vim
|
- vim
|
||||||
@@ -394,10 +409,12 @@ ubuntu:
|
|||||||
- zoxide
|
- zoxide
|
||||||
- zstd
|
- zstd
|
||||||
|
|
||||||
ubuntu-lts:
|
bootstrap_ubuntu_lts:
|
||||||
base:
|
base:
|
||||||
- btrfs-progs
|
- btrfs-progs
|
||||||
- cron
|
- cron
|
||||||
|
- cryptsetup
|
||||||
|
- cryptsetup-initramfs
|
||||||
- gnupg
|
- gnupg
|
||||||
- grub-efi
|
- grub-efi
|
||||||
- grub-efi-amd64-signed
|
- grub-efi-amd64-signed
|
||||||
@@ -432,7 +449,6 @@ ubuntu-lts:
|
|||||||
- ncurses-term
|
- ncurses-term
|
||||||
- net-tools
|
- net-tools
|
||||||
- network-manager
|
- network-manager
|
||||||
- open-vm-tools
|
|
||||||
- openssh-server
|
- openssh-server
|
||||||
- python-is-python3
|
- python-is-python3
|
||||||
- python3
|
- python3
|
||||||
@@ -446,6 +462,7 @@ ubuntu-lts:
|
|||||||
- tcpd
|
- tcpd
|
||||||
- tldr
|
- tldr
|
||||||
- tmux
|
- tmux
|
||||||
|
- tpm2-tools
|
||||||
- traceroute
|
- traceroute
|
||||||
- util-linux-extra
|
- util-linux-extra
|
||||||
- vim
|
- vim
|
||||||
|
|||||||
15
roles/cis/tasks/auth.yml
Normal file
15
roles/cis/tasks/auth.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
- name: Ensure the Default UMASK is Set Correctly
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: "/mnt/etc/profile"
|
||||||
|
regexp: "^(\\s*)umask\\s+\\d+"
|
||||||
|
line: "umask 027"
|
||||||
|
|
||||||
|
- name: Prevent Login to Accounts With Empty Password
|
||||||
|
ansible.builtin.replace:
|
||||||
|
dest: "{{ item }}"
|
||||||
|
regexp: "\\s*nullok"
|
||||||
|
replace: ""
|
||||||
|
loop:
|
||||||
|
- /mnt/etc/pam.d/system-auth
|
||||||
|
- /mnt/etc/pam.d/password-auth
|
||||||
12
roles/cis/tasks/crypto.yml
Normal file
12
roles/cis/tasks/crypto.yml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
- name: Configure System Cryptography Policy
|
||||||
|
when: os in ["almalinux", "rhel9", "rhel10", "rocky"]
|
||||||
|
ansible.builtin.command: arch-chroot /mnt /usr/bin/update-crypto-policies --set DEFAULT:NO-SHA1
|
||||||
|
register: cis_crypto_policy_result
|
||||||
|
changed_when: "'Setting system-wide crypto-policies to' in cis_crypto_policy_result.stdout"
|
||||||
|
|
||||||
|
- name: Mask Systemd Services
|
||||||
|
ansible.builtin.command: >
|
||||||
|
arch-chroot /mnt systemctl mask nftables bluetooth rpcbind
|
||||||
|
register: cis_mask_services_result
|
||||||
|
changed_when: cis_mask_services_result.rc == 0
|
||||||
19
roles/cis/tasks/files.yml
Normal file
19
roles/cis/tasks/files.yml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
- name: Ensure files exist
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: touch
|
||||||
|
mode: "0600"
|
||||||
|
loop:
|
||||||
|
- /mnt/etc/at.allow
|
||||||
|
- /mnt/etc/cron.allow
|
||||||
|
- /mnt/etc/hosts.allow
|
||||||
|
- /mnt/etc/hosts.deny
|
||||||
|
|
||||||
|
- name: Ensure files do not exist
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: absent
|
||||||
|
loop:
|
||||||
|
- /mnt/etc/at.deny
|
||||||
|
- /mnt/etc/cron.deny
|
||||||
@@ -1,250 +1,14 @@
|
|||||||
---
|
---
|
||||||
- name: Configurationg System for CIS conformity
|
- name: Include CIS hardening tasks
|
||||||
block:
|
ansible.builtin.include_tasks: "{{ cis_task }}"
|
||||||
- name: Disable Kernel Modules
|
loop:
|
||||||
ansible.builtin.copy:
|
- modules.yml
|
||||||
dest: /mnt/etc/modprobe.d/cis.conf
|
- sysctl.yml
|
||||||
mode: "0644"
|
- auth.yml
|
||||||
content: |
|
- crypto.yml
|
||||||
CIS LVL 3 Restrictions
|
- files.yml
|
||||||
install freevxfs /bin/false
|
- security_lines.yml
|
||||||
install jffs2 /bin/false
|
- permissions.yml
|
||||||
install hfs /bin/false
|
- sshd.yml
|
||||||
install hfsplus /bin/false
|
loop_control:
|
||||||
install cramfs /bin/false
|
loop_var: cis_task
|
||||||
install squashfs /bin/false
|
|
||||||
install udf /bin/false
|
|
||||||
install usb-storage /bin/false
|
|
||||||
|
|
||||||
install dccp /bin/false
|
|
||||||
install sctp /bin/false
|
|
||||||
install rds /bin/false
|
|
||||||
install tipc /bin/false
|
|
||||||
|
|
||||||
- name: Create USB Rules
|
|
||||||
ansible.builtin.copy:
|
|
||||||
dest: /mnt/etc/udev/rules.d/10-cis_usb_devices.sh
|
|
||||||
mode: "0644"
|
|
||||||
content: |
|
|
||||||
By default, disable all.
|
|
||||||
ACTION=="add", SUBSYSTEMS=="usb", TEST=="authorized_default", ATTR{authorized_default}="0"
|
|
||||||
|
|
||||||
Enable hub devices.
|
|
||||||
ACTION=="add", ATTR{bDeviceClass}=="09", TEST=="authorized", ATTR{authorized}="1"
|
|
||||||
|
|
||||||
Enables keyboard devices
|
|
||||||
ACTION=="add", ATTR{product}=="*[Kk]eyboard*", TEST=="authorized", ATTR{authorized}="1"
|
|
||||||
|
|
||||||
PS2-USB converter
|
|
||||||
ACTION=="add", ATTR{product}=="*Thinnet TM*", TEST=="authorized", ATTR{authorized}="1"
|
|
||||||
|
|
||||||
- name: Create a consolidated sysctl configuration file
|
|
||||||
ansible.builtin.copy:
|
|
||||||
dest: /mnt/etc/sysctl.d/10-cis.conf
|
|
||||||
mode: "0644"
|
|
||||||
content: |
|
|
||||||
## CIS Sysctl configurations
|
|
||||||
kernel.yama.ptrace_scope=1
|
|
||||||
kernel.randomize_va_space=2
|
|
||||||
|
|
||||||
# Network
|
|
||||||
net.ipv4.ip_forward=0
|
|
||||||
net.ipv4.tcp_syncookies=1
|
|
||||||
net.ipv4.icmp_echo_ignore_broadcasts=1
|
|
||||||
net.ipv4.icmp_ignore_bogus_error_responses=1
|
|
||||||
net.ipv4.conf.all.log_martians = 1
|
|
||||||
net.ipv4.conf.all.rp_filter = 1
|
|
||||||
net.ipv4.conf.all.secure_redirects = 0
|
|
||||||
net.ipv4.conf.all.send_redirects = 0
|
|
||||||
net.ipv4.conf.all.accept_redirects = 0
|
|
||||||
net.ipv4.conf.all.accept_source_route=0
|
|
||||||
net.ipv4.conf.default.log_martians = 1
|
|
||||||
net.ipv4.conf.default.rp_filter = 1
|
|
||||||
net.ipv4.conf.default.secure_redirects = 0
|
|
||||||
net.ipv4.conf.default.send_redirects = 0
|
|
||||||
net.ipv4.conf.default.accept_redirects = 0
|
|
||||||
net.ipv6.conf.all.accept_redirects = 0
|
|
||||||
net.ipv6.conf.all.disable_ipv6 = 1
|
|
||||||
net.ipv6.conf.default.accept_redirects = 0
|
|
||||||
net.ipv6.conf.default.disable_ipv6 = 1
|
|
||||||
net.ipv6.conf.lo.disable_ipv6 = 1
|
|
||||||
|
|
||||||
# - name: Adjust login.defs
|
|
||||||
# replace:
|
|
||||||
# path: /mnt/etc/login.defs
|
|
||||||
# regexp: "{{ item.regexp }}"
|
|
||||||
# replace: "{{ item.replace }}"
|
|
||||||
# loop:
|
|
||||||
# - { regexp: '^PASS_MAX_DAYS.*', replace: 'PASS_MAX_DAYS 90' }
|
|
||||||
# - { regexp: '^PASS_MIN_DAYS.*', replace: 'PASS_MIN_DAYS 7' }
|
|
||||||
# - { regexp: '^UMASK.*', replace: 'UMASK 027' }
|
|
||||||
|
|
||||||
- name: Ensure the Default UMASK is Set Correctly
|
|
||||||
ansible.builtin.lineinfile:
|
|
||||||
path: "/mnt/etc/profile"
|
|
||||||
regexp: "^(\\s*)umask\\s+\\d+"
|
|
||||||
line: "umask 027"
|
|
||||||
|
|
||||||
- name: Prevent Login to Accounts With Empty Password
|
|
||||||
ansible.builtin.replace:
|
|
||||||
dest: "{{ item }}"
|
|
||||||
regexp: "nullok"
|
|
||||||
loop:
|
|
||||||
- /mnt/etc/pam.d/system-auth
|
|
||||||
- /mnt/etc/pam.d/password-auth
|
|
||||||
|
|
||||||
- name: Configure System Cryptography Policy
|
|
||||||
when: os in ["almalinux", "rhel9", "rhel10", "rocky"]
|
|
||||||
ansible.builtin.command: arch-chroot /mnt /usr/bin/update-crypto-policies --set DEFAULT:NO-SHA1
|
|
||||||
register: crypto_policy_result
|
|
||||||
changed_when: "'Setting system-wide crypto-policies to' in crypto_policy_result.stdout"
|
|
||||||
|
|
||||||
- name: Mask Systemd Services
|
|
||||||
ansible.builtin.command: >
|
|
||||||
arch-chroot /mnt systemctl mask nftables bluetooth rpcbind
|
|
||||||
changed_when: result.rc == 0
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Ensure files exist
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "{{ item }}"
|
|
||||||
state: touch
|
|
||||||
mode: "0600"
|
|
||||||
loop:
|
|
||||||
- /mnt/etc/at.allow
|
|
||||||
- /mnt/etc/cron.allow
|
|
||||||
- /mnt/etc/hosts.allow
|
|
||||||
- /mnt/etc/hosts.deny
|
|
||||||
|
|
||||||
- name: Ensure files do not exist
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "{{ item }}"
|
|
||||||
state: touch
|
|
||||||
mode: "0600"
|
|
||||||
loop:
|
|
||||||
- /mnt/etc/at.deny
|
|
||||||
- /mnt/etc/cron.deny
|
|
||||||
|
|
||||||
- name: Add Security related lines into config files
|
|
||||||
ansible.builtin.lineinfile:
|
|
||||||
path: "{{ item.path }}"
|
|
||||||
line: "{{ item.content }}"
|
|
||||||
loop:
|
|
||||||
- { path: /mnt/etc/security/limits.conf, content: "* hard core 0" }
|
|
||||||
- { path: /mnt/etc/security/pwquality.conf, content: minlen = 14 }
|
|
||||||
- { path: /mnt/etc/security/pwquality.conf, content: dcredit = -1 }
|
|
||||||
- { path: /mnt/etc/security/pwquality.conf, content: ucredit = -1 }
|
|
||||||
- { path: /mnt/etc/security/pwquality.conf, content: ocredit = -1 }
|
|
||||||
- { path: /mnt/etc/security/pwquality.conf, content: lcredit = -1 }
|
|
||||||
- {
|
|
||||||
path: '/mnt/etc/{{ "bashrc" if os in ["almalinux", "fedora", "rhel8", "rhel9", "rhel10", "rocky"] else "bash.bashrc" }}',
|
|
||||||
content: umask 077,
|
|
||||||
}
|
|
||||||
- {
|
|
||||||
path: '/mnt/etc/{{ "bashrc" if os in ["almalinux", "fedora", "rhel8", "rhel9", "rhel10", "rocky"] else "bash.bashrc" }}',
|
|
||||||
content: export TMOUT=3000,
|
|
||||||
}
|
|
||||||
- {
|
|
||||||
path: '/mnt/{{ "usr/lib/systemd/journald.conf" if os == "fedora" else "etc/systemd/journald.conf" }}',
|
|
||||||
content: Storage=persistent,
|
|
||||||
}
|
|
||||||
- {
|
|
||||||
path: /mnt/etc/sudoers,
|
|
||||||
content: Defaults logfile="/var/log/sudo.log",
|
|
||||||
}
|
|
||||||
- { path: /mnt/etc/pam.d/su, content: auth required pam_wheel.so }
|
|
||||||
- {
|
|
||||||
path:
|
|
||||||
'/mnt/etc/{{ "pam.d/common-auth" if os in ["debian11", "debian12", "ubuntu", "ubuntu-lts"]
|
|
||||||
else "authselect/system-auth" if os == "fedora" else "pam.d/system-auth" }}',
|
|
||||||
content: auth required pam_faillock.so onerr=fail audit silent deny=5 unlock_time=900,
|
|
||||||
}
|
|
||||||
- {
|
|
||||||
path:
|
|
||||||
'/mnt/etc/{{ "pam.d/common-account" if os in ["debian11", "debian12", "ubuntu", "ubuntu-lts"] else "authselect/system-auth"
|
|
||||||
if os == "fedora" else "pam.d/system-auth" }}',
|
|
||||||
content: account required pam_faillock.so,
|
|
||||||
}
|
|
||||||
- {
|
|
||||||
path: '/mnt/etc/pam.d/{{ "common-password" if os in ["debian11", "debian12", "ubuntu", "ubuntu-lts"] else "passwd" }}',
|
|
||||||
content: "password [success=1 default=ignore] pam_unix.so obscure sha512 remember=5",
|
|
||||||
}
|
|
||||||
- { path: /mnt/etc/hosts.deny, content: "ALL: ALL" }
|
|
||||||
- { path: /mnt/etc/hosts.allow, content: "sshd: ALL" }
|
|
||||||
|
|
||||||
- name: Set permissions for various files and directories
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "{{ item.path }}"
|
|
||||||
owner: "{{ item.owner | default(omit) }}"
|
|
||||||
group: "{{ item.group | default(omit) }}"
|
|
||||||
mode: "{{ item.mode }}"
|
|
||||||
loop: >
|
|
||||||
{{ [
|
|
||||||
{ "path": "/mnt/etc/ssh/sshd_config", "mode": "0600" },
|
|
||||||
{ "path": "/mnt/etc/cron.hourly", "mode": "0700" },
|
|
||||||
{ "path": "/mnt/etc/cron.daily", "mode": "0700" },
|
|
||||||
{ "path": "/mnt/etc/cron.weekly", "mode": "0700" },
|
|
||||||
{ "path": "/mnt/etc/cron.monthly", "mode": "0700" },
|
|
||||||
{ "path": "/mnt/etc/cron.d", "mode": "0700" },
|
|
||||||
{ "path": "/mnt/etc/crontab", "mode": "0600" },
|
|
||||||
{ "path": "/mnt/etc/logrotate.conf", "mode": "0644" },
|
|
||||||
{ "path": "/mnt/usr/sbin/pppd", "mode": "0754" } if os not in ["rhel8", "rhel9", "rhel10"] else None,
|
|
||||||
{ "path": "/mnt/usr/bin/" + ("fusermount3" if os in ["almalinux", "archlinux", "debian12", "fedora", "rhel9", "rhel10", "rocky"]
|
|
||||||
else "fusermount"), "mode": "755" },
|
|
||||||
{ "path": "/mnt/usr/bin/" + ("write.ul" if os == "debian11" else "write"), "mode": "755" }
|
|
||||||
] | reject("none") }}
|
|
||||||
|
|
||||||
- name: Adjust SSHD config
|
|
||||||
ansible.builtin.lineinfile:
|
|
||||||
path: /mnt/etc/ssh/sshd_config
|
|
||||||
regexp: ^\s*#?{{ item.option }}\s+.*$
|
|
||||||
line: "{{ item.option }} {{ item.value }}"
|
|
||||||
with_items:
|
|
||||||
- { option: LogLevel, value: VERBOSE }
|
|
||||||
- { option: LoginGraceTime, value: "60" }
|
|
||||||
- { option: PermitRootLogin, value: "no" }
|
|
||||||
- { option: StrictModes, value: "yes" }
|
|
||||||
- { option: MaxAuthTries, value: "4" }
|
|
||||||
- { option: MaxSessions, value: "10" }
|
|
||||||
- { option: MaxStartups, value: 10:30:60 }
|
|
||||||
- { option: PubkeyAuthentication, value: "yes" }
|
|
||||||
- { option: HostbasedAuthentication, value: "no" }
|
|
||||||
- { option: IgnoreRhosts, value: "yes" }
|
|
||||||
- { option: PasswordAuthentication, value: "no" }
|
|
||||||
- { option: PermitEmptyPasswords, value: "no" }
|
|
||||||
- { option: KerberosAuthentication, value: "no" }
|
|
||||||
- { option: GSSAPIAuthentication, value: "no" }
|
|
||||||
- { option: AllowAgentForwarding, value: "no" }
|
|
||||||
- { option: AllowTcpForwarding, value: "no" }
|
|
||||||
- { option: ChallengeResponseAuthentication, value: "no" }
|
|
||||||
- { option: GatewayPorts, value: "no" }
|
|
||||||
- { option: X11Forwarding, value: "no" }
|
|
||||||
- { option: PermitUserEnvironment, value: "no" }
|
|
||||||
- { option: ClientAliveInterval, value: "300" }
|
|
||||||
- { option: ClientAliveCountMax, value: "1" }
|
|
||||||
- { option: PermitTunnel, value: "no" }
|
|
||||||
- { option: Banner, value: /etc/issue.net }
|
|
||||||
|
|
||||||
- name: Append CIS Specific configurations to sshd_config
|
|
||||||
ansible.builtin.lineinfile:
|
|
||||||
path: /mnt/etc/ssh/sshd_config
|
|
||||||
line: |2-
|
|
||||||
|
|
||||||
## CIS Specific
|
|
||||||
Protocol 2
|
|
||||||
|
|
||||||
### Ciphers and keying ###
|
|
||||||
RekeyLimit 512M 6h
|
|
||||||
KexAlgorithms mlkem768x25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256
|
|
||||||
Ciphers aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
|
|
||||||
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com
|
|
||||||
|
|
||||||
###########################
|
|
||||||
|
|
||||||
AllowStreamLocalForwarding no
|
|
||||||
PermitUserRC no
|
|
||||||
|
|
||||||
AllowUsers *
|
|
||||||
AllowGroups *
|
|
||||||
DenyUsers nobody
|
|
||||||
DenyGroups nobody
|
|
||||||
|
|||||||
38
roles/cis/tasks/modules.yml
Normal file
38
roles/cis/tasks/modules.yml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
- name: Disable Kernel Modules
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /mnt/etc/modprobe.d/cis.conf
|
||||||
|
mode: "0644"
|
||||||
|
content: |
|
||||||
|
# CIS LVL 3 Restrictions
|
||||||
|
install freevxfs /bin/false
|
||||||
|
install jffs2 /bin/false
|
||||||
|
install hfs /bin/false
|
||||||
|
install hfsplus /bin/false
|
||||||
|
install cramfs /bin/false
|
||||||
|
install squashfs /bin/false
|
||||||
|
install udf /bin/false
|
||||||
|
install usb-storage /bin/false
|
||||||
|
install dccp /bin/false
|
||||||
|
install sctp /bin/false
|
||||||
|
install rds /bin/false
|
||||||
|
install tipc /bin/false
|
||||||
|
|
||||||
|
- name: Remove legacy USB rules file
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /mnt/etc/udev/rules.d/10-cis_usb_devices.sh
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Create USB rules
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /mnt/etc/udev/rules.d/10-cis_usb_devices.rules
|
||||||
|
mode: "0644"
|
||||||
|
content: |
|
||||||
|
# By default, disable all.
|
||||||
|
ACTION=="add", SUBSYSTEMS=="usb", TEST=="authorized_default", ATTR{authorized_default}="0"
|
||||||
|
# Enable hub devices.
|
||||||
|
ACTION=="add", ATTR{bDeviceClass}=="09", TEST=="authorized", ATTR{authorized}="1"
|
||||||
|
# Enable keyboard devices.
|
||||||
|
ACTION=="add", ATTR{product}=="*[Kk]eyboard*", TEST=="authorized", ATTR{authorized}="1"
|
||||||
|
# PS2-USB converter.
|
||||||
|
ACTION=="add", ATTR{product}=="*Thinnet TM*", TEST=="authorized", ATTR{authorized}="1"
|
||||||
37
roles/cis/tasks/permissions.yml
Normal file
37
roles/cis/tasks/permissions.yml
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
---
|
||||||
|
- name: Build CIS permission targets
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
cis_permission_targets: >-
|
||||||
|
{{
|
||||||
|
[
|
||||||
|
{ "path": "/mnt/etc/ssh/sshd_config", "mode": "0600" },
|
||||||
|
{ "path": "/mnt/etc/cron.hourly", "mode": "0700" },
|
||||||
|
{ "path": "/mnt/etc/cron.daily", "mode": "0700" },
|
||||||
|
{ "path": "/mnt/etc/cron.weekly", "mode": "0700" },
|
||||||
|
{ "path": "/mnt/etc/cron.monthly", "mode": "0700" },
|
||||||
|
{ "path": "/mnt/etc/cron.d", "mode": "0700" },
|
||||||
|
{ "path": "/mnt/etc/crontab", "mode": "0600" },
|
||||||
|
{ "path": "/mnt/etc/logrotate.conf", "mode": "0644" },
|
||||||
|
{ "path": "/mnt/usr/sbin/pppd", "mode": "0754" } if os not in ["rhel8", "rhel9", "rhel10"] else None,
|
||||||
|
{ "path": "/mnt/usr/bin/" + ("fusermount3" if os in ["archlinux", "debian12", "fedora", "rhel9",
|
||||||
|
"rhel10", "rocky"] else "fusermount"), "mode": "755" },
|
||||||
|
{ "path": "/mnt/usr/bin/" + ("write.ul" if os == "debian11" else "write"), "mode": "755" }
|
||||||
|
] | reject("none")
|
||||||
|
}}
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Check CIS permission targets
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ item.path }}"
|
||||||
|
loop: "{{ cis_permission_targets }}"
|
||||||
|
register: cis_permission_stats
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Set permissions for existing targets
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item.item.path }}"
|
||||||
|
owner: "{{ item.item.owner | default(omit) }}"
|
||||||
|
group: "{{ item.item.group | default(omit) }}"
|
||||||
|
mode: "{{ item.item.mode }}"
|
||||||
|
loop: "{{ cis_permission_stats.results }}"
|
||||||
|
when: item.stat.exists
|
||||||
46
roles/cis/tasks/security_lines.yml
Normal file
46
roles/cis/tasks/security_lines.yml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
- name: Add Security related lines into config files
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: "{{ item.path }}"
|
||||||
|
line: "{{ item.content }}"
|
||||||
|
loop:
|
||||||
|
- {path: /mnt/etc/security/limits.conf, content: "* hard core 0"}
|
||||||
|
- {path: /mnt/etc/security/pwquality.conf, content: minlen = 14}
|
||||||
|
- {path: /mnt/etc/security/pwquality.conf, content: dcredit = -1}
|
||||||
|
- {path: /mnt/etc/security/pwquality.conf, content: ucredit = -1}
|
||||||
|
- {path: /mnt/etc/security/pwquality.conf, content: ocredit = -1}
|
||||||
|
- {path: /mnt/etc/security/pwquality.conf, content: lcredit = -1}
|
||||||
|
- {path: '/mnt/etc/{{ "bashrc" if is_rhel | default(false) else "bash.bashrc" }}', content: umask 077}
|
||||||
|
- {path: '/mnt/etc/{{ "bashrc" if is_rhel | default(false) else "bash.bashrc" }}', content: export TMOUT=3000}
|
||||||
|
- {path: '/mnt/{{ "usr/lib/systemd/journald.conf" if os == "fedora" else "etc/systemd/journald.conf" }}', content: Storage=persistent}
|
||||||
|
- {path: /mnt/etc/sudoers, content: Defaults logfile="/var/log/sudo.log"}
|
||||||
|
- {path: /mnt/etc/pam.d/su, content: auth required pam_wheel.so}
|
||||||
|
- path: >-
|
||||||
|
/mnt/etc/{{
|
||||||
|
"pam.d/common-auth"
|
||||||
|
if os in ["debian11", "debian12", "ubuntu", "ubuntu-lts"]
|
||||||
|
else "authselect/system-auth"
|
||||||
|
if os == "fedora"
|
||||||
|
else "pam.d/system-auth"
|
||||||
|
}}
|
||||||
|
content: >-
|
||||||
|
auth required pam_faillock.so onerr=fail audit silent deny=5 unlock_time=900
|
||||||
|
- path: >-
|
||||||
|
/mnt/etc/{{
|
||||||
|
"pam.d/common-account"
|
||||||
|
if os in ["debian11", "debian12", "ubuntu", "ubuntu-lts"]
|
||||||
|
else "authselect/system-auth"
|
||||||
|
if os == "fedora"
|
||||||
|
else "pam.d/system-auth"
|
||||||
|
}}
|
||||||
|
content: account required pam_faillock.so
|
||||||
|
- path: >-
|
||||||
|
/mnt/etc/pam.d/{{
|
||||||
|
"common-password"
|
||||||
|
if os in ["debian11", "debian12", "ubuntu", "ubuntu-lts"]
|
||||||
|
else "passwd"
|
||||||
|
}}
|
||||||
|
content: >-
|
||||||
|
password [success=1 default=ignore] pam_unix.so obscure sha512 remember=5
|
||||||
|
- {path: /mnt/etc/hosts.deny, content: "ALL: ALL"}
|
||||||
|
- {path: /mnt/etc/hosts.allow, content: "sshd: ALL"}
|
||||||
51
roles/cis/tasks/sshd.yml
Normal file
51
roles/cis/tasks/sshd.yml
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
---
|
||||||
|
- name: Adjust SSHD config
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /mnt/etc/ssh/sshd_config
|
||||||
|
regexp: ^\s*#?{{ item.option }}\s+.*$
|
||||||
|
line: "{{ item.option }} {{ item.value }}"
|
||||||
|
loop:
|
||||||
|
- {option: LogLevel, value: VERBOSE}
|
||||||
|
- {option: LoginGraceTime, value: "60"}
|
||||||
|
- {option: PermitRootLogin, value: "no"}
|
||||||
|
- {option: StrictModes, value: "yes"}
|
||||||
|
- {option: MaxAuthTries, value: "4"}
|
||||||
|
- {option: MaxSessions, value: "10"}
|
||||||
|
- {option: MaxStartups, value: "10:30:60"}
|
||||||
|
- {option: PubkeyAuthentication, value: "yes"}
|
||||||
|
- {option: HostbasedAuthentication, value: "no"}
|
||||||
|
- {option: IgnoreRhosts, value: "yes"}
|
||||||
|
- {option: PasswordAuthentication, value: "no"}
|
||||||
|
- {option: PermitEmptyPasswords, value: "no"}
|
||||||
|
- {option: KerberosAuthentication, value: "no"}
|
||||||
|
- {option: GSSAPIAuthentication, value: "no"}
|
||||||
|
- {option: AllowAgentForwarding, value: "no"}
|
||||||
|
- {option: AllowTcpForwarding, value: "no"}
|
||||||
|
- {option: ChallengeResponseAuthentication, value: "no"}
|
||||||
|
- {option: GatewayPorts, value: "no"}
|
||||||
|
- {option: X11Forwarding, value: "no"}
|
||||||
|
- {option: PermitUserEnvironment, value: "no"}
|
||||||
|
- {option: ClientAliveInterval, value: "300"}
|
||||||
|
- {option: ClientAliveCountMax, value: "1"}
|
||||||
|
- {option: PermitTunnel, value: "no"}
|
||||||
|
- {option: Banner, value: /etc/issue.net}
|
||||||
|
|
||||||
|
- name: Append CIS specific configurations to sshd_config
|
||||||
|
ansible.builtin.blockinfile:
|
||||||
|
path: /mnt/etc/ssh/sshd_config
|
||||||
|
marker: "# {mark} CIS SSH HARDENING"
|
||||||
|
block: |-
|
||||||
|
## CIS Specific
|
||||||
|
Protocol 2
|
||||||
|
### Ciphers and keying ###
|
||||||
|
RekeyLimit 512M 6h
|
||||||
|
KexAlgorithms mlkem768x25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256
|
||||||
|
Ciphers aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
|
||||||
|
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com
|
||||||
|
###########################
|
||||||
|
AllowStreamLocalForwarding no
|
||||||
|
PermitUserRC no
|
||||||
|
AllowUsers *
|
||||||
|
AllowGroups *
|
||||||
|
DenyUsers nobody
|
||||||
|
DenyGroups nobody
|
||||||
30
roles/cis/tasks/sysctl.yml
Normal file
30
roles/cis/tasks/sysctl.yml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
---
|
||||||
|
- name: Create a consolidated sysctl configuration file
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /mnt/etc/sysctl.d/10-cis.conf
|
||||||
|
mode: "0644"
|
||||||
|
content: |
|
||||||
|
## CIS Sysctl configurations
|
||||||
|
kernel.yama.ptrace_scope=1
|
||||||
|
kernel.randomize_va_space=2
|
||||||
|
# Network
|
||||||
|
net.ipv4.ip_forward=0
|
||||||
|
net.ipv4.tcp_syncookies=1
|
||||||
|
net.ipv4.icmp_echo_ignore_broadcasts=1
|
||||||
|
net.ipv4.icmp_ignore_bogus_error_responses=1
|
||||||
|
net.ipv4.conf.all.log_martians = 1
|
||||||
|
net.ipv4.conf.all.rp_filter = 1
|
||||||
|
net.ipv4.conf.all.secure_redirects = 0
|
||||||
|
net.ipv4.conf.all.send_redirects = 0
|
||||||
|
net.ipv4.conf.all.accept_redirects = 0
|
||||||
|
net.ipv4.conf.all.accept_source_route=0
|
||||||
|
net.ipv4.conf.default.log_martians = 1
|
||||||
|
net.ipv4.conf.default.rp_filter = 1
|
||||||
|
net.ipv4.conf.default.secure_redirects = 0
|
||||||
|
net.ipv4.conf.default.send_redirects = 0
|
||||||
|
net.ipv4.conf.default.accept_redirects = 0
|
||||||
|
net.ipv6.conf.all.accept_redirects = 0
|
||||||
|
net.ipv6.conf.all.disable_ipv6 = 1
|
||||||
|
net.ipv6.conf.default.accept_redirects = 0
|
||||||
|
net.ipv6.conf.default.disable_ipv6 = 1
|
||||||
|
net.ipv6.conf.lo.disable_ipv6 = 1
|
||||||
113
roles/cleanup/tasks/libvirt.yml
Normal file
113
roles/cleanup/tasks/libvirt.yml
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
---
|
||||||
|
- name: Remove Archiso and cloud-init disks
|
||||||
|
when: hypervisor == "libvirt"
|
||||||
|
delegate_to: localhost
|
||||||
|
become: false
|
||||||
|
block:
|
||||||
|
- name: Set libvirt image paths
|
||||||
|
vars:
|
||||||
|
cleanup_libvirt_image_dir_value: "{{ vm_path | default('/var/lib/libvirt/images') }}"
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
cleanup_libvirt_image_dir: "{{ cleanup_libvirt_image_dir_value }}"
|
||||||
|
cleanup_libvirt_cloudinit_path: >-
|
||||||
|
{{ [cleanup_libvirt_image_dir_value, hostname ~ '-cloudinit.iso'] | ansible.builtin.path_join }}
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Read current VM XML definition
|
||||||
|
community.libvirt.virt:
|
||||||
|
command: get_xml
|
||||||
|
name: "{{ hostname }}"
|
||||||
|
register: cleanup_libvirt_get_xml
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Initialize cleaned VM XML
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
cleanup_libvirt_domain_xml: "{{ cleanup_libvirt_get_xml.get_xml }}"
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Remove boot ISO device from VM XML (target match)
|
||||||
|
community.general.xml:
|
||||||
|
xmlstring: "{{ cleanup_libvirt_domain_xml }}"
|
||||||
|
xpath: "/domain/devices/disk[target/@dev='sda']"
|
||||||
|
state: absent
|
||||||
|
register: cleanup_libvirt_xml_strip_boot
|
||||||
|
|
||||||
|
- name: Update cleaned VM XML after removing boot ISO
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
cleanup_libvirt_domain_xml: "{{ cleanup_libvirt_xml_strip_boot.xmlstring }}"
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Remove boot ISO device from VM XML (source match)
|
||||||
|
when: boot_iso is defined and (boot_iso | length > 0)
|
||||||
|
community.general.xml:
|
||||||
|
xmlstring: "{{ cleanup_libvirt_domain_xml }}"
|
||||||
|
xpath: "/domain/devices/disk[contains(source/@file, '{{ boot_iso | basename }}')]"
|
||||||
|
state: absent
|
||||||
|
register: cleanup_libvirt_xml_strip_boot_source
|
||||||
|
|
||||||
|
- name: Update cleaned VM XML after removing boot ISO source match
|
||||||
|
when: boot_iso is defined and (boot_iso | length > 0)
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
cleanup_libvirt_domain_xml: "{{ cleanup_libvirt_xml_strip_boot_source.xmlstring }}"
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Remove cloud-init ISO device from VM XML (target match)
|
||||||
|
community.general.xml:
|
||||||
|
xmlstring: "{{ cleanup_libvirt_domain_xml }}"
|
||||||
|
xpath: "/domain/devices/disk[target/@dev='sdb']"
|
||||||
|
state: absent
|
||||||
|
register: cleanup_libvirt_xml_strip_cloudinit
|
||||||
|
|
||||||
|
- name: Update cleaned VM XML after removing cloud-init ISO
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
cleanup_libvirt_domain_xml: "{{ cleanup_libvirt_xml_strip_cloudinit.xmlstring }}"
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Remove cloud-init ISO device from VM XML (source match)
|
||||||
|
community.general.xml:
|
||||||
|
xmlstring: "{{ cleanup_libvirt_domain_xml }}"
|
||||||
|
xpath: "/domain/devices/disk[contains(source/@file, '{{ hostname }}-cloudinit.iso')]"
|
||||||
|
state: absent
|
||||||
|
register: cleanup_libvirt_xml_strip_cloudinit_source
|
||||||
|
|
||||||
|
- name: Update cleaned VM XML after removing cloud-init ISO source match
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
cleanup_libvirt_domain_xml: "{{ cleanup_libvirt_xml_strip_cloudinit_source.xmlstring }}"
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Strip XML declaration for libvirt define
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
cleanup_libvirt_domain_xml_clean: >-
|
||||||
|
{{
|
||||||
|
cleanup_libvirt_domain_xml
|
||||||
|
| replace('\ufeff', '')
|
||||||
|
| regex_replace("(?is)<\\?xml[^>]*\\?>", "")
|
||||||
|
| regex_replace("(?i)encoding=[\"'][^\"']+[\"']", "")
|
||||||
|
| trim
|
||||||
|
}}
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Update VM definition without installer media
|
||||||
|
community.libvirt.virt:
|
||||||
|
command: define
|
||||||
|
xml: "{{ cleanup_libvirt_domain_xml_clean }}"
|
||||||
|
|
||||||
|
- name: Remove cloud-init disk
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ cleanup_libvirt_cloudinit_path }}"
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Ensure VM is powered off before restart
|
||||||
|
community.libvirt.virt:
|
||||||
|
name: "{{ hostname }}"
|
||||||
|
state: destroyed
|
||||||
|
|
||||||
|
- name: Start the VM
|
||||||
|
community.libvirt.virt:
|
||||||
|
name: "{{ hostname }}"
|
||||||
|
state: running
|
||||||
|
|
||||||
|
- name: Wait for VM to boot up
|
||||||
|
delegate_to: "{{ inventory_hostname }}"
|
||||||
|
ansible.builtin.wait_for_connection:
|
||||||
|
timeout: 300
|
||||||
@@ -1,132 +1,8 @@
|
|||||||
---
|
---
|
||||||
- name: Unmount Disks
|
- name: Cleanup physical install
|
||||||
vars:
|
when: install_type == "physical"
|
||||||
ansible_connection: ssh
|
ansible.builtin.include_tasks: physical.yml
|
||||||
block:
|
|
||||||
- name: Disable Swap
|
|
||||||
ansible.builtin.command: swapoff -a
|
|
||||||
register: swapoff_result
|
|
||||||
changed_when: swapoff_result.rc == 0
|
|
||||||
|
|
||||||
- name: Unmount /mnt if mounted
|
- name: Cleanup virtual install
|
||||||
ansible.builtin.command: umount -R /mnt
|
when: install_type == "virtual"
|
||||||
register: unmount_result
|
ansible.builtin.include_tasks: virtual.yml
|
||||||
changed_when: unmount_result.rc == 0
|
|
||||||
|
|
||||||
- name: Verify /mnt is no longer mounted
|
|
||||||
ansible.builtin.command: grep ' /mnt ' /proc/mounts
|
|
||||||
register: verify_unmount
|
|
||||||
retries: 5
|
|
||||||
delay: 5
|
|
||||||
until: verify_unmount.rc != 0
|
|
||||||
when: unmount_result.rc == 0
|
|
||||||
changed_when: false
|
|
||||||
failed_when: verify_unmount.rc not in [0, 1]
|
|
||||||
|
|
||||||
- name: Shutdown the VM
|
|
||||||
community.general.shutdown:
|
|
||||||
vars:
|
|
||||||
ansible_connection: ssh
|
|
||||||
|
|
||||||
- name: Setup Cleanup
|
|
||||||
when: hypervisor == "proxmox"
|
|
||||||
delegate_to: localhost
|
|
||||||
become: false
|
|
||||||
block:
|
|
||||||
- name: Cleanup Setup Disks
|
|
||||||
community.general.proxmox_disk:
|
|
||||||
api_host: "{{ hypervisor_url }}"
|
|
||||||
api_user: "{{ hypervisor_username }}"
|
|
||||||
api_password: "{{ hypervisor_password }}"
|
|
||||||
name: "{{ hostname }}"
|
|
||||||
vmid: "{{ vm_id }}"
|
|
||||||
disk: "{{ item }}"
|
|
||||||
state: absent
|
|
||||||
loop:
|
|
||||||
- ide0
|
|
||||||
- ide2
|
|
||||||
|
|
||||||
- name: Start the VM
|
|
||||||
community.general.proxmox_kvm:
|
|
||||||
api_host: "{{ hypervisor_url }}"
|
|
||||||
api_user: "{{ hypervisor_username }}"
|
|
||||||
api_password: "{{ hypervisor_password }}"
|
|
||||||
node: "{{ hypervisor_node }}"
|
|
||||||
vmid: "{{ vm_id }}"
|
|
||||||
state: restarted
|
|
||||||
|
|
||||||
- name: Clean vCenter VM
|
|
||||||
when: hypervisor == "vmware"
|
|
||||||
delegate_to: localhost
|
|
||||||
become: false
|
|
||||||
block:
|
|
||||||
- name: Remove CD-ROM from VM in vCenter
|
|
||||||
when: hypervisor == "vmware"
|
|
||||||
failed_when: false
|
|
||||||
community.vmware.vmware_guest:
|
|
||||||
hostname: "{{ hypervisor_url }}"
|
|
||||||
username: "{{ hypervisor_username }}"
|
|
||||||
password: "{{ hypervisor_password }}"
|
|
||||||
validate_certs: false
|
|
||||||
datacenter: "{{ hypervisor_cluster }}"
|
|
||||||
name: "{{ hostname }}"
|
|
||||||
cdrom:
|
|
||||||
- controller_number: 0
|
|
||||||
unit_number: 0
|
|
||||||
controller_type: sata
|
|
||||||
type: iso
|
|
||||||
iso_path: "{{ boot_iso }}"
|
|
||||||
state: absent
|
|
||||||
- controller_number: 0
|
|
||||||
unit_number: 1
|
|
||||||
controller_type: sata
|
|
||||||
type: iso
|
|
||||||
iso_path: "{{ rhel_iso | default(omit) }}"
|
|
||||||
state: absent
|
|
||||||
|
|
||||||
- name: Start VM in vCenter
|
|
||||||
when: hypervisor == "vmware"
|
|
||||||
community.vmware.vmware_guest_powerstate:
|
|
||||||
hostname: "{{ hypervisor_url }}"
|
|
||||||
username: "{{ hypervisor_username }}"
|
|
||||||
password: "{{ hypervisor_password }}"
|
|
||||||
validate_certs: false
|
|
||||||
datacenter: "{{ hypervisor_cluster }}"
|
|
||||||
name: "{{ hostname }}"
|
|
||||||
state: powered-on
|
|
||||||
|
|
||||||
- name: Remove Archiso and cloud-init disks
|
|
||||||
when: hypervisor == "libvirt"
|
|
||||||
delegate_to: localhost
|
|
||||||
become: false
|
|
||||||
block:
|
|
||||||
- name: Remove cloud-init disk
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "{{ vm_path | default('/var/lib/libvirt/images/') }}{{ hostname }}-cloudinit.iso"
|
|
||||||
state: absent
|
|
||||||
|
|
||||||
- name: Get list of CD-ROM devices
|
|
||||||
ansible.builtin.shell: set -o pipefail && virsh --connect qemu:///system domblklist {{ hostname }} --details | grep 'cdrom' | awk '{print $3}'
|
|
||||||
changed_when: false
|
|
||||||
register: cdrom_devices
|
|
||||||
|
|
||||||
- name: Wait for VM to spin down
|
|
||||||
ansible.builtin.wait_for:
|
|
||||||
timeout: 15
|
|
||||||
|
|
||||||
- name: Remove CD-ROM devices
|
|
||||||
when: cdrom_devices.stdout_lines | length > 0
|
|
||||||
ansible.builtin.command: virsh --connect qemu:///system detach-disk {{ hostname }} {{ item }} --persistent
|
|
||||||
with_items: "{{ cdrom_devices.stdout_lines | select('ne', 'sdc') | list }}"
|
|
||||||
changed_when: result.rc == 0
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Start the VM
|
|
||||||
community.libvirt.virt:
|
|
||||||
name: "{{ hostname }}"
|
|
||||||
state: running
|
|
||||||
|
|
||||||
- name: Wait for VM to boot up
|
|
||||||
delegate_to: "{{ inventory_hostname }}"
|
|
||||||
ansible.builtin.wait_for_connection:
|
|
||||||
timeout: 300
|
|
||||||
|
|||||||
13
roles/cleanup/tasks/physical.yml
Normal file
13
roles/cleanup/tasks/physical.yml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
- name: Unmount installer mounts
|
||||||
|
ansible.builtin.include_tasks: unmount.yml
|
||||||
|
|
||||||
|
- name: Trigger reboot into installed system
|
||||||
|
ansible.builtin.command:
|
||||||
|
argv:
|
||||||
|
- reboot
|
||||||
|
async: 1
|
||||||
|
poll: 0
|
||||||
|
changed_when: true
|
||||||
|
failed_when: false
|
||||||
|
ignore_unreachable: true
|
||||||
27
roles/cleanup/tasks/proxmox.yml
Normal file
27
roles/cleanup/tasks/proxmox.yml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
- name: Setup Cleanup
|
||||||
|
when: hypervisor == "proxmox"
|
||||||
|
delegate_to: localhost
|
||||||
|
become: false
|
||||||
|
block:
|
||||||
|
- name: Cleanup Setup Disks
|
||||||
|
community.proxmox.proxmox_disk:
|
||||||
|
api_host: "{{ hypervisor_url }}"
|
||||||
|
api_user: "{{ hypervisor_username }}"
|
||||||
|
api_password: "{{ hypervisor_password }}"
|
||||||
|
name: "{{ hostname }}"
|
||||||
|
vmid: "{{ vm_id }}"
|
||||||
|
disk: "{{ item }}"
|
||||||
|
state: absent
|
||||||
|
loop:
|
||||||
|
- ide0
|
||||||
|
- ide2
|
||||||
|
|
||||||
|
- name: Start the VM
|
||||||
|
community.proxmox.proxmox_kvm:
|
||||||
|
api_host: "{{ hypervisor_url }}"
|
||||||
|
api_user: "{{ hypervisor_username }}"
|
||||||
|
api_password: "{{ hypervisor_password }}"
|
||||||
|
node: "{{ hypervisor_node }}"
|
||||||
|
vmid: "{{ vm_id }}"
|
||||||
|
state: restarted
|
||||||
4
roles/cleanup/tasks/shutdown.yml
Normal file
4
roles/cleanup/tasks/shutdown.yml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
- name: Shutdown the VM
|
||||||
|
become: true
|
||||||
|
community.general.shutdown:
|
||||||
23
roles/cleanup/tasks/unmount.yml
Normal file
23
roles/cleanup/tasks/unmount.yml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
- name: Unmount Disks
|
||||||
|
become: true
|
||||||
|
block:
|
||||||
|
- name: Disable Swap
|
||||||
|
ansible.builtin.command: swapoff -a
|
||||||
|
register: cleanup_swapoff_result
|
||||||
|
changed_when: cleanup_swapoff_result.rc == 0
|
||||||
|
|
||||||
|
- name: Unmount /mnt if mounted
|
||||||
|
ansible.builtin.command: umount -R /mnt
|
||||||
|
register: cleanup_unmount_result
|
||||||
|
changed_when: cleanup_unmount_result.rc == 0
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Verify /mnt is no longer mounted
|
||||||
|
ansible.builtin.command: grep ' /mnt ' /proc/mounts
|
||||||
|
until: cleanup_verify_unmount.rc != 0
|
||||||
|
retries: 5
|
||||||
|
delay: 5
|
||||||
|
register: cleanup_verify_unmount
|
||||||
|
changed_when: false
|
||||||
|
failed_when: cleanup_verify_unmount.rc not in [0, 1]
|
||||||
15
roles/cleanup/tasks/virtual.yml
Normal file
15
roles/cleanup/tasks/virtual.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
- name: Unmount installer mounts
|
||||||
|
ansible.builtin.include_tasks: unmount.yml
|
||||||
|
|
||||||
|
- name: Shutdown installer environment
|
||||||
|
ansible.builtin.include_tasks: shutdown.yml
|
||||||
|
|
||||||
|
- name: Cleanup hypervisor resources
|
||||||
|
ansible.builtin.include_tasks: proxmox.yml
|
||||||
|
|
||||||
|
- name: Cleanup vCenter resources
|
||||||
|
ansible.builtin.include_tasks: vmware.yml
|
||||||
|
|
||||||
|
- name: Cleanup libvirt resources
|
||||||
|
ansible.builtin.include_tasks: libvirt.yml
|
||||||
40
roles/cleanup/tasks/vmware.yml
Normal file
40
roles/cleanup/tasks/vmware.yml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
---
|
||||||
|
- name: Clean vCenter VM
|
||||||
|
when: hypervisor == "vmware"
|
||||||
|
delegate_to: localhost
|
||||||
|
become: false
|
||||||
|
block:
|
||||||
|
- name: Remove CD-ROM from VM in vCenter
|
||||||
|
when: hypervisor == "vmware"
|
||||||
|
community.vmware.vmware_guest:
|
||||||
|
hostname: "{{ hypervisor_url }}"
|
||||||
|
username: "{{ hypervisor_username }}"
|
||||||
|
password: "{{ hypervisor_password }}"
|
||||||
|
validate_certs: false
|
||||||
|
datacenter: "{{ hypervisor_datacenter }}"
|
||||||
|
name: "{{ hostname }}"
|
||||||
|
cdrom:
|
||||||
|
- controller_number: 0
|
||||||
|
unit_number: 0
|
||||||
|
controller_type: sata
|
||||||
|
type: iso
|
||||||
|
iso_path: "{{ boot_iso }}"
|
||||||
|
state: absent
|
||||||
|
- controller_number: 0
|
||||||
|
unit_number: 1
|
||||||
|
controller_type: sata
|
||||||
|
type: iso
|
||||||
|
iso_path: "{{ rhel_iso | default(omit) }}"
|
||||||
|
state: absent
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Start VM in vCenter
|
||||||
|
when: hypervisor == "vmware"
|
||||||
|
vmware.vmware.vm_powerstate:
|
||||||
|
hostname: "{{ hypervisor_url }}"
|
||||||
|
username: "{{ hypervisor_username }}"
|
||||||
|
password: "{{ hypervisor_password }}"
|
||||||
|
validate_certs: false
|
||||||
|
datacenter: "{{ hypervisor_datacenter }}"
|
||||||
|
name: "{{ hostname }}"
|
||||||
|
state: powered-on
|
||||||
65
roles/configuration/tasks/bootloader.yml
Normal file
65
roles/configuration/tasks/bootloader.yml
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
---
|
||||||
|
- name: Configure Bootloader
|
||||||
|
block:
|
||||||
|
- name: Install Bootloader
|
||||||
|
vars:
|
||||||
|
configuration_use_efibootmgr: "{{ is_rhel | default(false) }}"
|
||||||
|
configuration_efi_dir: >-
|
||||||
|
{{ "/boot/efi" if os | lower in ["ubuntu", "ubuntu-lts"] else "/boot" }}
|
||||||
|
configuration_bootloader_id: >-
|
||||||
|
{{ "ubuntu" if os | lower in ["ubuntu", "ubuntu-lts"] else os }}
|
||||||
|
configuration_efi_vendor: >-
|
||||||
|
{{ "redhat" if os | lower in ["rhel8", "rhel9", "rhel10"] else os | lower }}
|
||||||
|
configuration_efibootmgr_cmd: >-
|
||||||
|
/usr/sbin/efibootmgr -c -L '{{ os }}' -d "{{ install_drive }}" -p 1
|
||||||
|
-l '\efi\EFI\{{ configuration_efi_vendor }}\shimx64.efi'
|
||||||
|
configuration_grub_cmd: >-
|
||||||
|
/usr/sbin/grub-install --target=x86_64-efi
|
||||||
|
--efi-directory={{ configuration_efi_dir }}
|
||||||
|
--bootloader-id={{ configuration_bootloader_id }}
|
||||||
|
configuration_bootloader_cmd: >-
|
||||||
|
{{ configuration_efibootmgr_cmd if configuration_use_efibootmgr else configuration_grub_cmd }}
|
||||||
|
ansible.builtin.command: "arch-chroot /mnt {{ configuration_bootloader_cmd }}"
|
||||||
|
register: configuration_bootloader_result
|
||||||
|
changed_when: configuration_bootloader_result.rc == 0
|
||||||
|
|
||||||
|
- name: Ensure lvm2 for non btrfs filesystems
|
||||||
|
when: os | lower == "archlinux" and filesystem != "btrfs"
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /mnt/etc/mkinitcpio.conf
|
||||||
|
regexp: "^(HOOKS=.*block)(?!.*lvm2)(.*)"
|
||||||
|
line: '\1 lvm2\2'
|
||||||
|
backrefs: true
|
||||||
|
|
||||||
|
- name: Regenerate initramfs
|
||||||
|
vars:
|
||||||
|
configuration_initramfs_cmd: >-
|
||||||
|
{{
|
||||||
|
'/usr/sbin/mkinitcpio -P'
|
||||||
|
if os | lower == "archlinux"
|
||||||
|
else (
|
||||||
|
'/usr/sbin/update-initramfs -u -k all'
|
||||||
|
if is_debian | default(false)
|
||||||
|
else '/usr/bin/dracut --regenerate-all --force'
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
ansible.builtin.command: "arch-chroot /mnt {{ configuration_initramfs_cmd }}"
|
||||||
|
register: configuration_initramfs_result
|
||||||
|
changed_when: configuration_initramfs_result.rc == 0
|
||||||
|
|
||||||
|
- name: Generate grub config
|
||||||
|
vars:
|
||||||
|
configuration_efi_vendor: >-
|
||||||
|
{{ "redhat" if os | lower in ["rhel8", "rhel9", "rhel10"] else os | lower }}
|
||||||
|
configuration_grub_cfg_cmd: >-
|
||||||
|
{{ '/usr/sbin/grub2-mkconfig -o /boot/efi/EFI/' + configuration_efi_vendor + '/grub.cfg'
|
||||||
|
if is_rhel | default(false)
|
||||||
|
else '/usr/sbin/grub-mkconfig -o ' + (
|
||||||
|
'/boot/efi/EFI/ubuntu/grub.cfg'
|
||||||
|
if os | lower in ["ubuntu", "ubuntu-lts"]
|
||||||
|
else '/boot/grub/grub.cfg'
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
ansible.builtin.command: "arch-chroot /mnt {{ configuration_grub_cfg_cmd }}"
|
||||||
|
register: configuration_grub_result
|
||||||
|
changed_when: configuration_grub_result.rc == 0
|
||||||
365
roles/configuration/tasks/encryption.yml
Normal file
365
roles/configuration/tasks/encryption.yml
Normal file
@@ -0,0 +1,365 @@
|
|||||||
|
---
|
||||||
|
- name: Configure disk encryption
|
||||||
|
when: partitioning_luks_enabled | default(luks_enabled | default(false)) | bool
|
||||||
|
vars:
|
||||||
|
configuration_luks_passphrase_effective: >-
|
||||||
|
{{ (partitioning_luks_passphrase | default(luks_passphrase | default(''))) | string }}
|
||||||
|
block:
|
||||||
|
- name: Set LUKS configuration facts
|
||||||
|
vars:
|
||||||
|
configuration_luks_mapper_name_value: >-
|
||||||
|
{{
|
||||||
|
partitioning_luks_mapper_name
|
||||||
|
| default(luks_mapper_name | default('SYSTEM_DECRYPTED'))
|
||||||
|
}}
|
||||||
|
configuration_luks_device_value: >-
|
||||||
|
{{
|
||||||
|
partitioning_luks_device
|
||||||
|
| default(
|
||||||
|
install_drive
|
||||||
|
~ (partitioning_main_partition_suffix | default(2) | string)
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
configuration_luks_tpm2_pcrs_raw: >-
|
||||||
|
{{ partitioning_luks_tpm2_pcrs | default(luks_tpm2_pcrs | default('')) }}
|
||||||
|
configuration_luks_tpm2_pcrs_effective_value: >-
|
||||||
|
{{
|
||||||
|
(
|
||||||
|
configuration_luks_tpm2_pcrs_raw
|
||||||
|
if configuration_luks_tpm2_pcrs_raw is string
|
||||||
|
else (configuration_luks_tpm2_pcrs_raw | map('string') | join('+'))
|
||||||
|
)
|
||||||
|
| string
|
||||||
|
| replace(',', '+')
|
||||||
|
| regex_replace('\\s+', '')
|
||||||
|
| regex_replace('^\\+|\\+$', '')
|
||||||
|
}}
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
configuration_luks_mapper_name: "{{ configuration_luks_mapper_name_value }}"
|
||||||
|
configuration_luks_uuid: "{{ partitioning_luks_uuid | default('') }}"
|
||||||
|
configuration_luks_device: "{{ configuration_luks_device_value }}"
|
||||||
|
configuration_luks_options: >-
|
||||||
|
{{ partitioning_luks_options | default(luks_options | default('discard,tries=3')) }}
|
||||||
|
configuration_luks_auto_method: >-
|
||||||
|
{{
|
||||||
|
(partitioning_luks_auto_decrypt | default(luks_auto_decrypt | default(true)) | bool)
|
||||||
|
| ternary(
|
||||||
|
partitioning_luks_auto_decrypt_method | default(luks_auto_decrypt_method | default('tpm2')),
|
||||||
|
'manual'
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
configuration_luks_tpm2_device: >-
|
||||||
|
{{ partitioning_luks_tpm2_device | default(luks_tpm2_device | default('auto')) }}
|
||||||
|
configuration_luks_tpm2_pcrs: "{{ configuration_luks_tpm2_pcrs_raw }}"
|
||||||
|
configuration_luks_tpm2_pcrs_effective: "{{ configuration_luks_tpm2_pcrs_effective_value }}"
|
||||||
|
configuration_luks_keyfile_path: >-
|
||||||
|
/etc/cryptsetup-keys.d/{{ configuration_luks_mapper_name_value }}.key
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Validate LUKS UUID is available
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- configuration_luks_uuid | length > 0
|
||||||
|
fail_msg: LUKS UUID not available. Ensure partitioning ran before configuration.
|
||||||
|
|
||||||
|
- name: Validate LUKS passphrase for auto-decrypt
|
||||||
|
when: configuration_luks_auto_method in ['tpm2', 'keyfile']
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- configuration_luks_passphrase_effective | length > 0
|
||||||
|
fail_msg: luks_passphrase (or partitioning_luks_passphrase) must be set for LUKS auto-decrypt.
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
- name: Enroll TPM2 for LUKS
|
||||||
|
when: configuration_luks_auto_method == 'tpm2'
|
||||||
|
ansible.builtin.include_tasks: encryption/tpm2.yml
|
||||||
|
|
||||||
|
- name: Configure LUKS keyfile auto-decrypt
|
||||||
|
when: configuration_luks_auto_method == 'keyfile'
|
||||||
|
ansible.builtin.include_tasks: encryption/keyfile.yml
|
||||||
|
|
||||||
|
- name: Build LUKS parameters
|
||||||
|
vars:
|
||||||
|
configuration_luks_keyfile_in_use_value: "{{ configuration_luks_auto_method == 'keyfile' }}"
|
||||||
|
configuration_luks_option_list_value: >-
|
||||||
|
{{
|
||||||
|
(configuration_luks_options | trim).split(',')
|
||||||
|
if configuration_luks_options | trim | length > 0
|
||||||
|
else []
|
||||||
|
}}
|
||||||
|
configuration_luks_tpm2_option_list_value: >-
|
||||||
|
{{
|
||||||
|
(configuration_luks_auto_method == 'tpm2')
|
||||||
|
| ternary(
|
||||||
|
['tpm2-device=' + configuration_luks_tpm2_device]
|
||||||
|
+ (['tpm2-pcrs=' + configuration_luks_tpm2_pcrs_effective]
|
||||||
|
if configuration_luks_tpm2_pcrs_effective | length > 0 else []),
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
configuration_luks_crypttab_keyfile_value: >-
|
||||||
|
{{ configuration_luks_keyfile_path if configuration_luks_keyfile_in_use_value else 'none' }}
|
||||||
|
configuration_luks_crypttab_options_value: >-
|
||||||
|
{{
|
||||||
|
(['luks'] + configuration_luks_option_list_value + configuration_luks_tpm2_option_list_value)
|
||||||
|
| join(',')
|
||||||
|
}}
|
||||||
|
configuration_luks_rd_options_value: >-
|
||||||
|
{{ (configuration_luks_option_list_value + configuration_luks_tpm2_option_list_value) | join(',') }}
|
||||||
|
configuration_luks_kernel_args_value: >-
|
||||||
|
{{
|
||||||
|
(
|
||||||
|
['rd.luks.name=' + configuration_luks_uuid + '=' + configuration_luks_mapper_name]
|
||||||
|
+ (
|
||||||
|
['rd.luks.options=' + configuration_luks_uuid + '=' + configuration_luks_rd_options_value]
|
||||||
|
if configuration_luks_rd_options_value | length > 0 else []
|
||||||
|
)
|
||||||
|
+ (
|
||||||
|
['rd.luks.key=' + configuration_luks_uuid + '=' + configuration_luks_keyfile_path]
|
||||||
|
if configuration_luks_keyfile_in_use_value else []
|
||||||
|
)
|
||||||
|
) | join(' ')
|
||||||
|
}}
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
configuration_luks_keyfile_in_use: "{{ configuration_luks_keyfile_in_use_value }}"
|
||||||
|
configuration_luks_option_list: "{{ configuration_luks_option_list_value }}"
|
||||||
|
configuration_luks_tpm2_option_list: "{{ configuration_luks_tpm2_option_list_value }}"
|
||||||
|
configuration_luks_crypttab_keyfile: "{{ configuration_luks_crypttab_keyfile_value }}"
|
||||||
|
configuration_luks_crypttab_options: "{{ configuration_luks_crypttab_options_value }}"
|
||||||
|
configuration_luks_rd_options: "{{ configuration_luks_rd_options_value }}"
|
||||||
|
configuration_luks_kernel_args: "{{ configuration_luks_kernel_args_value }}"
|
||||||
|
|
||||||
|
- name: Remove LUKS keyfile if TPM2 auto-decrypt is active
|
||||||
|
when: configuration_luks_auto_method == 'tpm2'
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /mnt{{ configuration_luks_keyfile_path }}
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Write crypttab entry
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /mnt/etc/crypttab
|
||||||
|
regexp: "^{{ configuration_luks_mapper_name }}\\s"
|
||||||
|
line: >-
|
||||||
|
{{ configuration_luks_mapper_name }} UUID={{ configuration_luks_uuid }}
|
||||||
|
{{ configuration_luks_crypttab_keyfile }} {{ configuration_luks_crypttab_options }}
|
||||||
|
create: true
|
||||||
|
mode: "0600"
|
||||||
|
|
||||||
|
- name: Ensure keyfile pattern for initramfs-tools
|
||||||
|
when:
|
||||||
|
- is_debian | default(false)
|
||||||
|
- configuration_luks_keyfile_in_use
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /mnt/etc/cryptsetup-initramfs/conf-hook
|
||||||
|
regexp: '^KEYFILE_PATTERN='
|
||||||
|
line: 'KEYFILE_PATTERN=/etc/cryptsetup-keys.d/*.key'
|
||||||
|
create: true
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Configure mkinitcpio hooks for LUKS
|
||||||
|
when: os | lower == 'archlinux'
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /mnt/etc/mkinitcpio.conf
|
||||||
|
regexp: '^HOOKS='
|
||||||
|
line: >-
|
||||||
|
HOOKS=(base systemd autodetect microcode modconf kms keyboard sd-vconsole
|
||||||
|
block sd-encrypt lvm2 filesystems fsck)
|
||||||
|
|
||||||
|
- name: Read mkinitcpio configuration
|
||||||
|
when: os | lower == 'archlinux'
|
||||||
|
ansible.builtin.slurp:
|
||||||
|
src: /mnt/etc/mkinitcpio.conf
|
||||||
|
register: configuration_mkinitcpio_slurp
|
||||||
|
|
||||||
|
- name: Build mkinitcpio FILES list
|
||||||
|
when: os | lower == 'archlinux'
|
||||||
|
vars:
|
||||||
|
configuration_mkinitcpio_files_list_value: >-
|
||||||
|
{{
|
||||||
|
(
|
||||||
|
configuration_mkinitcpio_slurp.content | b64decode
|
||||||
|
| regex_findall('^FILES=\\(([^)]*)\\)', multiline=True)
|
||||||
|
| default([])
|
||||||
|
| first
|
||||||
|
| default('')
|
||||||
|
).split()
|
||||||
|
}}
|
||||||
|
configuration_mkinitcpio_files_list_new_value: >-
|
||||||
|
{{
|
||||||
|
(
|
||||||
|
(configuration_mkinitcpio_files_list_value + [configuration_luks_keyfile_path])
|
||||||
|
if configuration_luks_keyfile_in_use
|
||||||
|
else (
|
||||||
|
configuration_mkinitcpio_files_list_value
|
||||||
|
| reject('equalto', configuration_luks_keyfile_path)
|
||||||
|
| list
|
||||||
|
)
|
||||||
|
)
|
||||||
|
| unique
|
||||||
|
}}
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
configuration_mkinitcpio_files_list_new: "{{ configuration_mkinitcpio_files_list_new_value }}"
|
||||||
|
|
||||||
|
- name: Configure mkinitcpio FILES list
|
||||||
|
when: os | lower == 'archlinux'
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /mnt/etc/mkinitcpio.conf
|
||||||
|
regexp: '^FILES='
|
||||||
|
line: >-
|
||||||
|
FILES=({{
|
||||||
|
configuration_mkinitcpio_files_list_new | join(' ')
|
||||||
|
}})
|
||||||
|
|
||||||
|
- name: Ensure dracut config directory exists
|
||||||
|
when: is_rhel | default(false)
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /mnt/etc/dracut.conf.d
|
||||||
|
state: directory
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Configure dracut for LUKS
|
||||||
|
when: is_rhel | default(false)
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /mnt/etc/dracut.conf.d/crypt.conf
|
||||||
|
content: |
|
||||||
|
add_dracutmodules+=" crypt "
|
||||||
|
{% if configuration_luks_keyfile_in_use %}
|
||||||
|
install_items+=" {{ configuration_luks_keyfile_path }} "
|
||||||
|
{% endif %}
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Read kernel cmdline defaults
|
||||||
|
when: is_rhel | default(false)
|
||||||
|
ansible.builtin.slurp:
|
||||||
|
src: /mnt/etc/kernel/cmdline
|
||||||
|
register: configuration_kernel_cmdline_slurp
|
||||||
|
|
||||||
|
- name: Build kernel cmdline with LUKS args
|
||||||
|
when: is_rhel | default(false)
|
||||||
|
vars:
|
||||||
|
configuration_kernel_cmdline_current_value: >-
|
||||||
|
{{ configuration_kernel_cmdline_slurp.content | b64decode | trim }}
|
||||||
|
configuration_kernel_cmdline_list_value: >-
|
||||||
|
{{
|
||||||
|
configuration_kernel_cmdline_current_value.split()
|
||||||
|
if configuration_kernel_cmdline_current_value | length > 0 else []
|
||||||
|
}}
|
||||||
|
configuration_kernel_cmdline_filtered_value: >-
|
||||||
|
{{
|
||||||
|
configuration_kernel_cmdline_list_value
|
||||||
|
| reject('match', '^rd\\.luks\\.(name|options|key)=' ~ configuration_luks_uuid ~ '=')
|
||||||
|
| list
|
||||||
|
}}
|
||||||
|
configuration_kernel_cmdline_new_value: >-
|
||||||
|
{{
|
||||||
|
(configuration_kernel_cmdline_filtered_value + configuration_luks_kernel_args.split())
|
||||||
|
| unique
|
||||||
|
| join(' ')
|
||||||
|
}}
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
configuration_kernel_cmdline_new: "{{ configuration_kernel_cmdline_new_value }}"
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Write kernel cmdline with LUKS args
|
||||||
|
when: is_rhel | default(false)
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /mnt/etc/kernel/cmdline
|
||||||
|
mode: "0644"
|
||||||
|
content: "{{ configuration_kernel_cmdline_new }}\n"
|
||||||
|
|
||||||
|
- name: Find BLS entries
|
||||||
|
when: is_rhel | default(false)
|
||||||
|
ansible.builtin.find:
|
||||||
|
paths: /mnt/boot/loader/entries
|
||||||
|
patterns: "*.conf"
|
||||||
|
register: configuration_kernel_bls_entries
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Update BLS options with LUKS args
|
||||||
|
when:
|
||||||
|
- is_rhel | default(false)
|
||||||
|
- configuration_kernel_bls_entries.files | length > 0
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: "{{ item.path }}"
|
||||||
|
regexp: '^options '
|
||||||
|
line: "options {{ configuration_kernel_cmdline_new }}"
|
||||||
|
loop: "{{ configuration_kernel_bls_entries.files }}"
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item.path }}"
|
||||||
|
|
||||||
|
- name: Read grub defaults
|
||||||
|
when: not is_rhel | default(false)
|
||||||
|
ansible.builtin.slurp:
|
||||||
|
src: /mnt/etc/default/grub
|
||||||
|
register: configuration_grub_slurp
|
||||||
|
|
||||||
|
- name: Build grub command lines with LUKS args
|
||||||
|
when: not is_rhel | default(false)
|
||||||
|
vars:
|
||||||
|
configuration_grub_content_value: "{{ configuration_grub_slurp.content | b64decode }}"
|
||||||
|
configuration_grub_cmdline_linux_value: >-
|
||||||
|
{{
|
||||||
|
configuration_grub_content_value
|
||||||
|
| regex_findall('^GRUB_CMDLINE_LINUX=\"(.*)\"', multiline=True)
|
||||||
|
| default([])
|
||||||
|
| first
|
||||||
|
| default('')
|
||||||
|
}}
|
||||||
|
configuration_grub_cmdline_default_value: >-
|
||||||
|
{{
|
||||||
|
configuration_grub_content_value
|
||||||
|
| regex_findall('^GRUB_CMDLINE_LINUX_DEFAULT=\"(.*)\"', multiline=True)
|
||||||
|
| default([])
|
||||||
|
| first
|
||||||
|
| default('')
|
||||||
|
}}
|
||||||
|
configuration_grub_cmdline_linux_list_value: >-
|
||||||
|
{{
|
||||||
|
configuration_grub_cmdline_linux_value.split()
|
||||||
|
if configuration_grub_cmdline_linux_value | length > 0 else []
|
||||||
|
}}
|
||||||
|
configuration_grub_cmdline_default_list_value: >-
|
||||||
|
{{
|
||||||
|
configuration_grub_cmdline_default_value.split()
|
||||||
|
if configuration_grub_cmdline_default_value | length > 0 else []
|
||||||
|
}}
|
||||||
|
configuration_luks_kernel_args_list_value: "{{ configuration_luks_kernel_args.split() }}"
|
||||||
|
configuration_grub_cmdline_linux_new_value: >-
|
||||||
|
{{
|
||||||
|
(
|
||||||
|
(
|
||||||
|
configuration_grub_cmdline_linux_list_value
|
||||||
|
| reject('match', '^rd\\.luks\\.(name|options|key)=' ~ configuration_luks_uuid ~ '=')
|
||||||
|
| list
|
||||||
|
)
|
||||||
|
+ configuration_luks_kernel_args_list_value
|
||||||
|
)
|
||||||
|
| unique
|
||||||
|
| join(' ')
|
||||||
|
}}
|
||||||
|
configuration_grub_cmdline_default_new_value: >-
|
||||||
|
{{
|
||||||
|
(
|
||||||
|
(
|
||||||
|
configuration_grub_cmdline_default_list_value
|
||||||
|
| reject('match', '^rd\\.luks\\.(name|options|key)=' ~ configuration_luks_uuid ~ '=')
|
||||||
|
| list
|
||||||
|
)
|
||||||
|
+ configuration_luks_kernel_args_list_value
|
||||||
|
)
|
||||||
|
| unique
|
||||||
|
| join(' ')
|
||||||
|
}}
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
configuration_grub_content: "{{ configuration_grub_content_value }}"
|
||||||
|
configuration_grub_cmdline_linux: "{{ configuration_grub_cmdline_linux_value }}"
|
||||||
|
configuration_grub_cmdline_default: "{{ configuration_grub_cmdline_default_value }}"
|
||||||
|
configuration_grub_cmdline_linux_new: "{{ configuration_grub_cmdline_linux_new_value }}"
|
||||||
|
configuration_grub_cmdline_default_new: "{{ configuration_grub_cmdline_default_new_value }}"
|
||||||
|
|
||||||
|
- name: Update GRUB_CMDLINE_LINUX_DEFAULT for LUKS
|
||||||
|
when: not is_rhel | default(false)
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /mnt/etc/default/grub
|
||||||
|
regexp: '^GRUB_CMDLINE_LINUX_DEFAULT='
|
||||||
|
line: 'GRUB_CMDLINE_LINUX_DEFAULT="{{ configuration_grub_cmdline_default_new }}"'
|
||||||
110
roles/configuration/tasks/encryption/keyfile.yml
Normal file
110
roles/configuration/tasks/encryption/keyfile.yml
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
---
|
||||||
|
- name: Configure LUKS keyfile auto-decrypt
|
||||||
|
block:
|
||||||
|
- name: Ensure cryptsetup key directory exists
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /mnt/etc/cryptsetup-keys.d
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0700"
|
||||||
|
|
||||||
|
- name: Ensure LUKS keyfile exists
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /mnt{{ configuration_luks_keyfile_path }}
|
||||||
|
content: >-
|
||||||
|
{{
|
||||||
|
lookup(
|
||||||
|
'community.general.random_string',
|
||||||
|
length=(partitioning_luks_keyfile_size | default(luks_keyfile_size | default(64)) | int),
|
||||||
|
override_all='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0600"
|
||||||
|
force: false
|
||||||
|
register: configuration_luks_keyfile_copy
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
- name: Ensure keyfile permissions
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /mnt{{ configuration_luks_keyfile_path }}
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0600"
|
||||||
|
|
||||||
|
- name: Check whether keyfile already unlocks the LUKS device
|
||||||
|
ansible.builtin.command:
|
||||||
|
argv:
|
||||||
|
- cryptsetup
|
||||||
|
- luksOpen
|
||||||
|
- --test-passphrase
|
||||||
|
- --key-file
|
||||||
|
- "/mnt{{ configuration_luks_keyfile_path }}"
|
||||||
|
- "{{ configuration_luks_device }}"
|
||||||
|
register: configuration_luks_keyfile_unlock_test
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
- name: Add keyfile to LUKS header
|
||||||
|
when: configuration_luks_keyfile_unlock_test.rc != 0
|
||||||
|
community.crypto.luks_device:
|
||||||
|
device: "{{ configuration_luks_device }}"
|
||||||
|
passphrase: "{{ configuration_luks_passphrase_effective }}"
|
||||||
|
new_keyfile: "/mnt{{ configuration_luks_keyfile_path }}"
|
||||||
|
register: configuration_luks_addkey_result
|
||||||
|
failed_when: false
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
- name: Regenerate keyfile and retry adding to LUKS header
|
||||||
|
when:
|
||||||
|
- configuration_luks_keyfile_unlock_test.rc != 0
|
||||||
|
- configuration_luks_keyfile_copy.changed | default(false) | bool
|
||||||
|
- configuration_luks_addkey_result is failed
|
||||||
|
block:
|
||||||
|
- name: Regenerate LUKS keyfile
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /mnt{{ configuration_luks_keyfile_path }}
|
||||||
|
content: >-
|
||||||
|
{{
|
||||||
|
lookup(
|
||||||
|
'community.general.random_string',
|
||||||
|
length=(partitioning_luks_keyfile_size | default(luks_keyfile_size | default(64)) | int),
|
||||||
|
override_all='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0600"
|
||||||
|
force: true
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
- name: Retry adding keyfile to LUKS header
|
||||||
|
community.crypto.luks_device:
|
||||||
|
device: "{{ configuration_luks_device }}"
|
||||||
|
passphrase: "{{ configuration_luks_passphrase_effective }}"
|
||||||
|
new_keyfile: "/mnt{{ configuration_luks_keyfile_path }}"
|
||||||
|
register: configuration_luks_addkey_retry
|
||||||
|
failed_when: false
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
- name: Re-check whether keyfile unlocks the LUKS device
|
||||||
|
ansible.builtin.command:
|
||||||
|
argv:
|
||||||
|
- cryptsetup
|
||||||
|
- luksOpen
|
||||||
|
- --test-passphrase
|
||||||
|
- --key-file
|
||||||
|
- "/mnt{{ configuration_luks_keyfile_path }}"
|
||||||
|
- "{{ configuration_luks_device }}"
|
||||||
|
register: configuration_luks_keyfile_unlock_test_after
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
- name: Fallback to manual LUKS unlock if keyfile enrollment failed
|
||||||
|
when: (configuration_luks_keyfile_unlock_test_after.rc | default(1)) != 0
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
configuration_luks_auto_method: manual
|
||||||
90
roles/configuration/tasks/encryption/tpm2.yml
Normal file
90
roles/configuration/tasks/encryption/tpm2.yml
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
---
|
||||||
|
- name: Enroll TPM2 for LUKS
|
||||||
|
block:
|
||||||
|
- name: Create temporary passphrase file for TPM2 enrollment
|
||||||
|
ansible.builtin.tempfile:
|
||||||
|
path: /mnt/tmp
|
||||||
|
prefix: luks-passphrase-
|
||||||
|
state: file
|
||||||
|
register: configuration_luks_tpm2_passphrase_tempfile
|
||||||
|
|
||||||
|
- name: Write passphrase into temporary file for TPM2 enrollment
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: "{{ configuration_luks_tpm2_passphrase_tempfile.path }}"
|
||||||
|
content: "{{ configuration_luks_passphrase_effective }}"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0600"
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
- name: Enroll TPM2 token
|
||||||
|
vars:
|
||||||
|
configuration_luks_enroll_args: >-
|
||||||
|
{{
|
||||||
|
[
|
||||||
|
'/usr/bin/systemd-cryptenroll',
|
||||||
|
'--tpm2-device=' + configuration_luks_tpm2_device,
|
||||||
|
'--tpm2-with-pin=false',
|
||||||
|
'--wipe-slot=tpm2',
|
||||||
|
'--unlock-key-file=' + (
|
||||||
|
configuration_luks_tpm2_passphrase_tempfile.path
|
||||||
|
| regex_replace('^/mnt', '')
|
||||||
|
)
|
||||||
|
]
|
||||||
|
+ (['--tpm2-pcrs=' + configuration_luks_tpm2_pcrs_effective]
|
||||||
|
if configuration_luks_tpm2_pcrs_effective | length > 0 else [])
|
||||||
|
+ [configuration_luks_device]
|
||||||
|
}}
|
||||||
|
configuration_luks_enroll_chroot_args: "{{ ['arch-chroot', '/mnt'] + configuration_luks_enroll_args }}"
|
||||||
|
ansible.builtin.command:
|
||||||
|
argv: "{{ configuration_luks_enroll_chroot_args }}"
|
||||||
|
register: configuration_luks_tpm2_enroll_chroot
|
||||||
|
changed_when: configuration_luks_tpm2_enroll_chroot.rc == 0
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Retry TPM2 enrollment in installer environment
|
||||||
|
when:
|
||||||
|
- (configuration_luks_tpm2_enroll_chroot.rc | default(1)) != 0
|
||||||
|
vars:
|
||||||
|
configuration_luks_enroll_args: >-
|
||||||
|
{{
|
||||||
|
[
|
||||||
|
'/usr/bin/systemd-cryptenroll',
|
||||||
|
'--tpm2-device=' + configuration_luks_tpm2_device,
|
||||||
|
'--tpm2-with-pin=false',
|
||||||
|
'--wipe-slot=tpm2',
|
||||||
|
'--unlock-key-file=' + configuration_luks_tpm2_passphrase_tempfile.path
|
||||||
|
]
|
||||||
|
+ (['--tpm2-pcrs=' + configuration_luks_tpm2_pcrs_effective]
|
||||||
|
if configuration_luks_tpm2_pcrs_effective | length > 0 else [])
|
||||||
|
+ [configuration_luks_device]
|
||||||
|
}}
|
||||||
|
ansible.builtin.command:
|
||||||
|
argv: "{{ configuration_luks_enroll_args }}"
|
||||||
|
register: configuration_luks_tpm2_enroll_host
|
||||||
|
changed_when: configuration_luks_tpm2_enroll_host.rc == 0
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Validate TPM2 enrollment succeeded
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- >-
|
||||||
|
(configuration_luks_tpm2_enroll_chroot.rc | default(1)) == 0
|
||||||
|
or (configuration_luks_tpm2_enroll_host.rc | default(1)) == 0
|
||||||
|
fail_msg: >-
|
||||||
|
TPM2 enrollment failed.
|
||||||
|
chroot rc={{ configuration_luks_tpm2_enroll_chroot.rc | default('n/a') }},
|
||||||
|
host rc={{ configuration_luks_tpm2_enroll_host.rc | default('n/a') }},
|
||||||
|
chroot stderr={{ configuration_luks_tpm2_enroll_chroot.stderr | default('') }},
|
||||||
|
host stderr={{ configuration_luks_tpm2_enroll_host.stderr | default('') }}
|
||||||
|
rescue:
|
||||||
|
- name: Fallback to keyfile auto-decrypt
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
configuration_luks_auto_method: keyfile
|
||||||
|
always:
|
||||||
|
- name: Remove TPM2 enrollment passphrase file
|
||||||
|
when: configuration_luks_tpm2_passphrase_tempfile.path is defined
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ configuration_luks_tpm2_passphrase_tempfile.path }}"
|
||||||
|
state: absent
|
||||||
|
changed_when: false
|
||||||
69
roles/configuration/tasks/extras.yml
Normal file
69
roles/configuration/tasks/extras.yml
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
---
|
||||||
|
- name: Append vim configurations to vimrc
|
||||||
|
ansible.builtin.blockinfile:
|
||||||
|
path: "{{ '/mnt/etc/vim/vimrc' if is_debian | default(false) else '/mnt/etc/vimrc' }}"
|
||||||
|
block: |
|
||||||
|
set encoding=utf-8
|
||||||
|
set number
|
||||||
|
set autoindent
|
||||||
|
set smartindent
|
||||||
|
set mouse=a
|
||||||
|
insertafter: EOF
|
||||||
|
marker: ""
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Add memory tuning parameters
|
||||||
|
ansible.builtin.blockinfile:
|
||||||
|
path: /mnt/etc/sysctl.d/90-memory.conf
|
||||||
|
create: true
|
||||||
|
block: |
|
||||||
|
vm.swappiness=10
|
||||||
|
vm.vfs_cache_pressure=50
|
||||||
|
vm.dirty_background_ratio=1
|
||||||
|
vm.dirty_ratio=10
|
||||||
|
vm.page-cluster=10
|
||||||
|
marker: ""
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Create zram config
|
||||||
|
when: os | lower not in ['debian11', 'rhel8']
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /mnt/etc/systemd/zram-generator.conf
|
||||||
|
content: |
|
||||||
|
[zram0]
|
||||||
|
zram-size = ram / 2
|
||||||
|
compression-algorithm = zstd
|
||||||
|
swap-priority = 100
|
||||||
|
fs-type = swap
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Copy Custom Shell config
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: custom.sh.j2
|
||||||
|
dest: /mnt/etc/profile.d/custom.sh
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Create login banner
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: "{{ item }}"
|
||||||
|
content: |
|
||||||
|
**************************************************************
|
||||||
|
* WARNING: Unauthorized access to this system is prohibited. *
|
||||||
|
* All activities are monitored and logged. *
|
||||||
|
* Disconnect immediately if you are not an authorized user. *
|
||||||
|
**************************************************************
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
loop:
|
||||||
|
- /mnt/etc/issue
|
||||||
|
- /mnt/etc/issue.net
|
||||||
|
|
||||||
|
- name: Remove motd files
|
||||||
|
when: os | lower in ["rhel8", "rhel9", "rhel10"]
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: absent
|
||||||
|
loop:
|
||||||
|
- /mnt/etc/motd.d/cockpit
|
||||||
|
- /mnt/etc/motd.d/insights-client
|
||||||
65
roles/configuration/tasks/fstab.yml
Normal file
65
roles/configuration/tasks/fstab.yml
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
---
|
||||||
|
- name: Generate fstab content
|
||||||
|
ansible.builtin.command:
|
||||||
|
argv:
|
||||||
|
- genfstab
|
||||||
|
- -LU
|
||||||
|
- /mnt
|
||||||
|
register: configuration_fstab_result
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Write fstab
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /mnt/etc/fstab
|
||||||
|
content: "{{ configuration_fstab_result.stdout }}\n"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Remove deprecated attr2 and disable large extent
|
||||||
|
when: os | lower in ["almalinux", "rhel8", "rhel9", "rhel10", "rocky"] and filesystem == "xfs"
|
||||||
|
ansible.builtin.replace:
|
||||||
|
path: /mnt/etc/fstab
|
||||||
|
regexp: "(xfs.*?)(attr2)"
|
||||||
|
replace: '\1allocsize=64m'
|
||||||
|
|
||||||
|
- name: Replace ISO UUID entry with /dev/sr0 in fstab
|
||||||
|
when: os in ["rhel8", "rhel9", "rhel10"]
|
||||||
|
vars:
|
||||||
|
configuration_fstab_dvd_line: >-
|
||||||
|
{{
|
||||||
|
'/usr/local/install/redhat/rhel.iso /usr/local/install/redhat/dvd iso9660 loop,nofail 0 0'
|
||||||
|
if hypervisor == 'vmware'
|
||||||
|
else '/dev/sr0 /usr/local/install/redhat/dvd iso9660 ro,relatime,nojoliet,check=s,map=n,nofail 0 0'
|
||||||
|
}}
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /mnt/etc/fstab
|
||||||
|
regexp: '^.*\/dvd.*$'
|
||||||
|
line: "{{ configuration_fstab_dvd_line }}"
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Write image from RHEL ISO to the target machine
|
||||||
|
when: os in ["rhel8", "rhel9", "rhel10"] and hypervisor == 'vmware'
|
||||||
|
ansible.builtin.command:
|
||||||
|
argv:
|
||||||
|
- dd
|
||||||
|
- if=/dev/sr1
|
||||||
|
- of=/mnt/usr/local/install/redhat/rhel.iso
|
||||||
|
- bs=4M
|
||||||
|
creates: /mnt/usr/local/install/redhat/rhel.iso
|
||||||
|
register: configuration_rhel_iso_result
|
||||||
|
changed_when: configuration_rhel_iso_result.rc == 0
|
||||||
|
|
||||||
|
- name: Ensure TempFS is configured in fstab
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /mnt/etc/fstab
|
||||||
|
regexp: "{{ fstab_entry.regexp }}"
|
||||||
|
line: "{{ fstab_entry.line }}"
|
||||||
|
insertafter: EOF
|
||||||
|
loop:
|
||||||
|
- {regexp: '^# TempFS$', line: '# TempFS'}
|
||||||
|
- {regexp: '^tmpfs\\s+/tmp\\s+', line: 'tmpfs /tmp tmpfs defaults,nosuid,nodev,noexec 0 0'}
|
||||||
|
- {regexp: '^tmpfs\\s+/var/tmp\\s+', line: 'tmpfs /var/tmp tmpfs defaults,nosuid,nodev,noexec 0 0'}
|
||||||
|
- {regexp: '^tmpfs\\s+/dev/shm\\s+', line: 'tmpfs /dev/shm tmpfs defaults,nosuid,nodev,noexec 0 0'}
|
||||||
|
loop_control:
|
||||||
|
loop_var: fstab_entry
|
||||||
109
roles/configuration/tasks/grub.yml
Normal file
109
roles/configuration/tasks/grub.yml
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
---
|
||||||
|
- name: Configure grub
|
||||||
|
when: not is_rhel | default(false)
|
||||||
|
block:
|
||||||
|
- name: Add commandline information to grub config
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
dest: /mnt/etc/default/grub
|
||||||
|
regexp: ^GRUB_CMDLINE_LINUX_DEFAULT=
|
||||||
|
line: GRUB_CMDLINE_LINUX_DEFAULT="loglevel=3"
|
||||||
|
|
||||||
|
- name: Change Grub time
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
dest: /mnt/etc/default/grub
|
||||||
|
regexp: ^GRUB_TIMEOUT=
|
||||||
|
line: GRUB_TIMEOUT=1
|
||||||
|
|
||||||
|
- name: Ensure grub defaults file exists for RHEL-based systems
|
||||||
|
when: is_rhel | default(false)
|
||||||
|
block:
|
||||||
|
- name: Build RHEL kernel command line defaults
|
||||||
|
vars:
|
||||||
|
configuration_grub_root_uuid_value: >-
|
||||||
|
{{
|
||||||
|
(
|
||||||
|
partitioning_main_uuid.stdout
|
||||||
|
if (filesystem | lower) == 'btrfs'
|
||||||
|
else (partitioning_uuid_root | default([]) | first | default(''))
|
||||||
|
)
|
||||||
|
| default('')
|
||||||
|
| trim
|
||||||
|
}}
|
||||||
|
configuration_grub_lvm_args_value: >-
|
||||||
|
{{
|
||||||
|
['resume=/dev/mapper/sys-swap', 'rd.lvm.lv=sys/root', 'rd.lvm.lv=sys/swap']
|
||||||
|
if (filesystem | lower) != 'btrfs'
|
||||||
|
else []
|
||||||
|
}}
|
||||||
|
configuration_grub_root_flags_value: >-
|
||||||
|
{{ ['rootflags=subvol=@'] if (filesystem | lower) == 'btrfs' else [] }}
|
||||||
|
configuration_grub_cmdline_linux_base_value: >-
|
||||||
|
{{
|
||||||
|
(['crashkernel=auto'] + configuration_grub_lvm_args_value)
|
||||||
|
| join(' ')
|
||||||
|
}}
|
||||||
|
configuration_grub_kernel_cmdline_base_value: >-
|
||||||
|
{{
|
||||||
|
(
|
||||||
|
(['root=UUID=' + configuration_grub_root_uuid_value]
|
||||||
|
if configuration_grub_root_uuid_value | length > 0 else [])
|
||||||
|
+ ['ro', 'crashkernel=auto']
|
||||||
|
+ configuration_grub_lvm_args_value
|
||||||
|
+ configuration_grub_root_flags_value
|
||||||
|
)
|
||||||
|
| join(' ')
|
||||||
|
}}
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
configuration_grub_cmdline_linux_base: "{{ configuration_grub_cmdline_linux_base_value }}"
|
||||||
|
configuration_kernel_cmdline_base: "{{ configuration_grub_kernel_cmdline_base_value }}"
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Check if grub defaults file exists
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: /mnt/etc/default/grub
|
||||||
|
register: configuration_grub_defaults_stat
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Create default grub configuration
|
||||||
|
when: not configuration_grub_defaults_stat.stat.exists
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /mnt/etc/default/grub
|
||||||
|
mode: "0644"
|
||||||
|
content: |
|
||||||
|
GRUB_TIMEOUT=5
|
||||||
|
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
|
||||||
|
GRUB_DEFAULT=saved
|
||||||
|
GRUB_DISABLE_SUBMENU=true
|
||||||
|
GRUB_TERMINAL_OUTPUT="console"
|
||||||
|
GRUB_CMDLINE_LINUX="{{ configuration_grub_cmdline_linux_base }}"
|
||||||
|
GRUB_DISABLE_RECOVERY="true"
|
||||||
|
GRUB_ENABLE_BLSCFG=true
|
||||||
|
|
||||||
|
- name: Ensure kernel cmdline directory exists
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /mnt/etc/kernel
|
||||||
|
state: directory
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Write kernel cmdline defaults
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /mnt/etc/kernel/cmdline
|
||||||
|
mode: "0644"
|
||||||
|
content: "{{ configuration_kernel_cmdline_base }}\n"
|
||||||
|
|
||||||
|
- name: Find BLS entries
|
||||||
|
ansible.builtin.find:
|
||||||
|
paths: /mnt/boot/loader/entries
|
||||||
|
patterns: "*.conf"
|
||||||
|
register: configuration_grub_bls_entries
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Update BLS options with kernel cmdline defaults
|
||||||
|
when: configuration_grub_bls_entries.files | length > 0
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: "{{ item.path }}"
|
||||||
|
regexp: '^options '
|
||||||
|
line: "options {{ configuration_kernel_cmdline_base }}"
|
||||||
|
loop: "{{ configuration_grub_bls_entries.files }}"
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item.path }}"
|
||||||
88
roles/configuration/tasks/locales.yml
Normal file
88
roles/configuration/tasks/locales.yml
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
---
|
||||||
|
- name: Set local timezone
|
||||||
|
ansible.builtin.command: "{{ item }}"
|
||||||
|
loop:
|
||||||
|
- systemctl daemon-reload
|
||||||
|
- arch-chroot /mnt ln -sf /usr/share/zoneinfo/Europe/Vienna /etc/localtime
|
||||||
|
register: configuration_timezone_result
|
||||||
|
changed_when: configuration_timezone_result.rc == 0
|
||||||
|
|
||||||
|
- name: Setup locales
|
||||||
|
block:
|
||||||
|
- name: Configure locale.gen
|
||||||
|
when: not is_rhel | default(false)
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
dest: /mnt/etc/locale.gen
|
||||||
|
regexp: "{{ item.regex }}"
|
||||||
|
line: "{{ item.line }}"
|
||||||
|
loop:
|
||||||
|
- {regex: en_US\.UTF-8 UTF-8, line: en_US.UTF-8 UTF-8}
|
||||||
|
|
||||||
|
- name: Generate locales
|
||||||
|
when: not is_rhel | default(false)
|
||||||
|
ansible.builtin.command: arch-chroot /mnt /usr/sbin/locale-gen
|
||||||
|
register: configuration_locale_result
|
||||||
|
changed_when: configuration_locale_result.rc == 0
|
||||||
|
|
||||||
|
- name: Set hostname
|
||||||
|
vars:
|
||||||
|
configuration_hostname_fqdn: >-
|
||||||
|
{{
|
||||||
|
hostname
|
||||||
|
if '.' in hostname
|
||||||
|
else (
|
||||||
|
hostname + '.' + vm_dns_search
|
||||||
|
if vm_dns_search is defined and vm_dns_search | length
|
||||||
|
else hostname
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
ansible.builtin.copy:
|
||||||
|
content: "{{ configuration_hostname_fqdn }}"
|
||||||
|
dest: /mnt/etc/hostname
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Add host entry to /etc/hosts
|
||||||
|
vars:
|
||||||
|
configuration_hostname_fqdn: >-
|
||||||
|
{{
|
||||||
|
hostname
|
||||||
|
if '.' in hostname
|
||||||
|
else (
|
||||||
|
hostname + '.' + vm_dns_search
|
||||||
|
if vm_dns_search is defined and vm_dns_search | length
|
||||||
|
else hostname
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
configuration_hostname_short: "{{ hostname.split('.')[0] }}"
|
||||||
|
configuration_hostname_entries: >-
|
||||||
|
{{ [configuration_hostname_fqdn, configuration_hostname_short] | unique | join(' ') }}
|
||||||
|
configuration_hosts_line: >-
|
||||||
|
{{ vm_ip | default(inventory_hostname) }} {{ configuration_hostname_entries }}
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /mnt/etc/hosts
|
||||||
|
line: "{{ configuration_hosts_line }}"
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Create vconsole.conf
|
||||||
|
ansible.builtin.copy:
|
||||||
|
content: KEYMAP=us
|
||||||
|
dest: /mnt/etc/vconsole.conf
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Create locale.conf
|
||||||
|
ansible.builtin.copy:
|
||||||
|
content: LANG=en_US.UTF-8
|
||||||
|
dest: /mnt/etc/locale.conf
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Ensure SSH password authentication is enabled
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /mnt/etc/ssh/sshd_config
|
||||||
|
regexp: "^#?PasswordAuthentication\\s+"
|
||||||
|
line: "PasswordAuthentication yes"
|
||||||
|
|
||||||
|
- name: SSH permit root login
|
||||||
|
ansible.builtin.replace:
|
||||||
|
path: /mnt/etc/ssh/sshd_config
|
||||||
|
regexp: "^#?PermitRootLogin.*"
|
||||||
|
replace: "PermitRootLogin yes"
|
||||||
@@ -1,324 +1,17 @@
|
|||||||
---
|
---
|
||||||
- name: Configuration
|
- name: Include configuration tasks
|
||||||
block:
|
ansible.builtin.include_tasks: "{{ configuration_task }}"
|
||||||
- name: Generate fstab
|
loop:
|
||||||
ansible.builtin.shell: genfstab -LU /mnt > /mnt/etc/fstab
|
- fstab.yml
|
||||||
changed_when: result.rc == 0
|
- locales.yml
|
||||||
register: result
|
- services.yml
|
||||||
|
- grub.yml
|
||||||
- name: Remove depricated attr2 and disable large extent
|
- encryption.yml
|
||||||
when: os in ["almalinux", "rhel8", "rhel9", "rhel10", "rocky"] and filesystem == "xfs"
|
- bootloader.yml
|
||||||
ansible.builtin.replace:
|
- extras.yml
|
||||||
path: /mnt/etc/fstab
|
- network.yml
|
||||||
regexp: "(xfs.*?)(attr2)"
|
- users.yml
|
||||||
replace: '\1allocsize=64m'
|
- sudo.yml
|
||||||
|
- selinux.yml
|
||||||
- name: Replace ISO UUID entry with /dev/sr0 in fstab
|
loop_control:
|
||||||
when: os in ["rhel8", "rhel9", "rhel10"]
|
loop_var: configuration_task
|
||||||
ansible.builtin.lineinfile:
|
|
||||||
path: /mnt/etc/fstab
|
|
||||||
regexp: '^.*\/dvd.*$'
|
|
||||||
line:
|
|
||||||
"{{ '/usr/local/install/redhat/rhel.iso /usr/local/install/redhat/dvd iso9660 loop,nofail 0 0' if hypervisor == 'vmware'
|
|
||||||
else '/dev/sr0 /usr/local/install/redhat/dvd iso9660 ro,relatime,nojoliet,check=s,map=n,nofail 0 0' }}"
|
|
||||||
state: present
|
|
||||||
backrefs: true
|
|
||||||
|
|
||||||
- name: Write image from RHEL ISO to the target machine
|
|
||||||
when: os in ["rhel8", "rhel9", "rhel10"] and hypervisor == 'vmware'
|
|
||||||
ansible.builtin.command: dd if=/dev/sr1 of=/mnt/usr/local/install/redhat/rhel.iso bs=4M
|
|
||||||
changed_when: result.rc == 0
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Append TempFS to fstab
|
|
||||||
ansible.builtin.lineinfile:
|
|
||||||
path: /mnt/etc/fstab
|
|
||||||
line: "{{ item }}"
|
|
||||||
insertafter: EOF
|
|
||||||
with_items:
|
|
||||||
- ""
|
|
||||||
- "# TempFS"
|
|
||||||
- tmpfs /tmp tmpfs defaults,nosuid,nodev,noexec 0 0
|
|
||||||
- tmpfs /var/tmp tmpfs defaults,nosuid,nodev,noexec 0 0
|
|
||||||
- tmpfs /dev/shm tmpfs defaults,nosuid,nodev,noexec 0 0
|
|
||||||
|
|
||||||
- name: Set local timezone
|
|
||||||
ansible.builtin.command: "{{ item }}"
|
|
||||||
changed_when: result.rc == 0
|
|
||||||
register: result
|
|
||||||
with_items:
|
|
||||||
- systemctl daemon-reload
|
|
||||||
- arch-chroot /mnt ln -sf /usr/share/zoneinfo/Europe/Vienna /etc/localtime
|
|
||||||
|
|
||||||
- name: Setup locales
|
|
||||||
block:
|
|
||||||
- name: Configure locale.gen
|
|
||||||
when: os | lower not in ['almalinux', 'fedora', 'rhel8', 'rhel9', 'rhel10', 'rocky']
|
|
||||||
ansible.builtin.lineinfile:
|
|
||||||
dest: /mnt/etc/locale.gen
|
|
||||||
regexp: "{{ item.regex }}"
|
|
||||||
line: "{{ item.line }}"
|
|
||||||
loop:
|
|
||||||
- { regex: en_US\.UTF-8 UTF-8, line: en_US.UTF-8 UTF-8 }
|
|
||||||
|
|
||||||
- name: Generate locales
|
|
||||||
when: os | lower not in ['almalinux', 'fedora', 'rhel8', 'rhel9', 'rhel10', 'rocky']
|
|
||||||
ansible.builtin.command: arch-chroot /mnt /usr/sbin/locale-gen
|
|
||||||
changed_when: result.rc == 0
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Set hostname
|
|
||||||
ansible.builtin.copy:
|
|
||||||
content: "{{ hostname }}{% if vm_dns_search is defined and vm_dns_search | length %}.{{ vm_dns_search }}{% endif %}"
|
|
||||||
dest: /mnt/etc/hostname
|
|
||||||
mode: "0644"
|
|
||||||
|
|
||||||
- name: Add host entry to /etc/hosts
|
|
||||||
ansible.builtin.lineinfile:
|
|
||||||
path: /mnt/etc/hosts
|
|
||||||
line: "{{ ansible_host }} {{ hostname }}{% if vm_dns_search is defined and vm_dns_search | length %} {{ hostname }}.{{ vm_dns_search }}{% endif %}"
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Create vconsole.conf
|
|
||||||
ansible.builtin.copy:
|
|
||||||
content: KEYMAP=us
|
|
||||||
dest: /mnt/etc/vconsole.conf
|
|
||||||
mode: "0644"
|
|
||||||
|
|
||||||
- name: Create locale.conf
|
|
||||||
ansible.builtin.copy:
|
|
||||||
content: LANG=en_US.UTF-8
|
|
||||||
dest: /mnt/etc/locale.conf
|
|
||||||
mode: "0644"
|
|
||||||
|
|
||||||
- name: SSH permit Password
|
|
||||||
ansible.builtin.replace:
|
|
||||||
path: /mnt/etc/ssh/sshd_config
|
|
||||||
regexp: "#PasswordAuthentication yes"
|
|
||||||
replace: PasswordAuthentication yes
|
|
||||||
|
|
||||||
- name: SSH permit root login
|
|
||||||
ansible.builtin.replace:
|
|
||||||
path: /mnt/etc/ssh/sshd_config
|
|
||||||
regexp: "^#?PermitRootLogin.*"
|
|
||||||
replace: "PermitRootLogin yes"
|
|
||||||
|
|
||||||
- name: Enable Systemd Services
|
|
||||||
ansible.builtin.command: >
|
|
||||||
arch-chroot /mnt systemctl enable NetworkManager
|
|
||||||
{{
|
|
||||||
' ssh' if os | lower in ['ubuntu', 'ubuntu-lts'] else
|
|
||||||
(' sshd' if os | lower not in ['debian11', 'debian12', 'debian13'] else '')
|
|
||||||
}}
|
|
||||||
{{
|
|
||||||
'logrotate systemd-resolved systemd-timesyncd systemd-networkd'
|
|
||||||
if os | lower == 'archlinux' else ''
|
|
||||||
}}
|
|
||||||
changed_when: result.rc == 0
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Configure grub
|
|
||||||
when: os | lower not in ['almalinux', 'fedora', 'rhel8', 'rhel9', 'rhel10', 'rocky']
|
|
||||||
block:
|
|
||||||
- name: Add commandline information to grub config
|
|
||||||
ansible.builtin.lineinfile:
|
|
||||||
dest: /mnt/etc/default/grub
|
|
||||||
regexp: ^GRUB_CMDLINE_LINUX_DEFAULT=
|
|
||||||
line: GRUB_CMDLINE_LINUX_DEFAULT="loglevel=3"
|
|
||||||
|
|
||||||
- name: Change Grub time
|
|
||||||
ansible.builtin.lineinfile:
|
|
||||||
dest: /mnt/etc/default/grub
|
|
||||||
regexp: ^GRUB_TIMEOUT=
|
|
||||||
line: GRUB_TIMEOUT=1
|
|
||||||
|
|
||||||
- name: Configure Bootloader
|
|
||||||
block:
|
|
||||||
- name: Install Bootloader
|
|
||||||
ansible.builtin.command: arch-chroot /mnt
|
|
||||||
{% if os | lower not in ["archlinux", "debian11", "debian12", "debian13", "ubuntu", "ubuntu-lts"] %} /usr/sbin/efibootmgr
|
|
||||||
-c -L '{{ os }}' -d "{{ install_drive }}" -p 1
|
|
||||||
-l '\efi\EFI\{% if os | lower in ["rhel8", "rhel9", "rhel10"] %}redhat{% else %}{{ os | lower }}{% endif %}\shimx64.efi'
|
|
||||||
{% else %}/usr/sbin/grub-install --target=x86_64-efi --efi-directory={{ "/boot/efi" if os | lower in ["ubuntu", "ubuntu-lts"] else "/boot" }}
|
|
||||||
--bootloader-id={{ "ubuntu" if os | lower in ["ubuntu", "ubuntu-lts"] else os }}
|
|
||||||
{% endif %}
|
|
||||||
changed_when: result.rc == 0
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Ensure lvm2 for non btrfs filesystems
|
|
||||||
when: os | lower == "archlinux" and filesystem != "btrfs"
|
|
||||||
ansible.builtin.lineinfile:
|
|
||||||
path: /mnt/etc/mkinitcpio.conf
|
|
||||||
regexp: "^(HOOKS=.*block)(?!.*lvm2)(.*)"
|
|
||||||
line: '\1 lvm2\2'
|
|
||||||
backrefs: true
|
|
||||||
|
|
||||||
- name: Regenerate initramfs
|
|
||||||
when: os | lower not in ["debian11", "debian12", "debian13", "ubuntu", "ubuntu-lts"]
|
|
||||||
ansible.builtin.command: arch-chroot /mnt
|
|
||||||
{% if os | lower == "archlinux" %} /usr/sbin/mkinitcpio -P
|
|
||||||
{% else %} /usr/bin/dracut --regenerate-all --force
|
|
||||||
{% endif %}
|
|
||||||
changed_when: result.rc == 0
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Generate grub config
|
|
||||||
ansible.builtin.command: arch-chroot /mnt
|
|
||||||
{% if os | lower not in ["archlinux", "debian11", "debian12", "debian13", "ubuntu", "ubuntu-lts"] %}
|
|
||||||
/usr/sbin/grub2-mkconfig -o /boot/efi/EFI/{% if os | lower in ["rhel8", "rhel9", "rhel10"] %}redhat{% else %}{{ os | lower }}{% endif %}/grub.cfg
|
|
||||||
{% else %}
|
|
||||||
/usr/sbin/grub-mkconfig -o {{ "/boot/efi/EFI/ubuntu/grub.cfg" if os | lower in ["ubuntu", "ubuntu-lts"] else "/boot/grub/grub.cfg" }}
|
|
||||||
{% endif %}
|
|
||||||
changed_when: result.rc == 0
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Extra Configuration
|
|
||||||
block:
|
|
||||||
- name: Append vim configurations to vimrc
|
|
||||||
failed_when: false
|
|
||||||
ansible.builtin.blockinfile:
|
|
||||||
path:
|
|
||||||
"{{ '/mnt/etc/vim/vimrc' if os | lower in ['debian11', 'debian12', 'debian13', 'ubuntu', 'ubuntu-lts']
|
|
||||||
else '/mnt/etc/vimrc' }}"
|
|
||||||
block: |
|
|
||||||
set encoding=utf-8
|
|
||||||
set number
|
|
||||||
set autoindent
|
|
||||||
set smartindent
|
|
||||||
set mouse=a
|
|
||||||
insertafter: EOF
|
|
||||||
marker: ""
|
|
||||||
|
|
||||||
- name: Add memory tuning parameters
|
|
||||||
ansible.builtin.blockinfile:
|
|
||||||
path: /mnt/etc/sysctl.d/90-memory.conf
|
|
||||||
create: true
|
|
||||||
block: |
|
|
||||||
vm.swappiness=10
|
|
||||||
vm.vfs_cache_pressure=50
|
|
||||||
vm.dirty_background_ratio=1
|
|
||||||
vm.dirty_ratio=10
|
|
||||||
vm.page-cluster=10
|
|
||||||
marker: ""
|
|
||||||
mode: "0644"
|
|
||||||
|
|
||||||
- name: Create zram config
|
|
||||||
when: os not in ['debian11', 'rhel8']
|
|
||||||
ansible.builtin.copy:
|
|
||||||
dest: /mnt/etc/systemd/zram-generator.conf
|
|
||||||
content: |
|
|
||||||
[zram0]
|
|
||||||
zram-size = ram / 2
|
|
||||||
compression-algorithm = zstd
|
|
||||||
swap-priority = 100
|
|
||||||
fs-type = swap
|
|
||||||
mode: "0644"
|
|
||||||
|
|
||||||
- name: Copy Custom Shell config
|
|
||||||
ansible.builtin.template:
|
|
||||||
src: custom.sh.j2
|
|
||||||
dest: /mnt/etc/profile.d/custom.sh
|
|
||||||
mode: "0644"
|
|
||||||
|
|
||||||
- name: Create login banner
|
|
||||||
ansible.builtin.copy:
|
|
||||||
dest: "{{ item }}"
|
|
||||||
content: |
|
|
||||||
**************************************************************
|
|
||||||
* WARNING: Unauthorized access to this system is prohibited. *
|
|
||||||
* All activities are monitored and logged. *
|
|
||||||
* Disconnect immediately if you are not an authorized user. *
|
|
||||||
**************************************************************
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: "0644"
|
|
||||||
loop:
|
|
||||||
- /mnt/etc/issue
|
|
||||||
- /etc/issue.net
|
|
||||||
|
|
||||||
- name: Remove motd files
|
|
||||||
when: os | lower in ["rhel8", "rhel9", "rhel10"]
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "{{ item }}"
|
|
||||||
state: absent
|
|
||||||
loop:
|
|
||||||
- /etc/motd.d/cockpit
|
|
||||||
- /etc/motd.d/insights-client
|
|
||||||
|
|
||||||
- name: Setup Network
|
|
||||||
block:
|
|
||||||
- name: Generate UUID for Network Profile
|
|
||||||
ansible.builtin.command: uuidgen
|
|
||||||
changed_when: net_uuid.rc == 0
|
|
||||||
register: net_uuid
|
|
||||||
|
|
||||||
- name: Retrieve Network Interface Name
|
|
||||||
ansible.builtin.shell: set -o pipefail && ip r | awk 'NR==1 {print $5}'
|
|
||||||
changed_when: net_inf.rc == 0
|
|
||||||
register: net_inf
|
|
||||||
|
|
||||||
- name: Register MAC Address of the Network Interface
|
|
||||||
ansible.builtin.shell: set -o pipefail && ip link show "{{ net_inf.stdout }}" | awk '/link\/ether/ {print $2}' | tr '[:lower:]' '[:upper:]'
|
|
||||||
register: net_mac
|
|
||||||
changed_when: net_mac.rc == 0
|
|
||||||
|
|
||||||
- name: Copy NetworkManager keyfile
|
|
||||||
ansible.builtin.template:
|
|
||||||
src: network.j2
|
|
||||||
dest: /mnt/etc/NetworkManager/system-connections/LAN.nmconnection
|
|
||||||
mode: "0600"
|
|
||||||
|
|
||||||
- name: Fix Ubuntu unmanaged devices
|
|
||||||
when: os | lower in ["ubuntu", "ubuntu-lts"]
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: /mnt/etc/NetworkManager/conf.d/10-globally-managed-devices.conf
|
|
||||||
state: touch
|
|
||||||
mode: "0644"
|
|
||||||
|
|
||||||
- name: Setup user account
|
|
||||||
block:
|
|
||||||
- name: Create user account
|
|
||||||
ansible.builtin.command: "{{ item }}"
|
|
||||||
with_items:
|
|
||||||
- arch-chroot /mnt /usr/sbin/useradd --create-home --user-group --groups
|
|
||||||
{{ "sudo" if os | lower in ["debian11", "debian12", "debian13", "ubuntu", "ubuntu-lts"] else "wheel" }}
|
|
||||||
{{ user_name }} --password {{ user_password | password_hash('sha512') }} --shell /bin/bash
|
|
||||||
- arch-chroot /mnt /usr/sbin/usermod --password '{{ root_password | password_hash('sha512') }}' root --shell /bin/bash
|
|
||||||
changed_when: result.rc == 0
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Add SSH public key to authorized_keys
|
|
||||||
when: user_public_key is defined
|
|
||||||
ansible.builtin.lineinfile:
|
|
||||||
path: /mnt/home/{{ user_name }}/.ssh/authorized_keys
|
|
||||||
line: "{{ user_public_key }}"
|
|
||||||
owner: 1000
|
|
||||||
group: 1000
|
|
||||||
mode: "0600"
|
|
||||||
create: true
|
|
||||||
|
|
||||||
- name: Give sudo access to wheel group
|
|
||||||
ansible.builtin.copy:
|
|
||||||
content: "{{ '%sudo ALL=(ALL) ALL' if os | lower in ['debian11', 'debian12', 'debian13', 'ubuntu', 'ubuntu-lts'] else '%wheel ALL=(ALL) ALL' }}"
|
|
||||||
dest: /mnt/etc/sudoers.d/01-wheel
|
|
||||||
mode: "0440"
|
|
||||||
validate: /usr/sbin/visudo --check --file=%s
|
|
||||||
|
|
||||||
- name: Fix SELinux
|
|
||||||
when: os | lower in ['almalinux', 'fedora', 'rhel8', 'rhel9', 'rhel10', 'rocky']
|
|
||||||
block:
|
|
||||||
- name: Fix SELinux by pre-labeling the filesystem before first boot
|
|
||||||
when: os | lower in ['almalinux', 'rhel8', 'rhel9', 'rhel10', 'rocky'] and (selinux | default(true) | bool)
|
|
||||||
ansible.builtin.command: >
|
|
||||||
arch-chroot /mnt /sbin/setfiles -v -F
|
|
||||||
-e /dev -e /proc -e /sys -e /run
|
|
||||||
/etc/selinux/targeted/contexts/files/file_contexts /
|
|
||||||
register: setfiles_result
|
|
||||||
changed_when: setfiles_result.rc == 0
|
|
||||||
|
|
||||||
- name: Disable SELinux
|
|
||||||
when: os | lower == "fedora" or not (selinux | default(true) | bool)
|
|
||||||
ansible.builtin.lineinfile:
|
|
||||||
path: /mnt/etc/selinux/config
|
|
||||||
regexp: ^SELINUX=
|
|
||||||
line: SELINUX=permissive
|
|
||||||
|
|||||||
96
roles/configuration/tasks/network.yml
Normal file
96
roles/configuration/tasks/network.yml
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
---
|
||||||
|
- name: Generate UUID for Network Profile
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
configuration_net_uuid: "{{ ('LAN-' ~ hostname) | ansible.builtin.to_uuid }}"
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Read network interfaces
|
||||||
|
ansible.builtin.command:
|
||||||
|
argv:
|
||||||
|
- ip
|
||||||
|
- -o
|
||||||
|
- link
|
||||||
|
- show
|
||||||
|
register: configuration_ip_link
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Resolve network interface and MAC address
|
||||||
|
vars:
|
||||||
|
configuration_net_inf_from_facts: "{{ (ansible_default_ipv4 | default({})).get('interface', '') }}"
|
||||||
|
configuration_net_inf_from_ip: >-
|
||||||
|
{{
|
||||||
|
(
|
||||||
|
configuration_ip_link.stdout
|
||||||
|
| default('')
|
||||||
|
| regex_findall('^[0-9]+: ([^:]+):', multiline=True)
|
||||||
|
| reject('equalto', 'lo')
|
||||||
|
| list
|
||||||
|
| first
|
||||||
|
)
|
||||||
|
| default('')
|
||||||
|
}}
|
||||||
|
configuration_net_inf_effective: >-
|
||||||
|
{{ configuration_net_inf_from_facts | default(configuration_net_inf_from_ip, true) }}
|
||||||
|
configuration_net_inf_regex: "{{ configuration_net_inf_effective | ansible.builtin.regex_escape }}"
|
||||||
|
configuration_net_mac_from_virtualization: "{{ virtualization_mac_address | default('') }}"
|
||||||
|
configuration_net_mac_from_facts: >-
|
||||||
|
{{
|
||||||
|
(
|
||||||
|
(ansible_facts | default({})).get(configuration_net_inf_effective, {}).get('macaddress', '')
|
||||||
|
)
|
||||||
|
| default(
|
||||||
|
(ansible_facts | default({})).get('ansible_' + configuration_net_inf_effective, {}).get('macaddress', ''),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
configuration_net_mac_from_ip: >-
|
||||||
|
{{
|
||||||
|
(
|
||||||
|
configuration_ip_link.stdout
|
||||||
|
| default('')
|
||||||
|
| regex_findall(
|
||||||
|
'^\\d+: ' ~ configuration_net_inf_regex ~ ':.*?link/ether\\s+([0-9A-Fa-f:]{17})',
|
||||||
|
multiline=True
|
||||||
|
)
|
||||||
|
| first
|
||||||
|
)
|
||||||
|
| default('')
|
||||||
|
}}
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
configuration_net_inf: "{{ configuration_net_inf_effective }}"
|
||||||
|
configuration_net_mac: >-
|
||||||
|
{{
|
||||||
|
(
|
||||||
|
configuration_net_mac_from_virtualization
|
||||||
|
| default(configuration_net_mac_from_facts, true)
|
||||||
|
| default(configuration_net_mac_from_ip, true)
|
||||||
|
)
|
||||||
|
| upper
|
||||||
|
}}
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Validate Network Interface Name
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- configuration_net_inf | length > 0
|
||||||
|
fail_msg: Failed to detect an active network interface.
|
||||||
|
|
||||||
|
- name: Validate Network Interface MAC Address
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- configuration_net_mac | length > 0
|
||||||
|
fail_msg: Failed to detect the MAC address for network interface {{ configuration_net_inf }}.
|
||||||
|
|
||||||
|
- name: Copy NetworkManager keyfile
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: network.j2
|
||||||
|
dest: /mnt/etc/NetworkManager/system-connections/LAN.nmconnection
|
||||||
|
mode: "0600"
|
||||||
|
|
||||||
|
- name: Fix Ubuntu unmanaged devices
|
||||||
|
when: os | lower in ["ubuntu", "ubuntu-lts"]
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /mnt/etc/NetworkManager/conf.d/10-globally-managed-devices.conf
|
||||||
|
state: touch
|
||||||
|
mode: "0644"
|
||||||
19
roles/configuration/tasks/selinux.yml
Normal file
19
roles/configuration/tasks/selinux.yml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
- name: Fix SELinux
|
||||||
|
when: is_rhel | default(false)
|
||||||
|
block:
|
||||||
|
- name: Fix SELinux by pre-labeling the filesystem before first boot
|
||||||
|
when: os | lower in ['almalinux', 'rhel8', 'rhel9', 'rhel10', 'rocky'] and (selinux | default(true) | bool)
|
||||||
|
ansible.builtin.command: >
|
||||||
|
arch-chroot /mnt /sbin/setfiles -v -F
|
||||||
|
-e /dev -e /proc -e /sys -e /run
|
||||||
|
/etc/selinux/targeted/contexts/files/file_contexts /
|
||||||
|
register: configuration_setfiles_result
|
||||||
|
changed_when: configuration_setfiles_result.rc == 0
|
||||||
|
|
||||||
|
- name: Disable SELinux
|
||||||
|
when: os | lower == "fedora" or not (selinux | default(true) | bool)
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /mnt/etc/selinux/config
|
||||||
|
regexp: ^SELINUX=
|
||||||
|
line: SELINUX=permissive
|
||||||
14
roles/configuration/tasks/services.yml
Normal file
14
roles/configuration/tasks/services.yml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
- name: Enable Systemd Services
|
||||||
|
ansible.builtin.command: >
|
||||||
|
arch-chroot /mnt systemctl enable NetworkManager
|
||||||
|
{{
|
||||||
|
' ssh' if os | lower in ['ubuntu', 'ubuntu-lts'] else
|
||||||
|
(' sshd' if os | lower not in ['debian11', 'debian12', 'debian13'] else '')
|
||||||
|
}}
|
||||||
|
{{
|
||||||
|
'logrotate systemd-resolved systemd-timesyncd systemd-networkd'
|
||||||
|
if os | lower == 'archlinux' else ''
|
||||||
|
}}
|
||||||
|
register: configuration_enable_services_result
|
||||||
|
changed_when: configuration_enable_services_result.rc == 0
|
||||||
7
roles/configuration/tasks/sudo.yml
Normal file
7
roles/configuration/tasks/sudo.yml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
- name: Give sudo access to wheel group
|
||||||
|
ansible.builtin.copy:
|
||||||
|
content: "{{ '%sudo ALL=(ALL) ALL' if is_debian | default(false) else '%wheel ALL=(ALL) ALL' }}"
|
||||||
|
dest: /mnt/etc/sudoers.d/01-wheel
|
||||||
|
mode: "0440"
|
||||||
|
validate: /usr/sbin/visudo --check --file=%s
|
||||||
37
roles/configuration/tasks/users.yml
Normal file
37
roles/configuration/tasks/users.yml
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
---
|
||||||
|
- name: Create user account
|
||||||
|
vars:
|
||||||
|
configuration_user_group: >-
|
||||||
|
{{ "sudo" if is_debian | default(false) else "wheel" }}
|
||||||
|
configuration_useradd_cmd: >-
|
||||||
|
arch-chroot /mnt /usr/sbin/useradd --create-home --user-group
|
||||||
|
--groups {{ configuration_user_group }} {{ user_name }}
|
||||||
|
--password {{ user_password | password_hash('sha512') }} --shell /bin/bash
|
||||||
|
configuration_root_cmd: >-
|
||||||
|
arch-chroot /mnt /usr/sbin/usermod --password
|
||||||
|
'{{ root_password | password_hash('sha512') }}' root --shell /bin/bash
|
||||||
|
ansible.builtin.command: "{{ item }}"
|
||||||
|
loop:
|
||||||
|
- "{{ configuration_useradd_cmd }}"
|
||||||
|
- "{{ configuration_root_cmd }}"
|
||||||
|
register: configuration_user_result
|
||||||
|
changed_when: configuration_user_result.rc == 0
|
||||||
|
|
||||||
|
- name: Ensure .ssh directory exists
|
||||||
|
when: user_public_key is defined
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /mnt/home/{{ user_name }}/.ssh
|
||||||
|
state: directory
|
||||||
|
owner: 1000
|
||||||
|
group: 1000
|
||||||
|
mode: "0700"
|
||||||
|
|
||||||
|
- name: Add SSH public key to authorized_keys
|
||||||
|
when: user_public_key is defined
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /mnt/home/{{ user_name }}/.ssh/authorized_keys
|
||||||
|
line: "{{ user_public_key }}"
|
||||||
|
owner: 1000
|
||||||
|
group: 1000
|
||||||
|
mode: "0600"
|
||||||
|
create: true
|
||||||
@@ -1,18 +1,33 @@
|
|||||||
[connection]
|
[connection]
|
||||||
id=LAN
|
id=LAN
|
||||||
uuid={{ net_uuid.stdout }}
|
uuid={{ configuration_net_uuid }}
|
||||||
type=ethernet
|
type=ethernet
|
||||||
|
|
||||||
[ethernet]
|
[ethernet]
|
||||||
mac-address={{ net_mac.stdout }}
|
mac-address={{ configuration_net_mac }}
|
||||||
|
|
||||||
[ipv4]
|
[ipv4]
|
||||||
address={{ vm_ip }}/{{ vm_nms | default (24) }},{{ vm_gw }}
|
{% set dns_value = vm_dns | default('') %}
|
||||||
dns={{ vm_dns }}
|
{% set dns_list_raw = dns_value if dns_value is iterable and dns_value is not string else dns_value.split(',') %}
|
||||||
{% if vm_dns_search is defined %}
|
{% set dns_list = dns_list_raw | map('trim') | reject('equalto', '') | list %}
|
||||||
dns-search={{ vm_dns_search }}
|
{% set search_value = vm_dns_search | default('') %}
|
||||||
{% endif %}
|
{% set search_list_raw = search_value if search_value is iterable and search_value is not string else search_value.split(',') %}
|
||||||
|
{% set search_list = search_list_raw | map('trim') | reject('equalto', '') | list %}
|
||||||
|
{% if vm_ip is defined and vm_ip | length %}
|
||||||
|
address1={{ vm_ip }}/{{ vm_nms | default(24) }}{{ (',' ~ vm_gw) if (vm_gw is defined and vm_gw | length) else '' }}
|
||||||
method=manual
|
method=manual
|
||||||
|
{% else %}
|
||||||
|
method=auto
|
||||||
|
{% endif %}
|
||||||
|
{% if dns_list %}
|
||||||
|
dns={{ dns_list | join(';') }}
|
||||||
|
{% endif %}
|
||||||
|
{% if dns_list or search_list %}
|
||||||
|
ignore-auto-dns=true
|
||||||
|
{% endif %}
|
||||||
|
{% if search_list %}
|
||||||
|
dns-search={{ search_list | join(';') }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
[ipv6]
|
[ipv6]
|
||||||
addr-gen-mode=stable-privacy
|
addr-gen-mode=stable-privacy
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
---
|
---
|
||||||
- name: Configre work environment
|
- name: Configure work environment
|
||||||
become: true
|
become: "{{ hypervisor != 'vmware' }}"
|
||||||
block:
|
block:
|
||||||
- name: Wait for connection
|
- name: Wait for connection
|
||||||
ansible.builtin.wait_for_connection:
|
ansible.builtin.wait_for_connection:
|
||||||
timeout: 60
|
timeout: 180
|
||||||
delay: 5
|
delay: 5
|
||||||
|
|
||||||
- name: Gather facts
|
- name: Gather facts
|
||||||
@@ -13,118 +13,144 @@
|
|||||||
- name: Check if host is booted from the Arch install media
|
- name: Check if host is booted from the Arch install media
|
||||||
ansible.builtin.stat:
|
ansible.builtin.stat:
|
||||||
path: /run/archiso
|
path: /run/archiso
|
||||||
register: archiso_stat
|
register: environment_archiso_stat
|
||||||
|
|
||||||
- name: Abort if the host is not booted from the Arch install media
|
- name: Abort if the host is not booted from the Arch install media
|
||||||
|
when:
|
||||||
|
- not (custom_iso | default(false) | bool)
|
||||||
|
- not environment_archiso_stat.stat.exists
|
||||||
ansible.builtin.fail:
|
ansible.builtin.fail:
|
||||||
msg: This host is not booted from the Arch install media!
|
msg: This host is not booted from the Arch install media!
|
||||||
when: not archiso_stat.stat.exists
|
|
||||||
|
|
||||||
- name: Register Network Interface
|
- name: Select primary Network Interface
|
||||||
when: hypervisor == "vmware"
|
when: hypervisor == "vmware"
|
||||||
ansible.builtin.shell: "set -o pipefail && ip l | awk -F': ' '!/lo/{print $2; exit}'"
|
ansible.builtin.set_fact:
|
||||||
changed_when: interface_name.rc == 0
|
environment_interface_name: >-
|
||||||
register: interface_name
|
{{
|
||||||
|
(
|
||||||
|
(ansible_facts.interfaces | default(ansible_facts['ansible_interfaces'] | default([])))
|
||||||
|
| reject('equalto', 'lo')
|
||||||
|
| list
|
||||||
|
| first
|
||||||
|
)
|
||||||
|
| default('')
|
||||||
|
}}
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
- name: Set IP-Address
|
- name: Set IP-Address
|
||||||
when: hypervisor == "vmware"
|
when:
|
||||||
ansible.builtin.command: "ip addr replace {{ ansible_host }}/{{ vm_nms | default(24) }} dev {{ interface_name.stdout }}"
|
- hypervisor == "vmware"
|
||||||
changed_when: result.rc == 0
|
- vm_ip is defined
|
||||||
register: result
|
- vm_ip | length
|
||||||
|
ansible.builtin.command: >-
|
||||||
|
ip addr replace {{ vm_ip }}/{{ vm_nms | default(24) }}
|
||||||
|
dev {{ environment_interface_name }}
|
||||||
|
register: environment_ip_result
|
||||||
|
changed_when: environment_ip_result.rc == 0
|
||||||
|
|
||||||
- name: Set Default Gateway
|
- name: Set Default Gateway
|
||||||
when: hypervisor == "vmware"
|
when:
|
||||||
|
- hypervisor == "vmware"
|
||||||
|
- vm_gw is defined
|
||||||
|
- vm_gw | length
|
||||||
|
- vm_ip is defined
|
||||||
|
- vm_ip | length
|
||||||
ansible.builtin.command: "ip route replace default via {{ vm_gw }}"
|
ansible.builtin.command: "ip route replace default via {{ vm_gw }}"
|
||||||
changed_when: result.rc == 0
|
register: environment_gateway_result
|
||||||
register: result
|
changed_when: environment_gateway_result.rc == 0
|
||||||
|
|
||||||
- name: Synchronize clock via NTP
|
- name: Synchronize clock via NTP
|
||||||
ansible.builtin.command: timedatectl set-ntp true
|
ansible.builtin.command: timedatectl set-ntp true
|
||||||
changed_when: result.rc == 0
|
register: environment_ntp_result
|
||||||
register: result
|
changed_when: false
|
||||||
|
|
||||||
- name: Configure SSH for root login
|
- name: Configure SSH for root login
|
||||||
when: hypervisor == "vmware" and (vmware_ssh is defined and vmware_ssh | bool)
|
when: hypervisor == "vmware" and (vmware_ssh is defined and vmware_ssh | bool)
|
||||||
block:
|
block:
|
||||||
- name: Allow empty passwords temporarily
|
- name: Allow login
|
||||||
ansible.builtin.replace:
|
ansible.builtin.replace:
|
||||||
path: /etc/ssh/sshd_config
|
path: /etc/ssh/sshd_config
|
||||||
regexp: "^#?PermitEmptyPasswords.*"
|
regexp: "{{ item.regexp }}"
|
||||||
replace: "PermitEmptyPasswords yes"
|
replace: "{{ item.replace }}"
|
||||||
|
loop:
|
||||||
- name: Allow root login
|
- regexp: "^#?PermitEmptyPasswords.*"
|
||||||
ansible.builtin.replace:
|
replace: "PermitEmptyPasswords yes"
|
||||||
path: /etc/ssh/sshd_config
|
- regexp: "^#?PermitRootLogin.*"
|
||||||
regexp: "^#?PermitRootLogin.*"
|
replace: "PermitRootLogin yes"
|
||||||
replace: "PermitRootLogin yes"
|
|
||||||
|
|
||||||
- name: Reload SSH service to apply changes
|
- name: Reload SSH service to apply changes
|
||||||
ansible.builtin.service:
|
ansible.builtin.service:
|
||||||
name: sshd
|
name: sshd
|
||||||
state: reloaded
|
state: reloaded
|
||||||
|
|
||||||
- name: Set connection back to SSH
|
- name: Set SSH connection for VMware
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
ansible_connection: ssh
|
ansible_connection: ssh
|
||||||
ansible_user: "root"
|
ansible_user: root
|
||||||
ansible_password: ""
|
|
||||||
ansible_become_password: ""
|
|
||||||
ansible_ssh_extra_args: "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
|
||||||
|
|
||||||
- name: Speed-up Bootstrap process
|
- name: Prepare installer environment
|
||||||
ansible.builtin.lineinfile:
|
|
||||||
path: /etc/pacman.conf
|
|
||||||
regexp: ^#ParallelDownloads =
|
|
||||||
line: ParallelDownloads = 20
|
|
||||||
|
|
||||||
- name: Wait for Pacman
|
|
||||||
ansible.builtin.wait_for:
|
|
||||||
timeout: 15
|
|
||||||
|
|
||||||
- name: Setup Pacman
|
|
||||||
community.general.pacman:
|
|
||||||
update_cache: true
|
|
||||||
force: true
|
|
||||||
name: "{{ item.name }}"
|
|
||||||
state: latest
|
|
||||||
loop:
|
|
||||||
- { name: glibc }
|
|
||||||
- { name: dnf, os: [almalinux, fedora, rhel8, rhel9, rhel10, rocky] }
|
|
||||||
- { name: debootstrap, os: [debian11, debian12, debian13, ubuntu, ubuntu-lts] }
|
|
||||||
- { name: debian-archive-keyring, os: [debian11, debian12, debian13] }
|
|
||||||
- { name: ubuntu-keyring, os: [ubuntu, ubuntu-lts] }
|
|
||||||
when: "'os' not in item or os in item.os"
|
|
||||||
retries: 4
|
|
||||||
delay: 15
|
|
||||||
|
|
||||||
- name: Prepare /iso mount and repository for RHEL-based systems
|
|
||||||
when: os | lower in ["rhel8", "rhel9", "rhel10"]
|
|
||||||
block:
|
block:
|
||||||
- name: Create /iso directory
|
- name: Speed-up Bootstrap process
|
||||||
ansible.builtin.file:
|
when: not (custom_iso | default(false) | bool)
|
||||||
path: /usr/local/install/redhat/dvd
|
ansible.builtin.lineinfile:
|
||||||
state: directory
|
path: /etc/pacman.conf
|
||||||
mode: "0755"
|
regexp: ^#ParallelDownloads =
|
||||||
|
line: ParallelDownloads = 20
|
||||||
|
|
||||||
- name: Mount RHEL ISO
|
- name: Wait for pacman lock to be released
|
||||||
ansible.posix.mount:
|
when: not (custom_iso | default(false) | bool)
|
||||||
src: "{{ '/dev/sr1' if hypervisor == 'vmware' else '/dev/sr2' }}"
|
ansible.builtin.wait_for:
|
||||||
path: /usr/local/install/redhat/dvd
|
path: /var/lib/pacman/db.lck
|
||||||
fstype: iso9660
|
state: absent
|
||||||
opts: "ro,loop"
|
timeout: 120
|
||||||
state: mounted
|
changed_when: false
|
||||||
|
|
||||||
- name: Configure RHEL Repos for installation
|
- name: Setup Pacman
|
||||||
when: os | lower in ["almalinux", "fedora", "rhel8", "rhel9", "rhel10", "rocky"]
|
when:
|
||||||
block:
|
- not (custom_iso | default(false) | bool)
|
||||||
- name: Create directories for repository files and RPM GPG keys
|
- "'os' not in item or os in item.os"
|
||||||
ansible.builtin.file:
|
community.general.pacman:
|
||||||
path: /etc/yum.repos.d
|
update_cache: true
|
||||||
state: directory
|
force: true
|
||||||
mode: "0755"
|
name: "{{ item.name }}"
|
||||||
|
state: latest
|
||||||
|
loop:
|
||||||
|
- {name: glibc}
|
||||||
|
- {name: dnf, os: [almalinux, fedora, rhel8, rhel9, rhel10, rocky]}
|
||||||
|
- {name: debootstrap, os: [debian11, debian12, debian13, ubuntu, ubuntu-lts]}
|
||||||
|
- {name: debian-archive-keyring, os: [debian11, debian12, debian13]}
|
||||||
|
- {name: ubuntu-keyring, os: [ubuntu, ubuntu-lts]}
|
||||||
|
retries: 4
|
||||||
|
delay: 15
|
||||||
|
|
||||||
- name: Create RHEL repository file
|
- name: Prepare /iso mount and repository for RHEL-based systems
|
||||||
ansible.builtin.template:
|
when: os | lower in ["rhel8", "rhel9", "rhel10"]
|
||||||
src: "{{ os | lower }}.repo.j2"
|
block:
|
||||||
dest: /etc/yum.repos.d/{{ os | lower }}.repo
|
- name: Create /iso directory
|
||||||
mode: "0644"
|
ansible.builtin.file:
|
||||||
|
path: /usr/local/install/redhat/dvd
|
||||||
|
state: directory
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Mount RHEL ISO
|
||||||
|
ansible.posix.mount:
|
||||||
|
src: "{{ '/dev/sr1' if hypervisor == 'vmware' else '/dev/sr2' }}"
|
||||||
|
path: /usr/local/install/redhat/dvd
|
||||||
|
fstype: iso9660
|
||||||
|
opts: "ro,loop"
|
||||||
|
state: mounted
|
||||||
|
|
||||||
|
- name: Configure RHEL Repos for installation
|
||||||
|
when: is_rhel | default(false)
|
||||||
|
block:
|
||||||
|
- name: Create directories for repository files and RPM GPG keys
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /etc/yum.repos.d
|
||||||
|
state: directory
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Create RHEL repository file
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: "{{ os | lower }}.repo.j2"
|
||||||
|
dest: /etc/yum.repos.d/{{ os | lower }}.repo
|
||||||
|
mode: "0644"
|
||||||
|
|||||||
@@ -3,54 +3,63 @@
|
|||||||
block:
|
block:
|
||||||
- name: Create btrfs filesystem in main volume
|
- name: Create btrfs filesystem in main volume
|
||||||
community.general.filesystem:
|
community.general.filesystem:
|
||||||
dev: "{{ install_drive }}{{ main_partition_suffix }}"
|
dev: "{{ partitioning_root_device }}"
|
||||||
fstype: btrfs
|
fstype: btrfs
|
||||||
force: true
|
force: true
|
||||||
|
opts: >-
|
||||||
|
{{
|
||||||
|
'-K'
|
||||||
|
if (partitioning_luks_enabled | bool)
|
||||||
|
and not ('discard' in (partitioning_luks_options | default('') | lower))
|
||||||
|
else omit
|
||||||
|
}}
|
||||||
|
|
||||||
- name: Prepare BTRFS Subvolume
|
- name: Prepare BTRFS Subvolume
|
||||||
ansible.posix.mount:
|
ansible.posix.mount:
|
||||||
path: /mnt
|
path: /mnt
|
||||||
src: "{{ install_drive }}{{ main_partition_suffix }}"
|
src: "{{ partitioning_root_device }}"
|
||||||
fstype: btrfs
|
fstype: btrfs
|
||||||
opts: rw,relatime,compress=zstd:15,ssd,space_cache=v2,discard=async
|
opts: rw,relatime,compress=zstd:15,ssd,space_cache=v2,discard=async
|
||||||
state: mounted
|
state: mounted
|
||||||
|
|
||||||
- name: Enable quotas on Btrfs filesystem
|
- name: Enable quotas on Btrfs filesystem
|
||||||
ansible.builtin.command: btrfs quota enable /mnt
|
ansible.builtin.command: btrfs quota enable /mnt
|
||||||
changed_when: result.rc == 0
|
register: partitioning_btrfs_quota_result
|
||||||
register: result
|
changed_when: false
|
||||||
|
|
||||||
- name: Make root subvolumes
|
- name: Make root subvolumes
|
||||||
when: cis | bool or item.subvol not in ['var_log_audit']
|
when: cis | bool or item.subvol not in ['var_log_audit']
|
||||||
ansible.builtin.command: btrfs su cr /mnt/{{ '@' if item.subvol == 'root' else '@' + item.subvol }}
|
ansible.builtin.command: btrfs su cr /mnt/{{ '@' if item.subvol == 'root' else '@' + item.subvol }}
|
||||||
changed_when: result.rc == 0
|
args:
|
||||||
register: result
|
creates: /mnt/{{ '@' if item.subvol == 'root' else '@' + item.subvol }}
|
||||||
loop:
|
loop:
|
||||||
- { subvol: root }
|
- {subvol: root}
|
||||||
- { subvol: swap }
|
- {subvol: swap}
|
||||||
- { subvol: home }
|
- {subvol: home}
|
||||||
- { subvol: var }
|
- {subvol: var}
|
||||||
- { subvol: var_log }
|
- {subvol: pkg}
|
||||||
- { subvol: var_log_audit }
|
- {subvol: var_log}
|
||||||
|
- {subvol: var_log_audit}
|
||||||
|
register: partitioning_btrfs_subvol_result
|
||||||
|
|
||||||
- name: Set quotas for subvolumes
|
- name: Set quotas for subvolumes
|
||||||
when: cis | bool or item.subvol not in ['var_log_audit']
|
when: cis | bool
|
||||||
ansible.builtin.command: btrfs qgroup limit {{ item.quota }} /mnt/{{ '@' if item.subvol == 'root' else '@' + item.subvol }}
|
ansible.builtin.command: btrfs qgroup limit {{ item.quota }} /mnt/{{ '@' if item.subvol == 'root' else '@' + item.subvol }}
|
||||||
changed_when: result.rc == 0
|
|
||||||
register: result
|
|
||||||
loop:
|
loop:
|
||||||
- { subvol: home, quota: 2G }
|
- {subvol: home, quota: 2G}
|
||||||
|
register: partitioning_btrfs_qgroup_result
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
- name: Create a Btrfs swap file
|
- name: Create a Btrfs swap file
|
||||||
ansible.builtin.command: >-
|
ansible.builtin.command: >-
|
||||||
btrfs filesystem mkswapfile --size {{ ((vm_memory | float / 1024 >= 16.0) | ternary((vm_memory
|
btrfs filesystem mkswapfile --size {{ partitioning_swap_size_gb }}g --uuid clear /mnt/@swap/swapfile
|
||||||
| float / 2048) | int, [vm_memory | float / 1024, 4.0] | max) | int) }}g --uuid clear /mnt/@swap/swapfile
|
args:
|
||||||
changed_when: result.rc == 0
|
creates: /mnt/@swap/swapfile
|
||||||
register: result
|
register: partitioning_btrfs_swap_result
|
||||||
|
|
||||||
- name: Unmount Partition
|
- name: Unmount Partition
|
||||||
ansible.posix.mount:
|
ansible.posix.mount:
|
||||||
path: /mnt
|
path: /mnt
|
||||||
src: "{{ install_drive }}{{ main_partition_suffix }}"
|
src: "{{ partitioning_root_device }}"
|
||||||
fstype: btrfs
|
fstype: btrfs
|
||||||
state: unmounted
|
state: unmounted
|
||||||
|
|||||||
@@ -6,20 +6,20 @@
|
|||||||
fstype: ext4
|
fstype: ext4
|
||||||
force: true
|
force: true
|
||||||
loop:
|
loop:
|
||||||
- { lv: root }
|
- {lv: root}
|
||||||
- { lv: home }
|
- {lv: home}
|
||||||
- { lv: var }
|
- {lv: var}
|
||||||
- { lv: var_log }
|
- {lv: var_log}
|
||||||
- { lv: var_log_audit }
|
- {lv: var_log_audit}
|
||||||
|
|
||||||
- name: Remove Unsupported features for older Systems
|
- name: Remove Unsupported features for older Systems
|
||||||
when: (os | lower in ['almalinux', 'debian11', 'rhel8', 'rhel9', 'rocky']) and (cis | bool or item.lv not in ['home', 'var', 'var_log', 'var_log_audit'])
|
when: (os | lower in ['almalinux', 'debian11', 'rhel8', 'rhel9', 'rocky']) and (cis | bool or item.lv not in ['home', 'var', 'var_log', 'var_log_audit'])
|
||||||
ansible.builtin.command: tune2fs -O "^orphan_file,^metadata_csum_seed" "/dev/sys/{{ item.lv }}"
|
ansible.builtin.command: tune2fs -O "^orphan_file,^metadata_csum_seed" "/dev/sys/{{ item.lv }}"
|
||||||
changed_when: result.rc == 0
|
|
||||||
register: result
|
|
||||||
loop:
|
loop:
|
||||||
- { lv: root }
|
- {lv: root}
|
||||||
- { lv: home }
|
- {lv: home}
|
||||||
- { lv: var }
|
- {lv: var}
|
||||||
- { lv: var_log }
|
- {lv: var_log}
|
||||||
- { lv: var_log_audit }
|
- {lv: var_log_audit}
|
||||||
|
register: partitioning_ext4_tune_result
|
||||||
|
changed_when: partitioning_ext4_tune_result.rc == 0
|
||||||
|
|||||||
@@ -1,33 +1,304 @@
|
|||||||
---
|
---
|
||||||
|
- name: Set partitioning defaults
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
partitioning_luks_enabled: "{{ partitioning_luks_enabled | default(luks_enabled | default(false)) | bool }}"
|
||||||
|
partitioning_luks_mapper_name: "{{ partitioning_luks_mapper_name | default(luks_mapper_name | default('SYSTEM_DECRYPTED')) }}"
|
||||||
|
partitioning_luks_type: "{{ partitioning_luks_type | default(luks_type | default('luks2')) }}"
|
||||||
|
partitioning_luks_cipher: "{{ partitioning_luks_cipher | default(luks_cipher | default('aes-xts-plain64')) }}"
|
||||||
|
partitioning_luks_hash: "{{ partitioning_luks_hash | default(luks_hash | default('sha512')) }}"
|
||||||
|
partitioning_luks_iter_time: "{{ partitioning_luks_iter_time | default(luks_iter_time | default(4000)) }}"
|
||||||
|
partitioning_luks_key_size: "{{ partitioning_luks_key_size | default(luks_key_size | default(512)) }}"
|
||||||
|
partitioning_luks_pbkdf: "{{ partitioning_luks_pbkdf | default(luks_pbkdf | default('argon2id')) }}"
|
||||||
|
partitioning_luks_use_urandom: "{{ partitioning_luks_use_urandom | default(luks_use_urandom | default(true)) | bool }}"
|
||||||
|
partitioning_luks_verify_passphrase: "{{ partitioning_luks_verify_passphrase | default(luks_verify_passphrase | default(true)) | bool }}"
|
||||||
|
partitioning_luks_auto_decrypt: "{{ partitioning_luks_auto_decrypt | default(luks_auto_decrypt | default(true)) | bool }}"
|
||||||
|
partitioning_luks_auto_decrypt_method: "{{ partitioning_luks_auto_decrypt_method | default(luks_auto_decrypt_method | default('tpm2')) }}"
|
||||||
|
partitioning_luks_tpm2_device: "{{ partitioning_luks_tpm2_device | default(luks_tpm2_device | default('auto')) }}"
|
||||||
|
partitioning_luks_tpm2_pcrs: "{{ partitioning_luks_tpm2_pcrs | default(luks_tpm2_pcrs | default('')) }}"
|
||||||
|
partitioning_luks_keyfile_size: "{{ partitioning_luks_keyfile_size | default(luks_keyfile_size | default(64)) }}"
|
||||||
|
partitioning_luks_options: "{{ partitioning_luks_options | default(luks_options | default('discard,tries=3')) }}"
|
||||||
|
partitioning_luks_device: >-
|
||||||
|
{{ install_drive ~ (partitioning_main_partition_suffix | string) }}
|
||||||
|
|
||||||
|
- name: Set partitioning root device
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
partitioning_root_device: >-
|
||||||
|
{{
|
||||||
|
'/dev/mapper/' + partitioning_luks_mapper_name
|
||||||
|
if partitioning_luks_enabled | bool
|
||||||
|
else install_drive ~ (partitioning_main_partition_suffix | string)
|
||||||
|
}}
|
||||||
|
|
||||||
|
- name: Set partitioning vm_size from input
|
||||||
|
when: vm_size is defined or partitioning_vm_size is defined
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
partitioning_vm_size: "{{ (partitioning_vm_size | default(vm_size)) | float }}"
|
||||||
|
|
||||||
|
- name: Set partitioning vm memory from input
|
||||||
|
when: vm_memory is defined or partitioning_vm_memory is defined
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
partitioning_vm_memory: "{{ (partitioning_vm_memory | default(vm_memory)) | float }}"
|
||||||
|
|
||||||
|
- name: Detect system memory for swap sizing
|
||||||
|
when: partitioning_vm_memory is not defined
|
||||||
|
block:
|
||||||
|
- name: Read system memory
|
||||||
|
ansible.builtin.command: awk '/MemTotal/ {print int($2/1024)}' /proc/meminfo
|
||||||
|
register: partitioning_memtotal_mb
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Set partitioning vm memory default
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
partitioning_vm_memory: "{{ (partitioning_memtotal_mb.stdout | default('4096') | int) | float }}"
|
||||||
|
|
||||||
|
- name: Calculate swap size
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
partitioning_swap_size_gb: >-
|
||||||
|
{{
|
||||||
|
((partitioning_vm_memory | float / 1024) >= 16.0)
|
||||||
|
| ternary(
|
||||||
|
(partitioning_vm_memory | float / 2048) | int,
|
||||||
|
[partitioning_vm_memory | float / 1024, 4.0] | max | int
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
|
||||||
|
- name: Set partitioning vm_size for physical installs
|
||||||
|
when:
|
||||||
|
- install_type == "physical"
|
||||||
|
- partitioning_vm_size is not defined
|
||||||
|
- install_drive is defined
|
||||||
|
block:
|
||||||
|
- name: Detect install drive size
|
||||||
|
ansible.builtin.command: "lsblk -b -dn -o SIZE {{ install_drive }}"
|
||||||
|
register: partitioning_disk_size_bytes
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Set partitioning vm_size from install drive size
|
||||||
|
when:
|
||||||
|
- partitioning_disk_size_bytes.stdout is defined
|
||||||
|
- (partitioning_disk_size_bytes.stdout | trim | length) > 0
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
partitioning_vm_size: >-
|
||||||
|
{{
|
||||||
|
(partitioning_disk_size_bytes.stdout | trim | int / 1024 / 1024 / 1024)
|
||||||
|
| round(2, 'floor')
|
||||||
|
}}
|
||||||
|
|
||||||
- name: Partition install drive
|
- name: Partition install drive
|
||||||
block:
|
block:
|
||||||
- name: Prepare partitions
|
- name: Prepare partitions
|
||||||
failed_when: false
|
block:
|
||||||
ansible.builtin.command: "{{ item.cmd }}"
|
- name: Disable swap
|
||||||
changed_when: result.rc == 0
|
ansible.builtin.command: swapoff -a
|
||||||
register: result
|
changed_when: false
|
||||||
loop:
|
failed_when: false
|
||||||
- { cmd: umount -l /mnt }
|
|
||||||
- { cmd: vgremove -f sys }
|
- name: Find mounts under /mnt
|
||||||
- {
|
ansible.builtin.command: findmnt -R /mnt -n -o TARGET
|
||||||
cmd: 'find /dev -wholename "{{ install_drive }}*" -exec wipefs --force --all {} \;',
|
register: partitioning_mounted_paths
|
||||||
}
|
changed_when: false
|
||||||
loop_control:
|
failed_when: false
|
||||||
label: "{{ item.cmd }}"
|
|
||||||
|
- name: Unmount /mnt mounts
|
||||||
|
when: partitioning_mounted_paths.stdout_lines | length > 0
|
||||||
|
ansible.posix.mount:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: unmounted
|
||||||
|
loop: "{{ partitioning_mounted_paths.stdout_lines | reverse }}"
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item }}"
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Remove LVM volume group
|
||||||
|
community.general.lvg:
|
||||||
|
vg: sys
|
||||||
|
state: absent
|
||||||
|
force: true
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Close LUKS mapper
|
||||||
|
when: partitioning_luks_enabled | bool
|
||||||
|
community.crypto.luks_device:
|
||||||
|
name: "{{ partitioning_luks_mapper_name }}"
|
||||||
|
state: closed
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Remove LUKS mapper device
|
||||||
|
when: partitioning_luks_enabled | bool
|
||||||
|
ansible.builtin.command: >-
|
||||||
|
dmsetup remove --force --retry {{ partitioning_luks_mapper_name }}
|
||||||
|
register: partitioning_dmsetup_remove
|
||||||
|
changed_when: partitioning_dmsetup_remove.rc == 0
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Remove LUKS signatures
|
||||||
|
when: partitioning_luks_enabled | bool
|
||||||
|
community.crypto.luks_device:
|
||||||
|
device: "{{ partitioning_luks_device }}"
|
||||||
|
state: absent
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Wipe filesystem signatures
|
||||||
|
ansible.builtin.command: >-
|
||||||
|
find /dev -wholename "{{ install_drive }}*" -exec wipefs --force --all {} \;
|
||||||
|
register: partitioning_wipefs_result
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Refresh kernel partition table
|
||||||
|
ansible.builtin.command: "{{ item }}"
|
||||||
|
loop:
|
||||||
|
- "partprobe {{ install_drive }}"
|
||||||
|
- "blockdev --rereadpt {{ install_drive }}"
|
||||||
|
- "udevadm settle"
|
||||||
|
register: partitioning_partprobe_result
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
- name: Define partitions
|
- name: Define partitions
|
||||||
community.general.parted:
|
block:
|
||||||
device: "{{ install_drive }}"
|
- name: Create partition layout
|
||||||
label: gpt
|
community.general.parted:
|
||||||
number: "{{ item.number }}"
|
device: "{{ install_drive }}"
|
||||||
part_end: "{{ item.part_end | default(omit) }}"
|
label: gpt
|
||||||
part_start: "{{ item.part_start | default(omit) }}"
|
number: "{{ item.number }}"
|
||||||
name: "{{ item.name }}"
|
part_end: "{{ item.part_end | default(omit) }}"
|
||||||
flags: "{{ item.flags | default(omit) }}"
|
part_start: "{{ item.part_start | default(omit) }}"
|
||||||
state: present
|
name: "{{ item.name }}"
|
||||||
|
flags: "{{ item.flags | default(omit) }}"
|
||||||
|
state: present
|
||||||
|
loop:
|
||||||
|
- {number: 1, part_end: 500MiB, name: boot, flags: [boot, esp]}
|
||||||
|
- {number: 2, part_start: 500MiB, name: root}
|
||||||
|
rescue:
|
||||||
|
- name: Refresh kernel partition table after failure
|
||||||
|
ansible.builtin.command: "{{ item }}"
|
||||||
|
loop:
|
||||||
|
- "partprobe {{ install_drive }}"
|
||||||
|
- "blockdev --rereadpt {{ install_drive }}"
|
||||||
|
- "udevadm settle"
|
||||||
|
register: partitioning_partprobe_retry
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Retry partition layout
|
||||||
|
community.general.parted:
|
||||||
|
device: "{{ install_drive }}"
|
||||||
|
label: gpt
|
||||||
|
number: "{{ item.number }}"
|
||||||
|
part_end: "{{ item.part_end | default(omit) }}"
|
||||||
|
part_start: "{{ item.part_start | default(omit) }}"
|
||||||
|
name: "{{ item.name }}"
|
||||||
|
flags: "{{ item.flags | default(omit) }}"
|
||||||
|
state: present
|
||||||
|
loop:
|
||||||
|
- {number: 1, part_end: 500MiB, name: boot, flags: [boot, esp]}
|
||||||
|
- {number: 2, part_start: 500MiB, name: root}
|
||||||
|
|
||||||
|
- name: Settle partition table
|
||||||
|
ansible.builtin.command: "{{ item }}"
|
||||||
loop:
|
loop:
|
||||||
- { number: 1, part_end: 500MiB, name: boot, flags: [boot, esp] }
|
- "partprobe {{ install_drive }}"
|
||||||
- { number: 2, part_start: 500MiB, name: root }
|
- "udevadm settle"
|
||||||
|
register: partitioning_partprobe_settle
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Configure LUKS encryption
|
||||||
|
when: partitioning_luks_enabled | bool
|
||||||
|
vars:
|
||||||
|
partitioning_luks_passphrase_effective: >-
|
||||||
|
{{ (partitioning_luks_passphrase | default(luks_passphrase | default(''))) | string }}
|
||||||
|
block:
|
||||||
|
- name: Validate LUKS passphrase
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- partitioning_luks_passphrase_effective | length > 0
|
||||||
|
fail_msg: luks_passphrase (or partitioning_luks_passphrase) must be set when LUKS is enabled.
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
- name: Ensure LUKS container exists
|
||||||
|
community.crypto.luks_device:
|
||||||
|
device: "{{ partitioning_luks_device }}"
|
||||||
|
state: present
|
||||||
|
type: "{{ partitioning_luks_type }}"
|
||||||
|
cipher: "{{ partitioning_luks_cipher }}"
|
||||||
|
hash: "{{ partitioning_luks_hash }}"
|
||||||
|
keysize: "{{ partitioning_luks_key_size }}"
|
||||||
|
pbkdf:
|
||||||
|
algorithm: "{{ partitioning_luks_pbkdf }}"
|
||||||
|
iteration_time: "{{ (partitioning_luks_iter_time | float) / 1000 }}"
|
||||||
|
passphrase: "{{ partitioning_luks_passphrase_effective }}"
|
||||||
|
register: partitioning_luks_format_result
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
- name: Force-close LUKS mapper
|
||||||
|
community.crypto.luks_device:
|
||||||
|
name: "{{ partitioning_luks_mapper_name }}"
|
||||||
|
state: closed
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Force-remove LUKS mapper device
|
||||||
|
ansible.builtin.command: >-
|
||||||
|
dmsetup remove --force --retry {{ partitioning_luks_mapper_name }}
|
||||||
|
register: partitioning_dmsetup_remove_after_format
|
||||||
|
changed_when: partitioning_dmsetup_remove_after_format.rc == 0
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Settle udev after removing LUKS mapper
|
||||||
|
ansible.builtin.command: udevadm settle
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Ensure LUKS mapper is opened
|
||||||
|
block:
|
||||||
|
- name: Open LUKS device
|
||||||
|
community.crypto.luks_device:
|
||||||
|
device: "{{ partitioning_luks_device }}"
|
||||||
|
state: opened
|
||||||
|
name: "{{ partitioning_luks_mapper_name }}"
|
||||||
|
passphrase: "{{ partitioning_luks_passphrase_effective }}"
|
||||||
|
allow_discards: "{{ 'discard' in (partitioning_luks_options | default('') | lower) }}"
|
||||||
|
register: partitioning_luks_open_result
|
||||||
|
no_log: true
|
||||||
|
rescue:
|
||||||
|
- name: Force-close stale LUKS mapper
|
||||||
|
community.crypto.luks_device:
|
||||||
|
name: "{{ partitioning_luks_mapper_name }}"
|
||||||
|
state: closed
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Force-remove stale LUKS mapper device
|
||||||
|
ansible.builtin.command: >-
|
||||||
|
dmsetup remove --force --retry {{ partitioning_luks_mapper_name }}
|
||||||
|
register: partitioning_dmsetup_remove_retry
|
||||||
|
changed_when: partitioning_dmsetup_remove_retry.rc == 0
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Settle udev after removing stale LUKS mapper
|
||||||
|
ansible.builtin.command: udevadm settle
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Retry opening LUKS device
|
||||||
|
community.crypto.luks_device:
|
||||||
|
device: "{{ partitioning_luks_device }}"
|
||||||
|
state: opened
|
||||||
|
name: "{{ partitioning_luks_mapper_name }}"
|
||||||
|
passphrase: "{{ partitioning_luks_passphrase_effective }}"
|
||||||
|
allow_discards: "{{ 'discard' in (partitioning_luks_options | default('') | lower) }}"
|
||||||
|
register: partitioning_luks_open_retry
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
- name: Get LUKS UUID
|
||||||
|
ansible.builtin.command: "cryptsetup luksUUID {{ partitioning_luks_device }}"
|
||||||
|
register: partitioning_luks_uuid_result
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Store LUKS UUID
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
partitioning_luks_uuid: "{{ partitioning_luks_uuid_result.stdout | trim }}"
|
||||||
|
|
||||||
- name: Create LVM logical volumes
|
- name: Create LVM logical volumes
|
||||||
when: filesystem != 'btrfs'
|
when: filesystem != 'btrfs'
|
||||||
@@ -35,7 +306,7 @@
|
|||||||
- name: Create LVM volume group
|
- name: Create LVM volume group
|
||||||
community.general.lvg:
|
community.general.lvg:
|
||||||
vg: sys
|
vg: sys
|
||||||
pvs: "{{ install_drive }}{{ main_partition_suffix }}"
|
pvs: "{{ partitioning_root_device }}"
|
||||||
|
|
||||||
- name: Create LVM logical volumes
|
- name: Create LVM logical volumes
|
||||||
when: cis | bool or item.lv not in ['home', 'var', 'var_log', 'var_log_audit']
|
when: cis | bool or item.lv not in ['home', 'var', 'var_log', 'var_log_audit']
|
||||||
@@ -47,31 +318,37 @@
|
|||||||
loop:
|
loop:
|
||||||
- lv: root
|
- lv: root
|
||||||
size: >-
|
size: >-
|
||||||
{{ [(((((vm_size | float) - 0.5 - ((cis | bool) | ternary(7.5, 0)) - (((vm_memory | float / 1024) > 16.0)
|
{{ [(((((partitioning_vm_size | float) - 0.5 - ((cis | bool) | ternary(7.5, 0)) - (((partitioning_vm_memory | float / 1024) > 16.0)
|
||||||
| ternary(((vm_memory | float / 2048) | int), (vm_memory | float / 1024)))) < 4)
|
| ternary(((partitioning_vm_memory | float / 2048) | int), (partitioning_vm_memory | float / 1024)))) < 4)
|
||||||
| ternary(4,((((vm_size | float) - 0.5 - ((cis | bool) | ternary(7.5, 0)) -
|
| ternary(4,((((partitioning_vm_size | float) - 0.5 - ((cis | bool) | ternary(7.5, 0)) -
|
||||||
(((vm_memory | float / 1024) > 16.0)| ternary(((vm_memory | float / 2048) | int), (vm_memory | float / 1024)))) > 12)
|
(((partitioning_vm_memory | float / 1024) > 16.0)
|
||||||
| ternary(((vm_size | float) * 0.4) | round(0, 'ceil'),((vm_size | float) - 0.5 - ((cis | bool)
|
| ternary(
|
||||||
| ternary(7.5, 0)) - (((vm_memory | float / 1024) > 16.0)
|
((partitioning_vm_memory | float / 2048) | int),
|
||||||
| ternary(((vm_memory | float / 2048) | int), (vm_memory | float / 1024))))))))), 4 ] | max | string + 'G' }}
|
(partitioning_vm_memory | float / 1024)
|
||||||
|
)))
|
||||||
|
> 12)
|
||||||
|
| ternary(((partitioning_vm_size | float) * 0.4) | round(0, 'ceil'),((partitioning_vm_size | float) - 0.5 - ((cis | bool)
|
||||||
|
| ternary(7.5, 0)) - (((partitioning_vm_memory | float / 1024) > 16.0)
|
||||||
|
| ternary(((partitioning_vm_memory | float / 2048) | int), (partitioning_vm_memory | float / 1024))))))))), 4 ] | max | string +
|
||||||
|
'G' }}
|
||||||
- lv: swap
|
- lv: swap
|
||||||
size: >-
|
size: >-
|
||||||
{{ ((((vm_size | float) - 0.5 - ((cis | bool) | ternary(7.5, 0))) - (((vm_memory | float / 1024) > 16.0)
|
{{ ((((partitioning_vm_size | float) - 0.5 - ((cis | bool) | ternary(7.5, 0))) - (((partitioning_vm_memory | float / 1024) > 16.0)
|
||||||
| ternary(((vm_memory | float / 2048) | int), (vm_memory | float / 1024)))) < 4)
|
| ternary(((partitioning_vm_memory | float / 2048) | int), (partitioning_vm_memory | float / 1024)))) < 4)
|
||||||
| ternary((((vm_size | float) - 0.5 - ((cis | bool) | ternary(7.5, 0))) - 4), (((vm_memory | float / 1024) > 16.0)
|
| ternary((((partitioning_vm_size | float) - 0.5 - ((cis | bool) | ternary(7.5, 0))) - 4), (((partitioning_vm_memory | float / 1024)
|
||||||
| ternary(((vm_memory | float / 2048) | int), (vm_memory | float / 1024)))) | string + 'G' }}
|
> 16.0)
|
||||||
|
| ternary(((partitioning_vm_memory | float / 2048) | int), (partitioning_vm_memory | float / 1024)))) | string + 'G' }}
|
||||||
- lv: home
|
- lv: home
|
||||||
size: "{{ ([([(((vm_size | float) - 20) * 0.1), 2] | max), 20] | min) | string + 'G' }}"
|
size: "{{ ([([(((partitioning_vm_size | float) - 20) * 0.1), 2] | max), 20] | min) | string + 'G' }}"
|
||||||
|
- {lv: var, size: "2G"}
|
||||||
- { lv: var, size: "2G" }
|
- {lv: var_log, size: "2G"}
|
||||||
- { lv: var_log, size: "2G" }
|
- {lv: var_log_audit, size: "1.5G"}
|
||||||
- { lv: var_log_audit, size: "1.5G" }
|
|
||||||
|
|
||||||
- name: Create filesystems
|
- name: Create filesystems
|
||||||
block:
|
block:
|
||||||
- name: Create FAT32 filesystem in boot partition
|
- name: Create FAT32 filesystem in boot partition
|
||||||
community.general.filesystem:
|
community.general.filesystem:
|
||||||
dev: "{{ install_drive }}{{ boot_partition_suffix }}"
|
dev: "{{ install_drive }}{{ partitioning_boot_partition_suffix }}"
|
||||||
fstype: vfat
|
fstype: vfat
|
||||||
opts: -F32 -n BOOT
|
opts: -F32 -n BOOT
|
||||||
force: true
|
force: true
|
||||||
@@ -86,20 +363,18 @@
|
|||||||
ansible.builtin.include_tasks: "{{ filesystem }}.yml"
|
ansible.builtin.include_tasks: "{{ filesystem }}.yml"
|
||||||
|
|
||||||
- name: Get UUID for boot filesystem
|
- name: Get UUID for boot filesystem
|
||||||
ansible.builtin.command: blkid -s UUID -o value '{{ install_drive }}{{ boot_partition_suffix }}'
|
ansible.builtin.command: blkid -s UUID -o value '{{ install_drive }}{{ partitioning_boot_partition_suffix }}'
|
||||||
|
register: partitioning_boot_uuid
|
||||||
changed_when: false
|
changed_when: false
|
||||||
register: boot_uuid
|
|
||||||
|
|
||||||
- name: Get UUID for main filesystem
|
- name: Get UUID for main filesystem
|
||||||
ansible.builtin.command: blkid -s UUID -o value '{{ install_drive }}{{ main_partition_suffix }}'
|
ansible.builtin.command: blkid -s UUID -o value '{{ partitioning_root_device }}'
|
||||||
|
register: partitioning_main_uuid
|
||||||
changed_when: false
|
changed_when: false
|
||||||
register: main_uuid
|
|
||||||
|
|
||||||
- name: Get UUIDs for LVM filesystems
|
- name: Get UUIDs for LVM filesystems
|
||||||
when: filesystem != 'btrfs' and (cis | bool or item not in ['home', 'var', 'var_log', 'var_log_audit'])
|
when: filesystem != 'btrfs' and (cis | bool or item not in ['home', 'var', 'var_log', 'var_log_audit'])
|
||||||
ansible.builtin.command: blkid -s UUID -o value /dev/sys/{{ item }}
|
ansible.builtin.command: blkid -s UUID -o value /dev/sys/{{ item }}
|
||||||
changed_when: false
|
|
||||||
register: uuid_result
|
|
||||||
loop:
|
loop:
|
||||||
- root
|
- root
|
||||||
- swap
|
- swap
|
||||||
@@ -107,72 +382,125 @@
|
|||||||
- var
|
- var
|
||||||
- var_log
|
- var_log
|
||||||
- var_log_audit
|
- var_log_audit
|
||||||
|
register: partitioning_uuid_result
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
- name: Assign UUIDs to Variables
|
- name: Assign UUIDs to Variables
|
||||||
when: filesystem != 'btrfs'
|
when: filesystem != 'btrfs'
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
uuid_root: "{{ uuid_result.results[0].stdout_lines }}"
|
partitioning_uuid_root: "{{ partitioning_uuid_result.results[0].stdout_lines }}"
|
||||||
uuid_swap: "{{ uuid_result.results[1].stdout_lines }}"
|
partitioning_uuid_swap: "{{ partitioning_uuid_result.results[1].stdout_lines }}"
|
||||||
uuid_home: "{{ uuid_result.results[2].stdout_lines if cis | bool else '' }}"
|
partitioning_uuid_home: "{{ partitioning_uuid_result.results[2].stdout_lines if cis | bool else '' }}"
|
||||||
uuid_var: "{{ uuid_result.results[3].stdout_lines if cis | bool else '' }}"
|
partitioning_uuid_var: "{{ partitioning_uuid_result.results[3].stdout_lines if cis | bool else '' }}"
|
||||||
uuid_var_log: "{{ uuid_result.results[4].stdout_lines if cis | bool else '' }}"
|
partitioning_uuid_var_log: "{{ partitioning_uuid_result.results[4].stdout_lines if cis | bool else '' }}"
|
||||||
uuid_var_log_audit: "{{ uuid_result.results[5].stdout_lines if cis | bool else '' }}"
|
partitioning_uuid_var_log_audit: "{{ partitioning_uuid_result.results[5].stdout_lines if cis | bool else '' }}"
|
||||||
|
|
||||||
- name: Mount filesystems
|
- name: Mount filesystems
|
||||||
block:
|
block:
|
||||||
- name: Mount filesystems and subvolumes
|
- name: Mount filesystems and subvolumes
|
||||||
when:
|
when:
|
||||||
- cis | bool or (not cis and (item.path == '/var/log' and filesystem == 'btrfs')
|
- >-
|
||||||
or (item.path not in ['/home', '/var', '/var/log', '/var/log/audit']))
|
cis | bool or (
|
||||||
- not (item.path == '/swap' and filesystem != 'btrfs')
|
not cis and (
|
||||||
|
(filesystem == 'btrfs' and item.path in ['/home', '/var/log', '/var/cache/pacman/pkg'])
|
||||||
|
or (item.path not in ['/home', '/var', '/var/log', '/var/log/audit', '/var/cache/pacman/pkg'])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
- >-
|
||||||
|
not (item.path in ['/swap', '/var/cache/pacman/pkg'] and filesystem != 'btrfs')
|
||||||
ansible.posix.mount:
|
ansible.posix.mount:
|
||||||
path: /mnt{{ item.path }}
|
path: /mnt{{ item.path }}
|
||||||
src: "{{ 'UUID=' + (main_uuid.stdout if filesystem == 'btrfs' else item.uuid) }}"
|
src: "{{ 'UUID=' + (partitioning_main_uuid.stdout if filesystem == 'btrfs' else item.uuid) }}"
|
||||||
fstype: "{{ filesystem }}"
|
fstype: "{{ filesystem }}"
|
||||||
opts: "{{ item.opts }}"
|
opts: "{{ item.opts }}"
|
||||||
state: mounted
|
state: mounted
|
||||||
loop:
|
loop:
|
||||||
- path: ""
|
- path: ""
|
||||||
uuid: "{{ uuid_root[0] | default(omit) }}"
|
uuid: "{{ partitioning_uuid_root[0] | default(omit) }}"
|
||||||
opts: "{{ 'defaults' if filesystem != 'btrfs' else 'rw,relatime,compress=zstd:15,ssd,space_cache=v2,discard=async,subvol=@' }}"
|
opts: >-
|
||||||
|
{{
|
||||||
|
'defaults'
|
||||||
|
if filesystem != 'btrfs'
|
||||||
|
else [
|
||||||
|
'rw', 'relatime', 'compress=zstd:15', 'ssd', 'space_cache=v2',
|
||||||
|
'discard=async', 'subvol=@'
|
||||||
|
] | join(',')
|
||||||
|
}}
|
||||||
- path: /swap
|
- path: /swap
|
||||||
opts: "rw,nosuid,nodev,relatime,compress=zstd:15,ssd,space_cache=v2,discard=async,subvol=@swap"
|
opts: >-
|
||||||
|
{{
|
||||||
|
[
|
||||||
|
'rw', 'nosuid', 'nodev', 'relatime', 'compress=zstd:15', 'ssd',
|
||||||
|
'space_cache=v2', 'discard=async', 'subvol=@swap'
|
||||||
|
] | join(',')
|
||||||
|
}}
|
||||||
- path: /home
|
- path: /home
|
||||||
uuid: "{{ uuid_home[0] | default(omit) }}"
|
uuid: "{{ partitioning_uuid_home[0] | default(omit) }}"
|
||||||
opts: "{{ 'defaults,nosuid,nodev' if filesystem != 'btrfs'
|
opts: >-
|
||||||
else 'rw,nosuid,nodev,relatime,compress=zstd:15,ssd,space_cache=v2,discard=async,subvol=@home' }}"
|
{{
|
||||||
|
'defaults,nosuid,nodev'
|
||||||
|
if filesystem != 'btrfs'
|
||||||
|
else [
|
||||||
|
'rw', 'nosuid', 'nodev', 'relatime', 'compress=zstd:15', 'ssd',
|
||||||
|
'space_cache=v2', 'discard=async', 'subvol=@home'
|
||||||
|
] | join(',')
|
||||||
|
}}
|
||||||
- path: /var
|
- path: /var
|
||||||
uuid: "{{ uuid_var[0] | default(omit) }}"
|
uuid: "{{ partitioning_uuid_var[0] | default(omit) }}"
|
||||||
opts: "{{ 'defaults,nosuid,nodev' if filesystem != 'btrfs'
|
opts: >-
|
||||||
else 'rw,nosuid,nodev,relatime,compress=zstd:15,ssd,space_cache=v2,discard=async,subvol=@var' }}"
|
{{
|
||||||
|
'defaults,nosuid,nodev'
|
||||||
|
if filesystem != 'btrfs'
|
||||||
|
else [
|
||||||
|
'rw', 'nosuid', 'nodev', 'relatime', 'compress=zstd:15', 'ssd',
|
||||||
|
'space_cache=v2', 'discard=async', 'subvol=@var'
|
||||||
|
] | join(',')
|
||||||
|
}}
|
||||||
- path: /var/log
|
- path: /var/log
|
||||||
uuid: "{{ uuid_var_log[0] | default(omit) }}"
|
uuid: "{{ partitioning_uuid_var_log[0] | default(omit) }}"
|
||||||
opts: "{{ 'defaults,nosuid,nodev,noexec' if filesystem != 'btrfs'
|
opts: >-
|
||||||
else 'rw,nosuid,nodev,noexec,relatime,compress=zstd:15,ssd,space_cache=v2,discard=async,subvol=@var_log' }}"
|
{{
|
||||||
|
'defaults,nosuid,nodev,noexec'
|
||||||
|
if filesystem != 'btrfs'
|
||||||
|
else [
|
||||||
|
'rw', 'nosuid', 'nodev', 'noexec', 'relatime', 'compress=zstd:15',
|
||||||
|
'ssd', 'space_cache=v2', 'discard=async', 'subvol=@var_log'
|
||||||
|
] | join(',')
|
||||||
|
}}
|
||||||
|
- path: /var/cache/pacman/pkg
|
||||||
|
uuid: "{{ partitioning_uuid_root | default([]) | first | default(omit) }}"
|
||||||
|
opts: >-
|
||||||
|
{{
|
||||||
|
'defaults,nosuid,nodev,noexec'
|
||||||
|
if filesystem != 'btrfs'
|
||||||
|
else [
|
||||||
|
'rw', 'nosuid', 'nodev', 'noexec', 'relatime', 'compress=zstd:15',
|
||||||
|
'ssd', 'space_cache=v2', 'discard=async', 'subvol=@pkg'
|
||||||
|
] | join(',')
|
||||||
|
}}
|
||||||
- path: /var/log/audit
|
- path: /var/log/audit
|
||||||
uuid: "{{ uuid_var_log_audit[0] | default(omit) }}"
|
uuid: "{{ partitioning_uuid_var_log_audit[0] | default(omit) }}"
|
||||||
opts: "{{ 'defaults,nosuid,nodev,noexec' if filesystem != 'btrfs'
|
opts: >-
|
||||||
else 'rw,nosuid,nodev,noexec,relatime,compress=zstd:15,ssd,space_cache=v2,discard=async,subvol=@var_log_audit' }}"
|
{{
|
||||||
|
'defaults,nosuid,nodev,noexec'
|
||||||
- name: Mount tmp and var_tmp filesystems
|
if filesystem != 'btrfs'
|
||||||
ansible.posix.mount:
|
else [
|
||||||
path: /mnt{{ item.path }}
|
'rw', 'nosuid', 'nodev', 'noexec', 'relatime', 'compress=zstd:15',
|
||||||
src: tmpfs
|
'ssd', 'space_cache=v2', 'discard=async', 'subvol=@var_log_audit'
|
||||||
fstype: tmpfs
|
] | join(',')
|
||||||
opts: defaults,nosuid,nodev,noexec
|
}}
|
||||||
state: mounted
|
|
||||||
loop:
|
|
||||||
- { path: /tmp }
|
|
||||||
- { path: /var/tmp }
|
|
||||||
|
|
||||||
- name: Mount boot filesystem
|
- name: Mount boot filesystem
|
||||||
ansible.posix.mount:
|
ansible.posix.mount:
|
||||||
path: "{{ '/mnt/boot/efi' if os | lower in ['rhel8', 'ubuntu', 'ubuntu-lts'] else '/mnt/boot' }}"
|
path: "{{ '/mnt/boot/efi' if os | lower in ['rhel8', 'ubuntu', 'ubuntu-lts'] else '/mnt/boot' }}"
|
||||||
src: UUID={{ boot_uuid.stdout }}
|
src: UUID={{ partitioning_boot_uuid.stdout }}
|
||||||
fstype: vfat
|
fstype: vfat
|
||||||
state: mounted
|
state: mounted
|
||||||
|
|
||||||
- name: Activate swap
|
- name: Activate swap
|
||||||
ansible.builtin.command: "{{ 'swapon /mnt/swap/swapfile' if filesystem == 'btrfs' else 'swapon -U ' + uuid_swap[0] }}"
|
vars:
|
||||||
changed_when: result.rc == 0
|
partitioning_swap_cmd: >-
|
||||||
register: result
|
{{ 'swapon /mnt/swap/swapfile' if filesystem == 'btrfs' else 'swapon -U ' + partitioning_uuid_swap[0] }}
|
||||||
|
ansible.builtin.command: "{{ partitioning_swap_cmd }}"
|
||||||
|
register: partitioning_swap_activate_result
|
||||||
|
changed_when: partitioning_swap_activate_result.rc == 0
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
fstype: xfs
|
fstype: xfs
|
||||||
force: true
|
force: true
|
||||||
loop:
|
loop:
|
||||||
- { lv: root }
|
- {lv: root}
|
||||||
- { lv: home }
|
- {lv: home}
|
||||||
- { lv: var }
|
- {lv: var}
|
||||||
- { lv: var_log }
|
- {lv: var_log}
|
||||||
- { lv: var_log_audit }
|
- {lv: var_log_audit}
|
||||||
|
|||||||
11
roles/virtualization/defaults/main.yml
Normal file
11
roles/virtualization/defaults/main.yml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
virtualization_tpm2_enabled: >-
|
||||||
|
{{
|
||||||
|
(partitioning_luks_enabled | default(luks_enabled | default(false)) | bool)
|
||||||
|
and (partitioning_luks_auto_decrypt | default(luks_auto_decrypt | default(true)) | bool)
|
||||||
|
and (
|
||||||
|
(partitioning_luks_auto_decrypt_method | default(luks_auto_decrypt_method | default('tpm2')))
|
||||||
|
| lower
|
||||||
|
== 'tpm2'
|
||||||
|
)
|
||||||
|
}}
|
||||||
@@ -1,22 +1,34 @@
|
|||||||
---
|
---
|
||||||
- name: Check if VM disk exists
|
- name: Set libvirt image paths
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
ansible.builtin.stat:
|
vars:
|
||||||
path: "{{ vm_path | default('/var/lib/libvirt/images/') }}{{ hostname }}.qcow2"
|
virtualization_libvirt_image_dir_value: "{{ vm_path | default('/var/lib/libvirt/images') }}"
|
||||||
register: vm_disk_stat
|
ansible.builtin.set_fact:
|
||||||
|
virtualization_libvirt_image_dir: "{{ virtualization_libvirt_image_dir_value }}"
|
||||||
|
virtualization_libvirt_disk_path: >-
|
||||||
|
{{ [virtualization_libvirt_image_dir_value, hostname ~ '.qcow2'] | ansible.builtin.path_join }}
|
||||||
|
virtualization_libvirt_cloudinit_path: >-
|
||||||
|
{{ [virtualization_libvirt_image_dir_value, hostname ~ '-cloudinit.iso'] | ansible.builtin.path_join }}
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
- name: Create VM disk
|
- name: Create VM disk
|
||||||
when: not vm_disk_stat.stat.exists
|
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
ansible.builtin.command: qemu-img create -f qcow2 {{ vm_path | default('/var/lib/libvirt/images/') }}{{ hostname }}.qcow2 {{ vm_size }}G
|
ansible.builtin.command:
|
||||||
changed_when: result.rc == 0
|
argv:
|
||||||
register: result
|
- qemu-img
|
||||||
|
- create
|
||||||
|
- -f
|
||||||
|
- qcow2
|
||||||
|
- "{{ virtualization_libvirt_disk_path }}"
|
||||||
|
- "{{ vm_size }}G"
|
||||||
|
creates: "{{ virtualization_libvirt_disk_path }}"
|
||||||
|
|
||||||
- name: Generate Random MAC Address
|
- name: Generate VM MAC address
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
ansible.builtin.shell: set -o pipefail && openssl rand -hex 5 | sed 's/\(..\)/\1:/g; s/.$//' | sed 's/^/02:/'
|
ansible.builtin.set_fact:
|
||||||
|
virtualization_mac_address: >-
|
||||||
|
{{ '52:54:00' | community.general.random_mac(seed=hostname) }}
|
||||||
changed_when: false
|
changed_when: false
|
||||||
register: mac_address_output
|
|
||||||
|
|
||||||
- name: Render cloud config templates
|
- name: Render cloud config templates
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
@@ -25,17 +37,19 @@
|
|||||||
dest: /tmp/{{ item.dest_prefix }}-{{ hostname }}.yml
|
dest: /tmp/{{ item.dest_prefix }}-{{ hostname }}.yml
|
||||||
mode: '0644'
|
mode: '0644'
|
||||||
loop:
|
loop:
|
||||||
- { src: cloud-user-data.yml.j2, dest_prefix: cloud-user-data }
|
- {src: cloud-user-data.yml.j2, dest_prefix: cloud-user-data}
|
||||||
- { src: cloud-network-config.yml.j2, dest_prefix: cloud-network-config }
|
- {src: cloud-network-config.yml.j2, dest_prefix: cloud-network-config}
|
||||||
|
|
||||||
- name: Create cloud-init disk
|
- name: Create cloud-init disk
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
ansible.builtin.command: >
|
ansible.builtin.command:
|
||||||
cloud-localds {{ vm_path | default('/var/lib/libvirt/images/') }}/{{ hostname }}-cloudinit.iso
|
argv:
|
||||||
/tmp/cloud-user-data-{{ hostname }}.yml
|
- cloud-localds
|
||||||
-N /tmp/cloud-network-config-{{ hostname }}.yml
|
- "{{ virtualization_libvirt_cloudinit_path }}"
|
||||||
changed_when: result.rc == 0
|
- "/tmp/cloud-user-data-{{ hostname }}.yml"
|
||||||
register: result
|
- -N
|
||||||
|
- "/tmp/cloud-network-config-{{ hostname }}.yml"
|
||||||
|
creates: "{{ virtualization_libvirt_cloudinit_path }}"
|
||||||
|
|
||||||
- name: Create VM using libvirt
|
- name: Create VM using libvirt
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
|
|||||||
@@ -1,7 +1,26 @@
|
|||||||
---
|
---
|
||||||
- name: Deploy VM on Proxmox
|
- name: Deploy VM on Proxmox
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
community.general.proxmox_kvm:
|
vars:
|
||||||
|
virtualization_dns_value: "{{ vm_dns | default('') }}"
|
||||||
|
virtualization_dns_list_raw: >-
|
||||||
|
{{
|
||||||
|
virtualization_dns_value
|
||||||
|
if virtualization_dns_value is iterable and virtualization_dns_value is not string
|
||||||
|
else virtualization_dns_value.split(',')
|
||||||
|
}}
|
||||||
|
virtualization_dns_list: >-
|
||||||
|
{{ virtualization_dns_list_raw | map('trim') | reject('equalto', '') | list }}
|
||||||
|
virtualization_search_value: "{{ vm_dns_search | default('') }}"
|
||||||
|
virtualization_search_list_raw: >-
|
||||||
|
{{
|
||||||
|
virtualization_search_value
|
||||||
|
if virtualization_search_value is iterable and virtualization_search_value is not string
|
||||||
|
else virtualization_search_value.split(',')
|
||||||
|
}}
|
||||||
|
virtualization_search_list: >-
|
||||||
|
{{ virtualization_search_list_raw | map('trim') | reject('equalto', '') | list }}
|
||||||
|
community.proxmox.proxmox_kvm:
|
||||||
api_host: "{{ hypervisor_url }}"
|
api_host: "{{ hypervisor_url }}"
|
||||||
api_user: "{{ hypervisor_username }}"
|
api_user: "{{ hypervisor_username }}"
|
||||||
api_password: "{{ hypervisor_password }}"
|
api_password: "{{ hypervisor_password }}"
|
||||||
@@ -17,7 +36,10 @@
|
|||||||
balloon: "{{ vm_ballo | default(omit) }}"
|
balloon: "{{ vm_ballo | default(omit) }}"
|
||||||
numa_enabled: true
|
numa_enabled: true
|
||||||
hotplug: network,disk
|
hotplug: network,disk
|
||||||
|
update: "{{ virtualization_tpm2_enabled | bool }}"
|
||||||
|
update_unsafe: "{{ virtualization_tpm2_enabled | bool }}"
|
||||||
bios: ovmf
|
bios: ovmf
|
||||||
|
machine: "{{ 'q35' if virtualization_tpm2_enabled | bool else omit }}"
|
||||||
boot: ac
|
boot: ac
|
||||||
scsihw: virtio-scsi-single
|
scsihw: virtio-scsi-single
|
||||||
scsi:
|
scsi:
|
||||||
@@ -27,6 +49,12 @@
|
|||||||
format: raw
|
format: raw
|
||||||
pre_enrolled_keys: false
|
pre_enrolled_keys: false
|
||||||
storage: "{{ hypervisor_storage }}"
|
storage: "{{ hypervisor_storage }}"
|
||||||
|
tpmstate0: >-
|
||||||
|
{{
|
||||||
|
{'storage': hypervisor_storage, 'version': '2.0'}
|
||||||
|
if virtualization_tpm2_enabled | bool
|
||||||
|
else omit
|
||||||
|
}}
|
||||||
ide:
|
ide:
|
||||||
ide0: "{{ boot_iso }},media=cdrom"
|
ide0: "{{ boot_iso }},media=cdrom"
|
||||||
ide1: "{{ rhel_iso + ',media=cdrom' if rhel_iso is defined else omit }}"
|
ide1: "{{ rhel_iso + ',media=cdrom' if rhel_iso is defined else omit }}"
|
||||||
@@ -34,14 +62,21 @@
|
|||||||
net:
|
net:
|
||||||
net0: virtio,bridge={{ vm_nif }}{% if vlan_name is defined and vlan_name %},tag={{ vlan_name }}{% endif %}
|
net0: virtio,bridge={{ vm_nif }}{% if vlan_name is defined and vlan_name %},tag={{ vlan_name }}{% endif %}
|
||||||
ipconfig:
|
ipconfig:
|
||||||
ipconfig0: ip={{ vm_ip }}/{{ vm_nms | default(24) }},gw={{ vm_gw }}
|
ipconfig0: >-
|
||||||
nameservers: "{{ vm_dns }}"
|
{{
|
||||||
|
'ip=' ~ vm_ip ~ '/' ~ (vm_nms | default(24))
|
||||||
|
~ (',gw=' ~ vm_gw if vm_gw is defined and vm_gw | length else '')
|
||||||
|
if vm_ip is defined and vm_ip | length
|
||||||
|
else 'ip=dhcp'
|
||||||
|
}}
|
||||||
|
nameservers: "{{ virtualization_dns_list if virtualization_dns_list | length else omit }}"
|
||||||
|
searchdomains: "{{ virtualization_search_list if virtualization_search_list | length else omit }}"
|
||||||
onboot: true
|
onboot: true
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
- name: Start VM on Proxmox
|
- name: Start VM on Proxmox
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
community.general.proxmox_kvm:
|
community.proxmox.proxmox_kvm:
|
||||||
api_host: "{{ hypervisor_url }}"
|
api_host: "{{ hypervisor_url }}"
|
||||||
api_user: "{{ hypervisor_username }}"
|
api_user: "{{ hypervisor_username }}"
|
||||||
api_password: "{{ hypervisor_password }}"
|
api_password: "{{ hypervisor_password }}"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
---
|
||||||
- name: Create VM in vCenter
|
- name: Create VM in vCenter
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
community.vmware.vmware_guest:
|
community.vmware.vmware_guest:
|
||||||
@@ -7,12 +8,12 @@
|
|||||||
validate_certs: false
|
validate_certs: false
|
||||||
datacenter: "{{ hypervisor_datacenter }}"
|
datacenter: "{{ hypervisor_datacenter }}"
|
||||||
cluster: "{{ hypervisor_cluster }}"
|
cluster: "{{ hypervisor_cluster }}"
|
||||||
folder: "{{ vm_path }}"
|
folder: "{{ vm_path | default(omit) }}"
|
||||||
name: "{{ hostname }}"
|
name: "{{ hostname }}"
|
||||||
guest_id: otherLinux64Guest
|
guest_id: otherLinux64Guest
|
||||||
annotation: |
|
annotation: |
|
||||||
{{ note | default('') }}
|
{{ note | default('') }}
|
||||||
state: poweredon
|
state: "{{ 'poweredoff' if virtualization_tpm2_enabled | bool else 'poweredon' }}"
|
||||||
disk:
|
disk:
|
||||||
- size_gb: "{{ vm_size }}"
|
- size_gb: "{{ vm_size }}"
|
||||||
type: thin
|
type: thin
|
||||||
@@ -46,9 +47,28 @@
|
|||||||
- name: "{{ vm_nif }}"
|
- name: "{{ vm_nif }}"
|
||||||
type: dhcp
|
type: dhcp
|
||||||
vlan: "{{ vlan_name | default(omit) }}"
|
vlan: "{{ vlan_name | default(omit) }}"
|
||||||
register: vmware_guest_result
|
|
||||||
failed_when:
|
- name: Ensure vTPM2 is enabled when required
|
||||||
- vmware_guest_result.failed is defined and vmware_guest_result.failed
|
when: virtualization_tpm2_enabled | bool
|
||||||
- "'error' in vmware_guest_result"
|
delegate_to: localhost
|
||||||
- "'failed' in vmware_guest_result"
|
community.vmware.vmware_guest_tpm:
|
||||||
- vmware_guest_result.rc is defined and vmware_guest_result.rc != 0
|
hostname: "{{ hypervisor_url }}"
|
||||||
|
username: "{{ hypervisor_username }}"
|
||||||
|
password: "{{ hypervisor_password }}"
|
||||||
|
validate_certs: false
|
||||||
|
datacenter: "{{ hypervisor_datacenter }}"
|
||||||
|
folder: "{{ vm_path | default(omit) }}"
|
||||||
|
name: "{{ hostname }}"
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Start VM in vCenter
|
||||||
|
when: virtualization_tpm2_enabled | bool
|
||||||
|
delegate_to: localhost
|
||||||
|
vmware.vmware.vm_powerstate:
|
||||||
|
hostname: "{{ hypervisor_url }}"
|
||||||
|
username: "{{ hypervisor_username }}"
|
||||||
|
password: "{{ hypervisor_password }}"
|
||||||
|
validate_certs: false
|
||||||
|
datacenter: "{{ hypervisor_datacenter }}"
|
||||||
|
name: "{{ hostname }}"
|
||||||
|
state: powered-on
|
||||||
|
|||||||
@@ -3,9 +3,44 @@ network:
|
|||||||
ethernets:
|
ethernets:
|
||||||
id0:
|
id0:
|
||||||
match:
|
match:
|
||||||
macaddress: "{{ mac_address_output.stdout }}"
|
macaddress: "{{ virtualization_mac_address }}"
|
||||||
|
{% set has_static = vm_ip is defined and vm_ip | length %}
|
||||||
|
{% set dns_value = vm_dns | default('') %}
|
||||||
|
{% set dns_list_raw = dns_value if dns_value is iterable and dns_value is not string else dns_value.split(',') %}
|
||||||
|
{% set dns_list = dns_list_raw | map('trim') | reject('equalto', '') | list %}
|
||||||
|
{% set search_value = vm_dns_search | default('') %}
|
||||||
|
{% set search_list_raw = search_value if search_value is iterable and search_value is not string else search_value.split(',') %}
|
||||||
|
{% set search_list = search_list_raw | map('trim') | reject('equalto', '') | list %}
|
||||||
|
{% if has_static %}
|
||||||
addresses:
|
addresses:
|
||||||
- "{{ vm_ip }}"
|
- "{{ vm_ip }}/{{ vm_nms | default(24) }}"
|
||||||
|
{% if vm_gw is defined and vm_gw | length %}
|
||||||
gateway4: "{{ vm_gw }}"
|
gateway4: "{{ vm_gw }}"
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
dhcp4: true
|
||||||
|
{% if (vm_dns is defined and vm_dns | length) or (vm_dns_search is defined and vm_dns_search | length) %}
|
||||||
|
dhcp4-overrides:
|
||||||
|
{% if vm_dns is defined and vm_dns | length %}
|
||||||
|
use-dns: false
|
||||||
|
{% endif %}
|
||||||
|
{% if vm_dns_search is defined and vm_dns_search | length %}
|
||||||
|
use-domains: false
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if dns_list or search_list %}
|
||||||
nameservers:
|
nameservers:
|
||||||
addresses: ['1.1.1.1', '1.0.0.1']
|
{% if dns_list %}
|
||||||
|
addresses:
|
||||||
|
{% for dns in dns_list %}
|
||||||
|
- "{{ dns }}"
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% if search_list %}
|
||||||
|
search:
|
||||||
|
{% for search in search_list %}
|
||||||
|
- "{{ search }}"
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
<devices>
|
<devices>
|
||||||
<disk type='file' device='disk'>
|
<disk type='file' device='disk'>
|
||||||
<driver name='qemu' type='qcow2'/>
|
<driver name='qemu' type='qcow2'/>
|
||||||
<source file='{{ vm_path | default('/var/lib/libvirt/images/') }}{{ hostname }}.qcow2'/>
|
<source file='{{ virtualization_libvirt_disk_path }}'/>
|
||||||
<target dev='vda' bus='virtio'/>
|
<target dev='vda' bus='virtio'/>
|
||||||
</disk>
|
</disk>
|
||||||
<disk type="file" device="cdrom">
|
<disk type="file" device="cdrom">
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
</disk>
|
</disk>
|
||||||
<disk type="file" device="cdrom">
|
<disk type="file" device="cdrom">
|
||||||
<driver name="qemu" type="raw"/>
|
<driver name="qemu" type="raw"/>
|
||||||
<source file="{{ vm_path | default('/var/lib/libvirt/images/') }}{{ hostname }}-cloudinit.iso"/>
|
<source file="{{ virtualization_libvirt_cloudinit_path }}"/>
|
||||||
<target dev="sdb" bus="sata"/>
|
<target dev="sdb" bus="sata"/>
|
||||||
</disk>
|
</disk>
|
||||||
{% if rhel_iso is defined %}
|
{% if rhel_iso is defined %}
|
||||||
@@ -45,10 +45,15 @@
|
|||||||
</disk>
|
</disk>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<interface type='network'>
|
<interface type='network'>
|
||||||
<mac address="{{ mac_address_output.stdout }}"/>
|
<mac address="{{ virtualization_mac_address }}"/>
|
||||||
<source network='default'/>
|
<source network='default'/>
|
||||||
<model type='virtio'/>
|
<model type='virtio'/>
|
||||||
</interface>
|
</interface>
|
||||||
|
{% if virtualization_tpm2_enabled | default(false) %}
|
||||||
|
<tpm model='tpm-crb'>
|
||||||
|
<backend type='emulator' version='2.0'/>
|
||||||
|
</tpm>
|
||||||
|
{% endif %}
|
||||||
<input type="tablet" bus="usb"/>
|
<input type="tablet" bus="usb"/>
|
||||||
<input type="mouse" bus="ps2"/>
|
<input type="mouse" bus="ps2"/>
|
||||||
<input type="keyboard" bus="ps2"/>
|
<input type="keyboard" bus="ps2"/>
|
||||||
|
|||||||
15
vars_baremetal_example.yml
Normal file
15
vars_baremetal_example.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
hypervisor: "none"
|
||||||
|
install_type: "physical"
|
||||||
|
install_drive: "/dev/sda"
|
||||||
|
|
||||||
|
os: "archlinux"
|
||||||
|
filesystem: "btrfs"
|
||||||
|
|
||||||
|
luks_enabled: true
|
||||||
|
luks_passphrase: "1234"
|
||||||
|
luks_mapper_name: "SYSTEM_DECRYPTED"
|
||||||
|
luks_auto_decrypt: true
|
||||||
|
luks_auto_decrypt_method: "tpm2"
|
||||||
|
luks_tpm2_device: "auto"
|
||||||
|
luks_tpm2_pcrs: "7"
|
||||||
@@ -1,18 +1,39 @@
|
|||||||
|
---
|
||||||
|
# Set vm_ip for static addressing. Remove vm_ip to use DHCP.
|
||||||
vm_ip: "{{ inventory_hostname }}"
|
vm_ip: "{{ inventory_hostname }}"
|
||||||
|
|
||||||
install_type: "virtual"
|
install_type: "virtual"
|
||||||
|
install_drive: "/dev/sda" # Use /dev/vda for virtio/libvirt.
|
||||||
|
custom_iso: false # Set true to skip ArchISO-specific validation and pacman setup.
|
||||||
|
|
||||||
hypervisor_url: "192.168.0.2"
|
hypervisor_url: "pve01.example.com"
|
||||||
hypervisor_username: "root@pam"
|
hypervisor_username: "root@pam"
|
||||||
hypervisor_password: "SomePassword"
|
hypervisor_password: "CHANGE_ME"
|
||||||
hypervisor_node: "NodeName"
|
hypervisor_node: "pve01"
|
||||||
hypervisor_storage: "local-btrfs"
|
hypervisor_storage: "local-lvm"
|
||||||
|
hypervisor_datacenter: "dc01"
|
||||||
|
hypervisor_cluster: "cluster01"
|
||||||
|
|
||||||
# For VMware-Tools
|
# VMware (only needed when hypervisor: vmware)
|
||||||
ansible_vmware_host: "{{ hypervisor_url }}"
|
# vm_path: "/Folder" # Optional folder path segment in vCenter.
|
||||||
ansible_vmware_user: "{{ hypervisor_username }}"
|
|
||||||
ansible_vmware_password: "{{ hypervisor_password }}"
|
|
||||||
ansible_vmware_guest_path: "/{{ hypervisor_cluster }}/vm{{ vm_path }}/{{ hostname }}"
|
|
||||||
ansible_vmware_validate_certs: no
|
|
||||||
ansible_vmware_tools_user: "root"
|
|
||||||
ansible_vmware_tools_password: ""
|
|
||||||
vmware_ssh: true
|
vmware_ssh: true
|
||||||
|
|
||||||
|
# LUKS disk encryption (optional)
|
||||||
|
# These map to partitioning_luks_* internally.
|
||||||
|
luks_enabled: false
|
||||||
|
luks_passphrase: "CHANGE_ME"
|
||||||
|
luks_mapper_name: "SYSTEM_DECRYPTED"
|
||||||
|
luks_auto_decrypt: true
|
||||||
|
luks_auto_decrypt_method: "tpm2"
|
||||||
|
luks_tpm2_device: "auto"
|
||||||
|
luks_tpm2_pcrs: "7"
|
||||||
|
luks_keyfile_size: 64
|
||||||
|
luks_options: "discard,tries=3"
|
||||||
|
luks_type: "luks2"
|
||||||
|
luks_cipher: "aes-xts-plain64"
|
||||||
|
luks_hash: "sha512"
|
||||||
|
luks_iter_time: 4000
|
||||||
|
luks_key_size: 512
|
||||||
|
luks_pbkdf: "argon2id"
|
||||||
|
luks_use_urandom: true
|
||||||
|
luks_verify_passphrase: true
|
||||||
|
|||||||
Reference in New Issue
Block a user