# Configuration Reference

## Variable Source Hierarchy

Variables resolve in standard Ansible precedence order. The role uses three layers:

1. **Role defaults** — `roles/ssh-baseline/defaults/main.yml` (lowest precedence; the safe baseline)
2. **Group vars** — `inventory/group_vars/all/main.yml` (organisation-wide overrides, including vault-sourced secrets)
3. **Host vars** — `inventory/host_vars/<hostname>.yml` (per-host overrides; not currently used in this repo but supported)

The `group_vars/all/main.yml` file overrides the most security-sensitive defaults (AD domain, OUs, groups, SCEPman URL) so they cannot drift even if a role default is accidentally edited.

---

## Group Vars (Organisation-Wide)

File: `inventory/group_vars/all/main.yml`

```yaml
---
# AD join credentials - sourced from vault.yml (encrypted)
ad_join_user: "{{ vault_ad_join_user }}"
ad_join_password: "{{ vault_ad_join_password }}"

# Domain configuration
ad_domain: "pbr.org.au"
ad_computer_ou: "OU=Linux,OU=Servers,OU=Computers,OU=PBR,DC=pbr,DC=org,DC=au"

# Access control via AD security groups (must exist in AD)
ad_server_access_group: "SG_ServerAccess"
ad_sudo_group: "SG_Sudo"

# SCEPman PKI - root CA distribution endpoint
scepman_ca_url: "https://pki.pbr.org.au/ca"

```

### Vault-Sourced Variables

<table id="bkmrk-group-varvault-keypu"><thead><tr><th>Group var</th><th>Vault key</th><th>Purpose</th></tr></thead><tbody><tr><td>`ad_join_user`</td><td>`vault_ad_join_user`</td><td>UPN of the AD service account used by `realm join`. Must have create-computer rights in the target OU.</td></tr><tr><td>`ad_join_password`</td><td>`vault_ad_join_password`</td><td>Password for the join service account.</td></tr></tbody></table>

The Duo credentials are also vault-sourced and referenced in `roles/ssh-baseline/templates/pam_duo.conf.j2`:

<table id="bkmrk-template-varvault-ke"><thead><tr><th>Template var</th><th>Vault key</th><th>Purpose</th></tr></thead><tbody><tr><td>`duo_ikey`</td><td>`vault_duo_ikey`</td><td>Duo Auth API integration key</td></tr><tr><td>`duo_skey`</td><td>`vault_duo_skey`</td><td>Duo Auth API secret key</td></tr><tr><td>`duo_api_host`</td><td>`vault_duo_api_host`</td><td>Duo API hostname (e.g. `api-XXXXXXXX.duosecurity.com`)</td></tr></tbody></table>

To edit the vault:

```bash
cd ~/pbr-infra
ansible-vault edit inventory/group_vars/all/vault.yml \
    --vault-password-file ~/.ansible_vault_pass
```

---

## Role Defaults: AD &amp; Access

File: `roles/ssh-baseline/defaults/main.yml` (referenced; group\_vars override these)

<table id="bkmrk-variabledefaultpurpo"><thead><tr><th>Variable</th><th>Default</th><th>Purpose</th></tr></thead><tbody><tr><td>`ad_domain`</td><td>`pbr.org.au`</td><td>AD DNS domain. Used for realm membership, krb5.conf, SSSD.</td></tr><tr><td>`ad_computer_ou`</td><td>Linux servers OU</td><td>OU where computer objects are created by `realm join`.</td></tr><tr><td>`ad_server_access_group`</td><td>`SG_ServerAccess`</td><td>AD security group for read-only SSH access (no sudo).</td></tr><tr><td>`ad_sudo_group`</td><td>`SG_Sudo`</td><td>AD security group for sudo-enabled users. Members trigger Duo on sudo.</td></tr><tr><td>`pbr_admin_allowed_sources`</td><td>`10.1.0.0/16,192.168.0.0/16`</td><td>Source-IP allow-list (CIDR, comma-separated, no spaces) for the `pbr_admin` break-glass `Match` block.</td></tr><tr><td>`ad_access_filter`</td><td>*See below*</td><td>LDAP filter applied by SSSD for access control. Default is `memberOf=<ServerAccess DN>` OR `memberOf=<Sudo DN>`, both fully qualified.</td></tr></tbody></table>

