feat(authentik): pin proxy outpost tokens; drop obsolete nextcloud patch #11

Open
Simon wants to merge 3 commits from feat/authentik-proxy-outpost-tokens into main
12 changed files with 195 additions and 2 deletions
Showing only changes of commit 0733d5710f - Show all commits

View file

@ -0,0 +1,58 @@
# authentik_outpost_proxy
Deploys an [authentik](https://goauthentik.io) proxy (ForwardAuth)
outpost via Docker Compose. The outpost serves the
`/outpost.goauthentik.io/auth/*` endpoints locally, so a Traefik
`ForwardAuth` middleware on the same host can gate services behind
authentik without routing the auth subrequest through additional reverse
proxies.
Use this when the protected service runs on a **different host** than the
authentik server: the embedded outpost only works for services co-located
with authentik (the subrequest must reach it without an intermediate proxy
mangling `X-Forwarded-Host`). Co-locating a proxy outpost with the service
keeps the ForwardAuth subrequest on the local docker network.
The outpost connects back to an authentik server using an outpost token
issued in the authentik admin interface (register the outpost there and
assign the proxy providers it should serve). The image version must match
the authentik server version.
## Requirements
- Docker and Docker Compose on the target host (e.g. via
`digitalboard.core.base`)
- Ansible collection: `community.docker`
- An authentik proxy outpost registered on the server, with the proxy
providers for the protected services assigned to it.
## Role variables
| Variable | Default | Description |
| --- | --- | --- |
| `authentik_outpost_proxy_image` | `ghcr.io/goauthentik/proxy:2026.2.2` | Outpost image (match the server version). |
| `authentik_outpost_proxy_host` | `https://authentik.local.test` | URL of the authentik server. |
| `authentik_outpost_proxy_token` | `changeme` | Outpost token — **override this**. |
| `authentik_outpost_proxy_insecure` | `"true"` | Skip TLS verification toward the authentik server. |
| `authentik_outpost_proxy_network` | `proxy` | Docker network the local Traefik routers and this outpost share. |
| `authentik_outpost_proxy_extra_hosts` | `[]` | Extra `host:ip` entries for in-container DNS. |
The local ForwardAuth middleware then points at the container over the
shared network, e.g.
`http://authentik-outpost-proxy-proxy-1:9000/outpost.goauthentik.io/auth/traefik`.
## Example
```yaml
- hosts: storage
become: true
roles:
- role: digitalboard.core.authentik_outpost_proxy
vars:
authentik_outpost_proxy_host: "https://auth.example.com"
authentik_outpost_proxy_token: "{{ vault_authentik_proxy_outpost_token }}"
```
## License
MIT-0

View file

@ -0,0 +1,28 @@
#SPDX-License-Identifier: MIT-0
---
# defaults file for authentik_outpost_proxy
# Base directory configuration (inherited from base role or defined here)
docker_compose_base_dir: /etc/docker/compose
docker_volume_base_dir: /srv/data
# Service configuration
authentik_outpost_proxy_service_name: authentik-outpost-proxy
authentik_outpost_proxy_docker_compose_dir: "{{ docker_compose_base_dir }}/{{ authentik_outpost_proxy_service_name }}"
# Container image (must match authentik server version)
authentik_outpost_proxy_image: "ghcr.io/goauthentik/proxy:2026.2.2"
# Connection to authentik server
authentik_outpost_proxy_host: "https://authentik.local.test"
authentik_outpost_proxy_token: "changeme"
authentik_outpost_proxy_insecure: "true"
# Traefik network the service-side routers live on, so the local
# ForwardAuth middleware can reach this outpost over the docker network.
authentik_outpost_proxy_network: "proxy"
# Extra hosts for DNS resolution within the container (e.g. pinning the
# authentik FQDN to a backend IP when the public name is unreachable).
authentik_outpost_proxy_extra_hosts: []
# - "auth.example.com:192.168.56.11"

View file

@ -0,0 +1,3 @@
#SPDX-License-Identifier: MIT-0
---
# handlers file for authentik_outpost_proxy

View file

@ -0,0 +1,28 @@
#SPDX-License-Identifier: MIT-0
galaxy_info:
author: digitalboard
description: Deploy an authentik proxy (ForwardAuth) outpost via Docker Compose, co-located with the services it protects
company: Digitalboard
license: MIT-0
min_ansible_version: "2.14"
platforms:
- name: Debian
versions:
- bookworm
- name: Ubuntu
versions:
- jammy
- noble
galaxy_tags:
- authentik
- proxy
- forwardauth
- outpost
- sso
- docker
- digitalboard
dependencies: []

View file

@ -0,0 +1,26 @@
#SPDX-License-Identifier: MIT-0
---
# tasks file for authentik_outpost_proxy
- name: Create docker compose directory
file:
path: "{{ authentik_outpost_proxy_docker_compose_dir }}"
state: directory
mode: '0755'
- name: Create docker-compose file for authentik proxy outpost
template:
src: docker-compose.yml.j2
dest: "{{ authentik_outpost_proxy_docker_compose_dir }}/docker-compose.yml"
mode: '0644'
- name: Start authentik proxy outpost container
community.docker.docker_compose_v2:
project_src: "{{ authentik_outpost_proxy_docker_compose_dir }}"
state: present
wait: true
wait_timeout: 120
retries: 3
delay: 15
register: result
until: result is not failed

View file

@ -0,0 +1,22 @@
services:
proxy:
image: {{ authentik_outpost_proxy_image }}
restart: unless-stopped
environment:
AUTHENTIK_HOST: {{ authentik_outpost_proxy_host }}
AUTHENTIK_TOKEN: {{ authentik_outpost_proxy_token }}
AUTHENTIK_INSECURE: "{{ authentik_outpost_proxy_insecure }}"
{% if authentik_outpost_proxy_extra_hosts | length > 0 %}
extra_hosts:
{% for host in authentik_outpost_proxy_extra_hosts %}
- "{{ host }}"
{% endfor %}
{% endif %}
labels:
- traefik.enable=false
networks:
- {{ authentik_outpost_proxy_network }}
networks:
{{ authentik_outpost_proxy_network }}:
external: true

View file

@ -0,0 +1,2 @@
#SPDX-License-Identifier: MIT-0
localhost

View file

@ -0,0 +1,6 @@
#SPDX-License-Identifier: MIT-0
---
- hosts: localhost
remote_user: root
roles:
- authentik_outpost_proxy

View file

@ -0,0 +1,3 @@
#SPDX-License-Identifier: MIT-0
---
# vars file for authentik_outpost_proxy

View file

@ -20,7 +20,15 @@ garage_image: "dxflrs/garage:v2.1.0"
garage_s3_domains:
- "storage.local.test"
garage_web_domain: "web.storage.local.test"
# Canonical WebUI console hostname (first entry of garage_webui_domains).
garage_webui_domain: "console.storage.local.test"
# FQDNs the WebUI console router accepts. The first entry is the canonical
# public domain; further entries cover internal *.int.* names so a DMZ
# reverseproxy can use a backend_host whose cert SAN matches (same pattern
# as garage_s3_domains). Defaults to just the canonical domain so existing
# inventories that only set garage_webui_domain keep working unchanged.
garage_webui_domains:
- "{{ garage_webui_domain }}"
# Garage WebUI configuration
garage_webui_enabled: true

View file

@ -45,7 +45,16 @@ argument_specs:
garage_webui_domain:
type: str
default: console.storage.local.test
description: Hostname serving the WebUI console.
description: Canonical WebUI console hostname (first entry of C(garage_webui_domains)).
garage_webui_domains:
type: list
elements: str
default: ['console.storage.local.test']
description:
- FQDNs the WebUI console router accepts. The first entry is the
canonical public domain; further entries cover internal
C(*.int.*) names so a DMZ reverseproxy can use a C(backend_host)
whose cert SAN matches. Defaults to just C(garage_webui_domain).
garage_webui_enabled:
type: bool

View file

@ -49,7 +49,7 @@ services:
labels:
- traefik.enable=true
- traefik.docker.network={{ garage_traefik_network }}
- traefik.http.routers.{{ garage_service_name }}-console.rule=Host(`{{ garage_webui_domain }}`)
- traefik.http.routers.{{ garage_service_name }}-console.rule={% for d in garage_webui_domains %}Host(`{{ d }}`){% if not loop.last %} || {% endif %}{% endfor +%}
{% if garage_use_ssl %}
- traefik.http.routers.{{ garage_service_name }}-console.entrypoints=websecure
- traefik.http.routers.{{ garage_service_name }}-console.tls=true