# dangerousthings.authforge Ansible role that installs and configures [AuthForge](https://github.com/dangerousthings/authforge), the FIDO2 / U2F / TOTP MFA stack for Ubuntu, on fleet hosts. The role: 1. Adds the `ppa:dangerousthings/authforge` PPA. 2. Installs `authforge-daemon`, `authforge-pam`, and `authforge-cli` (and optionally `authforge-gui` for desktop fleets). 3. Renders a TOML fleet policy file at `/etc/authforge/policy.d/90-fleet.conf` from your variables. 4. Restarts `authforge-daemon.service` whenever the policy file changes. 5. Seeds first-login pending-enrollment flags via `authforgectl pending set`. The role talks to AuthForge exclusively through `authforgectl` and the documented config-file shape - it does not touch daemon state directly. ## Requirements - Target host: Ubuntu 22.04 (jammy) or 24.04 (noble). - Control host: Ansible 2.14 or newer. - The host must be able to reach `ppa.launchpad.net` (or your internal mirror - override `authforge_ppa` to point at it). ## Role variables All variables and their defaults live in `defaults/main.yml`. | Variable | Default | Description | | --- | --- | --- | | `authforge_install_gui` | `false` | Also install the `authforge-gui` package (only useful on desktop fleets). | | `authforge_ppa` | `ppa:dangerousthings/authforge` | Source PPA. Override to use an internal mirror. | | `authforge_stacks` | `{}` | Map of PAM stack name to `{ mode, methods }`. `mode` is one of `disabled`, `optional`, `required`. `methods` is a list e.g. `["fido2", "totp"]`. | | `authforge_storage_backend` | `per-user` | Credential storage backend. `per-user` writes under each user's home; `central` uses `authforge_storage_central_path`. | | `authforge_storage_central_path` | `""` | Path for the central storage backend. Ignored when `authforge_storage_backend` is `per-user`. | | `authforge_firstrun_methods` | `["fido2"]` | Methods accepted during first-login enrollment. | | `authforge_firstrun_deadline_hours` | `0` | Hours before an unenrolled pending user is locked out. `0` disables the deadline. | | `authforge_pending_users` | `[]` | List of `{ user, methods }` to mark as pending-enrollment. | ## Example playbook ```yaml - hosts: workstations become: true roles: - role: dangerousthings.authforge vars: authforge_stacks: sudo: mode: required methods: [fido2] sshd: mode: optional methods: [fido2, totp] authforge_pending_users: - user: alice methods: [fido2] ``` A runnable copy lives at `examples/playbook.yml`. ## Idempotence notes - The `apt_repository`, `apt`, `template`, and `file` tasks are all idempotent; only the `authforgectl pending set` loop is forced to `changed_when: true` because the CLI does not currently expose a clean "is this user already pending?" check that's cheap to call from Ansible. Running `pending set` against an already-pending user is a no-op on the daemon side. - The handler restarts `authforge-daemon` only when the policy file contents actually change. ## License Apache-2.0. Same as the rest of AuthForge.