`ad_access_filter` default:

```text
(|(memberOf=CN=SG_ServerAccess,OU=Security,OU=Groups,DC=pbr,DC=org,DC=au)(memberOf=CN=SG_Sudo,OU=Security,OU=Groups,DC=pbr,DC=org,DC=au))
```

---

## Role Defaults: PKI (SCEPman)

<table id="bkmrk-variabledefaultpurpo-1"><thead><tr><th>Variable</th><th>Default</th><th>Purpose</th></tr></thead><tbody><tr><td>`scepman_ca_url`</td><td>`https://pki.pbr.org.au/ca`</td><td>Endpoint that returns the SCEPman root CA in DER format.</td></tr><tr><td>`scepman_ca_cert`</td><td>`/usr/local/share/ca-certificates/pbr-root-ca.crt`</td><td>PEM-format location of the trusted root CA (added to system trust store).</td></tr><tr><td>`scepman_ca_der`</td><td>`/etc/ssl/certs/pbr-root-ca.der`</td><td>DER-format location of the root CA (kept for reference; PEM is what's trusted).</td></tr></tbody></table>

---

## Role Defaults: System

<table id="bkmrk-variabledefaultpurpo-2"><thead><tr><th>Variable</th><th>Default</th><th>Purpose</th></tr></thead><tbody><tr><td>`timezone`</td><td>`Australia/Melbourne`</td><td>System timezone applied via `community.general.timezone`.</td></tr><tr><td>`manage_auditd`</td><td>`auto`</td><td>Whether to enable auditd. `auto` = skip on LXC (kernel audit netlink isolated), enable elsewhere. Accepts `true`, `false`, or `auto`.</td></tr></tbody></table>

---

## Role Defaults: SSH Hardening

These map directly to `sshd_config` directives in `10-pbr-hardening.conf`.

<table id="bkmrk-variabledefaultsshd_"><thead><tr><th>Variable</th><th>Default</th><th>sshd\_config directive</th><th>Notes</th></tr></thead><tbody><tr><td>`ssh_port`</td><td>`22`</td><td>`Port`</td><td>Changing this requires systemd ssh.socket overrides on Ubuntu 22.10+.</td></tr><tr><td>`ssh_banner`</td><td>`/etc/issue.net`</td><td>`Banner`</td><td>Path to legal banner file.</td></tr><tr><td>`ssh_log_level`</td><td>`VERBOSE`</td><td>`LogLevel`</td><td>CIS Ubuntu 22.04 recommendation.</td></tr><tr><td>`ssh_login_grace_time`</td><td>`60`</td><td>`LoginGraceTime`</td><td>Seconds before unauthenticated connection drops.</td></tr><tr><td>`ssh_max_auth_tries`</td><td>`3`</td><td>`MaxAuthTries`</td><td>Per-connection auth attempt cap.</td></tr><tr><td>`ssh_max_sessions`</td><td>`4`</td><td>`MaxSessions`</td><td>Concurrent multiplexed sessions per connection.</td></tr><tr><td>`ssh_max_startups`</td><td>`10:30:60`</td><td>`MaxStartups`</td><td>Concurrent unauthenticated connections (start:rate:full).</td></tr><tr><td>`ssh_client_alive_interval`</td><td>`300`</td><td>`ClientAliveInterval`</td><td>Seconds between keepalive probes.</td></tr><tr><td>`ssh_client_alive_count_max`</td><td>`2`</td><td>`ClientAliveCountMax`</td><td>Idle connections drop after `interval × count_max` seconds.</td></tr><tr><td>`ssh_permit_root_login`</td><td>`no`</td><td>`PermitRootLogin`</td><td>Hard no.</td></tr><tr><td>`ssh_password_authentication`</td><td>`no`</td><td>`PasswordAuthentication`</td><td>Disabled globally; re-enabled for `pbr_admin` via `Match` block.</td></tr><tr><td>`ssh_pubkey_authentication`</td><td>`yes`</td><td>`PubkeyAuthentication`</td><td>Required by all flows.</td></tr><tr><td>`ssh_kbdint`</td><td>`yes`</td><td>`KbdInteractiveAuthentication`</td><td>Required for Duo PAM keyboard-interactive.</td></tr><tr><td>`ssh_allow_tcp_forwarding`</td><td>`no`</td><td>`AllowTcpForwarding`</td><td>Disabled.</td></tr><tr><td>`ssh_x11_forwarding`</td><td>`no`</td><td>`X11Forwarding`</td><td>Disabled.</td></tr><tr><td>`ssh_allow_agent_forwarding`</td><td>`no`</td><td>`AllowAgentForwarding`</td><td>Disabled.</td></tr><tr><td>`ssh_compression`</td><td>`no`</td><td>`Compression`</td><td>Defence against compression-side-channel attacks.</td></tr><tr><td>`ssh_tcp_keep_alive`</td><td>`no`</td><td>`TCPKeepAlive`</td><td>Use SSH-level keep-alive instead.</td></tr><tr><td>`ssh_authentication_methods`</td><td>`publickey,keyboard-interactive`</td><td>`AuthenticationMethods`</td><td>Both required; keyboard-interactive is Duo via PAM.</td></tr></tbody></table>

### Modern Crypto

Algorithm lists prepended with the post-quantum hybrid KEX where available:

<table id="bkmrk-variabledefault-ssh_"><thead><tr><th>Variable</th><th>Default</th></tr></thead><tbody><tr><td>`ssh_ciphers`</td><td>`chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr`</td></tr><tr><td>`ssh_macs`</td><td>`hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com`</td></tr><tr><td>`ssh_kex_algorithms`</td><td>`sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256`</td></tr></tbody></table>

---

## Role Defaults: fail2ban

<table id="bkmrk-variabledefaultpurpo-3"><thead><tr><th>Variable</th><th>Default</th><th>Purpose</th></tr></thead><tbody><tr><td>`fail2ban_bantime_default`</td><td>`3600`</td><td>Default ban duration in seconds (1 hour) for non-sshd jails.</td></tr><tr><td>`fail2ban_findtime`</td><td>`600`</td><td>Window in seconds during which `maxretry` failures trigger a ban.</td></tr><tr><td>`fail2ban_maxretry_default`</td><td>`5`</td><td>Failures within `findtime` before ban (default for non-sshd jails).</td></tr><tr><td>`fail2ban_sshd_maxretry`</td><td>`3`</td><td>Tighter setting for the sshd jail.</td></tr><tr><td>`fail2ban_sshd_bantime`</td><td>`86400`</td><td>24-hour ban for sshd failures.</td></tr><tr><td>`fail2ban_ignoreip`</td><td>*list, see below*</td><td>CIDRs exempt from banning.</td></tr></tbody></table>

Default `fail2ban_ignoreip`:

```yaml
fail2ban_ignoreip:
  - "127.0.0.1/8"
  - "::1"
  - "10.1.0.0/16"        # PBR server LAN
  - "10.1.8.80/32"       # pbr-ansible-kl1 control node (explicit)
  - "192.168.0.0/16"     # Admin workstation VLANs supernet (TEMPORARY)
```

The 192.168.0.0/16 entry is annotated **TEMPORARY** in the role — intended to be removed when VLAN segmentation completes and admin workstations land on a single, well-defined CIDR.

---

## Role Defaults: Duo MFA

<table id="bkmrk-variabledefaultpurpo-4"><thead><tr><th>Variable</th><th>Default</th><th>Purpose</th></tr></thead><tbody><tr><td>`duo_failmode`</td><td>`safe`</td><td>`safe` = allow login if Duo cloud unreachable (fall through to single-factor publickey); `secure` = deny login during outage.</td></tr><tr><td>`duo_pushinfo`</td><td>`yes`</td><td>Include hostname and command in the Duo push notification.</td></tr><tr><td>`duo_prompts`</td><td>`3`</td><td>Max retries at the Duo prompt before failure.</td></tr><tr><td>`duo_autopush`</td><td>`yes`</td><td>Auto-send push to user's primary device.</td></tr><tr><td>`break_glass_user`</td><td>`pbr_admin`</td><td>Username carved out of the Duo PAM flow.</td></tr><tr><td>`duo_sudo_enabled`</td><td>`true`</td><td>Toggle Duo MFA on sudo (v2.4+).</td></tr><tr><td>`sudo_timestamp_timeout`</td><td>`30`</td><td>Minutes the sudo credential cache lasts; reduces Duo prompts during a session.</td></tr></tbody></table>

---

## Preflight Role Defaults

File: `roles/preflight/defaults/main.yml`

<table id="bkmrk-variabledefaultpurpo-5"><thead><tr><th>Variable</th><th>Default</th><th>Purpose</th></tr></thead><tbody><tr><td>`preflight_min_ubuntu_major`</td><td>`22`</td><td>Minimum Ubuntu major version. 22.04 LTS is the floor.</td></tr><tr><td>`preflight_required_users`</td><td>`[ansible, pbr_admin]`</td><td>Local accounts that must exist before baseline.</td></tr><tr><td>`preflight_ad_ports`</td><td>`[88, 389]`</td><td>Ports tested for AD DC reachability. 88 = Kerberos, 389 = LDAP.</td></tr><tr><td>`preflight_skip_schema_check`</td><td>`false`</td><td>Set true to bypass the AD schema check if `python3-ldap` is unavailable on the control node and you've verified schema manually.</td></tr></tbody></table>

---

## Override Patterns

### Per-host override via host\_vars

Create `inventory/host_vars/<hostname>.yml`. Example: a host that requires a tighter source-IP allow-list:

```yaml
---
# inventory/host_vars/pbr-pos-belgrave.yml
pbr_admin_allowed_sources: "10.1.8.0/24"  # POS LAN only
fail2ban_sshd_bantime: 604800              # 7 days for POS hosts
```

### Forcing auditd on/off per host

```yaml
---
# inventory/host_vars/pbr-graylog-kl1.yml
# Force-skip auditd even if the host migrates from LXC to KVM
manage_auditd: false
```

### Adding a CIDR to fail2ban ignoreip

Override the full list (Ansible doesn't merge list defaults by default):

```yaml
fail2ban_ignoreip:
  - "127.0.0.1/8"
  - "::1"
  - "10.1.0.0/16"
  - "10.1.8.80/32"
  - "192.168.0.0/16"
  - "203.0.113.42/32"   # NEW: external admin static IP
```

---

## ansible.cfg Settings

The runtime configuration on `pbr-ansible-kl1` is fixed by `ansible.cfg` in the repo root:

```ini
[defaults]
inventory           = inventory/hosts.yml
remote_user         = ansible
private_key_file    = ~/.ssh/ansible_svc
host_key_checking   = True
retry_files_enabled = False
stdout_callback     = yaml
interpreter_python  = auto_silent
vault_password_file = ~/.ansible_vault_pass
roles_path          = roles
collections_path    = collections
forks               = 5

[privilege_escalation]
become              = True
become_method       = sudo
become_user         = root
become_ask_pass     = False

[ssh_connection]
pipelining          = True
ssh_args            = -o ControlMaster=auto -o ControlPersist=60s
```

**Notable settings:**

- `host_key_checking = True` — rejects connection to hosts with unknown SSH host keys. Adding a new host requires accepting its host key once (the bootstrap step naturally surfaces this).
- `vault_password_file` is set in `ansible.cfg`, so the `--vault-password-file` flag is technically redundant on the command line. It's included explicitly in this book's runbooks for portability if the config changes.
- `forks = 5` caps concurrency. Combined with `serial: 1` in playbooks, the effective concurrency is 1 host at a time.
- `pipelining = True` reduces task overhead by skipping the SCP/SFTP transfer of small modules.

---

## Collection Requirements

File: `requirements.yml`

```yaml
---
collections:
  - name: ansible.posix
    version: ">=2.1.0"
  - name: community.general
    version: ">=12.0.0"
  - name: paloaltonetworks.panos
    version: ">=2.20"
  - name: arubanetworks.aoscx
    version: ">=10.0" 
```

**Used by ssh-baseline:** `ansible.posix` (assorted modules), `community.general` (`timezone` module, `ldap_search` for schema check).

**Other collections:** `paloaltonetworks.panos` and `arubanetworks.aoscx` are listed for future use cases (Palo Alto NGFW automation, AOS-CX switch config) but are not used by the ssh-baseline role.

Install/update collections:

```bash
cd ~/pbr-infra
ansible-galaxy collection install -r requirements.yml --upgrade
```

---

## Where to Read Next

- **AD Integration &amp; SSSD** — how the AD variables map to SSSD config
- **Duo MFA Integration** — how the Duo variables map to `pam_duo.conf` and the PAM stacks
- **SSH Hardening Reference** — how each SSH variable lands in the deployed config