diff --git a/.idea/jsonSchemas.xml b/.idea/jsonSchemas.xml index eb488a0..e5121b9 100644 --- a/.idea/jsonSchemas.xml +++ b/.idea/jsonSchemas.xml @@ -27,6 +27,13 @@ diff --git a/contrib/compose_helpers.j2 b/contrib/compose_helpers.j2 index b4f4010..5bb73a3 100644 --- a/contrib/compose_helpers.j2 +++ b/contrib/compose_helpers.j2 @@ -1,4 +1,4 @@ -{% macro traefik_labels(host, service="", port="") %} +{% macro traefik_labels(host, service="", port="", auth=false) %} traefik.enable=true - traefik.http.routers.{{ host }}.rule=Host(`{{ host }}.{{ domain }}`) - traefik.http.routers.{{ host }}.entrypoints=web @@ -10,8 +10,11 @@ traefik.enable=true - traefik.http.routers.{{ host }}-tls.tls.domains.0.sans=*.{{ domain }} {% if service -%} - traefik.http.routers.{{ host }}.service={{ service }} -{%- endif %} +{% endif %} {% if port -%} - traefik.http.services.{{ host }}.loadbalancer.server.port={{ port }} -{%- endif %} -{%- endmacro %} +{% endif %} +{% if auth -%} +- traefik.http.routers.{{ host }}-tls.middlewares=authentik@docker +{% endif %} +{% endmacro %} diff --git a/inventories/prod/group_vars/all.yml b/inventories/prod/group_vars/all.yml index 3c54186..e5ef8ff 100644 --- a/inventories/prod/group_vars/all.yml +++ b/inventories/prod/group_vars/all.yml @@ -8,3 +8,13 @@ wg_privkey: !vault | 3831353935663865390a383335333133613039386237653665653663346666626666616439323530 33626333383830383430313765386439323738336336333234303738383837356135353635366365 3066313962653537376430613963316132613663356665316238 + +github_consumer_key: 32d5cae58d744c56fcc9 +github_consumer_secret: !vault | + $ANSIBLE_VAULT;1.2;AES256;alpina + 36353230356266303131333732363736383633313038326161346434303061633464393738383433 + 3933343436316530306439326237353265363333656264620a373036383835313733303561333233 + 33343834313163613037643734653535306365326536383532366166313261323265616133333865 + 3362663865666466320a363338303436626532393665663564313937366362326263396431316538 + 33396237333766666635333039643338333133346636363966326437646334636138353934333834 + 3139363661653364306231303966346333643166326536383164 diff --git a/inventories/staging/group_vars/all.yml b/inventories/staging/group_vars/all.yml index 4d14df2..3bf1eb1 100644 --- a/inventories/staging/group_vars/all.yml +++ b/inventories/staging/group_vars/all.yml @@ -8,3 +8,13 @@ wg_privkey: !vault | 3662633131636332620a313334396161386230303936646566363162643831393965376563386432 37613538613466353266666566373836663037363139316463313335633335633536613232323062 3765366135356362326138313636646263646235656333386132 + +github_consumer_key: dbacb8621c37320eb745 +github_consumer_secret: !vault | + $ANSIBLE_VAULT;1.2;AES256;alpina + 65393439653532323865356337353164666331653438396564613663363865643233323666316537 + 6365303062326139366139623232366338663831333333610a343035313364383738396635633737 + 32616366393365643565636337633334363637356435386235373638653139326665353537363939 + 3936336336663264310a343137653436323831366237376539353231656463663164316133376333 + 37373937356438373335663234616165663739626663663635316335333534333566326632346437 + 3539656334346163663635376533376362626235343466303430 diff --git a/roles/arrstack/templates/docker-compose.yml.j2 b/roles/arrstack/templates/docker-compose.yml.j2 index 7400a5b..5d401d9 100644 --- a/roles/arrstack/templates/docker-compose.yml.j2 +++ b/roles/arrstack/templates/docker-compose.yml.j2 @@ -14,7 +14,7 @@ services: cap_add: - NET_ADMIN labels: - - {{ traefik_labels("qbit", port="8080") | indent(6) }} + - {{ traefik_labels("qbit", port="8080", auth=true) | indent(6) }} restart: unless-stopped networks: - default @@ -31,7 +31,7 @@ services: image: linuxserver/prowlarr:latest container_name: prowlarr labels: - - {{ traefik_labels("prowlarr", port="9696") | indent(6) }} + - {{ traefik_labels("prowlarr", port="9696", auth=true) | indent(6) }} restart: unless-stopped depends_on: - qbittorrent @@ -45,7 +45,7 @@ services: image: linuxserver/sonarr:latest container_name: sonarr labels: - - {{ traefik_labels("sonarr", port="8989") | indent(6) }} + - {{ traefik_labels("sonarr", port="8989", auth=true) | indent(6) }} restart: unless-stopped depends_on: - qbittorrent @@ -61,7 +61,7 @@ services: image: linuxserver/radarr:latest container_name: radarr labels: - - {{ traefik_labels("radarr", port="7878") | indent(6) }} + - {{ traefik_labels("radarr", port="7878", auth=true) | indent(6) }} restart: unless-stopped depends_on: - qbittorrent diff --git a/roles/authentik/templates/.env.authentik.j2 b/roles/authentik/templates/.env.authentik.j2 new file mode 100644 index 0000000..a0446de --- /dev/null +++ b/roles/authentik/templates/.env.authentik.j2 @@ -0,0 +1,21 @@ +AUTHENTIK_ERROR_REPORTING__ENABLED=true + +AUTHENTIK_REDIS__HOST=redis +AUTHENTIK_POSTGRESQL__HOST=postgres +AUTHENTIK_POSTGRESQL__USER=authentik +AUTHENTIK_POSTGRESQL__NAME=authentik +AUTHENTIK_POSTGRESQL__PASSWORD={{ db_password }} + +AUTHENTIK_SECRET_KEY={{ authentik_secret_key }} + +AUTHENTIK_EMAIL__HOST=smtp.sendgrid.net +AUTHENTIK_EMAIL__PORT=587 +AUTHENTIK_EMAIL__USERNAME=apikey +AUTHENTIK_EMAIL__PASSWORD={{ sengrid_api_key }} + +AUTHENTIK_EMAIL__USE_TLS=true +AUTHENTIK_EMAIL__TIMEOUT=10 +AUTHENTIK_EMAIL__FROM=auth@cazzzer.com + +AUTHENTIK_DEFAULT_USER_CHANGE_EMAIL=false +AUTHENTIK_DEFAULT_USER_CHANGE_USERNAME=false diff --git a/roles/authentik/templates/.env.db.j2 b/roles/authentik/templates/.env.db.j2 new file mode 100644 index 0000000..ab2eb10 --- /dev/null +++ b/roles/authentik/templates/.env.db.j2 @@ -0,0 +1,3 @@ +POSTGRES_USER=authentik +POSTGRES_DB=authentik +POSTGRES_PASSWORD={{ db_password }} diff --git a/roles/authentik/templates/.env.j2 b/roles/authentik/templates/.env.j2 new file mode 100644 index 0000000..32676c3 --- /dev/null +++ b/roles/authentik/templates/.env.j2 @@ -0,0 +1 @@ +AUTHENTIK_VERSION=2023.3 \ No newline at end of file diff --git a/roles/authentik/templates/blueprints/apps-oauth2.yaml.j2 b/roles/authentik/templates/blueprints/apps-oauth2.yaml.j2 new file mode 100644 index 0000000..2470cfe --- /dev/null +++ b/roles/authentik/templates/blueprints/apps-oauth2.yaml.j2 @@ -0,0 +1,51 @@ +version: 1 +metadata: + labels: + blueprints.goauthentik.io/instantiate: "true" + name: Alpina - OAuth2 Apps +entries: + {% set apps = { + "Gitea": { + "redirect_uris": "https://gitea."~ domain ~"/user/oauth2/Authentik/callback", + "icon": "https://gitea."~ domain ~"/assets/img/logo.svg", + }, + "Nextcloud": { + "redirect_uris": "https://nc."~ domain ~"/apps/sociallogin/custom_oidc/authentik", + "icon": "https://nc."~ domain ~"/apps/theming/favicon", + }, + } -%} + {% for app in apps.keys() -%} + - identifiers: + name: {{ app }} + model: authentik_providers_oauth2.oauth2provider + id: {{ app | lower }} + attrs: + access_code_validity: minutes=1 + access_token_validity: minutes=5 + authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]] + client_type: confidential + issuer_mode: per_provider + sub_mode: hashed_user_id + property_mappings: + - !Find [authentik_providers_oauth2.scopemapping, [scope_name, openid]] + - !Find [authentik_providers_oauth2.scopemapping, [scope_name, email]] + - !Find [authentik_providers_oauth2.scopemapping, [scope_name, profile]] + redirect_uris: {{ apps[app]["redirect_uris"] }} + refresh_token_validity: days=30 + signing_key: !Find [authentik_crypto.certificatekeypair, [name, "authentik Self-signed Certificate"]] + + - identifiers: + slug: {{ app | lower }} + model: authentik_core.application + id: {{ app | lower }} + attrs: + name: {{ app }} + group: "Apps" + meta_description: "Hello, I'm {{ app }}!" + meta_publisher: Alpina + # This isn't supported yet, https://github.com/goauthentik/authentik/issues/3484 + # meta_icon: "{{ apps[app]["icon"] }}" + open_in_new_tab: true + policy_engine_mode: any + provider: !KeyOf {{ app | lower }} + {% endfor %} diff --git a/roles/authentik/templates/blueprints/arrstack.yaml.j2 b/roles/authentik/templates/blueprints/arrstack.yaml.j2 new file mode 100644 index 0000000..906e1b5 --- /dev/null +++ b/roles/authentik/templates/blueprints/arrstack.yaml.j2 @@ -0,0 +1,65 @@ +version: 1 +metadata: + labels: + blueprints.goauthentik.io/instantiate: "true" + name: Alpina - Arrstack Proxy +entries: + - identifiers: + name: arrstack + model: authentik_core.group + id: arrstack + + {% for service in ["qBit", "Prowlarr", "Sonarr", "Radarr"] -%} + - identifiers: + name: {{ service }} + model: authentik_providers_proxy.proxyprovider + id: {{ service | lower }} + attrs: + access_token_validity: hours=24 + authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]] + certificate: !Find [authentik_crypto.certificatekeypair, [name, "authentik Self-signed Certificate"]] + intercept_header_auth: true + external_host: https://{{ service | lower }}.{{ domain }}/ + mode: forward_single + property_mappings: + - !Find [authentik_providers_oauth2.scopemapping, [scope_name, openid]] + - !Find [authentik_providers_oauth2.scopemapping, [scope_name, email]] + - !Find [authentik_providers_oauth2.scopemapping, [scope_name, profile]] + - !Find [authentik_providers_oauth2.scopemapping, [scope_name, ak_proxy]] + refresh_token_validity: days=30 + skip_path_regex: {{ "/images/qbittorrent-tray.svg" if service == "qBit" else "/Content/Images/logo.svg" }} + + - identifiers: + slug: {{ service | lower }} + model: authentik_core.application + id: {{ service | lower }} + attrs: + name: {{ service }} + group: "Arrstack" + meta_description: "Hello, I'm {{ service }}!" + meta_publisher: Alpina + # This isn't supported yet, https://github.com/goauthentik/authentik/issues/3484 + # meta_icon: "https://{{ service }}.{{ domain }}/Content/Images/logo.svg" + open_in_new_tab: true + policy_engine_mode: any + provider: !KeyOf {{ service | lower }} + + - identifiers: + group: !KeyOf arrstack + target: !Find [authentik_core.application, [slug, {{ service | lower }}]] + model: authentik_policies.policybinding + attrs: + enabled: true + order: 0 + timeout: 30 + {% endfor %} + + - identifiers: + managed: goauthentik.io/outposts/embedded + name: authentik Embedded Outpost + model: authentik_outposts.outpost + attrs: + providers: + {% for service in ["qBit", "Prowlarr", "Sonarr", "Radarr"] -%} + - !KeyOf {{ service | lower }} + {% endfor %} diff --git a/roles/authentik/templates/blueprints/default-authentication.yaml.j2 b/roles/authentik/templates/blueprints/default-authentication.yaml.j2 new file mode 100644 index 0000000..701902b --- /dev/null +++ b/roles/authentik/templates/blueprints/default-authentication.yaml.j2 @@ -0,0 +1,19 @@ +version: 1 +metadata: + labels: + blueprints.goauthentik.io/instantiate: "true" + name: Alpina - Default Identification Stage +entries: + - identifiers: + name: default-authentication-identification + model: authentik_stages_identification.identificationstage + attrs: + sources: + - !Find [authentik_core.source, [slug, authentik-built-in]] + - !Find [authentik_sources_oauth.oauthsource, [slug, github]] + + - identifiers: + slug: default-authentication-flow + model: authentik_flows.flow + attrs: + compatibility_mode: true diff --git a/roles/authentik/templates/blueprints/github-oauth.yaml.j2 b/roles/authentik/templates/blueprints/github-oauth.yaml.j2 new file mode 100644 index 0000000..93c93b4 --- /dev/null +++ b/roles/authentik/templates/blueprints/github-oauth.yaml.j2 @@ -0,0 +1,25 @@ +version: 1 +metadata: + labels: + blueprints.goauthentik.io/instantiate: "true" + name: Alpina - GitHub OAuth +entries: + - identifiers: + slug: github + model: authentik_sources_oauth.oauthsource + attrs: + name: GitHub + slug: github + access_token_url: https://github.com/login/oauth/access_token + additional_scopes: openid read:org + authentication_flow: !Find [authentik_flows.flow, [slug, default-source-authentication]] + authorization_url: https://github.com/login/oauth/authorize + consumer_key: {{ github_consumer_key }} + consumer_secret: {{ github_consumer_secret }} + enabled: true + enrollment_flow: !Find [authentik_flows.flow, [slug, default-source-enrollment]] + policy_engine_mode: any + profile_url: https://api.github.com/user + provider_type: github + user_matching_mode: email_link + user_path_template: goauthentik.io/sources/%(slug)s diff --git a/roles/authentik/templates/docker-compose.yml.j2 b/roles/authentik/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..35978a1 --- /dev/null +++ b/roles/authentik/templates/docker-compose.yml.j2 @@ -0,0 +1,63 @@ +{% from "contrib/compose_helpers.j2" import traefik_labels with context %} +{##} +version: "3.7" + +networks: + default: + traefik_traefik: + external: true + +services: + server: + image: ghcr.io/goauthentik/server:${AUTHENTIK_VERSION} + container_name: authentik_server + labels: + - {{ traefik_labels("auth", port="9000") | indent(6) }} + - traefik.http.middlewares.authentik.forwardauth.address=http://authentik_server:9000/outpost.goauthentik.io/auth/traefik + - traefik.http.middlewares.authentik.forwardauth.trustForwardHeader=true + - traefik.http.middlewares.authentik.forwardauth.authResponseHeaders=X-authentik-username,X-authentik-groups,X-authentik-email,X-authentik-name,X-authentik-uid,X-authentik-jwt,X-authentik-meta-jwks,X-authentik-meta-outpost,X-authentik-meta-provider,X-authentik-meta-app,X-authentik-meta-version + restart: unless-stopped + command: server + env_file: + - .env.authentik + networks: + - default + - traefik_traefik + + worker: + image: ghcr.io/goauthentik/server:${AUTHENTIK_VERSION} + container_name: authentik_worker + restart: unless-stopped + command: worker + env_file: + - .env.authentik + volumes: + - ./blueprints:/blueprints/alpina + - {{ base_volume_path }}/authentik/certs:/certs + + postgres: + image: postgres:12-alpine + container_name: authentik_postgres + restart: unless-stopped + env_file: + - .env.db + healthcheck: + test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"] + start_period: 20s + interval: 30s + retries: 5 + timeout: 5s + volumes: + - {{ base_volume_path }}/authentik/postgres:/var/lib/postgresql/data + + redis: + image: redis:alpine + container_name: authentik_redis + restart: unless-stopped + command: --save 60 1 --loglevel warning + healthcheck: + test: ["CMD-SHELL", "redis-cli ping | grep PONG"] + start_period: 20s + interval: 30s + retries: 5 + timeout: 3s diff --git a/roles/authentik/vars/app_config.yml b/roles/authentik/vars/app_config.yml new file mode 100644 index 0000000..69ad34a --- /dev/null +++ b/roles/authentik/vars/app_config.yml @@ -0,0 +1,18 @@ +$ANSIBLE_VAULT;1.2;AES256;alpina +38336166363764396232386330336236356663376532323666326237336636626661343963653838 +6362363439383865393864363535613664656565653138360a373066343138633337653536386138 +63373232616430626464303832313966353162626333393032656237313939366538643930613365 +6637373666616538370a353635393731356237316462326437326463636438306134323839323637 +31653333326531663236333862316533346533623761306135393233333730386131666235356663 +62313030323736373837633938646237303966373865353037656339613364386165646534373461 +64343164663533613931613461616166646632353362386638336162303935336466393133356265 +31643366623036356632646338616431663737636637656462316165363231383631353961383663 +35613565316638353361316632376263633866353562303832623562393832326439386230343237 +39386536376530336365336234363134643334303836326130396330626566366663303764313262 +33333333353738623230633139343135613730636161306662636136646361613863363461333462 +64633434323361643034333834643766336466333636616136616563643930636339663462633865 +34343133663737356633633264396433373334393065366130313563393231633932663231616137 +65643739333137393034623362303735643166326132343133643435613936373333333464356638 +32646436373264636161613630366661383265373537646239643562303237636663616638383030 +62363664633332663638396630366134613464363137323562646236383961373239333133323964 +3065