Compare commits
196 Commits
378d9a88c2
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 8056890460 | |||
| 085e16abe9 | |||
| 23f08b350b | |||
| 315fdef69f | |||
| 2d4127a688 | |||
| 1cc1966b97 | |||
| 4d72a8999f | |||
| e264d1cabc | |||
| aa6e356444 | |||
| fe0b72c9d8 | |||
| ce972e55dd | |||
| 2891de8fef | |||
| 696df925c6 | |||
| 65ef8cb1ca | |||
| 396d802dc3 | |||
| 90cc9add01 | |||
| eeaf3b0f0a | |||
| 0a76e07b39 | |||
| 82a1548b2e | |||
| 95b793885a | |||
| f7c020de52 | |||
| 7e4c2d87e2 | |||
| bc6bd2823f | |||
| 01e0ea8b4b | |||
| 75395cc8d2 | |||
| be80c4096c | |||
| f8e3ce62d4 | |||
| 78316a8946 | |||
| 5226206cab | |||
| d9e42c0c84 | |||
| b9484dadab | |||
| 230b14e2ab | |||
| f9a8791b4d | |||
| f46dea0748 | |||
| b1eedd30dc | |||
| 98d0a4954d | |||
| fd37b4ee96 | |||
| 7fe2a0dcc1 | |||
| cc77f646d7 | |||
| 2be6117aac | |||
| 232ab244ca | |||
| ef945d925a | |||
| 366299ea6d | |||
| 3da6894ff1 | |||
| e1db2ce434 | |||
| ae4fb6f43c | |||
| 2c23ce6cbb | |||
| 0211efbae7 | |||
| dda1287f23 | |||
| f62dba3ed6 | |||
| f08855456a | |||
| 4bce08e77b | |||
| 72ec492a33 | |||
| efad1b9a67 | |||
| 732784fa2d | |||
| a71d27c29d | |||
| 7953c2c285 | |||
| 7a1a44220b | |||
| 970af5ff73 | |||
| 035189d326 | |||
| ede6829a89 | |||
| b9156a0cac | |||
| 1c5f93e76f | |||
| fe635b0783 | |||
| 0b4d2320c0 | |||
| 11f7af1d9f | |||
| e3a52b889b | |||
| ff2e5fb6b8 | |||
| db62d360b7 | |||
| 3d3f1caa14 | |||
| 200e73e3ef | |||
| f5fda74cad | |||
| 9e4ae3ae33 | |||
| 052c89aa3e | |||
| 21e6edcf63 | |||
| 4961cc4b03 | |||
| a7497dbb0e | |||
| c764c209cb | |||
| 9096a8fc18 | |||
| 236df77406 | |||
| ba6938b225 | |||
| 919c2085d2 | |||
| 55e7b5e98c | |||
| ef81e6b121 | |||
| 2cf2f71b9c | |||
| 7b972053ef | |||
| 1afe5155ce | |||
| 67065520a2 | |||
| b3b6376d81 | |||
| 9f14556ef6 | |||
| 293b608c84 | |||
| 50a7011de7 | |||
| 8d0c948dff | |||
| 183ec709f6 | |||
| 6dd32b5a63 | |||
| 9fdf83aad3 | |||
| 15fc6e0dd1 | |||
| f866502d47 | |||
| 4291aa8c4a | |||
| 6e8ac0283a | |||
| c650c2b50c | |||
| 2cc06e3f7d | |||
| 8ba12fe4bf | |||
| c72ccd06aa | |||
| bfadc82e82 | |||
| c1b5793cab | |||
| 72dabe3107 | |||
| 0ff03d9d6f | |||
| 247e3e6c3b | |||
| d864a492ee | |||
| 2e7e4d6423 | |||
| 2d96b12367 | |||
| 9f3d638381 | |||
| 88aebd5276 | |||
| 29a493bf13 | |||
| 99e0fb9e5c | |||
| 8618f8cf03 | |||
| ccc53081f4 | |||
| 46b7f56425 | |||
| 3994d4192d | |||
| e22cf5cc60 | |||
| 08a35b2b6b | |||
| e357c7881a | |||
| 10d6095aad | |||
| fcc2ace185 | |||
| e3d61d5fdc | |||
| 1af1ea8ffb | |||
| 9ebfc500a2 | |||
| 8a655993bd | |||
| ff4f9cdb07 | |||
| d8d4371195 | |||
| fea97ba140 | |||
| 72305d48a3 | |||
| 03cc238237 | |||
| 5328d7cce3 | |||
| 785667c0d6 | |||
| 4cfde890f3 | |||
| 5bc981ffc7 | |||
| 510bf0af89 | |||
| fa175eeb78 | |||
| 42b38f0d02 | |||
| 98bdb9b824 | |||
| d499e222bb | |||
| 1201fe8f4b | |||
| 5742a9fd78 | |||
| 0c82d4da87 | |||
| 5930ef0759 | |||
| 6e60a6e4b4 | |||
| 0a3363f725 | |||
| 367a77945e | |||
| b6ab48d062 | |||
| 8cc54806c1 | |||
| bcbddf0955 | |||
| 111cb79f2f | |||
| c437e4c43d | |||
| d164b6a573 | |||
| 1e625fd138 | |||
| 051b7a376f | |||
| 77b5920ddb | |||
| 61fdf1461a | |||
| 6c311159d8 | |||
| 7e6d8e73b4 | |||
| 7374b0a4e2 | |||
| ab694ef49c | |||
| 48cedc8efc | |||
| ca5caba602 | |||
| 9ad4e96806 | |||
| 6e2f081794 | |||
| 8ac881ada1 | |||
| 446736da3b | |||
| 15706c5d84 | |||
| 2cba40508b | |||
| d8f39e855c | |||
| 86656f6dbb | |||
| 3af9ccddf2 | |||
| b2fa0ab91d | |||
| 8fef1b695b | |||
| 1130c1688a | |||
| 3d56456ad4 | |||
| 2b97049dec | |||
| 82118be5f9 | |||
| 92a0f18240 | |||
| bd8ae76703 | |||
| a3d2452cd6 | |||
| 8cdf32e85e | |||
| 58e9ded653 | |||
| 187c5feac2 | |||
| d21351aed9 | |||
| 559fa6eab7 | |||
| 7ac696393a | |||
| bf1ee09d48 | |||
| f65d8cff98 | |||
| f698e04779 | |||
| 1272a30e2e | |||
| 3a512213d0 | |||
| 689be63a16 |
4
.ansible-lint
Normal file
4
.ansible-lint
Normal file
@@ -0,0 +1,4 @@
|
||||
skip_list:
|
||||
- run-once
|
||||
exclude_paths:
|
||||
- roles/global_defaults/
|
||||
195
README.md
195
README.md
@@ -1,6 +1,6 @@
|
||||
# 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
|
||||
|
||||
@@ -8,13 +8,15 @@ Most of the roles are adaptable for use with systems beyond ArchLinux, requiring
|
||||
|
||||
**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.
|
||||
- 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
|
||||
|
||||
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 |
|
||||
| ---------- | ---------------------------------- |
|
||||
@@ -23,7 +25,7 @@ This playbook supports multiple Linux distributions with specific versions tailo
|
||||
| debian11 | Debian 11 (Bullseye) |
|
||||
| debian12 | Debian 12 (Bookworm) |
|
||||
| debian13 | Debian 13 (Trixie) |
|
||||
| fedora | Fedora 42 |
|
||||
| fedora | Fedora 43 |
|
||||
| rhel8 | Red Hat Enterprise Linux 8 |
|
||||
| rhel9 | Red Hat Enterprise Linux 9 |
|
||||
| rhel10 | Red Hat Enterprise Linux 10 |
|
||||
@@ -49,24 +51,86 @@ The playbook uses the ArchLinux ISO as a foundational tool to provides an effici
|
||||
|
||||
## 2. Global Variables
|
||||
|
||||
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 can be supplied via inventory or `-e @vars_example.yml`. 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 |
|
||||
| ----------------------- | ---------------------------------------------------------- | ----------------------------------------- |
|
||||
| `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` |
|
||||
| `vlan_name` (optional) | VLAN for the VM's network interface. | `vlan100` |
|
||||
| `hypervisor` | Type of hypervisor (required for virtual installs). | `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 (default)` |
|
||||
| `selinux` (optional) | Toggle SELinux where supported. | `true (default)`, `false` |
|
||||
| `firewalld_enabled` (optional) | Toggle firewalld package/service enablement. | `true (default)`, `false` |
|
||||
| `ssh_enabled` (optional) | Toggle SSH server package/service enablement. | `true (default)`, `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 (default)` |
|
||||
| `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`, `manual` |
|
||||
| `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` |
|
||||
|
||||
### 2.5 Partitioning Overrides (advanced)
|
||||
|
||||
Use these only when you need to override the default layout logic.
|
||||
|
||||
| Variable | Description | Example Value |
|
||||
| ---------------------------- | -------------------------------------------------------- | ------------- |
|
||||
| `partitioning_efi_size_mib` | ESP size in MiB. | `512` |
|
||||
| `partitioning_boot_size_mib` | `/boot` size in MiB when a separate boot is used. | `1024` |
|
||||
| `partitioning_separate_boot` | Force a separate `/boot` partition. | `true` |
|
||||
| `partitioning_boot_fs_fstype` | Filesystem for `/boot` when separate. | `ext4` |
|
||||
| `partitioning_use_full_disk` | Use remaining LVM space for the root volume. | `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**.
|
||||
|
||||
@@ -74,30 +138,52 @@ 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.
|
||||
|
||||
| Variable | Description | Example Value |
|
||||
| --------------------- | -------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
|
||||
| `cis` (optional) | Adjusts the installation to be CIS level 3 conformant. | `true`, `false` |
|
||||
| `selinux` (optional) | Toggle SELinux, `false` means it should be disabled.` | `true`, `false` |
|
||||
| `filesystem` | Filesystem type for the VM's primary storage. | `btrfs`, `ext4`, `xfs` |
|
||||
| `hostname` | The hostname assigned to the virtual machine or system. | `vm01` |
|
||||
| `os` | Operating system to be installed on the VM. | `archlinux`, `almalinux`, `debian11`, `debian12`, `fedora`, `rhel8`, `rhel9`, `rhel10`, `rocky`, `ubuntu`, `ubuntu-lts` |
|
||||
| `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` |
|
||||
| `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` |
|
||||
| `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` |
|
||||
| `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` |
|
||||
| `vm_gw` | Default gateway IP address for the virtual machine's network configuration. | `192.168.0.1` |
|
||||
| `vm_id` | Unique identifier for the virtual machine. | `101` |
|
||||
| `vm_ip` | IP address assigned to the virtual machine. | `192.168.0.10` |
|
||||
| `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` |
|
||||
| `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` |
|
||||
| `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` |
|
||||
### 3.1 System Identity and OS
|
||||
|
||||
| Variable | Description | Example Value |
|
||||
| ------------ | -------------------------------------- | ---------------------- |
|
||||
| `ansible_host` | Ansible connection address for the host. | `192.168.0.10` |
|
||||
| `os` | Operating system to be installed. | `ubuntu-lts` |
|
||||
| `filesystem` | Filesystem type for the root volume. | `btrfs`, `ext4`, `xfs` |
|
||||
| `hostname` | The hostname assigned to the system. | `vm01` |
|
||||
|
||||
### 3.2 Credentials and Access
|
||||
|
||||
These are prompted by default via `vars_prompt` in `main.yml`, but can be supplied via inventory/vars/`-e` for non-interactive runs.
|
||||
|
||||
| Variable | Description | Example Value |
|
||||
| ----------------- | ---------------------------------- | ----------------- |
|
||||
| `root_password` | Root password (vault recommended). | `SecurePass123` |
|
||||
| `user_name` | Username for a user account. | `adminuser` |
|
||||
| `user_password` | Password for the user account. | `UserPass123` |
|
||||
| `user_public_key` | SSH Key for the user account. | `ssh-ed25519 AAAA` |
|
||||
|
||||
### 3.3 Networking
|
||||
|
||||
| Variable | Description | Example Value |
|
||||
| --------------- | -------------------------------------------------------------- | ----------------- |
|
||||
| `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 (min 20). | `20` |
|
||||
| `vm_memory` | Amount of memory in MB. | `2048` |
|
||||
| `vm_cpus` | Number of CPU cores (virtual installs). | `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
|
||||
|
||||
@@ -107,14 +193,31 @@ Before running the playbook, ensure you have Ansible installed and configured co
|
||||
|
||||
### 4.2 Running the Playbook
|
||||
|
||||
Execute the playbook using the `ansible-playbook` command, ensuring that all necessary variables are defined, typically by specifying a `vars.yml` file containing the required configurations.
|
||||
Execute the playbook using the `ansible-playbook` command, ensuring that all necessary variables are defined, typically by specifying a vars file (such as `vars_example.yml`) containing the required configurations.
|
||||
|
||||
### 4.3 Example Usage
|
||||
|
||||
An effective way to use the playbook involves defining all necessary configurations within a `vars.yml` file. This file should include all relevant global variables tailored to your specific deployment requirements. Additionally, you should prepare an inventory file (`inventory.yml`) that lists all the hosts along with any specific inventory variables they might need. Then, you can run the playbook as follows:
|
||||
An effective way to use the playbook involves defining all necessary configurations within a vars file (for example, `vars_example.yml`). This file should include all relevant global variables tailored to your specific deployment requirements. Additionally, you should prepare an inventory file (`inventory.yml`) that lists all the hosts along with any specific inventory variables they might need. Then, you can run the playbook as follows:
|
||||
|
||||
```bash
|
||||
ansible-playbook -i inventory.yml -e @vars.yml main.yml
|
||||
ansible-playbook -i inventory.yml -e @vars_example.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 the vars file and the inventory file.
|
||||
|
||||
Use `inventory_example.yml`, `inventory_libvirt_example.yml`, `vars_example.yml`, and the bare-metal examples as starting points for new inventories.
|
||||
|
||||
## Notes
|
||||
|
||||
- `vm_size`/`vm_memory`/`vm_cpus` 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.
|
||||
- Molecule is scaffolded with a delegated driver and a no-op converge for lint-only validation.
|
||||
- With LUKS enabled on Debian/Ubuntu and RHEL-based systems, provisioning uses an ESP (512 MiB), a separate `/boot`
|
||||
(1 GiB, same as `filesystem` unless `btrfs` uses ext4 on Debian/Ubuntu or xfs on RHEL-based), and the encrypted root;
|
||||
adjust sizes via
|
||||
`partitioning_efi_size_mib` and `partitioning_boot_size_mib` if needed.
|
||||
- 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,50 @@
|
||||
---
|
||||
all:
|
||||
vars:
|
||||
hypervisor: 'proxmox'
|
||||
install_drive: '/dev/sda'
|
||||
cis: true
|
||||
boot_iso: "local-btrfs:iso/archlinux-x86_64.iso"
|
||||
install_type: "virtual"
|
||||
hypervisor: "proxmox"
|
||||
install_drive: "/dev/sda"
|
||||
boot_iso: "local:iso/archlinux-x86_64.iso"
|
||||
vm_nif: "vmbr0"
|
||||
children:
|
||||
promox-kvm:
|
||||
hosts:
|
||||
192.168.122.10:
|
||||
hostname: proxy
|
||||
vm_id: 100
|
||||
os: archlinux
|
||||
filesystem: btrfs
|
||||
vm_memory: "2048"
|
||||
vm_ballo: "1024"
|
||||
vm_cpus: "2"
|
||||
vm_size: "5"
|
||||
vm_nif: vmbr1
|
||||
vm_gw: 192.168.122.1
|
||||
vm_dns: 1.1.1.1
|
||||
vm_dns_search: "example.com"
|
||||
192.168.122.11:
|
||||
hostname: database
|
||||
vm_id: 101
|
||||
os: rhel9
|
||||
filesystem: xfs
|
||||
vm_memory: "6144"
|
||||
vm_ballo: "3072"
|
||||
vm_cpus: "4"
|
||||
vm_size: "40"
|
||||
vm_nif: vmbr1
|
||||
vm_gw: 192.168.122.1
|
||||
vm_dns: 1.1.1.1
|
||||
rhel_iso: "local-btrfs:iso/rhel-9.4-x86_64-dvd.iso"
|
||||
proxmox:
|
||||
hosts:
|
||||
app01.example.com:
|
||||
ansible_host: 10.0.0.10
|
||||
hostname: "app01.example.com"
|
||||
os: "archlinux"
|
||||
filesystem: "btrfs"
|
||||
vm_id: 100
|
||||
vm_cpus: 2
|
||||
vm_memory: 4096
|
||||
vm_size: 40
|
||||
vm_ip: 10.0.0.10
|
||||
vm_nms: 24
|
||||
vm_gw: 10.0.0.1
|
||||
vm_dns:
|
||||
- 1.1.1.1
|
||||
- 1.0.0.1
|
||||
extra_packages:
|
||||
- jq
|
||||
- tmux
|
||||
db01.example.com:
|
||||
ansible_host: 10.0.0.11
|
||||
hostname: "db01.example.com"
|
||||
os: "rhel9"
|
||||
filesystem: "xfs"
|
||||
vm_id: 101
|
||||
vm_cpus: 4
|
||||
vm_memory: 8192
|
||||
vm_size: 80
|
||||
vm_ip: 10.0.0.11
|
||||
vm_nms: 24
|
||||
vm_gw: 10.0.0.1
|
||||
vm_dns: "1.1.1.1,1.0.0.1"
|
||||
rhel_iso: "local:iso/rhel-9.4-x86_64-dvd.iso"
|
||||
luks_enabled: true
|
||||
luks_passphrase: "CHANGE_ME"
|
||||
luks_auto_decrypt_method: "keyfile"
|
||||
luks_keyfile_size: 128
|
||||
cis: true
|
||||
selinux: false
|
||||
firewalld_enabled: false
|
||||
|
||||
56
inventory_libvirt_example.yml
Normal file
56
inventory_libvirt_example.yml
Normal file
@@ -0,0 +1,56 @@
|
||||
---
|
||||
all:
|
||||
vars:
|
||||
install_type: "virtual"
|
||||
hypervisor: "libvirt"
|
||||
install_drive: "/dev/vda"
|
||||
boot_iso: "/var/lib/libvirt/images/archlinux-x86_64.iso"
|
||||
children:
|
||||
libvirt:
|
||||
hosts:
|
||||
web01.example.com:
|
||||
ansible_host: 192.168.122.10
|
||||
hostname: "web01.example.com"
|
||||
os: "debian12"
|
||||
filesystem: "ext4"
|
||||
vm_cpus: 2
|
||||
vm_memory: 2048
|
||||
vm_size: 30
|
||||
vm_ip: 192.168.122.10
|
||||
vm_nms: 24
|
||||
vm_gw: 192.168.122.1
|
||||
vm_dns: 1.1.1.1
|
||||
extra_packages:
|
||||
- nginx
|
||||
- fail2ban
|
||||
vault01.example.com:
|
||||
ansible_host: 192.168.122.11
|
||||
hostname: "vault01.example.com"
|
||||
os: "ubuntu-lts"
|
||||
filesystem: "btrfs"
|
||||
vm_cpus: 2
|
||||
vm_memory: 4096
|
||||
vm_size: 40
|
||||
vm_ip: 192.168.122.11
|
||||
vm_nms: 24
|
||||
vm_gw: 192.168.122.1
|
||||
vm_dns_search: "example.com"
|
||||
luks_enabled: true
|
||||
luks_passphrase: "CHANGE_ME"
|
||||
luks_auto_decrypt_method: "keyfile"
|
||||
firewalld_enabled: false
|
||||
rhel9.example.com:
|
||||
ansible_host: 192.168.122.12
|
||||
hostname: "rhel9.example.com"
|
||||
os: "rhel9"
|
||||
filesystem: "xfs"
|
||||
vm_cpus: 4
|
||||
vm_memory: 8192
|
||||
vm_size: 80
|
||||
vm_ip: 192.168.122.12
|
||||
vm_nms: 24
|
||||
vm_gw: 192.168.122.1
|
||||
vm_dns: "1.1.1.1,1.0.0.1"
|
||||
vm_path: "/srv/libvirt/images"
|
||||
rhel_iso: "/var/lib/libvirt/images/rhel-9.4-x86_64-dvd.iso"
|
||||
vlan_name: "100"
|
||||
95
main.yml
95
main.yml
@@ -1,7 +1,7 @@
|
||||
---
|
||||
- name: Create and configure VMs
|
||||
hosts: all
|
||||
strategy: free
|
||||
strategy: free # noqa: run-once[play]
|
||||
gather_facts: false
|
||||
become: true
|
||||
vars_prompt:
|
||||
@@ -24,41 +24,10 @@
|
||||
prompt: |
|
||||
What is your root password?
|
||||
confirm: true
|
||||
vars_files: vars.yml
|
||||
pre_tasks:
|
||||
- name: Set ansible_python_interpreter
|
||||
when: os | lower in ["almalinux", "rhel8", "rhel9", "rhel10", "rocky"]
|
||||
ansible.builtin.set_fact:
|
||||
ansible_python_interpreter: /usr/bin/python3
|
||||
|
||||
- name: Set default variables
|
||||
ansible.builtin.set_fact:
|
||||
cis: false
|
||||
|
||||
- name: Set SSH Access
|
||||
when: hypervisor != "vmware"
|
||||
ansible.builtin.set_fact:
|
||||
ansible_user: "{{ user_name }}"
|
||||
ansible_password: "{{ user_password }}"
|
||||
ansible_become_password: "{{ user_password }}"
|
||||
ansible_ssh_extra_args: "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
||||
|
||||
- name: Validate variables
|
||||
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"
|
||||
ansible.builtin.set_fact:
|
||||
ansible_connection: vmware_tools
|
||||
- name: Load global defaults
|
||||
ansible.builtin.import_role:
|
||||
name: global_defaults
|
||||
|
||||
roles:
|
||||
- role: virtualization
|
||||
@@ -73,31 +42,61 @@
|
||||
|
||||
- role: partitioning
|
||||
vars:
|
||||
boot_partition_suffix: 1
|
||||
main_partition_suffix: 2
|
||||
partitioning_boot_partition_suffix: 1
|
||||
partitioning_main_partition_suffix: 2
|
||||
|
||||
- role: bootstrap
|
||||
|
||||
- role: configuration
|
||||
|
||||
- role: cis
|
||||
when: cis | bool
|
||||
when: cis_enabled
|
||||
|
||||
- role: cleanup
|
||||
when: install_type == "virtual"
|
||||
vars:
|
||||
ansible_connection: local
|
||||
when: install_type in ["virtual", "physical"]
|
||||
become: false
|
||||
|
||||
tasks:
|
||||
- name: Set final SSH Credentials
|
||||
when: hypervisor != 'vmware' or (hypervisor == 'vmware' and vmware_ssh | bool)
|
||||
post_tasks:
|
||||
- name: Set post-reboot connection flags
|
||||
ansible.builtin.set_fact:
|
||||
post_reboot_can_connect: >-
|
||||
{{
|
||||
(ansible_connection | default('ssh')) != 'ssh'
|
||||
or (vm_ip is defined and (vm_ip | 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 | bool
|
||||
ansible.builtin.set_fact:
|
||||
ansible_user: "{{ user_name }}"
|
||||
ansible_password: "{{ user_password }}"
|
||||
ansible_become_password: "{{ user_password }}"
|
||||
ansible_ssh_extra_args: "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
||||
|
||||
- name: Check if VM is back and running
|
||||
when: not (hypervisor == 'vmware' and cis | bool)
|
||||
ansible.builtin.wait_for_connection:
|
||||
timeout: 300
|
||||
- name: Install post-reboot extra packages
|
||||
vars:
|
||||
post_install_extra_packages: >-
|
||||
{{
|
||||
(
|
||||
extra_packages
|
||||
if (extra_packages is iterable and extra_packages is not string)
|
||||
else (extra_packages | string).split(',')
|
||||
)
|
||||
| map('trim')
|
||||
| reject('equalto', '')
|
||||
| list
|
||||
}}
|
||||
when:
|
||||
- post_reboot_can_connect | bool
|
||||
- extra_packages is defined
|
||||
- extra_packages | length > 0
|
||||
- post_install_extra_packages | length > 0
|
||||
ansible.builtin.package:
|
||||
name: "{{ post_install_extra_packages }}"
|
||||
state: present
|
||||
|
||||
8
molecule/default/converge.yml
Normal file
8
molecule/default/converge.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
- name: Molecule converge placeholder
|
||||
hosts: all
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- name: Skip destructive provisioning in Molecule
|
||||
ansible.builtin.debug:
|
||||
msg: "Molecule scenario is lint-only; run main.yml against disposable hosts."
|
||||
19
molecule/default/molecule.yml
Normal file
19
molecule/default/molecule.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
dependency:
|
||||
name: galaxy
|
||||
driver:
|
||||
name: delegated
|
||||
platforms:
|
||||
- name: localhost
|
||||
provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
converge: converge.yml
|
||||
inventory:
|
||||
host_vars:
|
||||
localhost:
|
||||
ansible_connection: local
|
||||
lint:
|
||||
name: ansible-lint
|
||||
verifier:
|
||||
name: ansible
|
||||
9
molecule/default/verify.yml
Normal file
9
molecule/default/verify.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
- name: Molecule verify placeholder
|
||||
hosts: all
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- name: Verify placeholder
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- true
|
||||
20
roles/bootstrap/tasks/almalinux.yml
Normal file
20
roles/bootstrap/tasks/almalinux.yml
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
- name: Bootstrap AlmaLinux 9
|
||||
vars:
|
||||
bootstrap_alma_extra: >-
|
||||
{{
|
||||
lookup('vars', bootstrap_var_key)
|
||||
| reject('equalto', '')
|
||||
| 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
|
||||
- >-
|
||||
{{ chroot_command }} /mnt dnf --releasever=9 --setopt=install_weak_deps=False
|
||||
install -y {{ bootstrap_alma_extra }}
|
||||
register: bootstrap_result
|
||||
changed_when: bootstrap_result.rc == 0
|
||||
11
roles/bootstrap/tasks/archlinux.yml
Normal file
11
roles/bootstrap/tasks/archlinux.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
- name: Bootstrap ArchLinux
|
||||
vars:
|
||||
bootstrap_archlinux_packages: >-
|
||||
{{
|
||||
lookup('vars', bootstrap_var_key)
|
||||
}}
|
||||
ansible.builtin.command: >-
|
||||
pacstrap /mnt {{ bootstrap_archlinux_packages | reject('equalto', '') | 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 | reject('equalto', '') | join(',') }}"
|
||||
bootstrap_debian_extra: >-
|
||||
{{
|
||||
(
|
||||
bootstrap_debian_extra_list
|
||||
)
|
||||
| reject('equalto', '')
|
||||
| join(' ')
|
||||
}}
|
||||
ansible.builtin.command: "{{ item }}"
|
||||
loop:
|
||||
- >-
|
||||
debootstrap --include={{ bootstrap_debian_base }}
|
||||
{{ bootstrap_debian_release }} /mnt http://deb.debian.org/debian/
|
||||
- "{{ chroot_command }} /mnt apt install -y {{ bootstrap_debian_extra }}"
|
||||
- "{{ chroot_command }} /mnt apt remove -y libcups2 libavahi-common3 libavahi-common-data"
|
||||
register: bootstrap_result
|
||||
changed_when: bootstrap_result.rc == 0
|
||||
22
roles/bootstrap/tasks/fedora.yml
Normal file
22
roles/bootstrap/tasks/fedora.yml
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
- name: Bootstrap Fedora 43
|
||||
vars:
|
||||
bootstrap_fedora_extra: >-
|
||||
{{
|
||||
lookup('vars', bootstrap_var_key)
|
||||
| reject('equalto', '')
|
||||
| join(' ')
|
||||
}}
|
||||
ansible.builtin.command: "{{ item }}"
|
||||
loop:
|
||||
- >-
|
||||
dnf --releasever=43 --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
|
||||
- >-
|
||||
{{ chroot_command }} /mnt dnf --releasever=43 --setopt=install_weak_deps=False
|
||||
install -y {{ bootstrap_fedora_extra }}
|
||||
- "{{ chroot_command }} /mnt dnf reinstall -y kernel-core"
|
||||
register: bootstrap_result
|
||||
changed_when: bootstrap_result.rc == 0
|
||||
@@ -1,101 +1,33 @@
|
||||
---
|
||||
- name: Run OS-specific bootstrap process
|
||||
vars:
|
||||
bootstrap_os_key: "{{ os | lower }}"
|
||||
bootstrap_var_key: "{{ 'bootstrap_' + (os | lower | replace('-', '_')) }}"
|
||||
block:
|
||||
- name: Bootstrap ArchLinux
|
||||
when: os | lower == 'archlinux'
|
||||
ansible.builtin.command: pacstrap /mnt {{ archlinux | join(' ') }} --asexplicit
|
||||
changed_when: result.rc == 0
|
||||
register: result
|
||||
- name: Include AlmaLinux bootstrap tasks
|
||||
when: bootstrap_os_key == 'almalinux'
|
||||
ansible.builtin.include_tasks: almalinux.yml
|
||||
|
||||
- name: Bootstrap Debian System
|
||||
when: os | lower in ['debian11', 'debian12', 'debian13']
|
||||
ansible.builtin.command: "{{ item }}"
|
||||
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: Include ArchLinux bootstrap tasks
|
||||
when: bootstrap_os_key == 'archlinux'
|
||||
ansible.builtin.include_tasks: archlinux.yml
|
||||
|
||||
- name: Bootstrap Ubuntu System
|
||||
when: os | lower in ['ubuntu', 'ubuntu-lts']
|
||||
ansible.builtin.command: "{{ item }}"
|
||||
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: Include Debian bootstrap tasks
|
||||
when: bootstrap_os_key in ['debian11', 'debian12', 'debian13']
|
||||
ansible.builtin.include_tasks: debian.yml
|
||||
|
||||
- name: Bootstrap AlmaLinux 9
|
||||
when: os | lower == 'almalinux'
|
||||
ansible.builtin.command: "{{ item }}"
|
||||
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: Include Fedora bootstrap tasks
|
||||
when: bootstrap_os_key == 'fedora'
|
||||
ansible.builtin.include_tasks: fedora.yml
|
||||
|
||||
- name: Bootstrap Fedora 42
|
||||
when: os | lower == 'fedora'
|
||||
ansible.builtin.command: "{{ item }}"
|
||||
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: Include Rocky bootstrap tasks
|
||||
when: bootstrap_os_key == 'rocky'
|
||||
ansible.builtin.include_tasks: rocky.yml
|
||||
|
||||
- name: Bootstrap RockyLinux 9
|
||||
when: os | lower == 'rocky'
|
||||
ansible.builtin.command: "{{ item }}"
|
||||
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: Include RHEL bootstrap tasks
|
||||
when: bootstrap_os_key in ['rhel8', 'rhel9', 'rhel10']
|
||||
ansible.builtin.include_tasks: rhel.yml
|
||||
|
||||
- name: Bootstrap RHEL System
|
||||
when: os | lower in ['rhel8', 'rhel9', 'rhel10']
|
||||
block:
|
||||
- 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
|
||||
- name: Include Ubuntu bootstrap tasks
|
||||
when: bootstrap_os_key in ['ubuntu', 'ubuntu-lts']
|
||||
ansible.builtin.include_tasks: ubuntu.yml
|
||||
|
||||
61
roles/bootstrap/tasks/rhel.yml
Normal file
61
roles/bootstrap/tasks/rhel.yml
Normal file
@@ -0,0 +1,61 @@
|
||||
---
|
||||
- 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: "{{ chroot_command }} /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)
|
||||
| reject('equalto', '')
|
||||
| join(' ')
|
||||
}}
|
||||
ansible.builtin.command: >-
|
||||
{{ chroot_command }} /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
|
||||
21
roles/bootstrap/tasks/rocky.yml
Normal file
21
roles/bootstrap/tasks/rocky.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
- name: Bootstrap RockyLinux 9
|
||||
vars:
|
||||
bootstrap_rocky_extra: >-
|
||||
{{
|
||||
lookup('vars', bootstrap_var_key)
|
||||
| reject('equalto', '')
|
||||
| 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
|
||||
- >-
|
||||
{{ chroot_command }} /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 | reject('equalto', '') | join(',') }}"
|
||||
bootstrap_ubuntu_extra: >-
|
||||
{{
|
||||
(
|
||||
bootstrap_ubuntu_extra_list
|
||||
)
|
||||
| reject('equalto', '')
|
||||
| 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
|
||||
- "{{ chroot_command }} /mnt sed -i '1s|$| universe|' /etc/apt/sources.list"
|
||||
- "{{ chroot_command }} /mnt apt update"
|
||||
- "{{ chroot_command }} /mnt apt install -y {{ bootstrap_ubuntu_extra }}"
|
||||
register: bootstrap_result
|
||||
changed_when: bootstrap_result.rc == 0
|
||||
@@ -1,8 +1,10 @@
|
||||
almalinux:
|
||||
---
|
||||
bootstrap_almalinux:
|
||||
- bind-utils
|
||||
- dbus-daemon
|
||||
- dhcp-client
|
||||
- efibootmgr
|
||||
- "{{ 'firewalld' if firewalld_enabled | bool else '' }}"
|
||||
- glibc-langpack-de
|
||||
- glibc-langpack-en
|
||||
- grub2
|
||||
@@ -13,23 +15,26 @@ almalinux:
|
||||
- nfs-utils
|
||||
- nfsv4-client-utils
|
||||
- mtr
|
||||
- open-vm-tools
|
||||
- ppp
|
||||
- shim
|
||||
- tmux
|
||||
- "{{ 'cryptsetup' if luks_enabled else '' }}"
|
||||
- "{{ 'tpm2-tools' if luks_enabled else '' }}"
|
||||
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
|
||||
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
|
||||
- vim
|
||||
- wget
|
||||
- zram-generator
|
||||
- zstd
|
||||
|
||||
archlinux:
|
||||
bootstrap_archlinux:
|
||||
- base
|
||||
- btrfs-progs
|
||||
- cronie
|
||||
- dhcpcd
|
||||
- efibootmgr
|
||||
- fastfetch
|
||||
- firewalld
|
||||
- "{{ 'firewalld' if firewalld_enabled | bool else '' }}"
|
||||
- fish
|
||||
- fzf
|
||||
- grub
|
||||
@@ -43,22 +48,24 @@ archlinux:
|
||||
- ncdu
|
||||
- networkmanager
|
||||
- nfs-utils
|
||||
- open-vm-tools
|
||||
- openssh
|
||||
- "{{ 'openssh' if ssh_enabled | bool else '' }}"
|
||||
- ppp
|
||||
- prometheus-node-exporter
|
||||
- python-psycopg2
|
||||
- qemu-guest-agent
|
||||
- reflector
|
||||
- rsync
|
||||
- sudo
|
||||
- tldr
|
||||
- tmux
|
||||
- "{{ 'cryptsetup' if luks_enabled else '' }}"
|
||||
- "{{ 'tpm2-tools' if luks_enabled else '' }}"
|
||||
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
|
||||
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
|
||||
- vim
|
||||
- wireguard-tools
|
||||
- zram-generator
|
||||
|
||||
debian11:
|
||||
bootstrap_debian11:
|
||||
base:
|
||||
- apparmor-utils
|
||||
- btrfs-progs
|
||||
@@ -68,12 +75,14 @@ debian11:
|
||||
- grub-efi
|
||||
- grub-efi-amd64-signed
|
||||
- grub2-common
|
||||
- "{{ 'cryptsetup' if luks_enabled else '' }}"
|
||||
- "{{ 'cryptsetup-initramfs' if luks_enabled else '' }}"
|
||||
- linux-image-amd64
|
||||
- locales
|
||||
- logrotate
|
||||
- lvm2
|
||||
- net-tools
|
||||
- openssh-server
|
||||
- "{{ 'openssh-server' if ssh_enabled | bool else '' }}"
|
||||
- python3
|
||||
- sudo
|
||||
- xfsprogs
|
||||
@@ -82,7 +91,7 @@ debian11:
|
||||
- bat
|
||||
- curl
|
||||
- entr
|
||||
- firewalld
|
||||
- "{{ 'firewalld' if firewalld_enabled | bool else '' }}"
|
||||
- fish
|
||||
- fzf
|
||||
- htop
|
||||
@@ -93,7 +102,6 @@ debian11:
|
||||
- ncdu
|
||||
- neofetch
|
||||
- network-manager
|
||||
- open-vm-tools
|
||||
- python-is-python3
|
||||
- ripgrep
|
||||
- rsync
|
||||
@@ -102,11 +110,14 @@ debian11:
|
||||
- syslog-ng
|
||||
- tcpd
|
||||
- tldr
|
||||
- "{{ 'tpm2-tools' if luks_enabled else '' }}"
|
||||
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
|
||||
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
|
||||
- vim
|
||||
- wget
|
||||
- zstd
|
||||
|
||||
debian12:
|
||||
bootstrap_debian12:
|
||||
base:
|
||||
- btrfs-progs
|
||||
- cron
|
||||
@@ -114,6 +125,8 @@ debian12:
|
||||
- grub-efi
|
||||
- grub-efi-amd64-signed
|
||||
- grub2-common
|
||||
- "{{ 'cryptsetup' if luks_enabled else '' }}"
|
||||
- "{{ 'cryptsetup-initramfs' if luks_enabled else '' }}"
|
||||
- linux-image-amd64
|
||||
- locales
|
||||
- logrotate
|
||||
@@ -127,7 +140,7 @@ debian12:
|
||||
- curl
|
||||
- duf
|
||||
- entr
|
||||
- firewalld
|
||||
- "{{ 'firewalld' if firewalld_enabled | bool else '' }}"
|
||||
- fish
|
||||
- fzf
|
||||
- htop
|
||||
@@ -140,8 +153,7 @@ debian12:
|
||||
- neofetch
|
||||
- net-tools
|
||||
- network-manager
|
||||
- open-vm-tools
|
||||
- openssh-server
|
||||
- "{{ 'openssh-server' if ssh_enabled | bool else '' }}"
|
||||
- python-is-python3
|
||||
- python3
|
||||
- ripgrep
|
||||
@@ -153,11 +165,14 @@ debian12:
|
||||
- systemd-zram-generator
|
||||
- tcpd
|
||||
- tldr
|
||||
- "{{ 'tpm2-tools' if luks_enabled else '' }}"
|
||||
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
|
||||
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
|
||||
- vim
|
||||
- wget
|
||||
- zstd
|
||||
|
||||
debian13:
|
||||
bootstrap_debian13:
|
||||
base:
|
||||
- btrfs-progs
|
||||
- cron
|
||||
@@ -165,6 +180,8 @@ debian13:
|
||||
- grub-efi
|
||||
- grub-efi-amd64-signed
|
||||
- grub2-common
|
||||
- "{{ 'cryptsetup' if luks_enabled else '' }}"
|
||||
- "{{ 'cryptsetup-initramfs' if luks_enabled else '' }}"
|
||||
- linux-image-amd64
|
||||
- locales
|
||||
- logrotate
|
||||
@@ -179,7 +196,7 @@ debian13:
|
||||
- duf
|
||||
- entr
|
||||
- fastfetch
|
||||
- firewalld
|
||||
- "{{ 'firewalld' if firewalld_enabled | bool else '' }}"
|
||||
- fish
|
||||
- fzf
|
||||
- htop
|
||||
@@ -191,8 +208,7 @@ debian13:
|
||||
- ncdu
|
||||
- net-tools
|
||||
- network-manager
|
||||
- open-vm-tools
|
||||
- openssh-server
|
||||
- "{{ 'openssh-server' if ssh_enabled | bool else '' }}"
|
||||
- python-is-python3
|
||||
- python3
|
||||
- ripgrep
|
||||
@@ -202,11 +218,14 @@ debian13:
|
||||
- syslog-ng
|
||||
- systemd-zram-generator
|
||||
- tcpd
|
||||
- "{{ 'tpm2-tools' if luks_enabled else '' }}"
|
||||
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
|
||||
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
|
||||
- vim
|
||||
- wget
|
||||
- zstd
|
||||
|
||||
fedora:
|
||||
bootstrap_fedora:
|
||||
- bat
|
||||
- bind-utils
|
||||
- btrfs-progs
|
||||
@@ -215,6 +234,7 @@ fedora:
|
||||
- duf
|
||||
- efibootmgr
|
||||
- entr
|
||||
- "{{ 'firewalld' if firewalld_enabled | bool else '' }}"
|
||||
- fish
|
||||
- fzf
|
||||
- glibc-langpack-de
|
||||
@@ -229,22 +249,26 @@ fedora:
|
||||
- nc
|
||||
- nfs-utils
|
||||
- nfsv4-client-utils
|
||||
- open-vm-tools
|
||||
- polkit
|
||||
- ppp
|
||||
- ripgrep
|
||||
- shim
|
||||
- tmux
|
||||
- "{{ 'cryptsetup' if luks_enabled else '' }}"
|
||||
- "{{ 'tpm2-tools' if luks_enabled else '' }}"
|
||||
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
|
||||
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
|
||||
- vim-default-editor
|
||||
- wget
|
||||
- zoxide
|
||||
- zram-generator
|
||||
- zstd
|
||||
|
||||
rhel8:
|
||||
bootstrap_rhel8:
|
||||
- bind-utils
|
||||
- dhcp-client
|
||||
- efibootmgr
|
||||
- "{{ 'firewalld' if firewalld_enabled | bool else '' }}"
|
||||
- glibc-langpack-de
|
||||
- glibc-langpack-en
|
||||
- grub2
|
||||
@@ -255,18 +279,22 @@ rhel8:
|
||||
- mtr
|
||||
- ncurses-term
|
||||
- nfs-utils
|
||||
- open-vm-tools
|
||||
- policycoreutils-python-utils
|
||||
- python39
|
||||
- shim
|
||||
- tmux
|
||||
- "{{ 'cryptsetup' if luks_enabled else '' }}"
|
||||
- "{{ 'tpm2-tools' if luks_enabled else '' }}"
|
||||
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
|
||||
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
|
||||
- vim
|
||||
- zstd
|
||||
|
||||
rhel9:
|
||||
bootstrap_rhel9:
|
||||
- bind-utils
|
||||
- dhcp-client
|
||||
- efibootmgr
|
||||
- "{{ 'firewalld' if firewalld_enabled | bool else '' }}"
|
||||
- glibc-langpack-de
|
||||
- glibc-langpack-en
|
||||
- grub2
|
||||
@@ -277,18 +305,22 @@ rhel9:
|
||||
- mtr
|
||||
- ncurses-term
|
||||
- nfs-utils
|
||||
- open-vm-tools
|
||||
- policycoreutils-python-utils
|
||||
- python
|
||||
- shim
|
||||
- tmux
|
||||
- "{{ 'cryptsetup' if luks_enabled else '' }}"
|
||||
- "{{ 'tpm2-tools' if luks_enabled else '' }}"
|
||||
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
|
||||
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
|
||||
- vim
|
||||
- zram-generator
|
||||
- zstd
|
||||
|
||||
rhel10:
|
||||
bootstrap_rhel10:
|
||||
- bind-utils
|
||||
- efibootmgr
|
||||
- "{{ 'firewalld' if firewalld_enabled | bool else '' }}"
|
||||
- glibc-langpack-de
|
||||
- glibc-langpack-en
|
||||
- grub2
|
||||
@@ -299,20 +331,24 @@ rhel10:
|
||||
- mtr
|
||||
- ncurses-term
|
||||
- nfs-utils
|
||||
- open-vm-tools
|
||||
- policycoreutils-python-utils
|
||||
- python
|
||||
- shim
|
||||
- tmux
|
||||
- "{{ 'cryptsetup' if luks_enabled else '' }}"
|
||||
- "{{ 'tpm2-tools' if luks_enabled else '' }}"
|
||||
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
|
||||
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
|
||||
- vim
|
||||
- zram-generator
|
||||
- zstd
|
||||
|
||||
rocky:
|
||||
bootstrap_rocky:
|
||||
- bind-utils
|
||||
- dbus-daemon
|
||||
- dhcp-client
|
||||
- efibootmgr
|
||||
- "{{ 'firewalld' if firewalld_enabled | bool else '' }}"
|
||||
- glibc-langpack-de
|
||||
- glibc-langpack-en
|
||||
- grub2
|
||||
@@ -323,18 +359,21 @@ rocky:
|
||||
- nc
|
||||
- nfs-utils
|
||||
- nfsv4-client-utils
|
||||
- open-vm-tools
|
||||
- ppp
|
||||
- shim
|
||||
- telnet
|
||||
- tmux
|
||||
- "{{ 'cryptsetup' if luks_enabled else '' }}"
|
||||
- "{{ 'tpm2-tools' if luks_enabled else '' }}"
|
||||
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
|
||||
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
|
||||
- util-linux-core
|
||||
- vim
|
||||
- wget
|
||||
- zram-generator
|
||||
- zstd
|
||||
|
||||
ubuntu:
|
||||
bootstrap_ubuntu:
|
||||
base:
|
||||
- btrfs-progs
|
||||
- cron
|
||||
@@ -342,7 +381,8 @@ ubuntu:
|
||||
- grub-efi
|
||||
- grub-efi-amd64-signed
|
||||
- grub2-common
|
||||
- initramfs-tools
|
||||
- "{{ 'cryptsetup' if luks_enabled else '' }}"
|
||||
- "{{ 'cryptsetup-initramfs' if luks_enabled else '' }}"
|
||||
- linux-image-generic
|
||||
- locales
|
||||
- lvm2
|
||||
@@ -360,7 +400,7 @@ ubuntu:
|
||||
- eza
|
||||
- fdupes
|
||||
- fio
|
||||
- firewalld
|
||||
- "{{ 'firewalld' if firewalld_enabled | bool else '' }}"
|
||||
- fish
|
||||
- htop
|
||||
- jq
|
||||
@@ -372,8 +412,7 @@ ubuntu:
|
||||
- ncurses-term
|
||||
- net-tools
|
||||
- network-manager
|
||||
- open-vm-tools
|
||||
- openssh-server
|
||||
- "{{ 'openssh-server' if ssh_enabled | bool else '' }}"
|
||||
- python-is-python3
|
||||
- python3
|
||||
- ripgrep
|
||||
@@ -386,6 +425,9 @@ ubuntu:
|
||||
- tcpd
|
||||
- tldr
|
||||
- tmux
|
||||
- "{{ 'tpm2-tools' if luks_enabled else '' }}"
|
||||
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
|
||||
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
|
||||
- traceroute
|
||||
- util-linux-extra
|
||||
- vim
|
||||
@@ -394,7 +436,7 @@ ubuntu:
|
||||
- zoxide
|
||||
- zstd
|
||||
|
||||
ubuntu-lts:
|
||||
bootstrap_ubuntu_lts:
|
||||
base:
|
||||
- btrfs-progs
|
||||
- cron
|
||||
@@ -402,7 +444,8 @@ ubuntu-lts:
|
||||
- grub-efi
|
||||
- grub-efi-amd64-signed
|
||||
- grub2-common
|
||||
- initramfs-tools
|
||||
- "{{ 'cryptsetup' if luks_enabled else '' }}"
|
||||
- "{{ 'cryptsetup-initramfs' if luks_enabled else '' }}"
|
||||
- linux-image-generic
|
||||
- locales
|
||||
- lvm2
|
||||
@@ -420,7 +463,7 @@ ubuntu-lts:
|
||||
- eza
|
||||
- fdupes
|
||||
- fio
|
||||
- firewalld
|
||||
- "{{ 'firewalld' if firewalld_enabled | bool else '' }}"
|
||||
- fish
|
||||
- htop
|
||||
- jq
|
||||
@@ -432,8 +475,7 @@ ubuntu-lts:
|
||||
- ncurses-term
|
||||
- net-tools
|
||||
- network-manager
|
||||
- open-vm-tools
|
||||
- openssh-server
|
||||
- "{{ 'openssh-server' if ssh_enabled | bool else '' }}"
|
||||
- python-is-python3
|
||||
- python3
|
||||
- ripgrep
|
||||
@@ -446,6 +488,9 @@ ubuntu-lts:
|
||||
- tcpd
|
||||
- tldr
|
||||
- tmux
|
||||
- "{{ 'tpm2-tools' if luks_enabled else '' }}"
|
||||
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
|
||||
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
|
||||
- traceroute
|
||||
- util-linux-extra
|
||||
- vim
|
||||
|
||||
21
roles/cis/defaults/main.yml
Normal file
21
roles/cis/defaults/main.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
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")
|
||||
}}
|
||||
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: "{{ chroot_command }} /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: >
|
||||
{{ chroot_command }} /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
|
||||
block:
|
||||
- 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: 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
|
||||
- name: Include CIS hardening tasks
|
||||
ansible.builtin.include_tasks: "{{ cis_task }}"
|
||||
loop:
|
||||
- modules.yml
|
||||
- sysctl.yml
|
||||
- auth.yml
|
||||
- crypto.yml
|
||||
- files.yml
|
||||
- security_lines.yml
|
||||
- permissions.yml
|
||||
- sshd.yml
|
||||
loop_control:
|
||||
loop_var: cis_task
|
||||
|
||||
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"
|
||||
16
roles/cis/tasks/permissions.yml
Normal file
16
roles/cis/tasks/permissions.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
- 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 else "bash.bashrc" }}', content: umask 077}
|
||||
- {path: '/mnt/etc/{{ "bashrc" if is_rhel 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
|
||||
5
roles/cleanup/defaults/main.yml
Normal file
5
roles/cleanup/defaults/main.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
cleanup_libvirt_image_dir: >-
|
||||
{{ vm_path if vm_path is defined and vm_path | length > 0 else '/var/lib/libvirt/images' }}
|
||||
cleanup_libvirt_cloudinit_path: >-
|
||||
{{ [cleanup_libvirt_image_dir, hostname ~ '-cloudinit.iso'] | ansible.builtin.path_join }}
|
||||
104
roles/cleanup/tasks/libvirt.yml
Normal file
104
roles/cleanup/tasks/libvirt.yml
Normal file
@@ -0,0 +1,104 @@
|
||||
---
|
||||
- name: Remove Archiso and cloud-init disks
|
||||
when: hypervisor == "libvirt"
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
block:
|
||||
- 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
|
||||
vars:
|
||||
ansible_connection: ssh
|
||||
block:
|
||||
- name: Disable Swap
|
||||
ansible.builtin.command: swapoff -a
|
||||
register: swapoff_result
|
||||
changed_when: swapoff_result.rc == 0
|
||||
- name: Cleanup physical install
|
||||
when: install_type == "physical"
|
||||
ansible.builtin.include_tasks: physical.yml
|
||||
|
||||
- name: Unmount /mnt if mounted
|
||||
ansible.builtin.command: umount -R /mnt
|
||||
register: unmount_result
|
||||
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
|
||||
- name: Cleanup virtual install
|
||||
when: install_type == "virtual"
|
||||
ansible.builtin.include_tasks: virtual.yml
|
||||
|
||||
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 if rhel_iso is defined and rhel_iso | length > 0 else 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
|
||||
64
roles/configuration/tasks/bootloader.yml
Normal file
64
roles/configuration/tasks/bootloader.yml
Normal file
@@ -0,0 +1,64 @@
|
||||
---
|
||||
- name: Configure Bootloader
|
||||
block:
|
||||
- name: Install Bootloader
|
||||
vars:
|
||||
configuration_use_efibootmgr: "{{ is_rhel | bool }}"
|
||||
configuration_efi_dir: "{{ partitioning_efi_mountpoint }}"
|
||||
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: "{{ chroot_command }} /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/bin/env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin '
|
||||
+ '/usr/sbin/update-initramfs -u -k all'
|
||||
if is_debian | bool
|
||||
else '/usr/bin/dracut --regenerate-all --force'
|
||||
)
|
||||
}}
|
||||
ansible.builtin.command: "{{ chroot_command }} /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 '
|
||||
+ partitioning_efi_mountpoint
|
||||
+ '/EFI/' + configuration_efi_vendor + '/grub.cfg'
|
||||
if is_rhel | bool
|
||||
else '/usr/sbin/grub-mkconfig -o /boot/grub/grub.cfg'
|
||||
}}
|
||||
ansible.builtin.command: "{{ chroot_command }} /mnt {{ configuration_grub_cfg_cmd }}"
|
||||
register: configuration_grub_result
|
||||
changed_when: configuration_grub_result.rc == 0
|
||||
355
roles/configuration/tasks/encryption.yml
Normal file
355
roles/configuration/tasks/encryption.yml
Normal file
@@ -0,0 +1,355 @@
|
||||
---
|
||||
- name: Configure disk encryption
|
||||
when: partitioning_luks_enabled | bool
|
||||
vars:
|
||||
configuration_luks_passphrase_effective: >-
|
||||
{{ partitioning_luks_passphrase | string }}
|
||||
block:
|
||||
- name: Set LUKS configuration facts
|
||||
vars:
|
||||
configuration_luks_mapper_name_value: >-
|
||||
{{ partitioning_luks_mapper_name }}
|
||||
configuration_luks_device_value: "{{ partitioning_luks_device }}"
|
||||
configuration_luks_tpm2_pcrs_raw: >-
|
||||
{{ partitioning_luks_tpm2_pcrs }}
|
||||
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 }}
|
||||
configuration_luks_auto_method: >-
|
||||
{{
|
||||
(partitioning_luks_auto_decrypt | bool)
|
||||
| ternary(
|
||||
partitioning_luks_auto_decrypt_method,
|
||||
'manual'
|
||||
)
|
||||
}}
|
||||
configuration_luks_tpm2_device: >-
|
||||
{{ partitioning_luks_tpm2_device }}
|
||||
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 | bool
|
||||
- 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 | bool
|
||||
ansible.builtin.file:
|
||||
path: /mnt/etc/dracut.conf.d
|
||||
state: directory
|
||||
mode: "0755"
|
||||
|
||||
- name: Configure dracut for LUKS
|
||||
when: is_rhel | bool
|
||||
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 | bool
|
||||
ansible.builtin.slurp:
|
||||
src: /mnt/etc/kernel/cmdline
|
||||
register: configuration_kernel_cmdline_slurp
|
||||
|
||||
- name: Build kernel cmdline with LUKS args
|
||||
when: is_rhel | bool
|
||||
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 | bool
|
||||
ansible.builtin.copy:
|
||||
dest: /mnt/etc/kernel/cmdline
|
||||
mode: "0644"
|
||||
content: "{{ configuration_kernel_cmdline_new }}\n"
|
||||
|
||||
- name: Find BLS entries
|
||||
when: is_rhel | bool
|
||||
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 | bool
|
||||
- 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 | bool
|
||||
ansible.builtin.slurp:
|
||||
src: /mnt/etc/default/grub
|
||||
register: configuration_grub_slurp
|
||||
|
||||
- name: Build grub command lines with LUKS args
|
||||
when: not is_rhel | bool
|
||||
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 | bool
|
||||
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 | 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 is defined and configuration_luks_keyfile_copy.changed | 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 | 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_cmd: >-
|
||||
{{ chroot_command }} /mnt {{ configuration_luks_enroll_args | join(' ') }}
|
||||
ansible.builtin.command: "{{ configuration_luks_enroll_chroot_cmd }}"
|
||||
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
|
||||
71
roles/configuration/tasks/extras.yml
Normal file
71
roles/configuration/tasks/extras.yml
Normal file
@@ -0,0 +1,71 @@
|
||||
---
|
||||
- name: Append vim configurations to vimrc
|
||||
ansible.builtin.blockinfile:
|
||||
path: "{{ '/mnt/etc/vim/vimrc' if is_debian | bool 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']
|
||||
- swap_enabled | bool
|
||||
ansible.builtin.copy:
|
||||
dest: /mnt/etc/systemd/zram-generator.conf
|
||||
content: |
|
||||
[zram0]
|
||||
zram-size = ram / 2
|
||||
compression-algorithm = {{ 'zstd' if zstd_enabled | bool else 'lz4' }}
|
||||
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
|
||||
120
roles/configuration/tasks/grub.yml
Normal file
120
roles/configuration/tasks/grub.yml
Normal file
@@ -0,0 +1,120 @@
|
||||
---
|
||||
- name: Configure grub defaults
|
||||
when: not is_rhel | bool
|
||||
ansible.builtin.lineinfile:
|
||||
dest: /mnt/etc/default/grub
|
||||
regexp: "{{ item.regexp }}"
|
||||
line: "{{ item.line }}"
|
||||
loop:
|
||||
- regexp: ^GRUB_CMDLINE_LINUX_DEFAULT=
|
||||
line: GRUB_CMDLINE_LINUX_DEFAULT="loglevel=3"
|
||||
- regexp: ^GRUB_TIMEOUT=
|
||||
line: GRUB_TIMEOUT=1
|
||||
|
||||
- name: Ensure grub defaults file exists for RHEL-based systems
|
||||
when: is_rhel | bool
|
||||
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: >-
|
||||
{{
|
||||
(
|
||||
['rd.lvm.lv=sys/root']
|
||||
+ (
|
||||
['rd.lvm.lv=sys/swap', 'resume=/dev/mapper/sys-swap']
|
||||
if swap_enabled | bool
|
||||
else []
|
||||
)
|
||||
)
|
||||
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=1
|
||||
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 }}"
|
||||
|
||||
- name: Enable GRUB cryptodisk for encrypted /boot
|
||||
when: partitioning_grub_enable_cryptodisk | bool
|
||||
ansible.builtin.lineinfile:
|
||||
path: /mnt/etc/default/grub
|
||||
regexp: '^GRUB_ENABLE_CRYPTODISK='
|
||||
line: GRUB_ENABLE_CRYPTODISK=y
|
||||
91
roles/configuration/tasks/locales.yml
Normal file
91
roles/configuration/tasks/locales.yml
Normal file
@@ -0,0 +1,91 @@
|
||||
---
|
||||
- name: Reload systemd in installer environment
|
||||
ansible.builtin.systemd:
|
||||
daemon_reload: true
|
||||
|
||||
- name: Set local timezone
|
||||
ansible.builtin.file:
|
||||
src: /usr/share/zoneinfo/Europe/Vienna
|
||||
dest: /mnt/etc/localtime
|
||||
state: link
|
||||
force: true
|
||||
|
||||
- name: Setup locales
|
||||
block:
|
||||
- name: Configure locale.gen
|
||||
when: not is_rhel | bool
|
||||
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 | bool
|
||||
ansible.builtin.command: "{{ chroot_command }} /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 if vm_ip is defined and vm_ip | length > 0 else 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
|
||||
block:
|
||||
- name: Generate fstab
|
||||
ansible.builtin.shell: genfstab -LU /mnt > /mnt/etc/fstab
|
||||
changed_when: result.rc == 0
|
||||
register: result
|
||||
|
||||
- name: Remove depricated attr2 and disable large extent
|
||||
when: os 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"]
|
||||
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
|
||||
- name: Include configuration tasks
|
||||
ansible.builtin.include_tasks: "{{ configuration_task }}"
|
||||
loop:
|
||||
- fstab.yml
|
||||
- locales.yml
|
||||
- services.yml
|
||||
- grub.yml
|
||||
- encryption.yml
|
||||
- bootloader.yml
|
||||
- extras.yml
|
||||
- network.yml
|
||||
- users.yml
|
||||
- sudo.yml
|
||||
- selinux.yml
|
||||
loop_control:
|
||||
loop_var: configuration_task
|
||||
|
||||
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 | bool
|
||||
block:
|
||||
- name: Fix SELinux by pre-labeling the filesystem before first boot
|
||||
when: os | lower in ['almalinux', 'rhel8', 'rhel9', 'rhel10', 'rocky'] and selinux | bool
|
||||
ansible.builtin.command: >
|
||||
{{ chroot_command }} /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 | bool
|
||||
ansible.builtin.lineinfile:
|
||||
path: /mnt/etc/selinux/config
|
||||
regexp: ^SELINUX=
|
||||
line: SELINUX=permissive
|
||||
16
roles/configuration/tasks/services.yml
Normal file
16
roles/configuration/tasks/services.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
- name: Enable Systemd Services
|
||||
ansible.builtin.command: >
|
||||
{{ chroot_command }} /mnt systemctl enable NetworkManager
|
||||
{{ ' firewalld' if firewalld_enabled | bool else '' }}
|
||||
{{
|
||||
(' ssh' if os | lower in ['ubuntu', 'ubuntu-lts'] else
|
||||
(' sshd' if os | lower not in ['debian11', 'debian12', 'debian13'] else ''))
|
||||
if ssh_enabled | bool 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 | bool 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 | bool else "wheel" }}
|
||||
configuration_useradd_cmd: >-
|
||||
{{ chroot_command }} /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: >-
|
||||
{{ chroot_command }} /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 | length > 0
|
||||
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 | length > 0
|
||||
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,30 @@
|
||||
[connection]
|
||||
id=LAN
|
||||
uuid={{ net_uuid.stdout }}
|
||||
uuid={{ configuration_net_uuid }}
|
||||
type=ethernet
|
||||
|
||||
[ethernet]
|
||||
mac-address={{ net_mac.stdout }}
|
||||
|
||||
[ipv4]
|
||||
address={{ vm_ip }}/{{ vm_nms | default (24) }},{{ vm_gw }}
|
||||
dns={{ vm_dns }}
|
||||
{% if vm_dns_search is defined %}
|
||||
dns-search={{ vm_dns_search }}
|
||||
{% endif %}
|
||||
{% set dns_value = vm_dns if vm_dns is defined else '' %}
|
||||
{% 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 if vm_dns_search is defined else '' %}
|
||||
{% 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 }}{{ (',' ~ vm_gw) if (vm_gw is defined and vm_gw | length) else '' }}
|
||||
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]
|
||||
addr-gen-mode=stable-privacy
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
---
|
||||
- name: Configre work environment
|
||||
become: true
|
||||
- name: Configure work environment
|
||||
become: "{{ hypervisor != 'vmware' }}"
|
||||
block:
|
||||
- name: Wait for connection
|
||||
ansible.builtin.wait_for_connection:
|
||||
timeout: 60
|
||||
timeout: 180
|
||||
delay: 5
|
||||
|
||||
- name: Gather facts
|
||||
@@ -13,118 +13,175 @@
|
||||
- name: Check if host is booted from the Arch install media
|
||||
ansible.builtin.stat:
|
||||
path: /run/archiso
|
||||
register: archiso_stat
|
||||
register: environment_archiso_stat
|
||||
|
||||
- name: Abort if the host is not booted from the Arch install media
|
||||
when:
|
||||
- not (custom_iso | bool)
|
||||
- not environment_archiso_stat.stat.exists
|
||||
ansible.builtin.fail:
|
||||
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"
|
||||
ansible.builtin.shell: "set -o pipefail && ip l | awk -F': ' '!/lo/{print $2; exit}'"
|
||||
changed_when: interface_name.rc == 0
|
||||
register: interface_name
|
||||
ansible.builtin.set_fact:
|
||||
environment_interface_name: >-
|
||||
{{
|
||||
(
|
||||
(ansible_facts.interfaces | default(ansible_facts['ansible_interfaces'] | default([])))
|
||||
| reject('equalto', 'lo')
|
||||
| list
|
||||
| first
|
||||
)
|
||||
| default('')
|
||||
}}
|
||||
changed_when: false
|
||||
|
||||
- name: Set IP-Address
|
||||
when: hypervisor == "vmware"
|
||||
ansible.builtin.command: "ip addr replace {{ ansible_host }}/{{ vm_nms | default(24) }} dev {{ interface_name.stdout }}"
|
||||
changed_when: result.rc == 0
|
||||
register: result
|
||||
when:
|
||||
- hypervisor == "vmware"
|
||||
- vm_ip is defined and vm_ip | length > 0
|
||||
ansible.builtin.command: >-
|
||||
ip addr replace {{ vm_ip }}/{{ vm_nms }}
|
||||
dev {{ environment_interface_name }}
|
||||
register: environment_ip_result
|
||||
changed_when: environment_ip_result.rc == 0
|
||||
|
||||
- name: Set Default Gateway
|
||||
when: hypervisor == "vmware"
|
||||
when:
|
||||
- hypervisor == "vmware"
|
||||
- vm_gw is defined and vm_gw | length > 0
|
||||
- vm_ip is defined and vm_ip | length > 0
|
||||
ansible.builtin.command: "ip route replace default via {{ vm_gw }}"
|
||||
changed_when: result.rc == 0
|
||||
register: result
|
||||
register: environment_gateway_result
|
||||
changed_when: environment_gateway_result.rc == 0
|
||||
|
||||
- name: Synchronize clock via NTP
|
||||
ansible.builtin.command: timedatectl set-ntp true
|
||||
changed_when: result.rc == 0
|
||||
register: result
|
||||
register: environment_ntp_result
|
||||
changed_when: false
|
||||
|
||||
- name: Configure SSH for root login
|
||||
when: hypervisor == "vmware" and (vmware_ssh is defined and vmware_ssh | bool)
|
||||
when: hypervisor == "vmware" and vmware_ssh | bool
|
||||
block:
|
||||
- name: Allow empty passwords temporarily
|
||||
- name: Allow login
|
||||
ansible.builtin.replace:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: "^#?PermitEmptyPasswords.*"
|
||||
replace: "PermitEmptyPasswords yes"
|
||||
|
||||
- name: Allow root login
|
||||
ansible.builtin.replace:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: "^#?PermitRootLogin.*"
|
||||
replace: "PermitRootLogin yes"
|
||||
regexp: "{{ item.regexp }}"
|
||||
replace: "{{ item.replace }}"
|
||||
loop:
|
||||
- regexp: "^#?PermitEmptyPasswords.*"
|
||||
replace: "PermitEmptyPasswords yes"
|
||||
- regexp: "^#?PermitRootLogin.*"
|
||||
replace: "PermitRootLogin yes"
|
||||
|
||||
- name: Reload SSH service to apply changes
|
||||
ansible.builtin.service:
|
||||
name: sshd
|
||||
state: reloaded
|
||||
|
||||
- name: Set connection back to SSH
|
||||
- name: Set SSH connection for VMware
|
||||
ansible.builtin.set_fact:
|
||||
ansible_connection: ssh
|
||||
ansible_user: "root"
|
||||
ansible_password: ""
|
||||
ansible_become_password: ""
|
||||
ansible_ssh_extra_args: "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
||||
ansible_user: root
|
||||
|
||||
- name: Speed-up Bootstrap process
|
||||
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"]
|
||||
- name: Prepare installer environment
|
||||
block:
|
||||
- name: Create /iso directory
|
||||
ansible.builtin.file:
|
||||
path: /usr/local/install/redhat/dvd
|
||||
state: directory
|
||||
mode: "0755"
|
||||
- name: Speed-up Bootstrap process
|
||||
when: not (custom_iso | bool)
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/pacman.conf
|
||||
regexp: ^#ParallelDownloads =
|
||||
line: ParallelDownloads = 20
|
||||
|
||||
- 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: Wait for pacman lock to be released
|
||||
when: not (custom_iso | bool)
|
||||
ansible.builtin.wait_for:
|
||||
path: /var/lib/pacman/db.lck
|
||||
state: absent
|
||||
timeout: 120
|
||||
changed_when: false
|
||||
|
||||
- name: Configure RHEL Repos for installation
|
||||
when: os | lower in ["almalinux", "fedora", "rhel8", "rhel9", "rhel10", "rocky"]
|
||||
- name: Setup Pacman
|
||||
when:
|
||||
- not (custom_iso | bool)
|
||||
- "'os' not in item or os in item.os"
|
||||
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]}
|
||||
retries: 4
|
||||
delay: 15
|
||||
|
||||
- name: Prepare /iso mount and repository for RHEL-based systems
|
||||
when: os | lower in ["rhel8", "rhel9", "rhel10"]
|
||||
block:
|
||||
- name: Create /iso directory
|
||||
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 | bool
|
||||
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"
|
||||
|
||||
- name: Check for third-party preparation tasks
|
||||
run_once: true
|
||||
become: false
|
||||
delegate_to: localhost
|
||||
vars:
|
||||
ansible_connection: local
|
||||
block:
|
||||
- name: Create directories for repository files and RPM GPG keys
|
||||
ansible.builtin.file:
|
||||
path: /etc/yum.repos.d
|
||||
state: directory
|
||||
mode: "0755"
|
||||
- name: Resolve third-party preparation task path
|
||||
ansible.builtin.set_fact:
|
||||
environment_thirdparty_tasks_path: >-
|
||||
{{
|
||||
thirdparty_preparation_tasks_path
|
||||
if thirdparty_preparation_tasks_path | regex_search('^/')
|
||||
else playbook_dir + '/' + thirdparty_preparation_tasks_path
|
||||
}}
|
||||
changed_when: false
|
||||
|
||||
- name: Create RHEL repository file
|
||||
ansible.builtin.template:
|
||||
src: "{{ os | lower }}.repo.j2"
|
||||
dest: /etc/yum.repos.d/{{ os | lower }}.repo
|
||||
mode: "0644"
|
||||
- name: Stat third-party preparation tasks
|
||||
ansible.builtin.stat:
|
||||
path: "{{ environment_thirdparty_tasks_path }}"
|
||||
register: environment_thirdparty_tasks_stat
|
||||
changed_when: false
|
||||
|
||||
- name: Run third-party preparation tasks
|
||||
when:
|
||||
- thirdparty_preparation_tasks_path | length > 0
|
||||
- environment_thirdparty_tasks_stat.stat.exists
|
||||
ansible.builtin.include_tasks: >-
|
||||
{{
|
||||
thirdparty_preparation_tasks_path
|
||||
if thirdparty_preparation_tasks_path | regex_search('^/')
|
||||
else playbook_dir + '/' + thirdparty_preparation_tasks_path
|
||||
}}
|
||||
|
||||
31
roles/global_defaults/defaults/main.yml
Normal file
31
roles/global_defaults/defaults/main.yml
Normal file
@@ -0,0 +1,31 @@
|
||||
---
|
||||
hypervisor: "none"
|
||||
custom_iso: false
|
||||
cis: false
|
||||
selinux: true
|
||||
vmware_ssh: false
|
||||
firewalld_enabled: true
|
||||
ssh_enabled: true
|
||||
zstd_enabled: true
|
||||
swap_enabled: true
|
||||
chroot_command: "arch-chroot"
|
||||
thirdparty_preparation_tasks_path: "dropins/preparation.yml"
|
||||
|
||||
cis_enabled: "{{ cis | bool }}"
|
||||
|
||||
luks_enabled: false
|
||||
luks_mapper_name: "SYSTEM_DECRYPTED"
|
||||
luks_auto_decrypt: true
|
||||
luks_auto_decrypt_method: "tpm2"
|
||||
luks_tpm2_device: "auto"
|
||||
luks_tpm2_pcrs: ""
|
||||
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
|
||||
114
roles/global_defaults/tasks/main.yml
Normal file
114
roles/global_defaults/tasks/main.yml
Normal file
@@ -0,0 +1,114 @@
|
||||
---
|
||||
- name: Global defaults loaded
|
||||
ansible.builtin.debug:
|
||||
msg: Global defaults loaded.
|
||||
changed_when: false
|
||||
|
||||
- name: Validate variables
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- install_type is defined and install_type in ["virtual", "physical"]
|
||||
- hypervisor in ["libvirt", "proxmox", "vmware", "none"]
|
||||
- >-
|
||||
install_type is defined and (
|
||||
install_type == "physical"
|
||||
or hypervisor in ["libvirt", "proxmox", "vmware"]
|
||||
)
|
||||
- filesystem is defined and filesystem in ["btrfs", "ext4", "xfs"]
|
||||
- install_drive is defined and install_drive | length > 0
|
||||
- hostname is defined and hostname | length > 0
|
||||
- >-
|
||||
os is defined and os in [
|
||||
"archlinux", "almalinux", "debian11", "debian12", "debian13", "fedora",
|
||||
"rhel8", "rhel9", "rhel10", "rocky", "ubuntu", "ubuntu-lts"
|
||||
]
|
||||
- >-
|
||||
os is defined and (
|
||||
os not in ["rhel8", "rhel9", "rhel10"]
|
||||
or (rhel_iso is defined and rhel_iso | length > 0)
|
||||
)
|
||||
- >-
|
||||
install_type is defined and (
|
||||
install_type == "physical"
|
||||
or (boot_iso is defined and boot_iso | length > 0)
|
||||
)
|
||||
- >-
|
||||
install_type is defined and (
|
||||
install_type == "physical"
|
||||
or (vm_cpus is defined and (vm_cpus | int) > 0)
|
||||
)
|
||||
- >-
|
||||
install_type is defined and (
|
||||
install_type == "physical"
|
||||
or (vm_size is defined and (vm_size | float) > 0)
|
||||
)
|
||||
- >-
|
||||
install_type is defined and (
|
||||
install_type == "physical"
|
||||
or (vm_memory is defined and (vm_memory | float) > 0)
|
||||
)
|
||||
- >-
|
||||
install_type is defined and filesystem is defined and (
|
||||
install_type == "physical"
|
||||
or (
|
||||
vm_size is defined
|
||||
and (vm_size | int) >= 20
|
||||
)
|
||||
)
|
||||
- >-
|
||||
install_type is defined and (
|
||||
install_type == "physical"
|
||||
or (
|
||||
vm_size is defined
|
||||
and vm_memory is defined
|
||||
and filesystem is defined
|
||||
and (
|
||||
filesystem != "btrfs"
|
||||
or (
|
||||
(vm_size | float)
|
||||
>= (
|
||||
(vm_memory | float / 1024 >= 16.0)
|
||||
| ternary(
|
||||
(vm_memory | float / 2048),
|
||||
[vm_memory | float / 1024, 4.0] | max
|
||||
)
|
||||
+ 5.5
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
- >-
|
||||
vm_ip is not defined
|
||||
or vm_ip | length == 0
|
||||
or (vm_nms is defined and (vm_nms | int) > 0)
|
||||
fail_msg: Invalid input specified, please try again.
|
||||
|
||||
- name: Set OS family flags
|
||||
ansible.builtin.set_fact:
|
||||
is_rhel: "{{ os | lower in ['almalinux', 'fedora', 'rhel8', 'rhel9', 'rhel10', 'rocky'] }}"
|
||||
is_debian: "{{ os | 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_python_interpreter: /usr/bin/python3
|
||||
changed_when: false
|
||||
|
||||
- name: Set SSH access
|
||||
when:
|
||||
- install_type == "virtual"
|
||||
- hypervisor != "vmware"
|
||||
ansible.builtin.set_fact:
|
||||
ansible_user: "{{ user_name }}"
|
||||
ansible_password: "{{ user_password }}"
|
||||
ansible_become_password: "{{ user_password }}"
|
||||
ansible_ssh_extra_args: "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
||||
|
||||
- name: Set connection for VMware
|
||||
when: hypervisor == "vmware"
|
||||
ansible.builtin.set_fact:
|
||||
ansible_connection: vmware_tools
|
||||
142
roles/partitioning/defaults/main.yml
Normal file
142
roles/partitioning/defaults/main.yml
Normal file
@@ -0,0 +1,142 @@
|
||||
---
|
||||
partitioning_luks_enabled: "{{ luks_enabled | bool }}"
|
||||
partitioning_luks_passphrase: "{{ luks_passphrase }}"
|
||||
partitioning_luks_mapper_name: "{{ luks_mapper_name }}"
|
||||
partitioning_luks_type: "{{ luks_type }}"
|
||||
partitioning_luks_cipher: "{{ luks_cipher }}"
|
||||
partitioning_luks_hash: "{{ luks_hash }}"
|
||||
partitioning_luks_iter_time: "{{ luks_iter_time }}"
|
||||
partitioning_luks_key_size: "{{ luks_key_size }}"
|
||||
partitioning_luks_pbkdf: "{{ luks_pbkdf }}"
|
||||
partitioning_luks_use_urandom: "{{ luks_use_urandom | bool }}"
|
||||
partitioning_luks_verify_passphrase: "{{ luks_verify_passphrase | bool }}"
|
||||
partitioning_luks_auto_decrypt: "{{ luks_auto_decrypt | bool }}"
|
||||
partitioning_luks_auto_decrypt_method: "{{ luks_auto_decrypt_method }}"
|
||||
partitioning_luks_tpm2_device: "{{ luks_tpm2_device }}"
|
||||
partitioning_luks_tpm2_pcrs: "{{ luks_tpm2_pcrs }}"
|
||||
partitioning_luks_keyfile_size: "{{ luks_keyfile_size }}"
|
||||
partitioning_luks_options: "{{ luks_options }}"
|
||||
partitioning_btrfs_compress_opt: "{{ 'compress=zstd:15' if zstd_enabled | bool else '' }}"
|
||||
partitioning_boot_partition_suffix: 1
|
||||
partitioning_main_partition_suffix: 2
|
||||
partitioning_efi_size_mib: 512
|
||||
partitioning_efi_start_mib: 1
|
||||
partitioning_efi_end_mib: "{{ (partitioning_efi_start_mib | int) + (partitioning_efi_size_mib | int) }}"
|
||||
partitioning_boot_size_mib: 1024
|
||||
partitioning_use_full_disk: true
|
||||
partitioning_separate_boot: >-
|
||||
{{
|
||||
(partitioning_luks_enabled | bool)
|
||||
and (os | lower not in ['archlinux'])
|
||||
}}
|
||||
partitioning_boot_fs_fstype: >-
|
||||
{{
|
||||
(filesystem | lower)
|
||||
if (filesystem | lower) != 'btrfs'
|
||||
else ('xfs' if is_rhel else 'ext4')
|
||||
}}
|
||||
partitioning_boot_fs_partition_suffix: >-
|
||||
{{
|
||||
((partitioning_boot_partition_suffix | int) + 1)
|
||||
if (partitioning_separate_boot | bool) else ''
|
||||
}}
|
||||
partitioning_root_partition_suffix: >-
|
||||
{{
|
||||
(partitioning_main_partition_suffix | int)
|
||||
+ (1 if (partitioning_separate_boot | bool) else 0)
|
||||
}}
|
||||
partitioning_efi_mountpoint: >-
|
||||
{{
|
||||
'/boot/efi'
|
||||
if (partitioning_separate_boot | bool)
|
||||
else (
|
||||
'/boot/efi'
|
||||
if is_rhel or (os | lower in ['debian11', 'debian12', 'debian13', 'ubuntu', 'ubuntu-lts'])
|
||||
else '/boot'
|
||||
)
|
||||
}}
|
||||
partitioning_boot_end_mib: "{{ (partitioning_efi_end_mib | int) + (partitioning_boot_size_mib | int) }}"
|
||||
partitioning_reserved_gb: >-
|
||||
{{
|
||||
(
|
||||
(partitioning_efi_size_mib | float)
|
||||
+ ((partitioning_boot_size_mib | float) if (partitioning_separate_boot | bool) else 0)
|
||||
) / 1024
|
||||
}}
|
||||
partitioning_layout: >-
|
||||
{{
|
||||
[
|
||||
{
|
||||
'number': 1,
|
||||
'part_start': (partitioning_efi_start_mib | string) + 'MiB',
|
||||
'part_end': (partitioning_efi_end_mib | string) + 'MiB',
|
||||
'name': 'efi',
|
||||
'flags': ['boot', 'esp']
|
||||
},
|
||||
{
|
||||
'number': 2,
|
||||
'part_start': (partitioning_efi_end_mib | string) + 'MiB',
|
||||
'part_end': (partitioning_boot_end_mib | string) + 'MiB',
|
||||
'name': 'boot'
|
||||
},
|
||||
{
|
||||
'number': 3,
|
||||
'part_start': (partitioning_boot_end_mib | string) + 'MiB',
|
||||
'name': 'root'
|
||||
}
|
||||
]
|
||||
if partitioning_separate_boot | bool else
|
||||
[
|
||||
{
|
||||
'number': 1,
|
||||
'part_start': (partitioning_efi_start_mib | string) + 'MiB',
|
||||
'part_end': (partitioning_efi_end_mib | string) + 'MiB',
|
||||
'name': 'boot',
|
||||
'flags': ['boot', 'esp']
|
||||
},
|
||||
{
|
||||
'number': 2,
|
||||
'part_start': (partitioning_efi_end_mib | string) + 'MiB',
|
||||
'name': 'root'
|
||||
}
|
||||
]
|
||||
}}
|
||||
partitioning_grub_enable_cryptodisk: >-
|
||||
{{
|
||||
(partitioning_luks_enabled | bool)
|
||||
and not (partitioning_separate_boot | bool)
|
||||
and (partitioning_efi_mountpoint == '/boot/efi')
|
||||
}}
|
||||
partitioning_luks_device: "{{ install_drive ~ (partitioning_root_partition_suffix | string) }}"
|
||||
partitioning_root_device: >-
|
||||
{{
|
||||
'/dev/mapper/' + partitioning_luks_mapper_name
|
||||
if (partitioning_luks_enabled | bool)
|
||||
else install_drive ~ (partitioning_root_partition_suffix | string)
|
||||
}}
|
||||
partitioning_vm_size_effective: >-
|
||||
{{
|
||||
(
|
||||
partitioning_vm_size
|
||||
if (partitioning_vm_size is defined and (partitioning_vm_size | float) > 0)
|
||||
else (vm_size if vm_size is defined else 0)
|
||||
)
|
||||
| float
|
||||
}}
|
||||
partitioning_vm_memory_effective: >-
|
||||
{{
|
||||
(
|
||||
partitioning_vm_memory
|
||||
if (partitioning_vm_memory is defined and (partitioning_vm_memory | float) > 0)
|
||||
else (vm_memory if vm_memory is defined else 0)
|
||||
)
|
||||
| float
|
||||
}}
|
||||
partitioning_swap_size_gb: >-
|
||||
{{
|
||||
((partitioning_vm_memory_effective / 1024) >= 16.0)
|
||||
| ternary(
|
||||
(partitioning_vm_memory_effective / 2048) | int,
|
||||
[partitioning_vm_memory_effective / 1024, 4.0] | max | int
|
||||
)
|
||||
}}
|
||||
@@ -3,54 +3,78 @@
|
||||
block:
|
||||
- name: Create btrfs filesystem in main volume
|
||||
community.general.filesystem:
|
||||
dev: "{{ install_drive }}{{ main_partition_suffix }}"
|
||||
dev: "{{ partitioning_root_device }}"
|
||||
fstype: btrfs
|
||||
force: true
|
||||
opts: >-
|
||||
{{
|
||||
'-K'
|
||||
if (partitioning_luks_enabled | bool)
|
||||
and not ('discard' in (partitioning_luks_options | lower))
|
||||
else omit
|
||||
}}
|
||||
|
||||
- name: Prepare BTRFS Subvolume
|
||||
ansible.posix.mount:
|
||||
path: /mnt
|
||||
src: "{{ install_drive }}{{ main_partition_suffix }}"
|
||||
src: "{{ partitioning_root_device }}"
|
||||
fstype: btrfs
|
||||
opts: rw,relatime,compress=zstd:15,ssd,space_cache=v2,discard=async
|
||||
opts: >-
|
||||
{{
|
||||
[
|
||||
'rw',
|
||||
'relatime',
|
||||
partitioning_btrfs_compress_opt,
|
||||
'ssd',
|
||||
'space_cache=v2',
|
||||
'discard=async'
|
||||
]
|
||||
| reject('equalto', '')
|
||||
| join(',')
|
||||
}}
|
||||
state: mounted
|
||||
|
||||
- name: Enable quotas on Btrfs filesystem
|
||||
ansible.builtin.command: btrfs quota enable /mnt
|
||||
changed_when: result.rc == 0
|
||||
register: result
|
||||
register: partitioning_btrfs_quota_result
|
||||
changed_when: false
|
||||
|
||||
- name: Make root subvolumes
|
||||
when: cis | bool or item.subvol not in ['var_log_audit']
|
||||
when:
|
||||
- cis_enabled or item.subvol not in ['var_log_audit']
|
||||
- swap_enabled | bool or item.subvol != 'swap'
|
||||
ansible.builtin.command: btrfs su cr /mnt/{{ '@' if item.subvol == 'root' else '@' + item.subvol }}
|
||||
changed_when: result.rc == 0
|
||||
register: result
|
||||
args:
|
||||
creates: /mnt/{{ '@' if item.subvol == 'root' else '@' + item.subvol }}
|
||||
loop:
|
||||
- { subvol: root }
|
||||
- { subvol: swap }
|
||||
- { subvol: home }
|
||||
- { subvol: var }
|
||||
- { subvol: var_log }
|
||||
- { subvol: var_log_audit }
|
||||
- {subvol: root}
|
||||
- {subvol: swap}
|
||||
- {subvol: home}
|
||||
- {subvol: var}
|
||||
- {subvol: pkg}
|
||||
- {subvol: var_log}
|
||||
- {subvol: var_log_audit}
|
||||
register: partitioning_btrfs_subvol_result
|
||||
|
||||
- name: Set quotas for subvolumes
|
||||
when: cis | bool or item.subvol not in ['var_log_audit']
|
||||
when: cis_enabled
|
||||
ansible.builtin.command: btrfs qgroup limit {{ item.quota }} /mnt/{{ '@' if item.subvol == 'root' else '@' + item.subvol }}
|
||||
changed_when: result.rc == 0
|
||||
register: result
|
||||
loop:
|
||||
- { subvol: home, quota: 2G }
|
||||
- {subvol: home, quota: 2G}
|
||||
register: partitioning_btrfs_qgroup_result
|
||||
changed_when: false
|
||||
|
||||
- name: Create a Btrfs swap file
|
||||
when: swap_enabled | bool
|
||||
ansible.builtin.command: >-
|
||||
btrfs filesystem mkswapfile --size {{ ((vm_memory | float / 1024 >= 16.0) | ternary((vm_memory
|
||||
| float / 2048) | int, [vm_memory | float / 1024, 4.0] | max) | int) }}g --uuid clear /mnt/@swap/swapfile
|
||||
changed_when: result.rc == 0
|
||||
register: result
|
||||
btrfs filesystem mkswapfile --size {{ partitioning_swap_size_gb }}g --uuid clear /mnt/@swap/swapfile
|
||||
args:
|
||||
creates: /mnt/@swap/swapfile
|
||||
register: partitioning_btrfs_swap_result
|
||||
|
||||
- name: Unmount Partition
|
||||
ansible.posix.mount:
|
||||
path: /mnt
|
||||
src: "{{ install_drive }}{{ main_partition_suffix }}"
|
||||
src: "{{ partitioning_root_device }}"
|
||||
fstype: btrfs
|
||||
state: unmounted
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
---
|
||||
- name: Create and format ext4 logical volumes
|
||||
when: cis | bool or item.lv not in ['home', 'var', 'var_log', 'var_log_audit']
|
||||
when: cis_enabled or item.lv not in ['home', 'var', 'var_log', 'var_log_audit']
|
||||
community.general.filesystem:
|
||||
dev: /dev/sys/{{ item.lv }}
|
||||
fstype: ext4
|
||||
force: true
|
||||
loop:
|
||||
- { lv: root }
|
||||
- { lv: home }
|
||||
- { lv: var }
|
||||
- { lv: var_log }
|
||||
- { lv: var_log_audit }
|
||||
- {lv: root}
|
||||
- {lv: home}
|
||||
- {lv: var}
|
||||
- {lv: var_log}
|
||||
- {lv: var_log_audit}
|
||||
|
||||
- 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_enabled 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 }}"
|
||||
changed_when: result.rc == 0
|
||||
register: result
|
||||
loop:
|
||||
- { lv: root }
|
||||
- { lv: home }
|
||||
- { lv: var }
|
||||
- { lv: var_log }
|
||||
- { lv: var_log_audit }
|
||||
- {lv: root}
|
||||
- {lv: home}
|
||||
- {lv: var}
|
||||
- {lv: var_log}
|
||||
- {lv: var_log_audit}
|
||||
register: partitioning_ext4_tune_result
|
||||
changed_when: partitioning_ext4_tune_result.rc == 0
|
||||
|
||||
@@ -1,33 +1,253 @@
|
||||
---
|
||||
- name: Detect system memory for swap sizing
|
||||
when:
|
||||
- swap_enabled | bool
|
||||
- partitioning_vm_memory is not defined or (partitioning_vm_memory | float) <= 0
|
||||
- vm_memory is not defined or (vm_memory | float) <= 0
|
||||
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: Set partitioning vm_size for physical installs
|
||||
when:
|
||||
- install_type == "physical"
|
||||
- partitioning_vm_size is not defined or (partitioning_vm_size | float) <= 0
|
||||
- vm_size is not defined or (vm_size | float) <= 0
|
||||
- install_drive | length > 0
|
||||
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
|
||||
block:
|
||||
- name: Prepare partitions
|
||||
failed_when: false
|
||||
ansible.builtin.command: "{{ item.cmd }}"
|
||||
changed_when: result.rc == 0
|
||||
register: result
|
||||
loop:
|
||||
- { cmd: umount -l /mnt }
|
||||
- { cmd: vgremove -f sys }
|
||||
- {
|
||||
cmd: 'find /dev -wholename "{{ install_drive }}*" -exec wipefs --force --all {} \;',
|
||||
}
|
||||
loop_control:
|
||||
label: "{{ item.cmd }}"
|
||||
block:
|
||||
- name: Disable swap
|
||||
ansible.builtin.command: swapoff -a
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Find mounts under /mnt
|
||||
ansible.builtin.command: findmnt -R /mnt -n -o TARGET
|
||||
register: partitioning_mounted_paths
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- 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
|
||||
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
|
||||
block:
|
||||
- name: Create 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: "{{ partitioning_layout }}"
|
||||
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: "{{ partitioning_layout }}"
|
||||
|
||||
- name: Settle partition table
|
||||
ansible.builtin.command: "{{ item }}"
|
||||
loop:
|
||||
- { number: 1, part_end: 500MiB, name: boot, flags: [boot, esp] }
|
||||
- { number: 2, part_start: 500MiB, name: root }
|
||||
- "partprobe {{ install_drive }}"
|
||||
- "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 | 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 | 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 | 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
|
||||
when: filesystem != 'btrfs'
|
||||
@@ -35,10 +255,142 @@
|
||||
- name: Create LVM volume group
|
||||
community.general.lvg:
|
||||
vg: sys
|
||||
pvs: "{{ install_drive }}{{ main_partition_suffix }}"
|
||||
pvs: "{{ partitioning_root_device }}"
|
||||
|
||||
- name: Create LVM logical volumes
|
||||
when: cis | bool or item.lv not in ['home', 'var', 'var_log', 'var_log_audit']
|
||||
when:
|
||||
- cis_enabled or item.lv not in ['home', 'var', 'var_log', 'var_log_audit']
|
||||
- swap_enabled | bool or item.lv != 'swap'
|
||||
vars:
|
||||
partitioning_lvm_extent_reserve_count: 10
|
||||
partitioning_lvm_extent_size_mib: 4
|
||||
partitioning_lvm_extent_reserve_gb: >-
|
||||
{{
|
||||
(
|
||||
(partitioning_lvm_extent_reserve_count | float)
|
||||
* (partitioning_lvm_extent_size_mib | float)
|
||||
/ 1024
|
||||
) | round(2, 'ceil')
|
||||
}}
|
||||
partitioning_lvm_swap_target_gb: >-
|
||||
{{
|
||||
(
|
||||
[
|
||||
(partitioning_vm_memory_effective | float / 1024),
|
||||
4
|
||||
] | max | float
|
||||
)
|
||||
if swap_enabled | bool
|
||||
else 0
|
||||
}}
|
||||
partitioning_lvm_swap_cap_gb: >-
|
||||
{{
|
||||
(
|
||||
4
|
||||
+ [
|
||||
(partitioning_vm_size_effective | float) - 20,
|
||||
0
|
||||
] | max
|
||||
)
|
||||
if swap_enabled | bool
|
||||
else 0
|
||||
}}
|
||||
partitioning_lvm_swap_target_effective_gb: >-
|
||||
{{
|
||||
(
|
||||
[
|
||||
partitioning_lvm_swap_target_gb,
|
||||
partitioning_lvm_swap_cap_gb
|
||||
] | min
|
||||
)
|
||||
if swap_enabled | bool
|
||||
else 0
|
||||
}}
|
||||
partitioning_lvm_swap_max_gb: >-
|
||||
{{
|
||||
(
|
||||
[
|
||||
(
|
||||
(partitioning_vm_size_effective | float)
|
||||
- (partitioning_reserved_gb | float)
|
||||
- (cis_enabled | ternary(7.5, 0))
|
||||
- partitioning_lvm_extent_reserve_gb
|
||||
- 4
|
||||
),
|
||||
0
|
||||
] | max
|
||||
)
|
||||
if swap_enabled | bool
|
||||
else 0
|
||||
}}
|
||||
partitioning_lvm_available_gb: >-
|
||||
{{
|
||||
(
|
||||
(partitioning_vm_size_effective | float)
|
||||
- (partitioning_reserved_gb | float)
|
||||
- (cis_enabled | ternary(7.5, 0))
|
||||
- partitioning_lvm_extent_reserve_gb
|
||||
- partitioning_lvm_swap_target_effective_gb
|
||||
) | float
|
||||
}}
|
||||
partitioning_lvm_home_gb: >-
|
||||
{{
|
||||
([([(((partitioning_vm_size_effective | float) - 20) * 0.1), 2] | max), 20] | min)
|
||||
}}
|
||||
partitioning_lvm_root_default_gb: >-
|
||||
{{
|
||||
[
|
||||
(
|
||||
((partitioning_lvm_available_gb | float) < 4)
|
||||
| ternary(
|
||||
4,
|
||||
(
|
||||
((partitioning_lvm_available_gb | float) > 12)
|
||||
| ternary(
|
||||
((partitioning_vm_size_effective | float) * 0.4)
|
||||
| round(0, 'ceil'),
|
||||
partitioning_lvm_available_gb
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
4
|
||||
] | max
|
||||
}}
|
||||
partitioning_lvm_swap_gb: >-
|
||||
{{
|
||||
(
|
||||
[
|
||||
partitioning_lvm_swap_target_effective_gb,
|
||||
partitioning_lvm_swap_max_gb
|
||||
] | min | round(2, 'floor')
|
||||
)
|
||||
if swap_enabled | bool
|
||||
else 0
|
||||
}}
|
||||
partitioning_lvm_root_full_gb: >-
|
||||
{{
|
||||
[
|
||||
(
|
||||
(partitioning_vm_size_effective | float)
|
||||
- (partitioning_reserved_gb | float)
|
||||
- (partitioning_lvm_swap_gb | float)
|
||||
- partitioning_lvm_extent_reserve_gb
|
||||
- (
|
||||
(partitioning_lvm_home_gb | float) + 5.5
|
||||
if cis_enabled
|
||||
else 0
|
||||
)
|
||||
),
|
||||
4
|
||||
] | max | round(2, 'floor')
|
||||
}}
|
||||
partitioning_lvm_root_gb: >-
|
||||
{{
|
||||
partitioning_lvm_root_full_gb
|
||||
if partitioning_use_full_disk | bool
|
||||
else partitioning_lvm_root_default_gb
|
||||
}}
|
||||
community.general.lvol:
|
||||
vg: sys
|
||||
lv: "{{ item.lv }}"
|
||||
@@ -46,38 +398,46 @@
|
||||
state: present
|
||||
loop:
|
||||
- lv: root
|
||||
size: >-
|
||||
{{ [(((((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)))) < 4)
|
||||
| ternary(4,((((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)
|
||||
| ternary(((vm_size | float) * 0.4) | round(0, 'ceil'),((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))))))))), 4 ] | max | string + 'G' }}
|
||||
size: "{{ partitioning_lvm_root_gb | string + 'G' }}"
|
||||
- lv: swap
|
||||
size: >-
|
||||
{{ ((((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)))) < 4)
|
||||
| ternary((((vm_size | float) - 0.5 - ((cis | bool) | ternary(7.5, 0))) - 4), (((vm_memory | float / 1024) > 16.0)
|
||||
| ternary(((vm_memory | float / 2048) | int), (vm_memory | float / 1024)))) | string + 'G' }}
|
||||
size: "{{ partitioning_lvm_swap_gb | string + 'G' }}"
|
||||
- lv: home
|
||||
size: "{{ ([([(((vm_size | float) - 20) * 0.1), 2] | max), 20] | min) | string + 'G' }}"
|
||||
|
||||
- { lv: var, size: "2G" }
|
||||
- { lv: var_log, size: "2G" }
|
||||
- { lv: var_log_audit, size: "1.5G" }
|
||||
size: "{{ partitioning_lvm_home_gb | string + 'G' }}"
|
||||
- {lv: var, size: "2G"}
|
||||
- {lv: var_log, size: "2G"}
|
||||
- {lv: var_log_audit, size: "1.5G"}
|
||||
|
||||
- name: Create filesystems
|
||||
block:
|
||||
- name: Create FAT32 filesystem in boot partition
|
||||
community.general.filesystem:
|
||||
dev: "{{ install_drive }}{{ boot_partition_suffix }}"
|
||||
dev: "{{ install_drive }}{{ partitioning_boot_partition_suffix }}"
|
||||
fstype: vfat
|
||||
opts: -F32 -n BOOT
|
||||
force: true
|
||||
|
||||
- name: Create filesystem for /boot partition
|
||||
when: partitioning_separate_boot | bool
|
||||
community.general.filesystem:
|
||||
dev: "{{ install_drive }}{{ partitioning_boot_fs_partition_suffix }}"
|
||||
fstype: "{{ partitioning_boot_fs_fstype }}"
|
||||
force: true
|
||||
|
||||
- name: Remove unsupported ext4 features from /boot
|
||||
when:
|
||||
- partitioning_separate_boot | bool
|
||||
- partitioning_boot_fs_fstype == 'ext4'
|
||||
- os | lower in ['almalinux', 'debian11', 'rhel8', 'rhel9', 'rocky']
|
||||
ansible.builtin.command: >-
|
||||
tune2fs -O "^orphan_file,^metadata_csum_seed"
|
||||
"{{ install_drive }}{{ partitioning_boot_fs_partition_suffix }}"
|
||||
register: partitioning_boot_ext4_tune_result
|
||||
changed_when: partitioning_boot_ext4_tune_result.rc == 0
|
||||
|
||||
- name: Create swap filesystem
|
||||
when: filesystem != 'btrfs'
|
||||
when:
|
||||
- filesystem != 'btrfs'
|
||||
- swap_enabled | bool
|
||||
community.general.filesystem:
|
||||
fstype: swap
|
||||
dev: /dev/sys/swap
|
||||
@@ -86,93 +446,220 @@
|
||||
ansible.builtin.include_tasks: "{{ filesystem }}.yml"
|
||||
|
||||
- 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
|
||||
|
||||
- name: Get UUID for /boot filesystem
|
||||
when: partitioning_separate_boot | bool
|
||||
ansible.builtin.command: >-
|
||||
blkid -s UUID -o value '{{ install_drive }}{{ partitioning_boot_fs_partition_suffix }}'
|
||||
register: partitioning_boot_fs_uuid
|
||||
changed_when: false
|
||||
register: boot_uuid
|
||||
|
||||
- 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
|
||||
register: main_uuid
|
||||
|
||||
- name: Get UUIDs for LVM filesystems
|
||||
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 }}
|
||||
- name: Get UUID for LVM root filesystem
|
||||
when: filesystem != 'btrfs'
|
||||
ansible.builtin.command: blkid -s UUID -o value /dev/sys/root
|
||||
register: partitioning_uuid_root_result
|
||||
changed_when: false
|
||||
|
||||
- name: Get UUID for LVM swap filesystem
|
||||
when:
|
||||
- filesystem != 'btrfs'
|
||||
- swap_enabled | bool
|
||||
ansible.builtin.command: blkid -s UUID -o value /dev/sys/swap
|
||||
register: partitioning_uuid_swap_result
|
||||
changed_when: false
|
||||
|
||||
- name: Get UUID for LVM home filesystem
|
||||
when:
|
||||
- filesystem != 'btrfs'
|
||||
- cis_enabled
|
||||
ansible.builtin.command: blkid -s UUID -o value /dev/sys/home
|
||||
register: partitioning_uuid_home_result
|
||||
changed_when: false
|
||||
|
||||
- name: Get UUID for LVM var filesystem
|
||||
when:
|
||||
- filesystem != 'btrfs'
|
||||
- cis_enabled
|
||||
ansible.builtin.command: blkid -s UUID -o value /dev/sys/var
|
||||
register: partitioning_uuid_var_result
|
||||
changed_when: false
|
||||
|
||||
- name: Get UUID for LVM var_log filesystem
|
||||
when:
|
||||
- filesystem != 'btrfs'
|
||||
- cis_enabled
|
||||
ansible.builtin.command: blkid -s UUID -o value /dev/sys/var_log
|
||||
register: partitioning_uuid_var_log_result
|
||||
changed_when: false
|
||||
|
||||
- name: Get UUID for LVM var_log_audit filesystem
|
||||
when:
|
||||
- filesystem != 'btrfs'
|
||||
- cis_enabled
|
||||
ansible.builtin.command: blkid -s UUID -o value /dev/sys/var_log_audit
|
||||
register: partitioning_uuid_var_log_audit_result
|
||||
changed_when: false
|
||||
register: uuid_result
|
||||
loop:
|
||||
- root
|
||||
- swap
|
||||
- home
|
||||
- var
|
||||
- var_log
|
||||
- var_log_audit
|
||||
|
||||
- name: Assign UUIDs to Variables
|
||||
when: filesystem != 'btrfs'
|
||||
ansible.builtin.set_fact:
|
||||
uuid_root: "{{ uuid_result.results[0].stdout_lines }}"
|
||||
uuid_swap: "{{ uuid_result.results[1].stdout_lines }}"
|
||||
uuid_home: "{{ uuid_result.results[2].stdout_lines if cis | bool else '' }}"
|
||||
uuid_var: "{{ uuid_result.results[3].stdout_lines if cis | bool else '' }}"
|
||||
uuid_var_log: "{{ 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_root: "{{ partitioning_uuid_root_result.stdout_lines | default([]) }}"
|
||||
partitioning_uuid_swap: >-
|
||||
{{
|
||||
partitioning_uuid_swap_result.stdout_lines | default([])
|
||||
if swap_enabled | bool
|
||||
else ''
|
||||
}}
|
||||
partitioning_uuid_home: >-
|
||||
{{
|
||||
partitioning_uuid_home_result.stdout_lines | default([])
|
||||
if cis_enabled
|
||||
else ''
|
||||
}}
|
||||
partitioning_uuid_var: >-
|
||||
{{
|
||||
partitioning_uuid_var_result.stdout_lines | default([])
|
||||
if cis_enabled
|
||||
else ''
|
||||
}}
|
||||
partitioning_uuid_var_log: >-
|
||||
{{
|
||||
partitioning_uuid_var_log_result.stdout_lines | default([])
|
||||
if cis_enabled
|
||||
else ''
|
||||
}}
|
||||
partitioning_uuid_var_log_audit: >-
|
||||
{{
|
||||
partitioning_uuid_var_log_audit_result.stdout_lines | default([])
|
||||
if cis_enabled
|
||||
else ''
|
||||
}}
|
||||
|
||||
- name: Mount filesystems
|
||||
block:
|
||||
- name: Mount filesystems and subvolumes
|
||||
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']))
|
||||
- not (item.path == '/swap' and filesystem != 'btrfs')
|
||||
- >-
|
||||
cis_enabled or (
|
||||
not cis_enabled 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')
|
||||
- swap_enabled | bool or item.path != '/swap'
|
||||
ansible.posix.mount:
|
||||
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 }}"
|
||||
opts: "{{ item.opts }}"
|
||||
state: mounted
|
||||
loop:
|
||||
- path: ""
|
||||
uuid: "{{ uuid_root[0] | default(omit) }}"
|
||||
opts: "{{ 'defaults' if filesystem != 'btrfs' else 'rw,relatime,compress=zstd:15,ssd,space_cache=v2,discard=async,subvol=@' }}"
|
||||
uuid: "{{ partitioning_uuid_root[0] | default(omit) }}"
|
||||
opts: >-
|
||||
{{
|
||||
'defaults'
|
||||
if filesystem != 'btrfs'
|
||||
else [
|
||||
'rw', 'relatime', partitioning_btrfs_compress_opt, 'ssd', 'space_cache=v2',
|
||||
'discard=async', 'subvol=@'
|
||||
] | reject('equalto', '') | join(',')
|
||||
}}
|
||||
- path: /swap
|
||||
opts: "rw,nosuid,nodev,relatime,compress=zstd:15,ssd,space_cache=v2,discard=async,subvol=@swap"
|
||||
opts: >-
|
||||
{{
|
||||
[
|
||||
'rw', 'nosuid', 'nodev', 'relatime', partitioning_btrfs_compress_opt, 'ssd',
|
||||
'space_cache=v2', 'discard=async', 'subvol=@swap'
|
||||
] | reject('equalto', '') | join(',')
|
||||
}}
|
||||
- path: /home
|
||||
uuid: "{{ uuid_home[0] | default(omit) }}"
|
||||
opts: "{{ 'defaults,nosuid,nodev' if filesystem != 'btrfs'
|
||||
else 'rw,nosuid,nodev,relatime,compress=zstd:15,ssd,space_cache=v2,discard=async,subvol=@home' }}"
|
||||
uuid: "{{ partitioning_uuid_home[0] | default(omit) }}"
|
||||
opts: >-
|
||||
{{
|
||||
'defaults,nosuid,nodev'
|
||||
if filesystem != 'btrfs'
|
||||
else [
|
||||
'rw', 'nosuid', 'nodev', 'relatime', partitioning_btrfs_compress_opt, 'ssd',
|
||||
'space_cache=v2', 'discard=async', 'subvol=@home'
|
||||
] | reject('equalto', '') | join(',')
|
||||
}}
|
||||
- path: /var
|
||||
uuid: "{{ uuid_var[0] | default(omit) }}"
|
||||
opts: "{{ 'defaults,nosuid,nodev' if filesystem != 'btrfs'
|
||||
else 'rw,nosuid,nodev,relatime,compress=zstd:15,ssd,space_cache=v2,discard=async,subvol=@var' }}"
|
||||
uuid: "{{ partitioning_uuid_var[0] | default(omit) }}"
|
||||
opts: >-
|
||||
{{
|
||||
'defaults,nosuid,nodev'
|
||||
if filesystem != 'btrfs'
|
||||
else [
|
||||
'rw', 'nosuid', 'nodev', 'relatime', partitioning_btrfs_compress_opt, 'ssd',
|
||||
'space_cache=v2', 'discard=async', 'subvol=@var'
|
||||
] | reject('equalto', '') | join(',')
|
||||
}}
|
||||
- path: /var/log
|
||||
uuid: "{{ uuid_var_log[0] | 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=@var_log' }}"
|
||||
uuid: "{{ partitioning_uuid_var_log[0] | default(omit) }}"
|
||||
opts: >-
|
||||
{{
|
||||
'defaults,nosuid,nodev,noexec'
|
||||
if filesystem != 'btrfs'
|
||||
else [
|
||||
'rw', 'nosuid', 'nodev', 'noexec', 'relatime', partitioning_btrfs_compress_opt,
|
||||
'ssd', 'space_cache=v2', 'discard=async', 'subvol=@var_log'
|
||||
] | reject('equalto', '') | 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', partitioning_btrfs_compress_opt,
|
||||
'ssd', 'space_cache=v2', 'discard=async', 'subvol=@pkg'
|
||||
] | reject('equalto', '') | join(',')
|
||||
}}
|
||||
- path: /var/log/audit
|
||||
uuid: "{{ uuid_var_log_audit[0] | 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=@var_log_audit' }}"
|
||||
uuid: "{{ partitioning_uuid_var_log_audit[0] | default(omit) }}"
|
||||
opts: >-
|
||||
{{
|
||||
'defaults,nosuid,nodev,noexec'
|
||||
if filesystem != 'btrfs'
|
||||
else [
|
||||
'rw', 'nosuid', 'nodev', 'noexec', 'relatime', partitioning_btrfs_compress_opt,
|
||||
'ssd', 'space_cache=v2', 'discard=async', 'subvol=@var_log_audit'
|
||||
] | reject('equalto', '') | join(',')
|
||||
}}
|
||||
|
||||
- name: Mount tmp and var_tmp filesystems
|
||||
- name: Mount /boot filesystem
|
||||
when: partitioning_separate_boot | bool
|
||||
ansible.posix.mount:
|
||||
path: /mnt{{ item.path }}
|
||||
src: tmpfs
|
||||
fstype: tmpfs
|
||||
opts: defaults,nosuid,nodev,noexec
|
||||
path: /mnt/boot
|
||||
src: "UUID={{ partitioning_boot_fs_uuid.stdout }}"
|
||||
fstype: "{{ partitioning_boot_fs_fstype }}"
|
||||
opts: defaults
|
||||
state: mounted
|
||||
loop:
|
||||
- { path: /tmp }
|
||||
- { path: /var/tmp }
|
||||
|
||||
- name: Mount boot filesystem
|
||||
ansible.posix.mount:
|
||||
path: "{{ '/mnt/boot/efi' if os | lower in ['rhel8', 'ubuntu', 'ubuntu-lts'] else '/mnt/boot' }}"
|
||||
src: UUID={{ boot_uuid.stdout }}
|
||||
path: "/mnt{{ partitioning_efi_mountpoint }}"
|
||||
src: UUID={{ partitioning_boot_uuid.stdout }}
|
||||
fstype: vfat
|
||||
state: mounted
|
||||
|
||||
- name: Activate swap
|
||||
ansible.builtin.command: "{{ 'swapon /mnt/swap/swapfile' if filesystem == 'btrfs' else 'swapon -U ' + uuid_swap[0] }}"
|
||||
changed_when: result.rc == 0
|
||||
register: result
|
||||
when: swap_enabled | bool
|
||||
vars:
|
||||
partitioning_swap_cmd: >-
|
||||
{{ '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
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
---
|
||||
- name: Create and format XFS logical volumes
|
||||
when: cis | bool or item.lv not in ['home', 'var', 'var_log', 'var_log_audit']
|
||||
when: cis_enabled or item.lv not in ['home', 'var', 'var_log', 'var_log_audit']
|
||||
community.general.filesystem:
|
||||
dev: /dev/sys/{{ item.lv }}
|
||||
fstype: xfs
|
||||
force: true
|
||||
loop:
|
||||
- { lv: root }
|
||||
- { lv: home }
|
||||
- { lv: var }
|
||||
- { lv: var_log }
|
||||
- { lv: var_log_audit }
|
||||
- {lv: root}
|
||||
- {lv: home}
|
||||
- {lv: var}
|
||||
- {lv: var_log}
|
||||
- {lv: var_log_audit}
|
||||
|
||||
19
roles/virtualization/defaults/main.yml
Normal file
19
roles/virtualization/defaults/main.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
virtualization_libvirt_image_dir: >-
|
||||
{{ vm_path if vm_path is defined and vm_path | length > 0 else '/var/lib/libvirt/images' }}
|
||||
virtualization_libvirt_disk_path: >-
|
||||
{{ [virtualization_libvirt_image_dir, hostname ~ '.qcow2'] | ansible.builtin.path_join }}
|
||||
virtualization_libvirt_cloudinit_path: >-
|
||||
{{ [virtualization_libvirt_image_dir, hostname ~ '-cloudinit.iso'] | ansible.builtin.path_join }}
|
||||
virtualization_mac_address: >-
|
||||
{{ '52:54:00' | community.general.random_mac(seed=hostname) }}
|
||||
|
||||
virtualization_tpm2_enabled: >-
|
||||
{{
|
||||
(partitioning_luks_enabled | bool)
|
||||
and (partitioning_luks_auto_decrypt | bool)
|
||||
and (
|
||||
(partitioning_luks_auto_decrypt_method | lower)
|
||||
== 'tpm2'
|
||||
)
|
||||
}}
|
||||
@@ -1,22 +1,15 @@
|
||||
---
|
||||
- name: Check if VM disk exists
|
||||
delegate_to: localhost
|
||||
ansible.builtin.stat:
|
||||
path: "{{ vm_path | default('/var/lib/libvirt/images/') }}{{ hostname }}.qcow2"
|
||||
register: vm_disk_stat
|
||||
|
||||
- name: Create VM disk
|
||||
when: not vm_disk_stat.stat.exists
|
||||
delegate_to: localhost
|
||||
ansible.builtin.command: qemu-img create -f qcow2 {{ vm_path | default('/var/lib/libvirt/images/') }}{{ hostname }}.qcow2 {{ vm_size }}G
|
||||
changed_when: result.rc == 0
|
||||
register: result
|
||||
|
||||
- name: Generate Random MAC Address
|
||||
delegate_to: localhost
|
||||
ansible.builtin.shell: set -o pipefail && openssl rand -hex 5 | sed 's/\(..\)/\1:/g; s/.$//' | sed 's/^/02:/'
|
||||
changed_when: false
|
||||
register: mac_address_output
|
||||
ansible.builtin.command:
|
||||
argv:
|
||||
- qemu-img
|
||||
- create
|
||||
- -f
|
||||
- qcow2
|
||||
- "{{ virtualization_libvirt_disk_path }}"
|
||||
- "{{ vm_size }}G"
|
||||
creates: "{{ virtualization_libvirt_disk_path }}"
|
||||
|
||||
- name: Render cloud config templates
|
||||
delegate_to: localhost
|
||||
@@ -25,17 +18,19 @@
|
||||
dest: /tmp/{{ item.dest_prefix }}-{{ hostname }}.yml
|
||||
mode: '0644'
|
||||
loop:
|
||||
- { src: cloud-user-data.yml.j2, dest_prefix: cloud-user-data }
|
||||
- { src: cloud-network-config.yml.j2, dest_prefix: cloud-network-config }
|
||||
- {src: cloud-user-data.yml.j2, dest_prefix: cloud-user-data}
|
||||
- {src: cloud-network-config.yml.j2, dest_prefix: cloud-network-config}
|
||||
|
||||
- name: Create cloud-init disk
|
||||
delegate_to: localhost
|
||||
ansible.builtin.command: >
|
||||
cloud-localds {{ vm_path | default('/var/lib/libvirt/images/') }}/{{ hostname }}-cloudinit.iso
|
||||
/tmp/cloud-user-data-{{ hostname }}.yml
|
||||
-N /tmp/cloud-network-config-{{ hostname }}.yml
|
||||
changed_when: result.rc == 0
|
||||
register: result
|
||||
ansible.builtin.command:
|
||||
argv:
|
||||
- cloud-localds
|
||||
- "{{ virtualization_libvirt_cloudinit_path }}"
|
||||
- "/tmp/cloud-user-data-{{ hostname }}.yml"
|
||||
- -N
|
||||
- "/tmp/cloud-network-config-{{ hostname }}.yml"
|
||||
creates: "{{ virtualization_libvirt_cloudinit_path }}"
|
||||
|
||||
- name: Create VM using libvirt
|
||||
delegate_to: localhost
|
||||
|
||||
@@ -1,7 +1,26 @@
|
||||
---
|
||||
- name: Deploy VM on Proxmox
|
||||
delegate_to: localhost
|
||||
community.general.proxmox_kvm:
|
||||
vars:
|
||||
virtualization_dns_value: "{{ vm_dns if vm_dns is defined else '' }}"
|
||||
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 if vm_dns_search is defined else '' }}"
|
||||
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_user: "{{ hypervisor_username }}"
|
||||
api_password: "{{ hypervisor_password }}"
|
||||
@@ -14,10 +33,13 @@
|
||||
cpu: host
|
||||
cores: "{{ vm_cpus }}"
|
||||
memory: "{{ vm_memory }}"
|
||||
balloon: "{{ vm_ballo | default(omit) }}"
|
||||
balloon: "{{ vm_ballo if vm_ballo is defined and vm_ballo | int > 0 else omit }}"
|
||||
numa_enabled: true
|
||||
hotplug: network,disk
|
||||
update: "{{ virtualization_tpm2_enabled | bool }}"
|
||||
update_unsafe: "{{ virtualization_tpm2_enabled | bool }}"
|
||||
bios: ovmf
|
||||
machine: "{{ 'q35' if virtualization_tpm2_enabled | bool else omit }}"
|
||||
boot: ac
|
||||
scsihw: virtio-scsi-single
|
||||
scsi:
|
||||
@@ -27,21 +49,34 @@
|
||||
format: raw
|
||||
pre_enrolled_keys: false
|
||||
storage: "{{ hypervisor_storage }}"
|
||||
tpmstate0: >-
|
||||
{{
|
||||
{'storage': hypervisor_storage, 'version': '2.0'}
|
||||
if virtualization_tpm2_enabled | bool
|
||||
else omit
|
||||
}}
|
||||
ide:
|
||||
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 and rhel_iso | length > 0 else omit }}"
|
||||
ide2: "{{ hypervisor_storage }}:cloudinit"
|
||||
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 | length > 0 %},tag={{ vlan_name }}{% endif %}
|
||||
ipconfig:
|
||||
ipconfig0: ip={{ vm_ip }}/{{ vm_nms | default(24) }},gw={{ vm_gw }}
|
||||
nameservers: "{{ vm_dns }}"
|
||||
ipconfig0: >-
|
||||
{{
|
||||
'ip=' ~ vm_ip ~ '/' ~ vm_nms
|
||||
~ (',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
|
||||
state: present
|
||||
|
||||
- name: Start VM on Proxmox
|
||||
delegate_to: localhost
|
||||
community.general.proxmox_kvm:
|
||||
community.proxmox.proxmox_kvm:
|
||||
api_host: "{{ hypervisor_url }}"
|
||||
api_user: "{{ hypervisor_username }}"
|
||||
api_password: "{{ hypervisor_password }}"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
- name: Create VM in vCenter
|
||||
delegate_to: localhost
|
||||
community.vmware.vmware_guest:
|
||||
@@ -7,12 +8,12 @@
|
||||
validate_certs: false
|
||||
datacenter: "{{ hypervisor_datacenter }}"
|
||||
cluster: "{{ hypervisor_cluster }}"
|
||||
folder: "{{ vm_path }}"
|
||||
folder: "{{ vm_path if vm_path is defined and vm_path | length > 0 else omit }}"
|
||||
name: "{{ hostname }}"
|
||||
guest_id: otherLinux64Guest
|
||||
annotation: |
|
||||
{{ note | default('') }}
|
||||
state: poweredon
|
||||
{{ note if note is defined else '' }}
|
||||
state: "{{ 'poweredoff' if virtualization_tpm2_enabled | bool else 'poweredon' }}"
|
||||
disk:
|
||||
- size_gb: "{{ vm_size }}"
|
||||
type: thin
|
||||
@@ -40,15 +41,34 @@
|
||||
"state": "present",
|
||||
"type": "iso",
|
||||
"iso_path": rhel_iso
|
||||
} ] if rhel_iso is defined and rhel_iso|length > 0 else [] )
|
||||
} ] if rhel_iso is defined and rhel_iso | length > 0 else [] )
|
||||
}}
|
||||
networks:
|
||||
- name: "{{ vm_nif }}"
|
||||
type: dhcp
|
||||
vlan: "{{ vlan_name | default(omit) }}"
|
||||
register: vmware_guest_result
|
||||
failed_when:
|
||||
- vmware_guest_result.failed is defined and vmware_guest_result.failed
|
||||
- "'error' in vmware_guest_result"
|
||||
- "'failed' in vmware_guest_result"
|
||||
- vmware_guest_result.rc is defined and vmware_guest_result.rc != 0
|
||||
vlan: "{{ vlan_name if vlan_name is defined and vlan_name | length > 0 else omit }}"
|
||||
|
||||
- name: Ensure vTPM2 is enabled when required
|
||||
when: virtualization_tpm2_enabled | bool
|
||||
delegate_to: localhost
|
||||
community.vmware.vmware_guest_tpm:
|
||||
hostname: "{{ hypervisor_url }}"
|
||||
username: "{{ hypervisor_username }}"
|
||||
password: "{{ hypervisor_password }}"
|
||||
validate_certs: false
|
||||
datacenter: "{{ hypervisor_datacenter }}"
|
||||
folder: "{{ vm_path if vm_path is defined and vm_path | length > 0 else 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:
|
||||
id0:
|
||||
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 if vm_dns is defined else '' %}
|
||||
{% 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 if vm_dns_search is defined else '' %}
|
||||
{% 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:
|
||||
- "{{ vm_ip }}"
|
||||
- "{{ vm_ip }}/{{ vm_nms }}"
|
||||
{% if vm_gw is defined and vm_gw | length %}
|
||||
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:
|
||||
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 %}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<domain type='kvm'>
|
||||
<name>{{ hostname }}</name>
|
||||
<memory>{{ vm_memory | int * 1024 }}</memory>
|
||||
{% if vm_ballo is defined %}<currentMemory>{{ vm_ballo | int * 1024 }}</currentMemory>{% endif %}
|
||||
{% if vm_ballo is defined and vm_ballo | int > 0 %}<currentMemory>{{ vm_ballo | int * 1024 }}</currentMemory>{% endif %}
|
||||
<vcpu placement='static'>{{ vm_cpus }}</vcpu>
|
||||
<os>
|
||||
<type arch='x86_64' machine="pc-q35-8.0">hvm</type>
|
||||
@@ -24,7 +24,7 @@
|
||||
<devices>
|
||||
<disk type='file' device='disk'>
|
||||
<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'/>
|
||||
</disk>
|
||||
<disk type="file" device="cdrom">
|
||||
@@ -34,10 +34,10 @@
|
||||
</disk>
|
||||
<disk type="file" device="cdrom">
|
||||
<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"/>
|
||||
</disk>
|
||||
{% if rhel_iso is defined %}
|
||||
{% if rhel_iso is defined and rhel_iso | length > 0 %}
|
||||
<disk type="file" device="cdrom">
|
||||
<driver name="qemu" type="raw"/>
|
||||
<source file="{{ rhel_iso }}"/>
|
||||
@@ -45,10 +45,15 @@
|
||||
</disk>
|
||||
{% endif %}
|
||||
<interface type='network'>
|
||||
<mac address="{{ mac_address_output.stdout }}"/>
|
||||
<mac address="{{ virtualization_mac_address }}"/>
|
||||
<source network='default'/>
|
||||
<model type='virtio'/>
|
||||
</interface>
|
||||
{% if virtualization_tpm2_enabled %}
|
||||
<tpm model='tpm-crb'>
|
||||
<backend type='emulator' version='2.0'/>
|
||||
</tpm>
|
||||
{% endif %}
|
||||
<input type="tablet" bus="usb"/>
|
||||
<input type="mouse" bus="ps2"/>
|
||||
<input type="keyboard" bus="ps2"/>
|
||||
|
||||
19
vars_baremetal_example.yml
Normal file
19
vars_baremetal_example.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
hypervisor: "none"
|
||||
install_type: "physical"
|
||||
install_drive: "/dev/sda"
|
||||
|
||||
os: "archlinux"
|
||||
filesystem: "btrfs"
|
||||
|
||||
cis: false
|
||||
selinux: true
|
||||
firewalld_enabled: true
|
||||
|
||||
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,42 @@
|
||||
---
|
||||
# Set vm_ip for static addressing. Remove vm_ip to use DHCP.
|
||||
vm_ip: "{{ inventory_hostname }}"
|
||||
|
||||
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.
|
||||
cis: false # Set true to enable CIS hardening.
|
||||
selinux: true # Toggle SELinux where supported.
|
||||
firewalld_enabled: true # Toggle firewalld package and service.
|
||||
|
||||
hypervisor_url: "192.168.0.2"
|
||||
hypervisor_url: "pve01.example.com"
|
||||
hypervisor_username: "root@pam"
|
||||
hypervisor_password: "SomePassword"
|
||||
hypervisor_node: "NodeName"
|
||||
hypervisor_storage: "local-btrfs"
|
||||
hypervisor_password: "CHANGE_ME"
|
||||
hypervisor_node: "pve01"
|
||||
hypervisor_storage: "local-lvm"
|
||||
hypervisor_datacenter: "dc01"
|
||||
hypervisor_cluster: "cluster01"
|
||||
|
||||
# For VMware-Tools
|
||||
ansible_vmware_host: "{{ hypervisor_url }}"
|
||||
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 (only needed when hypervisor: vmware)
|
||||
# vm_path: "/Folder" # Optional folder path segment in vCenter.
|
||||
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