Add optional SMTP configuration for Authentik, including email host, port, and credentials. Update README and .env.sample to clarify usage for outbound email settings. Introduce blueprint support for enhanced deployment flexibility, with assertions in Ansible tasks to ensure required variables are set when enabled.
This commit is contained in:
@@ -30,3 +30,4 @@ noble_authentik_install: true
|
||||
# Optional: public (or extra) Authentik hostnames on the same IdP — list of FQDNs. Pangolin: CNAME + resource → Newt → Traefik (see noble_authentik README).
|
||||
noble_authentik_ingress_extra_hosts:
|
||||
- auth.nikflix.ca
|
||||
noble_authentik_blueprints_enabled: true
|
||||
@@ -4,7 +4,7 @@ Installs **Authentik** (Helm `goauthentik/authentik`) as the cluster IdP, **oaut
|
||||
|
||||
## Enable
|
||||
|
||||
1. Copy repository **`.env.sample`** to **`.env`** and set every **`NOBLE_AUTHENTIK_*`** variable (see comments there).
|
||||
1. Copy repository **`.env.sample`** to **`.env`** and set all **required** **`NOBLE_AUTHENTIK_*`** values (see comments there; SMTP keys are optional).
|
||||
2. Set **`noble_authentik_install: true`** in **`ansible/inventory/group_vars/all.yml`** (or pass **`-e noble_authentik_install=true`**).
|
||||
3. Run **`ansible-playbook playbooks/noble.yml --tags authentik`** (or a full **`noble.yml`**) from **`ansible/`** with a working **`KUBECONFIG`**.
|
||||
|
||||
@@ -18,13 +18,43 @@ See **`defaults/main.yml`**. Hostnames default to **`auth.apps.noble.lab.pcenicn
|
||||
|
||||
Authentik stores file-backed data in **S3** (not a shared PVC on **`authentik-worker`**). Set **`NOBLE_AUTHENTIK_MEDIA_S3_BUCKET`** in **`.env`** to a **dedicated** bucket name (do **not** reuse the Velero backup bucket). **`NOBLE_VELERO_S3_URL`**, **`NOBLE_VELERO_AWS_ACCESS_KEY_ID`**, and **`NOBLE_VELERO_AWS_SECRET_ACCESS_KEY`** are reused automatically when the Authentik-specific S3 variables are unset; override with **`NOBLE_AUTHENTIK_S3_URL`** / **`NOBLE_AUTHENTIK_S3_ACCESS_KEY`** / **`NOBLE_AUTHENTIK_S3_SECRET_KEY`** if needed. Optional: **`NOBLE_AUTHENTIK_S3_REGION`** (defaults to **`us-east-1`** in Ansible), **`NOBLE_AUTHENTIK_S3_ADDRESSING_STYLE`** (**`path`** vs **`virtual`** for some gateways). Create the bucket and grant the same credentials **read/write** to that bucket only. For browser uploads and public assets, follow [Authentik — S3 storage](https://docs.goauthentik.io/sys-mgmt/ops/storage-s3/) (CORS and policies). If you previously used a PVC for **`/data`**, sync into the new bucket (for example **`aws s3 sync`** from a volume snapshot or old mount) before relying on S3-only.
|
||||
|
||||
### Outbound email (SMTP)
|
||||
|
||||
Optional. Set **`NOBLE_AUTHENTIK_SMTP_HOST`** and **`NOBLE_AUTHENTIK_SMTP_FROM`** in repository **`.env`**; Ansible adds **`AUTHENTIK_EMAIL__HOST`**, **`AUTHENTIK_EMAIL__FROM`**, and related variables to Helm **`global.env`** (see [Authentik configuration — email](https://docs.goauthentik.io/install-config/configuration/#email-settings)). Omit **`NOBLE_AUTHENTIK_SMTP_HOST`** to skip SMTP env vars entirely. Optional overrides: **`NOBLE_AUTHENTIK_SMTP_PORT`** (default **587** in **`defaults/main.yml`**), **`NOBLE_AUTHENTIK_SMTP_USERNAME`**, **`NOBLE_AUTHENTIK_SMTP_PASSWORD`**, **`NOBLE_AUTHENTIK_SMTP_USE_TLS`** / **`USE_SSL`** / **`TIMEOUT`**. Re-run **`ansible-playbook playbooks/noble.yml --tags authentik`** after changes.
|
||||
|
||||
### Extra public hostname (Pangolin + Newt, same Authentik)
|
||||
|
||||
To expose the **same** Authentik instance on an **internet-facing** FQDN (while keeping the lab name on Traefik), set **`noble_authentik_ingress_extra_hosts`** in **`ansible/inventory/group_vars/all.yml`** (or **`-e`**) to a list of extra FQDNs, for example **`auth.example.com`**. Re-run **`ansible-playbook playbooks/noble.yml --tags authentik`**. Ansible extends **`server.ingress.hosts`** and **`tls[0].hosts`** so **cert-manager** issues one certificate with SANs for the primary **`noble_authentik_host`** plus those names (DNS must resolve for your issuer — often **Cloudflare** for public names, split horizon for lab).
|
||||
|
||||
Then in **Pangolin**: link the domain, create an **HTTP** resource for that hostname, and set the **target** to your **Newt** site with **`ip:port`** pointing at the cluster **Traefik** HTTPS entry (same pattern as **`clusters/noble/bootstrap/newt/README.md`** — typically the MetalLB / LAN VIP and **443**). One Newt tunnel can front many hostnames.
|
||||
|
||||
In **Authentik**, add a **Brand** (or equivalent) for the new hostname if you want different titles/favicon; OAuth **redirect URIs** for each app must include issuer URLs that match what browsers use (often you keep **internal** issuer URLs in cluster apps and use the public URL only for human login, or align all apps to the public issuer — pick one strategy to avoid mixed **`iss`** / callback mismatches).
|
||||
### Split routing, two Brands, and optional blueprints
|
||||
|
||||
This role supports a **single Authentik deployment** with **two hostnames** (lab + public) and **different Brands** per **`Host`**, without Authentik’s separate-database **Tenancy** feature (see [Tenancy](https://docs.goauthentik.io/sys-mgmt/tenancy) — alpha / licensing). [Brands](https://docs.goauthentik.io/brands/) choose default **authentication** (and related) **flows** and branding for each FQDN.
|
||||
|
||||
**Split routing (recommended):**
|
||||
|
||||
- **Lab / operator URL** — **`noble_authentik_host`** (default **`auth.apps.noble.lab.pcenicni.dev`**): keep DNS **internal-only** (split horizon, VPN, or LAN DNS). Do **not** publish this hostname as a Pangolin HTTP resource toward the internet unless you intentionally want it reachable off-LAN.
|
||||
- **Public URL** — entries in **`noble_authentik_ingress_extra_hosts`**: use Pangolin (or another edge) only for these names so casual users never need the lab FQDN.
|
||||
|
||||
Network isolation is enforced at **DNS and the tunnel**, not inside Authentik. Optionally add firewall / Traefik entrypoint rules for defense in depth.
|
||||
|
||||
**Two-Brand model:**
|
||||
|
||||
- **Lab Brand** — domain equals **`noble_authentik_host`**: use a **restricted authentication flow** so only operator groups (defaults: **`noble-admins`**, **`authentik Admins`**) can complete sign-in on that hostname. Your bootstrap / break-glass account must remain in one of those groups (see **`noble_authentik_ensure_admin_ui_access`** and **`configure_authentik.py`** group membership).
|
||||
- **Public Brand(s)** — one Brand per FQDN in **`noble_authentik_ingress_extra_hosts`**: use the stock **`default-authentication-flow`** (or replace with your own flow slug via a forked blueprint later). Assign general users to **`noble_authentik_blueprint_public_groups`** (defaults **`noble-public-users`**, **`noble-public-admins`**) for app policies and OAuth claims; **`noble-admins`** / **`noble-editors`** remain for cluster / Argo / Grafana as today.
|
||||
|
||||
**OAuth note:** Redirect URIs and **`iss`** must stay consistent with the hostname clients use (internal issuer for in-cluster apps vs public issuer is a deliberate choice — avoid mixing both for the same app).
|
||||
|
||||
**Mounted blueprints (optional):** set **`noble_authentik_blueprints_enabled: true`** in **`group_vars`** (or **`-e`**). On each **`--tags authentik`** run, Ansible renders Jinja templates under **`templates/blueprints/`** into a ConfigMap **`noble_authentik_blueprints_configmap_name`** (default **`authentik-noble-blueprints`**) and sets Helm **`blueprints.configMaps`** so **authentik-worker** loads them from **`/blueprints/mounted/cm-authentik-noble-blueprints/`** (see [Blueprints](https://docs.goauthentik.io/customize/blueprints/)). Files (apply in lexical order):
|
||||
|
||||
| Key | Purpose |
|
||||
| --- | --- |
|
||||
| **`10-noble-public-groups.yaml.j2`** | Ensures **`noble_authentik_blueprint_public_groups`** exist. |
|
||||
| **`20-noble-lab-operator-authentication-flow.yaml.j2`** | Flow **`noble_authentik_blueprint_lab_flow_slug`** + expression policy **`noble_authentik_blueprint_operator_policy_name`** (allowed groups **`noble_authentik_blueprint_lab_operator_groups`**). |
|
||||
| **`30-noble-brands-domain-split.yaml.j2`** | Brand for **`noble_authentik_host`** → lab flow; one Brand per **`noble_authentik_ingress_extra_hosts`** → default authentication. |
|
||||
|
||||
Tune titles via **`noble_authentik_blueprint_lab_brand_title`** and **`noble_authentik_blueprint_public_brand_title_prefix`**. After the worker applies blueprints, confirm **System → Brands** and **Flows** in the admin UI; fix any **`!Find`** failures if upstream default stage **names** change between Authentik versions.
|
||||
|
||||
### “Secondary tenant” (separate PostgreSQL schema — alpha)
|
||||
|
||||
@@ -41,6 +71,7 @@ When **`noble_authentik_configure_idp`** is true, Ansible creates/updates OAuth2
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Blueprints from Ansible fail to apply** (worker logs / **System → Blueprints**): confirm the ConfigMap exists (**`kubectl -n authentik get cm authentik-noble-blueprints`** unless you changed **`noble_authentik_blueprints_configmap_name`**), that Helm mounts it (**`blueprints.configMaps`** in the rendered extra values), and that every **`!Find`** in **`templates/blueprints/20-*.j2`** still matches your Authentik version’s default stage **names**. Re-run **`--tags authentik`** after editing templates.
|
||||
- **oauth2-proxy shows 500** on **`oauth2.apps…/oauth2/callback`** (logs: `email in id_token (...) isn't verified`): Authentik’s id_token often lacks **`email_verified: true`** for bootstrap users. **`clusters/noble/bootstrap/oauth2-proxy/values.yaml`** sets **`insecure-oidc-allow-unverified-email`** for the lab; otherwise verify the user’s email in Authentik, then **`helm upgrade oauth2-proxy`** (or **`--tags authentik`**).
|
||||
- Re-run **`configure_authentik.py`** only by executing **`noble.yml`** with **`--tags authentik`** after fixing `.env`.
|
||||
- If Authentik API calls fail, check flows exist (slug **`default-provider-authorization-implicit-consent`**) and TLS reaches **`AUTHENTIK_API_BASE`**.
|
||||
|
||||
@@ -26,6 +26,24 @@ noble_authentik_api_base: "{{ noble_authentik_public_url }}/api/v3"
|
||||
# Ansible merges these into **server.ingress.hosts** / **tls** (one cert Secret with multiple SANs).
|
||||
noble_authentik_ingress_extra_hosts: []
|
||||
|
||||
# Mounted **blueprints** (ConfigMap → worker `/blueprints/mounted/cm-*`). See README § split routing / two-Brand.
|
||||
noble_authentik_blueprints_enabled: false
|
||||
noble_authentik_blueprints_configmap_name: authentik-noble-blueprints
|
||||
# Directory groups for the public Brand(s); adjust names to match your apps’ policies / OAuth claims.
|
||||
noble_authentik_blueprint_public_groups:
|
||||
- noble-public-users
|
||||
- noble-public-admins
|
||||
# Lab-only authentication flow slug (Brand for **`noble_authentik_host`** points here).
|
||||
noble_authentik_blueprint_lab_flow_slug: noble-lab-operator-authentication-flow
|
||||
noble_authentik_blueprint_operator_policy_name: noble-lab-operators-only
|
||||
# Who may sign in on the **lab** hostname (`noble_authentik_host`). Bootstrap user should be in **noble-admins**
|
||||
# and/or **authentik Admins** (see **`noble_authentik_ensure_admin_ui_access`**).
|
||||
noble_authentik_blueprint_lab_operator_groups:
|
||||
- noble-admins
|
||||
- authentik Admins
|
||||
noble_authentik_blueprint_lab_brand_title: Noble lab (operators)
|
||||
noble_authentik_blueprint_public_brand_title_prefix: Noble public
|
||||
|
||||
noble_authentik_oauth2_proxy_host: oauth2.apps.noble.lab.pcenicni.dev
|
||||
|
||||
# Media: **S3** via Ansible **`global.env`** (same S3 **URL** + **access keys** as **Velero** when you omit Authentik-specific overrides).
|
||||
@@ -37,6 +55,17 @@ noble_authentik_s3_secret_key: ""
|
||||
noble_authentik_s3_region: "us-east-1"
|
||||
noble_authentik_s3_addressing_style: "path"
|
||||
|
||||
# Optional outbound SMTP (maps to **AUTHENTIK_EMAIL__*** in Helm **global.env**). Leave **noble_authentik_smtp_host**
|
||||
# empty to omit email env vars; set **NOBLE_AUTHENTIK_SMTP_HOST** (and **NOBLE_AUTHENTIK_SMTP_FROM**) in **.env** to enable.
|
||||
noble_authentik_smtp_host: ""
|
||||
noble_authentik_smtp_port: "587"
|
||||
noble_authentik_smtp_username: ""
|
||||
noble_authentik_smtp_password: ""
|
||||
noble_authentik_smtp_use_tls: "true"
|
||||
noble_authentik_smtp_use_ssl: "false"
|
||||
noble_authentik_smtp_timeout: "30"
|
||||
noble_authentik_smtp_from: ""
|
||||
|
||||
# OIDC client ids (must match Authentik providers created by configure script)
|
||||
noble_authentik_client_id_argocd: argocd
|
||||
noble_authentik_client_id_grafana: grafana
|
||||
|
||||
@@ -349,3 +349,168 @@
|
||||
- noble_authentik_s3_addr_from_env is defined
|
||||
- (noble_authentik_s3_addr_from_env.stdout | default('') | trim | length) > 0
|
||||
no_log: true
|
||||
|
||||
# --- Optional SMTP (AUTHENTIK_EMAIL__* via Helm global.env) ---
|
||||
- name: Load NOBLE_AUTHENTIK_SMTP_HOST from .env when unset
|
||||
ansible.builtin.shell: |
|
||||
set -a
|
||||
. "{{ noble_repo_root }}/.env"
|
||||
set +a
|
||||
printf '%s' "${NOBLE_AUTHENTIK_SMTP_HOST:-}"
|
||||
register: noble_authentik_smtp_host_from_env
|
||||
when:
|
||||
- noble_authentik_dotenv_stat.stat.exists | default(false)
|
||||
- noble_authentik_smtp_host | default('') | length == 0
|
||||
changed_when: false
|
||||
no_log: true
|
||||
|
||||
- name: Apply NOBLE_AUTHENTIK_SMTP_HOST from .env
|
||||
ansible.builtin.set_fact:
|
||||
noble_authentik_smtp_host: "{{ noble_authentik_smtp_host_from_env.stdout | trim }}"
|
||||
when:
|
||||
- noble_authentik_smtp_host_from_env is defined
|
||||
- (noble_authentik_smtp_host_from_env.stdout | default('') | trim | length) > 0
|
||||
no_log: true
|
||||
|
||||
- name: Load NOBLE_AUTHENTIK_SMTP_FROM from .env when unset
|
||||
ansible.builtin.shell: |
|
||||
set -a
|
||||
. "{{ noble_repo_root }}/.env"
|
||||
set +a
|
||||
printf '%s' "${NOBLE_AUTHENTIK_SMTP_FROM:-}"
|
||||
register: noble_authentik_smtp_from_from_env
|
||||
when:
|
||||
- noble_authentik_dotenv_stat.stat.exists | default(false)
|
||||
- noble_authentik_smtp_from | default('') | length == 0
|
||||
changed_when: false
|
||||
no_log: true
|
||||
|
||||
- name: Apply NOBLE_AUTHENTIK_SMTP_FROM from .env
|
||||
ansible.builtin.set_fact:
|
||||
noble_authentik_smtp_from: "{{ noble_authentik_smtp_from_from_env.stdout | trim }}"
|
||||
when:
|
||||
- noble_authentik_smtp_from_from_env is defined
|
||||
- (noble_authentik_smtp_from_from_env.stdout | default('') | trim | length) > 0
|
||||
no_log: true
|
||||
|
||||
- name: Load NOBLE_AUTHENTIK_SMTP_USERNAME from .env when unset
|
||||
ansible.builtin.shell: |
|
||||
set -a
|
||||
. "{{ noble_repo_root }}/.env"
|
||||
set +a
|
||||
printf '%s' "${NOBLE_AUTHENTIK_SMTP_USERNAME:-}"
|
||||
register: noble_authentik_smtp_username_from_env
|
||||
when:
|
||||
- noble_authentik_dotenv_stat.stat.exists | default(false)
|
||||
- noble_authentik_smtp_username | default('') | length == 0
|
||||
changed_when: false
|
||||
no_log: true
|
||||
|
||||
- name: Apply NOBLE_AUTHENTIK_SMTP_USERNAME from .env
|
||||
ansible.builtin.set_fact:
|
||||
noble_authentik_smtp_username: "{{ noble_authentik_smtp_username_from_env.stdout | trim }}"
|
||||
when:
|
||||
- noble_authentik_smtp_username_from_env is defined
|
||||
- (noble_authentik_smtp_username_from_env.stdout | default('') | trim | length) > 0
|
||||
no_log: true
|
||||
|
||||
- name: Load NOBLE_AUTHENTIK_SMTP_PASSWORD from .env when unset
|
||||
ansible.builtin.shell: |
|
||||
set -a
|
||||
. "{{ noble_repo_root }}/.env"
|
||||
set +a
|
||||
printf '%s' "${NOBLE_AUTHENTIK_SMTP_PASSWORD:-}"
|
||||
register: noble_authentik_smtp_password_from_env
|
||||
when:
|
||||
- noble_authentik_dotenv_stat.stat.exists | default(false)
|
||||
- noble_authentik_smtp_password | default('') | length == 0
|
||||
changed_when: false
|
||||
no_log: true
|
||||
|
||||
- name: Apply NOBLE_AUTHENTIK_SMTP_PASSWORD from .env
|
||||
ansible.builtin.set_fact:
|
||||
noble_authentik_smtp_password: "{{ noble_authentik_smtp_password_from_env.stdout | trim }}"
|
||||
when:
|
||||
- noble_authentik_smtp_password_from_env is defined
|
||||
- (noble_authentik_smtp_password_from_env.stdout | default('') | trim | length) > 0
|
||||
no_log: true
|
||||
|
||||
- name: Load NOBLE_AUTHENTIK_SMTP_PORT from .env
|
||||
ansible.builtin.shell: |
|
||||
set -a
|
||||
. "{{ noble_repo_root }}/.env"
|
||||
set +a
|
||||
printf '%s' "${NOBLE_AUTHENTIK_SMTP_PORT:-}"
|
||||
register: noble_authentik_smtp_port_from_env
|
||||
when:
|
||||
- noble_authentik_dotenv_stat.stat.exists | default(false)
|
||||
changed_when: false
|
||||
no_log: true
|
||||
|
||||
- name: Apply NOBLE_AUTHENTIK_SMTP_PORT from .env
|
||||
ansible.builtin.set_fact:
|
||||
noble_authentik_smtp_port: "{{ noble_authentik_smtp_port_from_env.stdout | trim }}"
|
||||
when:
|
||||
- noble_authentik_smtp_port_from_env is defined
|
||||
- (noble_authentik_smtp_port_from_env.stdout | default('') | trim | length) > 0
|
||||
no_log: true
|
||||
|
||||
- name: Load NOBLE_AUTHENTIK_SMTP_USE_TLS from .env
|
||||
ansible.builtin.shell: |
|
||||
set -a
|
||||
. "{{ noble_repo_root }}/.env"
|
||||
set +a
|
||||
printf '%s' "${NOBLE_AUTHENTIK_SMTP_USE_TLS:-}"
|
||||
register: noble_authentik_smtp_use_tls_from_env
|
||||
when:
|
||||
- noble_authentik_dotenv_stat.stat.exists | default(false)
|
||||
changed_when: false
|
||||
no_log: true
|
||||
|
||||
- name: Apply NOBLE_AUTHENTIK_SMTP_USE_TLS from .env
|
||||
ansible.builtin.set_fact:
|
||||
noble_authentik_smtp_use_tls: "{{ noble_authentik_smtp_use_tls_from_env.stdout | trim }}"
|
||||
when:
|
||||
- noble_authentik_smtp_use_tls_from_env is defined
|
||||
- (noble_authentik_smtp_use_tls_from_env.stdout | default('') | trim | length) > 0
|
||||
no_log: true
|
||||
|
||||
- name: Load NOBLE_AUTHENTIK_SMTP_USE_SSL from .env
|
||||
ansible.builtin.shell: |
|
||||
set -a
|
||||
. "{{ noble_repo_root }}/.env"
|
||||
set +a
|
||||
printf '%s' "${NOBLE_AUTHENTIK_SMTP_USE_SSL:-}"
|
||||
register: noble_authentik_smtp_use_ssl_from_env
|
||||
when:
|
||||
- noble_authentik_dotenv_stat.stat.exists | default(false)
|
||||
changed_when: false
|
||||
no_log: true
|
||||
|
||||
- name: Apply NOBLE_AUTHENTIK_SMTP_USE_SSL from .env
|
||||
ansible.builtin.set_fact:
|
||||
noble_authentik_smtp_use_ssl: "{{ noble_authentik_smtp_use_ssl_from_env.stdout | trim }}"
|
||||
when:
|
||||
- noble_authentik_smtp_use_ssl_from_env is defined
|
||||
- (noble_authentik_smtp_use_ssl_from_env.stdout | default('') | trim | length) > 0
|
||||
no_log: true
|
||||
|
||||
- name: Load NOBLE_AUTHENTIK_SMTP_TIMEOUT from .env
|
||||
ansible.builtin.shell: |
|
||||
set -a
|
||||
. "{{ noble_repo_root }}/.env"
|
||||
set +a
|
||||
printf '%s' "${NOBLE_AUTHENTIK_SMTP_TIMEOUT:-}"
|
||||
register: noble_authentik_smtp_timeout_from_env
|
||||
when:
|
||||
- noble_authentik_dotenv_stat.stat.exists | default(false)
|
||||
changed_when: false
|
||||
no_log: true
|
||||
|
||||
- name: Apply NOBLE_AUTHENTIK_SMTP_TIMEOUT from .env
|
||||
ansible.builtin.set_fact:
|
||||
noble_authentik_smtp_timeout: "{{ noble_authentik_smtp_timeout_from_env.stdout | trim }}"
|
||||
when:
|
||||
- noble_authentik_smtp_timeout_from_env is defined
|
||||
- (noble_authentik_smtp_timeout_from_env.stdout | default('') | trim | length) > 0
|
||||
no_log: true
|
||||
|
||||
@@ -39,6 +39,15 @@
|
||||
or reuse Velero's NOBLE_VELERO_S3_URL and NOBLE_VELERO_AWS_ACCESS_KEY_ID / NOBLE_VELERO_AWS_SECRET_ACCESS_KEY
|
||||
in .env (see .env.sample and clusters/noble/bootstrap/velero/README.md).
|
||||
|
||||
- name: Require Authentik SMTP From when SMTP host is set
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- noble_authentik_smtp_from | default('') | trim | length > 0
|
||||
fail_msg: >-
|
||||
When NOBLE_AUTHENTIK_SMTP_HOST is set, set NOBLE_AUTHENTIK_SMTP_FROM (sender address).
|
||||
See repository .env.sample and https://docs.goauthentik.io/install-config/configuration/#email-settings
|
||||
when: noble_authentik_smtp_host | default('') | trim | length > 0
|
||||
|
||||
- name: Ensure Ansible temp dir for rendered Helm values
|
||||
ansible.builtin.file:
|
||||
path: "{{ noble_repo_root }}/ansible/.ansible-tmp"
|
||||
@@ -65,6 +74,47 @@
|
||||
KUBECONFIG: "{{ noble_kubeconfig }}"
|
||||
changed_when: true
|
||||
|
||||
- name: Ensure dir for rendered Authentik blueprints
|
||||
ansible.builtin.file:
|
||||
path: "{{ noble_repo_root }}/ansible/.ansible-tmp/authentik-blueprints"
|
||||
state: directory
|
||||
mode: "0700"
|
||||
when: noble_authentik_blueprints_enabled | default(false) | bool
|
||||
|
||||
- name: Assert noble Authentik blueprint variables (when blueprints enabled)
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- noble_authentik_blueprint_public_groups | default([]) | length > 0
|
||||
- noble_authentik_blueprint_lab_operator_groups | default([]) | length > 0
|
||||
- noble_authentik_blueprint_lab_flow_slug | default('') | trim | length > 0
|
||||
fail_msg: >-
|
||||
When noble_authentik_blueprints_enabled is true, set noble_authentik_blueprint_public_groups (non-empty),
|
||||
noble_authentik_blueprint_lab_operator_groups (non-empty), and noble_authentik_blueprint_lab_flow_slug.
|
||||
See ansible/roles/noble_authentik/defaults/main.yml and README.
|
||||
when: noble_authentik_blueprints_enabled | default(false) | bool
|
||||
|
||||
- name: Render Authentik noble blueprint YAML files
|
||||
ansible.builtin.template:
|
||||
src: "blueprints/{{ item }}.j2"
|
||||
dest: "{{ noble_repo_root }}/ansible/.ansible-tmp/authentik-blueprints/{{ item }}"
|
||||
mode: "0600"
|
||||
loop:
|
||||
- 10-noble-public-groups.yaml
|
||||
- 20-noble-lab-operator-authentication-flow.yaml
|
||||
- 30-noble-brands-domain-split.yaml
|
||||
when: noble_authentik_blueprints_enabled | default(false) | bool
|
||||
|
||||
- name: Apply Authentik noble blueprints ConfigMap (worker mounts under /blueprints/mounted/cm-*)
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
kubectl -n "{{ noble_authentik_namespace }}" create configmap "{{ noble_authentik_blueprints_configmap_name }}" \
|
||||
--from-file="{{ noble_repo_root }}/ansible/.ansible-tmp/authentik-blueprints" \
|
||||
--dry-run=client -o yaml | kubectl apply -f -
|
||||
environment:
|
||||
KUBECONFIG: "{{ noble_kubeconfig }}"
|
||||
when: noble_authentik_blueprints_enabled | default(false) | bool
|
||||
changed_when: true
|
||||
|
||||
- name: Install Authentik (Helm)
|
||||
ansible.builtin.command:
|
||||
argv:
|
||||
|
||||
@@ -25,6 +25,24 @@ global:
|
||||
value: "{{ noble_authentik_s3_region }}"
|
||||
- name: AUTHENTIK_STORAGE__S3__ADDRESSING_STYLE
|
||||
value: "{{ noble_authentik_s3_addressing_style }}"
|
||||
{% if noble_authentik_smtp_host | default('') | trim | length > 0 %}
|
||||
- name: AUTHENTIK_EMAIL__HOST
|
||||
value: {{ noble_authentik_smtp_host | trim | to_json }}
|
||||
- name: AUTHENTIK_EMAIL__PORT
|
||||
value: {{ (noble_authentik_smtp_port | default('587') | string) | to_json }}
|
||||
- name: AUTHENTIK_EMAIL__USERNAME
|
||||
value: {{ noble_authentik_smtp_username | default('') | to_json }}
|
||||
- name: AUTHENTIK_EMAIL__PASSWORD
|
||||
value: {{ noble_authentik_smtp_password | default('') | to_json }}
|
||||
- name: AUTHENTIK_EMAIL__USE_TLS
|
||||
value: {{ (noble_authentik_smtp_use_tls | default('true') | string) | to_json }}
|
||||
- name: AUTHENTIK_EMAIL__USE_SSL
|
||||
value: {{ (noble_authentik_smtp_use_ssl | default('false') | string) | to_json }}
|
||||
- name: AUTHENTIK_EMAIL__TIMEOUT
|
||||
value: {{ (noble_authentik_smtp_timeout | default('30') | string) | to_json }}
|
||||
- name: AUTHENTIK_EMAIL__FROM
|
||||
value: {{ noble_authentik_smtp_from | trim | to_json }}
|
||||
{% endif %}
|
||||
postgresql:
|
||||
auth:
|
||||
password: "{{ noble_authentik_postgresql_password }}"
|
||||
@@ -46,3 +64,8 @@ server:
|
||||
- {{ h }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if noble_authentik_blueprints_enabled | default(false) | bool %}
|
||||
blueprints:
|
||||
configMaps:
|
||||
- {{ noble_authentik_blueprints_configmap_name }}
|
||||
{% endif %}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# Noble — directory groups for the **public** hostname Brand (see role README).
|
||||
# Groups are global to the instance; use policies and OAuth scope mappings to scope claims per app.
|
||||
version: 1
|
||||
metadata:
|
||||
name: noble-public-groups
|
||||
labels:
|
||||
blueprints.goauthentik.io/instantiate: "true"
|
||||
entries:
|
||||
{% for group in noble_authentik_blueprint_public_groups | default([]) %}
|
||||
- model: authentik_core.group
|
||||
identifiers:
|
||||
name: "{{ group | trim }}"
|
||||
{% endfor %}
|
||||
@@ -0,0 +1,101 @@
|
||||
# Noble — authentication flow for the **lab** hostname Brand: only members of operator groups may continue.
|
||||
# Reuses default identification / password / MFA / login stages; adds a policy on the password stage binding.
|
||||
version: 1
|
||||
metadata:
|
||||
name: noble-lab-operator-authentication
|
||||
labels:
|
||||
blueprints.goauthentik.io/instantiate: "true"
|
||||
entries:
|
||||
- model: authentik_blueprints.metaapplyblueprint
|
||||
attrs:
|
||||
identifiers:
|
||||
name: Default - Password change flow
|
||||
required: false
|
||||
- model: authentik_flows.flow
|
||||
id: flow
|
||||
identifiers:
|
||||
slug: {{ noble_authentik_blueprint_lab_flow_slug | trim | to_json }}
|
||||
attrs:
|
||||
name: Noble lab (operators)
|
||||
title: Noble lab — operators only
|
||||
designation: authentication
|
||||
authentication: none
|
||||
- id: noble-lab-identification-binding
|
||||
model: authentik_flows.flowstagebinding
|
||||
identifiers:
|
||||
order: 10
|
||||
stage: !Find [authentik_stages_identification.identificationstage, [name, default-authentication-identification]]
|
||||
target: !KeyOf flow
|
||||
- id: noble-lab-password-binding
|
||||
model: authentik_flows.flowstagebinding
|
||||
identifiers:
|
||||
order: 20
|
||||
stage: !Find [authentik_stages_password.passwordstage, [name, default-authentication-password]]
|
||||
target: !KeyOf flow
|
||||
attrs:
|
||||
re_evaluate_policies: true
|
||||
- id: noble-lab-authenticator-binding
|
||||
model: authentik_flows.flowstagebinding
|
||||
identifiers:
|
||||
order: 30
|
||||
stage: !Find [authentik_stages_authenticator_validate.authenticatorvalidatestage, [name, default-authentication-mfa-validation]]
|
||||
target: !KeyOf flow
|
||||
- model: authentik_flows.flowstagebinding
|
||||
identifiers:
|
||||
order: 100
|
||||
stage: !Find [authentik_stages_user_login.userloginstage, [name, default-authentication-login]]
|
||||
target: !KeyOf flow
|
||||
- model: authentik_policies_expression.expressionpolicy
|
||||
id: noble-lab-password-optional
|
||||
identifiers:
|
||||
name: noble-lab-password-optional
|
||||
attrs:
|
||||
expression: |
|
||||
flow_plan = request.context.get("flow_plan")
|
||||
if not flow_plan:
|
||||
return True
|
||||
return not hasattr(flow_plan.context.get("pending_user"), "backend")
|
||||
- model: authentik_policies_expression.expressionpolicy
|
||||
id: noble-lab-authenticator-validate-optional
|
||||
identifiers:
|
||||
name: noble-lab-authenticator-validate-optional
|
||||
attrs:
|
||||
expression: |
|
||||
flow_plan = request.context.get("flow_plan")
|
||||
if not flow_plan:
|
||||
return True
|
||||
return not (flow_plan.context.get("auth_method") == "auth_webauthn_pwl")
|
||||
- model: authentik_policies_expression.expressionpolicy
|
||||
id: noble-lab-operators-only
|
||||
identifiers:
|
||||
name: {{ noble_authentik_blueprint_operator_policy_name | trim | to_json }}
|
||||
attrs:
|
||||
expression: |
|
||||
u = context.get("pending_user")
|
||||
if u is None:
|
||||
return False
|
||||
{% for g in noble_authentik_blueprint_lab_operator_groups | default([]) %}
|
||||
if ak_is_group_member(u, name={{ g | trim | to_json }}):
|
||||
return True
|
||||
{% endfor %}
|
||||
ak_message("This login URL is for administrators only. Use the public Authentik hostname instead.")
|
||||
return False
|
||||
- model: authentik_policies.policybinding
|
||||
identifiers:
|
||||
order: 5
|
||||
target: !KeyOf noble-lab-password-binding
|
||||
policy: !KeyOf noble-lab-operators-only
|
||||
- model: authentik_policies.policybinding
|
||||
identifiers:
|
||||
order: 10
|
||||
target: !KeyOf noble-lab-password-binding
|
||||
policy: !KeyOf noble-lab-password-optional
|
||||
attrs:
|
||||
failure_result: true
|
||||
- model: authentik_policies.policybinding
|
||||
identifiers:
|
||||
order: 10
|
||||
target: !KeyOf noble-lab-authenticator-binding
|
||||
policy: !KeyOf noble-lab-authenticator-validate-optional
|
||||
attrs:
|
||||
failure_result: true
|
||||
@@ -0,0 +1,27 @@
|
||||
# Noble — Brands so **Host** selects authentication flow: lab hostname → operator-only flow; extra hosts → default login.
|
||||
version: 1
|
||||
metadata:
|
||||
name: noble-brands-domain-split
|
||||
labels:
|
||||
blueprints.goauthentik.io/instantiate: "true"
|
||||
entries:
|
||||
- model: authentik_brands.brand
|
||||
identifiers:
|
||||
domain: {{ noble_authentik_host | trim | to_json }}
|
||||
attrs:
|
||||
default: false
|
||||
title: {{ noble_authentik_blueprint_lab_brand_title | trim | to_json }}
|
||||
flow_authentication: !Find [authentik_flows.flow, [slug, {{ noble_authentik_blueprint_lab_flow_slug | trim | to_json }}]]
|
||||
flow_invalidation: !Find [authentik_flows.flow, [slug, default-invalidation-flow]]
|
||||
flow_user_settings: !Find [authentik_flows.flow, [slug, default-user-settings-flow]]
|
||||
{% for host in noble_authentik_ingress_extra_hosts | default([]) %}
|
||||
- model: authentik_brands.brand
|
||||
identifiers:
|
||||
domain: {{ host | trim | to_json }}
|
||||
attrs:
|
||||
default: false
|
||||
title: {{ ((noble_authentik_blueprint_public_brand_title_prefix | default('Noble public')) ~ ' (' ~ (host | trim) ~ ')') | to_json }}
|
||||
flow_authentication: !Find [authentik_flows.flow, [slug, default-authentication-flow]]
|
||||
flow_invalidation: !Find [authentik_flows.flow, [slug, default-invalidation-flow]]
|
||||
flow_user_settings: !Find [authentik_flows.flow, [slug, default-user-settings-flow]]
|
||||
{% endfor %}
|
||||
Reference in New Issue
Block a user