feat: добавить аддон authelia — SSO forward-auth и OIDC provider
Helm chart + Ansible role для Authelia 4.38: - Forward-auth для ingress-nginx через аннотации auth-url/auth-signin - OIDC provider: Gitea, Grafana, ArgoCD, MinIO, Vault, Nextcloud - SQLite default или PostgreSQL; опциональный Redis для сессий - RSA ключ OIDC генерируется автоматически если не задан в vault - ConfigMap authelia-forward-auth с готовыми аннотациями для любого сервиса - README: install, users, protect service, OIDC per-service, debug, test
This commit is contained in:
6
Makefile
6
Makefile
@@ -58,7 +58,7 @@ DOCKER_RUN := docker run --rm -it \
|
|||||||
addon-harbor addon-gitea addon-owncloud addon-nextcloud \
|
addon-harbor addon-gitea addon-owncloud addon-nextcloud \
|
||||||
addon-csi-s3 addon-csi-ceph addon-csi-glusterfs addon-vaultwarden \
|
addon-csi-s3 addon-csi-ceph addon-csi-glusterfs addon-vaultwarden \
|
||||||
addon-smtp-relay addon-vault addon-external-secrets \
|
addon-smtp-relay addon-vault addon-external-secrets \
|
||||||
addon-jenkins addon-netbird addon-mediaserver addon-hysteria2-server addon-splitgw addon-ingress-proxypass addon-ingress-add-domains addon-yandex-dns-controller addon-technitium-dns \
|
addon-jenkins addon-netbird addon-mediaserver addon-hysteria2-server addon-splitgw addon-ingress-proxypass addon-ingress-add-domains addon-yandex-dns-controller addon-technitium-dns addon-authelia \
|
||||||
add-node remove-node \
|
add-node remove-node \
|
||||||
add-etcd-node remove-etcd-node \
|
add-etcd-node remove-etcd-node \
|
||||||
etcd-backup etcd-restore etcd-list-snapshots \
|
etcd-backup etcd-restore etcd-list-snapshots \
|
||||||
@@ -436,6 +436,10 @@ addon-technitium-dns: _check_env _check_image ## Technitium DNS HA — Primary+S
|
|||||||
@printf "$(CYAN)Устанавливаю Technitium DNS HA...$(NC)\n"
|
@printf "$(CYAN)Устанавливаю Technitium DNS HA...$(NC)\n"
|
||||||
$(DOCKER_RUN) addon technitium-dns $(ARGS)
|
$(DOCKER_RUN) addon technitium-dns $(ARGS)
|
||||||
|
|
||||||
|
addon-authelia: _check_env _check_image ## Authelia SSO — Forward-auth + OIDC provider
|
||||||
|
@printf "$(CYAN)Устанавливаю Authelia SSO...$(NC)\n"
|
||||||
|
$(DOCKER_RUN) addon authelia $(ARGS)
|
||||||
|
|
||||||
# Generic цель — любой аддон из addons/<name>/playbook.yml
|
# Generic цель — любой аддон из addons/<name>/playbook.yml
|
||||||
addon-%: _check_env _check_image
|
addon-%: _check_env _check_image
|
||||||
@if [ ! -f "addons/$*/playbook.yml" ]; then \
|
@if [ ! -f "addons/$*/playbook.yml" ]; then \
|
||||||
|
|||||||
494
addons/authelia/README.md
Normal file
494
addons/authelia/README.md
Normal file
@@ -0,0 +1,494 @@
|
|||||||
|
# authelia
|
||||||
|
|
||||||
|
Self-hosted authentication system providing **forward-auth** for ingress-nginx and an **OIDC provider** for Gitea, Grafana, ArgoCD, MinIO, Vault, and Nextcloud.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
User → ingress-nginx → (auth-url) → Authelia :9091 → allowed/denied
|
||||||
|
↓
|
||||||
|
Authelia portal
|
||||||
|
auth.home.local
|
||||||
|
↓
|
||||||
|
users_database.yml
|
||||||
|
(argon2id passwords)
|
||||||
|
|
||||||
|
OIDC flow:
|
||||||
|
Service → Authelia /api/oidc/authorization → login → token → Service
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
Traffic routes:
|
||||||
|
auth.home.local → authelia ClusterIP :9091 (Ingress, NO forward-auth)
|
||||||
|
sonarr.home.local → sonarr service (Ingress + forward-auth annotations)
|
||||||
|
gitea.home.local → gitea service (Ingress, no forward-auth — OIDC handles it)
|
||||||
|
|
||||||
|
Kubernetes objects:
|
||||||
|
Deployment: authelia
|
||||||
|
Service: authelia (ClusterIP :9091)
|
||||||
|
Secrets: authelia-secrets (jwt, session, storage_encryption, oidc keys)
|
||||||
|
authelia-config (configuration.yml — contains OIDC client secrets)
|
||||||
|
authelia-users (users_database.yml)
|
||||||
|
PVC: authelia-data (SQLite db + notification.txt)
|
||||||
|
Ingress: authelia (auth.home.local)
|
||||||
|
ConfigMap: authelia-forward-auth (copy-paste annotation reference)
|
||||||
|
Deployment: authelia-redis (optional, redis.enabled=true)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Installation
|
||||||
|
|
||||||
|
### Step 1 — Generate secrets
|
||||||
|
|
||||||
|
Run these commands and save the output:
|
||||||
|
```bash
|
||||||
|
# Core secrets
|
||||||
|
openssl rand -base64 64 # → authelia_jwt_secret
|
||||||
|
openssl rand -base64 64 # → authelia_session_secret
|
||||||
|
openssl rand -base64 32 # → authelia_storage_encryption_key
|
||||||
|
openssl rand -base64 48 # → authelia_oidc_hmac_secret
|
||||||
|
|
||||||
|
# OIDC client secrets (one per enabled client)
|
||||||
|
openssl rand -hex 32 # → authelia_oidc_secret_gitea
|
||||||
|
openssl rand -hex 32 # → authelia_oidc_secret_grafana
|
||||||
|
```
|
||||||
|
|
||||||
|
> The **OIDC RSA private key** is auto-generated during deploy. Leave `authelia_oidc_private_key: ""` in vault. After first deploy, retrieve and save it (see note at end of deploy output).
|
||||||
|
|
||||||
|
### Step 2 — Generate admin password hash
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm authelia/authelia:latest authelia hash-password 'your-password'
|
||||||
|
# Output: $argon2id$v=19$m=65536,t=3,p=4$...
|
||||||
|
```
|
||||||
|
|
||||||
|
Copy the full `$argon2id$...` string.
|
||||||
|
|
||||||
|
### Step 3 — Edit vault.yml
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# group_vars/all/vault.yml (ansible-vault encrypted)
|
||||||
|
authelia_jwt_secret: "<output of openssl rand -base64 64>"
|
||||||
|
authelia_session_secret: "<output of openssl rand -base64 64>"
|
||||||
|
authelia_storage_encryption_key: "<output of openssl rand -base64 32>"
|
||||||
|
authelia_oidc_hmac_secret: "<output of openssl rand -base64 48>"
|
||||||
|
authelia_oidc_private_key: "" # auto-generated on first deploy
|
||||||
|
|
||||||
|
authelia_oidc_secret_gitea: "<output of openssl rand -hex 32>"
|
||||||
|
authelia_oidc_secret_grafana: "<output of openssl rand -hex 32>"
|
||||||
|
|
||||||
|
authelia_user_admin_password_hash: "$argon2id$v=19$m=65536,t=3,p=4$..."
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4 — Configure addons.yml
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# group_vars/all/addons.yml
|
||||||
|
addon_authelia: true
|
||||||
|
|
||||||
|
authelia_host: "auth.home.local"
|
||||||
|
authelia_domain: "home.local"
|
||||||
|
|
||||||
|
# OIDC clients to enable
|
||||||
|
authelia_oidc_gitea_enabled: true
|
||||||
|
authelia_oidc_grafana_enabled: true
|
||||||
|
|
||||||
|
# Domains to protect
|
||||||
|
authelia_protected_domains:
|
||||||
|
- sonarr.home.local
|
||||||
|
- radarr.home.local
|
||||||
|
- lidarr.home.local
|
||||||
|
- prowlarr.home.local
|
||||||
|
- pgadmin.home.local
|
||||||
|
|
||||||
|
# Domains requiring admin group
|
||||||
|
authelia_admin_domains:
|
||||||
|
- argocd.home.local
|
||||||
|
- vault.home.local
|
||||||
|
|
||||||
|
# Public bypass (no auth)
|
||||||
|
authelia_bypass_domains:
|
||||||
|
- plex.home.local
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5 — Deploy
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make addon-authelia
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 6 — Add DNS record
|
||||||
|
|
||||||
|
Add `auth.home.local` pointing to the kube-vip/ingress-nginx IP in Technitium DNS (or your DNS server).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Managing users
|
||||||
|
|
||||||
|
### Add a new user
|
||||||
|
|
||||||
|
1. Generate password hash:
|
||||||
|
```bash
|
||||||
|
docker run --rm authelia/authelia:latest authelia hash-password 'newpassword'
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Add to `group_vars/all/addons.yml`:
|
||||||
|
```yaml
|
||||||
|
authelia_users:
|
||||||
|
admin:
|
||||||
|
displayname: "Administrator"
|
||||||
|
email: "admin@home.local"
|
||||||
|
groups: [admins, users]
|
||||||
|
alice:
|
||||||
|
displayname: "Alice"
|
||||||
|
email: "alice@home.local"
|
||||||
|
groups: [users]
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Add to `vault.yml`:
|
||||||
|
```yaml
|
||||||
|
authelia_user_alice_password_hash: "$argon2id$..."
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Redeploy: `make addon-authelia`
|
||||||
|
|
||||||
|
### Groups
|
||||||
|
|
||||||
|
- `admins` — access to `authelia_admin_domains` (ArgoCD, Vault, Harbor, Dashboard)
|
||||||
|
- `users` — access to `authelia_protected_domains` (Sonarr, Radarr, etc.)
|
||||||
|
|
||||||
|
OIDC claims include the `groups` scope, so Grafana/Gitea can use group-based role mapping.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Protect a new service with forward-auth
|
||||||
|
|
||||||
|
### Step 1 — Add annotations to the service's Ingress
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: myservice
|
||||||
|
namespace: myservice
|
||||||
|
annotations:
|
||||||
|
kubernetes.io/ingress.class: nginx
|
||||||
|
# ── Authelia forward-auth ──────────────────────────────────────────────
|
||||||
|
nginx.ingress.kubernetes.io/auth-url: "http://authelia.authelia.svc.cluster.local:9091/api/authz/forward-auth"
|
||||||
|
nginx.ingress.kubernetes.io/auth-signin: "http://auth.home.local/?rd=$scheme://$host$escaped_request_uri"
|
||||||
|
nginx.ingress.kubernetes.io/auth-response-headers: "Remote-User,Remote-Name,Remote-Groups,Remote-Email"
|
||||||
|
nginx.ingress.kubernetes.io/auth-snippet: |
|
||||||
|
proxy_set_header X-Forwarded-Method $request_method;
|
||||||
|
spec:
|
||||||
|
rules:
|
||||||
|
- host: myservice.home.local
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: myservice
|
||||||
|
port:
|
||||||
|
number: 8080
|
||||||
|
```
|
||||||
|
|
||||||
|
> Get the exact URLs for your deployment:
|
||||||
|
> ```bash
|
||||||
|
> kubectl get cm authelia-forward-auth -n authelia -o jsonpath='{.data.annotations\.yaml}'
|
||||||
|
> ```
|
||||||
|
|
||||||
|
### Step 2 — Add to access control
|
||||||
|
|
||||||
|
Add `myservice.home.local` to the appropriate list in `addons.yml`:
|
||||||
|
```yaml
|
||||||
|
authelia_protected_domains:
|
||||||
|
- myservice.home.local
|
||||||
|
# ... existing entries
|
||||||
|
```
|
||||||
|
|
||||||
|
Then redeploy: `make addon-authelia`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. OIDC client configuration per service
|
||||||
|
|
||||||
|
### Gitea
|
||||||
|
|
||||||
|
In Gitea Admin → Site Administration → Authentication Sources → Add OAuth2:
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| Name | `Authelia` |
|
||||||
|
| OAuth2 Provider | `OpenID Connect` |
|
||||||
|
| Client ID | `gitea` |
|
||||||
|
| Client Secret | value of `authelia_oidc_secret_gitea` in vault |
|
||||||
|
| OpenID Connect Auto Discovery URL | `http://auth.home.local/.well-known/openid-configuration` |
|
||||||
|
| Scopes | `openid profile email groups` |
|
||||||
|
|
||||||
|
Restart Gitea. Users can now click "Sign in with Authelia" on the login page.
|
||||||
|
|
||||||
|
Optional — auto-create users and map admin group:
|
||||||
|
```ini
|
||||||
|
# app.ini
|
||||||
|
[oauth2]
|
||||||
|
USERNAME = preferred_username
|
||||||
|
UPDATE_AVATAR = true
|
||||||
|
|
||||||
|
[openid]
|
||||||
|
ENABLE_OPENID_SIGNIN = true
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Grafana
|
||||||
|
|
||||||
|
Add to Grafana's `grafana.ini` (or Helm values):
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[auth.generic_oauth]
|
||||||
|
enabled = true
|
||||||
|
name = Authelia
|
||||||
|
client_id = grafana
|
||||||
|
client_secret = <authelia_oidc_secret_grafana from vault>
|
||||||
|
scopes = openid profile email groups
|
||||||
|
auth_url = http://auth.home.local/api/oidc/authorization
|
||||||
|
token_url = http://auth.home.local/api/oidc/token
|
||||||
|
api_url = http://auth.home.local/api/oidc/userinfo
|
||||||
|
|
||||||
|
# Role mapping via Authelia groups
|
||||||
|
role_attribute_path = contains(groups[*], 'admins') && 'GrafanaAdmin' || 'Viewer'
|
||||||
|
allow_sign_up = true
|
||||||
|
```
|
||||||
|
|
||||||
|
Or in Helm values for the prometheus-stack addon:
|
||||||
|
```yaml
|
||||||
|
# group_vars/all/addons.yml
|
||||||
|
prometheus_grafana_oauth_enabled: true
|
||||||
|
prometheus_grafana_oauth_client_id: "grafana"
|
||||||
|
prometheus_grafana_oauth_client_secret: "..." # from vault
|
||||||
|
prometheus_grafana_oauth_auth_url: "http://auth.home.local/api/oidc/authorization"
|
||||||
|
prometheus_grafana_oauth_token_url: "http://auth.home.local/api/oidc/token"
|
||||||
|
prometheus_grafana_oauth_api_url: "http://auth.home.local/api/oidc/userinfo"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ArgoCD
|
||||||
|
|
||||||
|
Enable ArgoCD OIDC in `argocd-cm` ConfigMap:
|
||||||
|
```yaml
|
||||||
|
# values override for argocd Helm chart
|
||||||
|
server:
|
||||||
|
config:
|
||||||
|
oidc.config: |
|
||||||
|
name: Authelia
|
||||||
|
issuer: http://auth.home.local
|
||||||
|
clientID: argocd
|
||||||
|
clientSecret: $oidc.authelia.clientSecret
|
||||||
|
requestedScopes:
|
||||||
|
- openid
|
||||||
|
- profile
|
||||||
|
- email
|
||||||
|
- groups
|
||||||
|
requestedIDTokenClaims:
|
||||||
|
groups:
|
||||||
|
essential: true
|
||||||
|
```
|
||||||
|
|
||||||
|
Map Authelia groups to ArgoCD RBAC:
|
||||||
|
```yaml
|
||||||
|
# argocd-rbac-cm
|
||||||
|
policy.csv: |
|
||||||
|
g, admins, role:admin
|
||||||
|
policy.default: role:readonly
|
||||||
|
```
|
||||||
|
|
||||||
|
Store the secret in a K8s Secret `argocd-secret`:
|
||||||
|
```yaml
|
||||||
|
data:
|
||||||
|
oidc.authelia.clientSecret: <base64 of authelia_oidc_secret_argocd>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### MinIO
|
||||||
|
|
||||||
|
In MinIO Console → Identity → OpenID:
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| Config URL | `http://auth.home.local/.well-known/openid-configuration` |
|
||||||
|
| Client ID | `minio` |
|
||||||
|
| Client Secret | value of `authelia_oidc_secret_minio` |
|
||||||
|
| Claim Name | `groups` |
|
||||||
|
| Scopes | `openid,profile,email` |
|
||||||
|
|
||||||
|
Map Authelia group `admins` to MinIO policy `consoleAdmin`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Vault
|
||||||
|
|
||||||
|
Configure Vault OIDC auth method:
|
||||||
|
```bash
|
||||||
|
vault auth enable oidc
|
||||||
|
|
||||||
|
vault write auth/oidc/config \
|
||||||
|
oidc_discovery_url="http://auth.home.local" \
|
||||||
|
oidc_client_id="vault" \
|
||||||
|
oidc_client_secret="<authelia_oidc_secret_vault>" \
|
||||||
|
default_role="reader"
|
||||||
|
|
||||||
|
vault write auth/oidc/role/reader \
|
||||||
|
bound_audiences="vault" \
|
||||||
|
allowed_redirect_uris="https://vault.home.local/ui/vault/auth/oidc/oidc/callback" \
|
||||||
|
allowed_redirect_uris="https://vault.home.local/oidc/callback" \
|
||||||
|
user_claim="sub" \
|
||||||
|
groups_claim="groups" \
|
||||||
|
token_policies="default"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Debugging auth issues
|
||||||
|
|
||||||
|
### Check Authelia logs (real-time)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n authelia logs -l app.kubernetes.io/name=authelia -f --tail=100
|
||||||
|
```
|
||||||
|
|
||||||
|
Common log messages:
|
||||||
|
- `"ALLOW"` — request was allowed
|
||||||
|
- `"DENY"` — request was denied (check domain in `protectedDomains`)
|
||||||
|
- `"Redirecting"` — unauthenticated user redirected to login
|
||||||
|
- `"POST /api/firstfactor"` — login attempt
|
||||||
|
|
||||||
|
### Verify forward-auth endpoint is reachable
|
||||||
|
|
||||||
|
From within the cluster:
|
||||||
|
```bash
|
||||||
|
kubectl run curl-test --rm -it --image=curlimages/curl -- \
|
||||||
|
curl -v http://authelia.authelia.svc.cluster.local:9091/api/health
|
||||||
|
# Expected: {"status":"OK"}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test that a domain's annotations are applied
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl get ingress sonarr -n mediaserver -o yaml | grep auth-url
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check current access control configuration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n authelia exec deploy/authelia -- \
|
||||||
|
cat /config/configuration.yml | grep -A 30 "access_control:"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check active sessions (SQLite)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n authelia exec deploy/authelia -- \
|
||||||
|
sqlite3 /data/db.sqlite3 "SELECT subject, ip, last_activity FROM user_opaque_identifier LIMIT 20;"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Notification log (if SMTP disabled)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n authelia exec deploy/authelia -- cat /data/notification.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Test the login flow
|
||||||
|
|
||||||
|
### Forward-auth flow (e.g., Sonarr)
|
||||||
|
|
||||||
|
1. Open `http://sonarr.home.local/` in a private browser window
|
||||||
|
2. Should redirect to `http://auth.home.local/?rd=http%3A%2F%2Fsonarr.home.local%2F`
|
||||||
|
3. Enter credentials → should redirect back to Sonarr
|
||||||
|
4. Access granted
|
||||||
|
|
||||||
|
Test from command line:
|
||||||
|
```bash
|
||||||
|
# Step 1: login request (expect redirect to Authelia)
|
||||||
|
curl -I http://sonarr.home.local/
|
||||||
|
# Expected: 302 to auth.home.local
|
||||||
|
|
||||||
|
# Step 2: verify endpoint directly
|
||||||
|
curl -I -H "X-Forwarded-Host: sonarr.home.local" \
|
||||||
|
-H "X-Forwarded-URI: /" \
|
||||||
|
-H "X-Forwarded-Proto: http" \
|
||||||
|
http://authelia.authelia.svc.cluster.local:9091/api/authz/forward-auth
|
||||||
|
# Expected: 401 (unauthenticated) or 200 (if session cookie provided)
|
||||||
|
```
|
||||||
|
|
||||||
|
### OIDC flow (e.g., Gitea)
|
||||||
|
|
||||||
|
1. Open `http://gitea.home.local/user/oauth2/Authelia`
|
||||||
|
(or click "Sign in with Authelia" on Gitea login page)
|
||||||
|
2. Should redirect to Authelia login form
|
||||||
|
3. Login with admin credentials
|
||||||
|
4. Authelia redirects back to Gitea with authorization code
|
||||||
|
5. Gitea exchanges code for token — user is logged in
|
||||||
|
|
||||||
|
### Check OIDC discovery endpoint
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s http://auth.home.local/.well-known/openid-configuration | jq .
|
||||||
|
# Should return JSON with issuer, authorization_endpoint, token_endpoint, etc.
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Variables reference
|
||||||
|
|
||||||
|
| Variable | Default | Description |
|
||||||
|
|----------|---------|-------------|
|
||||||
|
| `authelia_host` | `auth.home.local` | Portal hostname |
|
||||||
|
| `authelia_domain` | `home.local` | Session cookie domain |
|
||||||
|
| `authelia_theme` | `dark` | UI theme |
|
||||||
|
| `authelia_two_factor_enabled` | `false` | Require TOTP/WebAuthn |
|
||||||
|
| `authelia_storage_type` | `sqlite` | `sqlite` or `postgresql` |
|
||||||
|
| `authelia_redis_enabled` | `false` | Built-in Redis for sessions |
|
||||||
|
| `authelia_smtp_enabled` | `false` | SMTP for 2FA/password-reset emails |
|
||||||
|
| `authelia_oidc_enabled` | `true` | Enable OIDC provider |
|
||||||
|
| `authelia_oidc_gitea_enabled` | `true` | Gitea OIDC client |
|
||||||
|
| `authelia_oidc_grafana_enabled` | `true` | Grafana OIDC client |
|
||||||
|
| `authelia_oidc_argocd_enabled` | `false` | ArgoCD OIDC client |
|
||||||
|
| `authelia_oidc_minio_enabled` | `false` | MinIO OIDC client |
|
||||||
|
| `authelia_oidc_vault_enabled` | `false` | Vault OIDC client |
|
||||||
|
| `authelia_ingress_tls_enabled` | `false` | TLS on auth portal |
|
||||||
|
| `authelia_protected_domains` | `[sonarr, radarr…]` | Domains requiring login |
|
||||||
|
| `authelia_admin_domains` | `[argocd, vault…]` | Admin-only domains |
|
||||||
|
| `authelia_bypass_domains` | `[]` | Public bypass domains |
|
||||||
|
| `authelia_oidc_domains` | `[gitea, grafana, minio]` | OIDC bypass (forward-auth off) |
|
||||||
|
|
||||||
|
### Vault secrets required
|
||||||
|
|
||||||
|
| Variable | Notes |
|
||||||
|
|----------|-------|
|
||||||
|
| `authelia_jwt_secret` | min 64 chars — `openssl rand -base64 64` |
|
||||||
|
| `authelia_session_secret` | min 64 chars |
|
||||||
|
| `authelia_storage_encryption_key` | min 20 chars — `openssl rand -base64 32` |
|
||||||
|
| `authelia_oidc_hmac_secret` | min 32 chars — `openssl rand -base64 48` |
|
||||||
|
| `authelia_oidc_private_key` | RSA PEM — leave empty, auto-generated |
|
||||||
|
| `authelia_oidc_secret_gitea` | `openssl rand -hex 32` |
|
||||||
|
| `authelia_oidc_secret_grafana` | `openssl rand -hex 32` |
|
||||||
|
| `authelia_user_admin_password_hash` | argon2id hash from `authelia hash-password` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Saving the auto-generated OIDC private key
|
||||||
|
|
||||||
|
After the first deploy, save the key to vault for reproducibility:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n authelia get secret authelia-secrets \
|
||||||
|
-o jsonpath='{.data.oidc_private_key}' | base64 -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Paste the PEM output into `vault.yml` as `authelia_oidc_private_key: |` (multiline YAML).
|
||||||
7
addons/authelia/playbook.yml
Normal file
7
addons/authelia/playbook.yml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
- name: Install Authelia SSO
|
||||||
|
hosts: k3s_master[0]
|
||||||
|
gather_facts: false
|
||||||
|
become: true
|
||||||
|
roles:
|
||||||
|
- role: "{{ playbook_dir }}/role"
|
||||||
21
addons/authelia/role/chart/Chart.yaml
Normal file
21
addons/authelia/role/chart/Chart.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: authelia
|
||||||
|
description: |
|
||||||
|
Self-hosted authentication portal with forward-auth for ingress-nginx
|
||||||
|
and OIDC provider for Gitea, Grafana, ArgoCD, MinIO, Vault, Nextcloud.
|
||||||
|
Supports file-based users, SQLite/PostgreSQL storage, optional Redis sessions.
|
||||||
|
type: application
|
||||||
|
version: 1.0.0
|
||||||
|
appVersion: "4.38.17"
|
||||||
|
keywords:
|
||||||
|
- authentication
|
||||||
|
- sso
|
||||||
|
- oidc
|
||||||
|
- forward-auth
|
||||||
|
- 2fa
|
||||||
|
home: https://www.authelia.com
|
||||||
|
sources:
|
||||||
|
- https://github.com/authelia/authelia
|
||||||
|
- https://git.antropoff.ru/DevOpsTools/K3S
|
||||||
|
maintainers:
|
||||||
|
- name: k3s-ansible
|
||||||
203
addons/authelia/role/chart/files/configuration.yml.tpl
Normal file
203
addons/authelia/role/chart/files/configuration.yml.tpl
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
---
|
||||||
|
# Authelia configuration — rendered by Helm via tpl()
|
||||||
|
# Secrets (jwt, session, storage_encryption, oidc_hmac, oidc_private_key)
|
||||||
|
# are injected via AUTHELIA_*_FILE environment variables — not in this file.
|
||||||
|
|
||||||
|
server:
|
||||||
|
host: 0.0.0.0
|
||||||
|
port: 9091
|
||||||
|
path: ""
|
||||||
|
buffers:
|
||||||
|
read: 4096
|
||||||
|
write: 4096
|
||||||
|
timeouts:
|
||||||
|
read: 6s
|
||||||
|
write: 6s
|
||||||
|
idle: 30s
|
||||||
|
|
||||||
|
log:
|
||||||
|
level: info
|
||||||
|
format: text
|
||||||
|
|
||||||
|
theme: {{ .Values.theme | quote }}
|
||||||
|
|
||||||
|
totp:
|
||||||
|
disable: false
|
||||||
|
issuer: {{ .Values.totp.issuer | quote }}
|
||||||
|
algorithm: sha1
|
||||||
|
digits: 6
|
||||||
|
period: {{ .Values.totp.period }}
|
||||||
|
skew: {{ .Values.totp.skew }}
|
||||||
|
secret_size: 32
|
||||||
|
|
||||||
|
webauthn:
|
||||||
|
disable: false
|
||||||
|
display_name: {{ .Values.domain | quote }}
|
||||||
|
attestation_conveyance_preference: indirect
|
||||||
|
user_verification: preferred
|
||||||
|
timeout: 60s
|
||||||
|
|
||||||
|
authentication_backend:
|
||||||
|
password_reset:
|
||||||
|
disable: false
|
||||||
|
refresh_interval: 5m
|
||||||
|
file:
|
||||||
|
path: /config/users_database.yml
|
||||||
|
watch: false
|
||||||
|
password:
|
||||||
|
algorithm: argon2id
|
||||||
|
iterations: 3
|
||||||
|
memory: 65536
|
||||||
|
parallelism: 4
|
||||||
|
key_length: 32
|
||||||
|
salt_length: 16
|
||||||
|
|
||||||
|
session:
|
||||||
|
name: {{ .Values.session.name | quote }}
|
||||||
|
domain: {{ .Values.session.domain | quote }}
|
||||||
|
same_site: {{ .Values.session.sameSite | quote }}
|
||||||
|
expiration: {{ .Values.session.expiration | quote }}
|
||||||
|
inactivity: {{ .Values.session.inactivity | quote }}
|
||||||
|
remember_me_duration: {{ .Values.session.rememberMeDuration | quote }}
|
||||||
|
{{- if .Values.redis.enabled }}
|
||||||
|
redis:
|
||||||
|
host: {{ printf "%s-redis" (include "authelia.name" .) | quote }}
|
||||||
|
port: 6379
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
regulation:
|
||||||
|
max_retries: 3
|
||||||
|
find_time: 2m
|
||||||
|
ban_time: 5m
|
||||||
|
|
||||||
|
storage:
|
||||||
|
{{- if eq .Values.storage.type "postgresql" }}
|
||||||
|
postgres:
|
||||||
|
host: {{ .Values.storage.postgresql.host | quote }}
|
||||||
|
port: {{ .Values.storage.postgresql.port }}
|
||||||
|
database: {{ .Values.storage.postgresql.database | quote }}
|
||||||
|
schema: {{ .Values.storage.postgresql.schema | quote }}
|
||||||
|
username: {{ .Values.storage.postgresql.username | quote }}
|
||||||
|
tls:
|
||||||
|
skip_verify: true
|
||||||
|
{{- else }}
|
||||||
|
local:
|
||||||
|
path: {{ .Values.storage.sqlite.path | quote }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
notifier:
|
||||||
|
disable_startup_check: true
|
||||||
|
{{- if .Values.notifier.smtp.enabled }}
|
||||||
|
smtp:
|
||||||
|
host: {{ .Values.notifier.smtp.host | quote }}
|
||||||
|
port: {{ .Values.notifier.smtp.port }}
|
||||||
|
username: {{ .Values.notifier.smtp.username | quote }}
|
||||||
|
sender: {{ .Values.notifier.smtp.sender | quote }}
|
||||||
|
tls:
|
||||||
|
skip_verify: {{ .Values.notifier.smtp.tls.skipVerify }}
|
||||||
|
{{- else }}
|
||||||
|
filesystem:
|
||||||
|
filename: /data/notification.txt
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
access_control:
|
||||||
|
default_policy: {{ .Values.accessControl.defaultPolicy | quote }}
|
||||||
|
rules:
|
||||||
|
|
||||||
|
# Authelia portal — always bypass (prevents auth loop)
|
||||||
|
- domain: {{ .Values.authHost | quote }}
|
||||||
|
policy: bypass
|
||||||
|
|
||||||
|
# Health check endpoints — bypass for monitoring
|
||||||
|
- domain: "*.{{ .Values.domain }}"
|
||||||
|
resources:
|
||||||
|
- "^/healthz(.*)$"
|
||||||
|
- "^/api/healthz(.*)$"
|
||||||
|
- "^/health$"
|
||||||
|
policy: bypass
|
||||||
|
|
||||||
|
{{- if .Values.accessControl.bypassDomains }}
|
||||||
|
# Public services — no authentication required
|
||||||
|
- domain:
|
||||||
|
{{- range .Values.accessControl.bypassDomains }}
|
||||||
|
- {{ . | quote }}
|
||||||
|
{{- end }}
|
||||||
|
policy: bypass
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- if .Values.accessControl.oidcDomains }}
|
||||||
|
# OIDC-enabled services — bypass forward-auth (OIDC handles authentication)
|
||||||
|
- domain:
|
||||||
|
{{- range .Values.accessControl.oidcDomains }}
|
||||||
|
- {{ . | quote }}
|
||||||
|
{{- end }}
|
||||||
|
policy: bypass
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- if .Values.accessControl.adminDomains }}
|
||||||
|
# Admin-only services — require 'admins' group
|
||||||
|
- domain:
|
||||||
|
{{- range .Values.accessControl.adminDomains }}
|
||||||
|
- {{ . | quote }}
|
||||||
|
{{- end }}
|
||||||
|
subject:
|
||||||
|
- "group:admins"
|
||||||
|
policy: {{ if .Values.twoFactor.enabled }}two_factor{{ else }}one_factor{{ end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- if .Values.accessControl.protectedDomains }}
|
||||||
|
# Protected services — login required
|
||||||
|
- domain:
|
||||||
|
{{- range .Values.accessControl.protectedDomains }}
|
||||||
|
- {{ . | quote }}
|
||||||
|
{{- end }}
|
||||||
|
policy: {{ if .Values.twoFactor.enabled }}two_factor{{ else }}one_factor{{ end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- if .Values.oidc.enabled }}
|
||||||
|
identity_providers:
|
||||||
|
oidc:
|
||||||
|
access_token_lifespan: {{ .Values.oidc.accessTokenLifespan | quote }}
|
||||||
|
authorize_code_lifespan: {{ .Values.oidc.authorizeCodeLifespan | quote }}
|
||||||
|
id_token_lifespan: {{ .Values.oidc.idTokenLifespan | quote }}
|
||||||
|
refresh_token_lifespan: {{ .Values.oidc.refreshTokenLifespan | quote }}
|
||||||
|
enable_client_debug_messages: false
|
||||||
|
minimum_parameter_entropy: 8
|
||||||
|
cors:
|
||||||
|
endpoints:
|
||||||
|
- authorization
|
||||||
|
- token
|
||||||
|
- revocation
|
||||||
|
- introspection
|
||||||
|
allowed_origins_from_client_redirect_uris: true
|
||||||
|
clients:
|
||||||
|
{{- range $name, $client := .Values.oidc.clients }}
|
||||||
|
{{- if $client.enabled }}
|
||||||
|
- id: {{ $client.id | quote }}
|
||||||
|
description: {{ $client.description | default $name | quote }}
|
||||||
|
# $plaintext$ prefix — Authelia 4.38+ plain-text client secret marker
|
||||||
|
secret: {{ printf "$plaintext$%s" $client.secret | quote }}
|
||||||
|
public: false
|
||||||
|
authorization_policy: one_factor
|
||||||
|
scopes:
|
||||||
|
{{- range $client.scopes }}
|
||||||
|
- {{ . | quote }}
|
||||||
|
{{- end }}
|
||||||
|
redirect_uris:
|
||||||
|
{{- range $client.redirectUris }}
|
||||||
|
- {{ . | quote }}
|
||||||
|
{{- end }}
|
||||||
|
grant_types:
|
||||||
|
{{- range $client.grantTypes }}
|
||||||
|
- {{ . | quote }}
|
||||||
|
{{- end }}
|
||||||
|
response_types:
|
||||||
|
- code
|
||||||
|
response_modes:
|
||||||
|
- form_post
|
||||||
|
- query
|
||||||
|
- fragment
|
||||||
|
userinfo_signing_algorithm: none
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
56
addons/authelia/role/chart/templates/NOTES.txt
Normal file
56
addons/authelia/role/chart/templates/NOTES.txt
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
╔══════════════════════════════════════════════════════════════╗
|
||||||
|
║ Authelia SSO — Deployed ║
|
||||||
|
╚══════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
|
Portal: http{{ if .Values.ingress.tls.enabled }}s{{ end }}://{{ .Values.authHost }}/
|
||||||
|
Namespace: {{ .Release.Namespace }}
|
||||||
|
OIDC: {{ if .Values.oidc.enabled }}enabled{{ else }}disabled{{ end }}
|
||||||
|
Redis: {{ if .Values.redis.enabled }}enabled{{ else }}disabled (memory sessions){{ end }}
|
||||||
|
Storage: {{ .Values.storage.type }}
|
||||||
|
|
||||||
|
─── Protect a new service ──────────────────────────────────────
|
||||||
|
|
||||||
|
Add to its Ingress:
|
||||||
|
nginx.ingress.kubernetes.io/auth-url: "http://{{ include "authelia.name" . }}.{{ .Release.Namespace }}.svc.cluster.local:9091/api/authz/forward-auth"
|
||||||
|
nginx.ingress.kubernetes.io/auth-signin: "http{{ if .Values.ingress.tls.enabled }}s{{ end }}://{{ .Values.authHost }}/?rd=$scheme://$host$escaped_request_uri"
|
||||||
|
nginx.ingress.kubernetes.io/auth-response-headers: "Remote-User,Remote-Name,Remote-Groups,Remote-Email"
|
||||||
|
nginx.ingress.kubernetes.io/auth-snippet: "proxy_set_header X-Forwarded-Method $request_method;"
|
||||||
|
|
||||||
|
Or get the full reference:
|
||||||
|
kubectl get cm {{ include "authelia.name" . }}-forward-auth -n {{ .Release.Namespace }} -o jsonpath='{.data.annotations\.yaml}'
|
||||||
|
|
||||||
|
─── OIDC Issuer ────────────────────────────────────────────────
|
||||||
|
|
||||||
|
http{{ if .Values.ingress.tls.enabled }}s{{ end }}://{{ .Values.authHost }}
|
||||||
|
|
||||||
|
Discovery: http{{ if .Values.ingress.tls.enabled }}s{{ end }}://{{ .Values.authHost }}/.well-known/openid-configuration
|
||||||
|
|
||||||
|
─── Logs / Debug ───────────────────────────────────────────────
|
||||||
|
|
||||||
|
kubectl -n {{ .Release.Namespace }} logs -l app.kubernetes.io/name={{ include "authelia.name" . }} -f
|
||||||
|
|
||||||
|
─── First login ────────────────────────────────────────────────
|
||||||
|
|
||||||
|
Open: http{{ if .Values.ingress.tls.enabled }}s{{ end }}://{{ .Values.authHost }}/
|
||||||
|
User: admin (or as configured in authelia_users)
|
||||||
|
Pass: the plaintext password whose hash you set in vault.yml
|
||||||
|
|
||||||
|
─── Access control rules ────────────────────────────────────────
|
||||||
|
{{- if .Values.accessControl.protectedDomains }}
|
||||||
|
Protected (login required):
|
||||||
|
{{- range .Values.accessControl.protectedDomains }}
|
||||||
|
- {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.accessControl.adminDomains }}
|
||||||
|
Admin-only (group: admins):
|
||||||
|
{{- range .Values.accessControl.adminDomains }}
|
||||||
|
- {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.accessControl.bypassDomains }}
|
||||||
|
Bypass (public):
|
||||||
|
{{- range .Values.accessControl.bypassDomains }}
|
||||||
|
- {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
37
addons/authelia/role/chart/templates/_helpers.tpl
Normal file
37
addons/authelia/role/chart/templates/_helpers.tpl
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{{- define "authelia.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "authelia.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "authelia.labels" -}}
|
||||||
|
helm.sh/chart: {{ include "authelia.chart" . }}
|
||||||
|
{{ include "authelia.selectorLabels" . }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "authelia.selectorLabels" -}}
|
||||||
|
app.kubernetes.io/name: {{ include "authelia.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Forward-auth URL for use in ingress-nginx annotations.
|
||||||
|
Returns the full URL to Authelia's authz endpoint inside the cluster.
|
||||||
|
*/}}
|
||||||
|
{{- define "authelia.forwardAuthUrl" -}}
|
||||||
|
{{- printf "http://%s.%s.svc.cluster.local:9091/api/authz/forward-auth" (include "authelia.name" .) .Release.Namespace }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Sign-in URL for redirecting unauthenticated users.
|
||||||
|
*/}}
|
||||||
|
{{- define "authelia.signinUrl" -}}
|
||||||
|
{{- if .Values.ingress.tls.enabled -}}
|
||||||
|
{{- printf "https://%s/?rd=$scheme://$host$escaped_request_uri" .Values.authHost }}
|
||||||
|
{{- else -}}
|
||||||
|
{{- printf "http://%s/?rd=$scheme://$host$escaped_request_uri" .Values.authHost }}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
---
|
||||||
|
# Reference ConfigMap: forward-auth annotations for ingress-nginx.
|
||||||
|
# Copy-paste these annotations onto any Ingress you want to protect with Authelia.
|
||||||
|
# Usage: kubectl get cm authelia-forward-auth -n {{ .Release.Namespace }} -o yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: {{ include "authelia.name" . }}-forward-auth
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "authelia.labels" . | nindent 4 }}
|
||||||
|
data:
|
||||||
|
# ── Paste these onto protected Ingress resources ─────────────────────────────
|
||||||
|
annotations.yaml: |
|
||||||
|
# Required on EVERY protected Ingress:
|
||||||
|
nginx.ingress.kubernetes.io/auth-url: "{{ include "authelia.forwardAuthUrl" . }}"
|
||||||
|
nginx.ingress.kubernetes.io/auth-signin: "{{ include "authelia.signinUrl" . }}"
|
||||||
|
nginx.ingress.kubernetes.io/auth-response-headers: "Remote-User,Remote-Name,Remote-Groups,Remote-Email"
|
||||||
|
nginx.ingress.kubernetes.io/auth-snippet: |
|
||||||
|
proxy_set_header X-Forwarded-Method $request_method;
|
||||||
|
|
||||||
|
# ── OIDC Issuer URL (for configuring OIDC clients) ────────────────────────────
|
||||||
|
oidc-issuer: |
|
||||||
|
{{ if .Values.ingress.tls.enabled }}https{{ else }}http{{ end }}://{{ .Values.authHost }}
|
||||||
|
|
||||||
|
# ── OIDC discovery endpoint ───────────────────────────────────────────────────
|
||||||
|
oidc-discovery: |
|
||||||
|
{{ if .Values.ingress.tls.enabled }}https{{ else }}http{{ end }}://{{ .Values.authHost }}/.well-known/openid-configuration
|
||||||
|
|
||||||
|
# ── Quick reference: protect a new service ────────────────────────────────────
|
||||||
|
howto: |
|
||||||
|
To protect myservice.home.local:
|
||||||
|
|
||||||
|
1. Add these annotations to the Service's Ingress:
|
||||||
|
nginx.ingress.kubernetes.io/auth-url: "{{ include "authelia.forwardAuthUrl" . }}"
|
||||||
|
nginx.ingress.kubernetes.io/auth-signin: "{{ include "authelia.signinUrl" . }}"
|
||||||
|
nginx.ingress.kubernetes.io/auth-response-headers: "Remote-User,Remote-Name,Remote-Groups,Remote-Email"
|
||||||
|
|
||||||
|
2. Add the domain to accessControl.protectedDomains in addons.yml and re-run:
|
||||||
|
make addon-authelia
|
||||||
|
|
||||||
|
3. Add to Technitium DNS (or /etc/hosts):
|
||||||
|
<kube-vip-IP> myservice.home.local
|
||||||
115
addons/authelia/role/chart/templates/deployment.yaml
Normal file
115
addons/authelia/role/chart/templates/deployment.yaml
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "authelia.name" . }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "authelia.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
# Recreate required for ReadWriteOnce PVC (SQLite)
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "authelia.selectorLabels" . | nindent 6 }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "authelia.selectorLabels" . | nindent 8 }}
|
||||||
|
annotations:
|
||||||
|
# Force pod restart when config/users secrets change
|
||||||
|
checksum/config: {{ tpl (.Files.Get "files/configuration.yml.tpl") . | sha256sum }}
|
||||||
|
checksum/secrets: {{ .Values.secrets | toJson | sha256sum }}
|
||||||
|
checksum/users: {{ .Values.users | toJson | sha256sum }}
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 8000
|
||||||
|
runAsGroup: 8000
|
||||||
|
fsGroup: 8000
|
||||||
|
containers:
|
||||||
|
- name: authelia
|
||||||
|
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
command:
|
||||||
|
- authelia
|
||||||
|
- --config=/config/configuration.yml
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 9091
|
||||||
|
protocol: TCP
|
||||||
|
env:
|
||||||
|
# Core secrets — read from mounted files
|
||||||
|
- name: AUTHELIA_JWT_SECRET_FILE
|
||||||
|
value: /secrets/jwt_secret
|
||||||
|
- name: AUTHELIA_SESSION_SECRET_FILE
|
||||||
|
value: /secrets/session_secret
|
||||||
|
- name: AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE
|
||||||
|
value: /secrets/storage_encryption_key
|
||||||
|
{{- if .Values.oidc.enabled }}
|
||||||
|
- name: AUTHELIA_IDENTITY_PROVIDERS_OIDC_HMAC_SECRET_FILE
|
||||||
|
value: /secrets/oidc_hmac_secret
|
||||||
|
- name: AUTHELIA_IDENTITY_PROVIDERS_OIDC_ISSUER_PRIVATE_KEY_FILE
|
||||||
|
value: /secrets/oidc_private_key
|
||||||
|
{{- end }}
|
||||||
|
{{- if eq .Values.storage.type "postgresql" }}
|
||||||
|
- name: AUTHELIA_STORAGE_POSTGRES_PASSWORD_FILE
|
||||||
|
value: /secrets/db_password
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.notifier.smtp.enabled }}
|
||||||
|
- name: AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE
|
||||||
|
value: /secrets/smtp_password
|
||||||
|
{{- end }}
|
||||||
|
- name: TZ
|
||||||
|
value: Europe/Moscow
|
||||||
|
volumeMounts:
|
||||||
|
- name: config
|
||||||
|
mountPath: /config
|
||||||
|
readOnly: true
|
||||||
|
- name: users
|
||||||
|
mountPath: /config/users_database.yml
|
||||||
|
subPath: users_database.yml
|
||||||
|
readOnly: true
|
||||||
|
- name: secrets
|
||||||
|
mountPath: /secrets
|
||||||
|
readOnly: true
|
||||||
|
- name: data
|
||||||
|
mountPath: /data
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /api/health
|
||||||
|
port: 9091
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 3
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /api/health
|
||||||
|
port: 9091
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 30
|
||||||
|
failureThreshold: 3
|
||||||
|
startupProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /api/health
|
||||||
|
port: 9091
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 5
|
||||||
|
failureThreshold: 12
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.resources | nindent 12 }}
|
||||||
|
volumes:
|
||||||
|
- name: config
|
||||||
|
secret:
|
||||||
|
secretName: {{ include "authelia.name" . }}-config
|
||||||
|
- name: users
|
||||||
|
secret:
|
||||||
|
secretName: {{ include "authelia.name" . }}-users
|
||||||
|
- name: secrets
|
||||||
|
secret:
|
||||||
|
secretName: {{ include "authelia.name" . }}-secrets
|
||||||
|
defaultMode: 0400
|
||||||
|
- name: data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: {{ include "authelia.name" . }}-data
|
||||||
36
addons/authelia/role/chart/templates/ingress.yaml
Normal file
36
addons/authelia/role/chart/templates/ingress.yaml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{{- if .Values.ingress.enabled }}
|
||||||
|
---
|
||||||
|
# Authelia portal ingress — accessible at authHost
|
||||||
|
# No forward-auth annotation here (would cause an auth loop)
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ include "authelia.name" . }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "authelia.labels" . | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
kubernetes.io/ingress.class: {{ .Values.ingress.ingressClass | quote }}
|
||||||
|
nginx.ingress.kubernetes.io/proxy-buffer-size: "128k"
|
||||||
|
{{- if .Values.ingress.tls.certManager.enabled }}
|
||||||
|
cert-manager.io/cluster-issuer: {{ .Values.ingress.tls.certManager.issuer | quote }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.ingress.tls.enabled }}
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- {{ .Values.authHost | quote }}
|
||||||
|
secretName: {{ .Values.ingress.tls.secretName | default (printf "%s-tls" (include "authelia.name" .)) | quote }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
- host: {{ .Values.authHost | quote }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ include "authelia.name" . }}
|
||||||
|
port:
|
||||||
|
number: 9091
|
||||||
|
{{- end }}
|
||||||
18
addons/authelia/role/chart/templates/pvc.yaml
Normal file
18
addons/authelia/role/chart/templates/pvc.yaml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
# PVC for Authelia data directory: SQLite database, notification log
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: {{ include "authelia.name" . }}-data
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "authelia.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
{{- if .Values.storage.storageClassName }}
|
||||||
|
storageClassName: {{ .Values.storage.storageClassName | quote }}
|
||||||
|
{{- end }}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: {{ .Values.storage.size }}
|
||||||
64
addons/authelia/role/chart/templates/redis.yaml
Normal file
64
addons/authelia/role/chart/templates/redis.yaml
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
{{- if .Values.redis.enabled }}
|
||||||
|
---
|
||||||
|
# Redis Deployment — session storage for Authelia (optional but recommended)
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "authelia.name" . }}-redis
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "authelia.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: redis
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "authelia.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: redis
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "authelia.selectorLabels" . | nindent 8 }}
|
||||||
|
app.kubernetes.io/component: redis
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: redis
|
||||||
|
image: {{ .Values.redis.image }}
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
command:
|
||||||
|
- redis-server
|
||||||
|
- --save ""
|
||||||
|
- --appendonly no
|
||||||
|
ports:
|
||||||
|
- name: redis
|
||||||
|
containerPort: 6379
|
||||||
|
protocol: TCP
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.redis.resources | nindent 12 }}
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command: [redis-cli, ping]
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "authelia.name" . }}-redis
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "authelia.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: redis
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
{{- include "authelia.selectorLabels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: redis
|
||||||
|
ports:
|
||||||
|
- name: redis
|
||||||
|
port: 6379
|
||||||
|
targetPort: 6379
|
||||||
|
protocol: TCP
|
||||||
|
{{- end }}
|
||||||
14
addons/authelia/role/chart/templates/secret-config.yaml
Normal file
14
addons/authelia/role/chart/templates/secret-config.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
# Authelia configuration.yml stored as Secret because it contains OIDC client secrets.
|
||||||
|
# Rendered via Helm tpl() from files/configuration.yml.tpl
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ include "authelia.name" . }}-config
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "authelia.labels" . | nindent 4 }}
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
configuration.yml: |
|
||||||
|
{{ tpl (.Files.Get "files/configuration.yml.tpl") . | indent 4 }}
|
||||||
24
addons/authelia/role/chart/templates/secret-main.yaml
Normal file
24
addons/authelia/role/chart/templates/secret-main.yaml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
# Authelia core secrets — mounted as files, read via AUTHELIA_*_FILE env vars.
|
||||||
|
# Contains: jwt_secret, session_secret, storage_encryption_key, oidc_hmac_secret,
|
||||||
|
# oidc_private_key (RSA PEM), db_password (optional), smtp_password (optional)
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ include "authelia.name" . }}-secrets
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "authelia.labels" . | nindent 4 }}
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
jwt_secret: {{ .Values.secrets.jwtSecret | quote }}
|
||||||
|
session_secret: {{ .Values.secrets.sessionSecret | quote }}
|
||||||
|
storage_encryption_key: {{ .Values.secrets.storageEncryptionKey | quote }}
|
||||||
|
oidc_hmac_secret: {{ .Values.secrets.oidcHmacSecret | quote }}
|
||||||
|
oidc_private_key: {{ .Values.secrets.oidcPrivateKey | quote }}
|
||||||
|
{{- if eq .Values.storage.type "postgresql" }}
|
||||||
|
db_password: {{ .Values.secrets.dbPassword | quote }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.notifier.smtp.enabled }}
|
||||||
|
smtp_password: {{ .Values.secrets.smtpPassword | quote }}
|
||||||
|
{{- end }}
|
||||||
25
addons/authelia/role/chart/templates/secret-users.yaml
Normal file
25
addons/authelia/role/chart/templates/secret-users.yaml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
# Authelia users_database.yml — file-based authentication backend.
|
||||||
|
# Passwords must be Argon2id hashes (see README for generation command).
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ include "authelia.name" . }}-users
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "authelia.labels" . | nindent 4 }}
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
users_database.yml: |
|
||||||
|
users:
|
||||||
|
{{- range $username, $user := .Values.users }}
|
||||||
|
{{ $username }}:
|
||||||
|
disabled: {{ $user.disabled | default false }}
|
||||||
|
displayname: {{ $user.displayname | quote }}
|
||||||
|
password: {{ $user.password | quote }}
|
||||||
|
email: {{ $user.email | quote }}
|
||||||
|
groups:
|
||||||
|
{{- range $user.groups }}
|
||||||
|
- {{ . | quote }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
17
addons/authelia/role/chart/templates/service.yaml
Normal file
17
addons/authelia/role/chart/templates/service.yaml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "authelia.name" . }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "authelia.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
{{- include "authelia.selectorLabels" . | nindent 4 }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 9091
|
||||||
|
targetPort: 9091
|
||||||
|
protocol: TCP
|
||||||
229
addons/authelia/role/chart/values.yaml
Normal file
229
addons/authelia/role/chart/values.yaml
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
# Authelia — SSO + Forward Auth
|
||||||
|
# Configure via: group_vars/all/addons.yml → authelia_* variables
|
||||||
|
# Secrets in: group_vars/all/vault.yml → authelia_* secrets
|
||||||
|
|
||||||
|
image:
|
||||||
|
repository: authelia/authelia
|
||||||
|
tag: "4.38.17"
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
# ── Domain ────────────────────────────────────────────────────────────────────
|
||||||
|
# Base domain and public hostname for the Authelia portal
|
||||||
|
domain: "home.local"
|
||||||
|
authHost: "auth.home.local"
|
||||||
|
|
||||||
|
# ── Theme / UX ────────────────────────────────────────────────────────────────
|
||||||
|
theme: dark # light | dark | grey | auto
|
||||||
|
|
||||||
|
# ── Secrets (all provided via Ansible vault, never hardcoded here) ────────────
|
||||||
|
# These are placed in a dedicated K8s Secret and mounted as files.
|
||||||
|
# Authelia reads them via AUTHELIA_*_FILE environment variables.
|
||||||
|
secrets:
|
||||||
|
jwtSecret: "" # min 64 chars — `openssl rand -base64 64`
|
||||||
|
sessionSecret: "" # min 64 chars — `openssl rand -base64 64`
|
||||||
|
storageEncryptionKey: "" # min 20 chars — `openssl rand -base64 32`
|
||||||
|
oidcHmacSecret: "" # min 32 chars — `openssl rand -base64 48`
|
||||||
|
oidcPrivateKey: "" # RSA-4096 PEM — auto-generated during deploy
|
||||||
|
dbPassword: "" # only if storage.type=postgresql
|
||||||
|
smtpPassword: "" # only if notifier.smtp.enabled
|
||||||
|
|
||||||
|
# ── Users (file-based auth backend) ──────────────────────────────────────────
|
||||||
|
# Passwords must be Argon2id hashes.
|
||||||
|
# Generate: docker run authelia/authelia:latest authelia hash-password 'yourpassword'
|
||||||
|
# Or: authelia hash-password 'yourpassword' (if installed locally)
|
||||||
|
users:
|
||||||
|
admin:
|
||||||
|
disabled: false
|
||||||
|
displayname: "Administrator"
|
||||||
|
password: "" # set in vault: authelia_user_admin_password_hash (argon2id)
|
||||||
|
email: "admin@home.local"
|
||||||
|
groups:
|
||||||
|
- admins
|
||||||
|
- users
|
||||||
|
|
||||||
|
# ── TOTP ──────────────────────────────────────────────────────────────────────
|
||||||
|
totp:
|
||||||
|
issuer: "home.local"
|
||||||
|
period: 30
|
||||||
|
skew: 1
|
||||||
|
|
||||||
|
# ── 2FA policy ────────────────────────────────────────────────────────────────
|
||||||
|
# false = one_factor (password only) for protected/admin domains
|
||||||
|
# true = two_factor (password + TOTP/WebAuthn) for protected/admin domains
|
||||||
|
twoFactor:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# ── Session ───────────────────────────────────────────────────────────────────
|
||||||
|
session:
|
||||||
|
name: authelia_session
|
||||||
|
domain: "home.local"
|
||||||
|
sameSite: lax
|
||||||
|
expiration: 1h
|
||||||
|
inactivity: 5m
|
||||||
|
rememberMeDuration: 1M
|
||||||
|
|
||||||
|
# ── Storage ───────────────────────────────────────────────────────────────────
|
||||||
|
storage:
|
||||||
|
type: sqlite # sqlite | postgresql
|
||||||
|
size: 1Gi
|
||||||
|
storageClassName: ""
|
||||||
|
sqlite:
|
||||||
|
path: /data/db.sqlite3
|
||||||
|
postgresql:
|
||||||
|
host: "postgresql.postgresql.svc.cluster.local"
|
||||||
|
port: 5432
|
||||||
|
database: authelia
|
||||||
|
username: authelia
|
||||||
|
schema: public
|
||||||
|
|
||||||
|
# ── Redis (built-in, optional) ────────────────────────────────────────────────
|
||||||
|
# When enabled, deploys a Redis sidecar for persistent session storage.
|
||||||
|
# Recommended for production; not required for homelab.
|
||||||
|
redis:
|
||||||
|
enabled: false
|
||||||
|
image: "redis:7-alpine"
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 20m
|
||||||
|
memory: 32Mi
|
||||||
|
limits:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 64Mi
|
||||||
|
|
||||||
|
# ── Notifier ──────────────────────────────────────────────────────────────────
|
||||||
|
notifier:
|
||||||
|
# SMTP — for password reset and 2FA enrollment emails
|
||||||
|
smtp:
|
||||||
|
enabled: false
|
||||||
|
host: ""
|
||||||
|
port: 587
|
||||||
|
username: ""
|
||||||
|
sender: "authelia@home.local"
|
||||||
|
tls:
|
||||||
|
skipVerify: false
|
||||||
|
# Filesystem — fallback: writes to /data/notification.txt (no email)
|
||||||
|
filesystem:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# ── Access Control ────────────────────────────────────────────────────────────
|
||||||
|
# Rules evaluated top-to-bottom. First match wins.
|
||||||
|
accessControl:
|
||||||
|
defaultPolicy: deny
|
||||||
|
|
||||||
|
# Public services — no authentication required
|
||||||
|
bypassDomains: []
|
||||||
|
# - plex.home.local
|
||||||
|
|
||||||
|
# OIDC-enabled services — bypass forward-auth (OIDC handles its own auth)
|
||||||
|
oidcDomains:
|
||||||
|
- gitea.home.local
|
||||||
|
- grafana.home.local
|
||||||
|
- minio.home.local
|
||||||
|
|
||||||
|
# Services requiring admin group membership
|
||||||
|
adminDomains:
|
||||||
|
- argocd.home.local
|
||||||
|
- vault.home.local
|
||||||
|
- harbor.home.local
|
||||||
|
- kubernetes-dashboard.home.local
|
||||||
|
|
||||||
|
# Services requiring login (one_factor or two_factor per twoFactor.enabled)
|
||||||
|
protectedDomains:
|
||||||
|
- sonarr.home.local
|
||||||
|
- radarr.home.local
|
||||||
|
- lidarr.home.local
|
||||||
|
- bazarr.home.local
|
||||||
|
- prowlarr.home.local
|
||||||
|
- pgadmin.home.local
|
||||||
|
- phpmyadmin.home.local
|
||||||
|
|
||||||
|
# ── OIDC Provider ─────────────────────────────────────────────────────────────
|
||||||
|
oidc:
|
||||||
|
enabled: true
|
||||||
|
accessTokenLifespan: 1h
|
||||||
|
authorizeCodeLifespan: 1m
|
||||||
|
idTokenLifespan: 1h
|
||||||
|
refreshTokenLifespan: 90m
|
||||||
|
|
||||||
|
clients:
|
||||||
|
gitea:
|
||||||
|
enabled: true
|
||||||
|
id: gitea
|
||||||
|
secret: "" # set in vault: authelia_oidc_secret_gitea
|
||||||
|
description: "Gitea"
|
||||||
|
redirectUris:
|
||||||
|
- https://gitea.home.local/user/oauth2/Authelia/callback
|
||||||
|
scopes: [openid, profile, email, groups]
|
||||||
|
grantTypes: [refresh_token, authorization_code]
|
||||||
|
|
||||||
|
grafana:
|
||||||
|
enabled: true
|
||||||
|
id: grafana
|
||||||
|
secret: "" # set in vault: authelia_oidc_secret_grafana
|
||||||
|
description: "Grafana"
|
||||||
|
redirectUris:
|
||||||
|
- https://grafana.home.local/login/generic_oauth
|
||||||
|
scopes: [openid, profile, email, groups]
|
||||||
|
grantTypes: [refresh_token, authorization_code]
|
||||||
|
|
||||||
|
argocd:
|
||||||
|
enabled: false
|
||||||
|
id: argocd
|
||||||
|
secret: "" # set in vault: authelia_oidc_secret_argocd
|
||||||
|
description: "ArgoCD"
|
||||||
|
redirectUris:
|
||||||
|
- https://argocd.home.local/auth/callback
|
||||||
|
scopes: [openid, profile, email, groups]
|
||||||
|
grantTypes: [refresh_token, authorization_code]
|
||||||
|
|
||||||
|
minio:
|
||||||
|
enabled: false
|
||||||
|
id: minio
|
||||||
|
secret: "" # set in vault: authelia_oidc_secret_minio
|
||||||
|
description: "MinIO"
|
||||||
|
redirectUris:
|
||||||
|
- https://minio.home.local/oauth_callback
|
||||||
|
scopes: [openid, profile, email]
|
||||||
|
grantTypes: [authorization_code]
|
||||||
|
|
||||||
|
vault:
|
||||||
|
enabled: false
|
||||||
|
id: vault
|
||||||
|
secret: "" # set in vault: authelia_oidc_secret_vault
|
||||||
|
description: "Vault"
|
||||||
|
redirectUris:
|
||||||
|
- https://vault.home.local/ui/vault/auth/oidc/oidc/callback
|
||||||
|
- https://vault.home.local/oidc/callback
|
||||||
|
scopes: [openid, profile, email, groups]
|
||||||
|
grantTypes: [refresh_token, authorization_code]
|
||||||
|
|
||||||
|
nextcloud:
|
||||||
|
enabled: false
|
||||||
|
id: nextcloud
|
||||||
|
secret: "" # set in vault: authelia_oidc_secret_nextcloud
|
||||||
|
description: "Nextcloud"
|
||||||
|
redirectUris:
|
||||||
|
- https://nextcloud.home.local/apps/user_oidc/code
|
||||||
|
scopes: [openid, profile, email, groups]
|
||||||
|
grantTypes: [refresh_token, authorization_code]
|
||||||
|
|
||||||
|
# ── Ingress ───────────────────────────────────────────────────────────────────
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
ingressClass: nginx
|
||||||
|
tls:
|
||||||
|
enabled: false
|
||||||
|
secretName: ""
|
||||||
|
certManager:
|
||||||
|
enabled: false
|
||||||
|
issuer: ""
|
||||||
|
issuerKind: ClusterIssuer
|
||||||
|
|
||||||
|
# ── Resources ─────────────────────────────────────────────────────────────────
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 256Mi
|
||||||
123
addons/authelia/role/defaults/main.yml
Normal file
123
addons/authelia/role/defaults/main.yml
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
---
|
||||||
|
# ── Namespace / release ───────────────────────────────────────────────────────
|
||||||
|
authelia_namespace: authelia
|
||||||
|
authelia_release_name: authelia
|
||||||
|
|
||||||
|
# ── Domain ────────────────────────────────────────────────────────────────────
|
||||||
|
authelia_domain: "home.local"
|
||||||
|
authelia_host: "auth.home.local"
|
||||||
|
|
||||||
|
# ── Theme ─────────────────────────────────────────────────────────────────────
|
||||||
|
authelia_theme: dark # light | dark | grey | auto
|
||||||
|
|
||||||
|
# ── 2FA enforcement ───────────────────────────────────────────────────────────
|
||||||
|
authelia_two_factor_enabled: false
|
||||||
|
|
||||||
|
# ── Session ───────────────────────────────────────────────────────────────────
|
||||||
|
authelia_session_expiration: "1h"
|
||||||
|
authelia_session_inactivity: "5m"
|
||||||
|
authelia_session_remember_me: "1M"
|
||||||
|
|
||||||
|
# ── Storage ───────────────────────────────────────────────────────────────────
|
||||||
|
authelia_storage_type: sqlite # sqlite | postgresql
|
||||||
|
authelia_storage_size: 1Gi
|
||||||
|
authelia_storage_class: ""
|
||||||
|
|
||||||
|
# PostgreSQL (only if authelia_storage_type=postgresql)
|
||||||
|
authelia_db_host: "postgresql.postgresql.svc.cluster.local"
|
||||||
|
authelia_db_port: 5432
|
||||||
|
authelia_db_name: authelia
|
||||||
|
authelia_db_user: authelia
|
||||||
|
|
||||||
|
# ── Redis session storage (optional) ─────────────────────────────────────────
|
||||||
|
authelia_redis_enabled: false
|
||||||
|
|
||||||
|
# ── SMTP notifier (optional) ──────────────────────────────────────────────────
|
||||||
|
authelia_smtp_enabled: false
|
||||||
|
authelia_smtp_host: ""
|
||||||
|
authelia_smtp_port: 587
|
||||||
|
authelia_smtp_username: ""
|
||||||
|
authelia_smtp_sender: "authelia@home.local"
|
||||||
|
authelia_smtp_tls_skip_verify: false
|
||||||
|
|
||||||
|
# ── Ingress ───────────────────────────────────────────────────────────────────
|
||||||
|
authelia_ingress_enabled: true
|
||||||
|
authelia_ingress_class: nginx
|
||||||
|
authelia_ingress_tls_enabled: false
|
||||||
|
authelia_ingress_tls_secret: ""
|
||||||
|
authelia_ingress_cert_manager_enabled: false
|
||||||
|
authelia_ingress_cert_manager_issuer: ""
|
||||||
|
|
||||||
|
# ── OIDC provider ─────────────────────────────────────────────────────────────
|
||||||
|
authelia_oidc_enabled: true
|
||||||
|
|
||||||
|
# Per-client toggles — secrets come from vault.yml
|
||||||
|
authelia_oidc_gitea_enabled: true
|
||||||
|
authelia_oidc_gitea_redirect: "https://gitea.home.local/user/oauth2/Authelia/callback"
|
||||||
|
|
||||||
|
authelia_oidc_grafana_enabled: true
|
||||||
|
authelia_oidc_grafana_redirect: "https://grafana.home.local/login/generic_oauth"
|
||||||
|
|
||||||
|
authelia_oidc_argocd_enabled: false
|
||||||
|
authelia_oidc_argocd_redirect: "https://argocd.home.local/auth/callback"
|
||||||
|
|
||||||
|
authelia_oidc_minio_enabled: false
|
||||||
|
authelia_oidc_minio_redirect: "https://minio.home.local/oauth_callback"
|
||||||
|
|
||||||
|
authelia_oidc_vault_enabled: false
|
||||||
|
authelia_oidc_vault_redirect_1: "https://vault.home.local/ui/vault/auth/oidc/oidc/callback"
|
||||||
|
authelia_oidc_vault_redirect_2: "https://vault.home.local/oidc/callback"
|
||||||
|
|
||||||
|
authelia_oidc_nextcloud_enabled: false
|
||||||
|
authelia_oidc_nextcloud_redirect: "https://nextcloud.home.local/apps/user_oidc/code"
|
||||||
|
|
||||||
|
# ── Access control ────────────────────────────────────────────────────────────
|
||||||
|
authelia_bypass_domains: []
|
||||||
|
# - plex.home.local
|
||||||
|
|
||||||
|
authelia_oidc_domains:
|
||||||
|
- gitea.home.local
|
||||||
|
- grafana.home.local
|
||||||
|
- minio.home.local
|
||||||
|
|
||||||
|
authelia_admin_domains:
|
||||||
|
- argocd.home.local
|
||||||
|
- vault.home.local
|
||||||
|
- harbor.home.local
|
||||||
|
- kubernetes-dashboard.home.local
|
||||||
|
|
||||||
|
authelia_protected_domains:
|
||||||
|
- sonarr.home.local
|
||||||
|
- radarr.home.local
|
||||||
|
- lidarr.home.local
|
||||||
|
- bazarr.home.local
|
||||||
|
- prowlarr.home.local
|
||||||
|
- pgadmin.home.local
|
||||||
|
- phpmyadmin.home.local
|
||||||
|
|
||||||
|
# ── Users ─────────────────────────────────────────────────────────────────────
|
||||||
|
# Passwords are Argon2id hashes — set in vault.yml: authelia_user_*_password_hash
|
||||||
|
# Generate: docker run authelia/authelia:latest authelia hash-password 'yourpassword'
|
||||||
|
authelia_users:
|
||||||
|
admin:
|
||||||
|
displayname: "Administrator"
|
||||||
|
email: "admin@home.local"
|
||||||
|
groups:
|
||||||
|
- admins
|
||||||
|
- users
|
||||||
|
|
||||||
|
# ── Secrets — ALL must be set in vault.yml ────────────────────────────────────
|
||||||
|
# authelia_jwt_secret: "" # openssl rand -base64 64
|
||||||
|
# authelia_session_secret: "" # openssl rand -base64 64
|
||||||
|
# authelia_storage_encryption_key: "" # openssl rand -base64 32
|
||||||
|
# authelia_oidc_hmac_secret: "" # openssl rand -base64 48
|
||||||
|
# authelia_oidc_private_key: "" # auto-generated during deploy if empty
|
||||||
|
# authelia_oidc_secret_gitea: "" # openssl rand -hex 32
|
||||||
|
# authelia_oidc_secret_grafana: "" # openssl rand -hex 32
|
||||||
|
# authelia_oidc_secret_argocd: ""
|
||||||
|
# authelia_oidc_secret_minio: ""
|
||||||
|
# authelia_oidc_secret_vault: ""
|
||||||
|
# authelia_oidc_secret_nextcloud: ""
|
||||||
|
# authelia_user_admin_password_hash: "" # argon2id hash
|
||||||
|
# authelia_db_password: "" # only if storage_type=postgresql
|
||||||
|
# authelia_smtp_password: "" # only if smtp_enabled=true
|
||||||
206
addons/authelia/role/tasks/main.yml
Normal file
206
addons/authelia/role/tasks/main.yml
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
---
|
||||||
|
# ── Validate required secrets ─────────────────────────────────────────────────
|
||||||
|
|
||||||
|
- name: Validate Authelia required secrets are set
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- authelia_jwt_secret is defined and authelia_jwt_secret | length >= 64
|
||||||
|
- authelia_session_secret is defined and authelia_session_secret | length >= 64
|
||||||
|
- authelia_storage_encryption_key is defined and authelia_storage_encryption_key | length >= 20
|
||||||
|
- authelia_oidc_hmac_secret is defined and authelia_oidc_hmac_secret | length >= 32
|
||||||
|
fail_msg: >
|
||||||
|
Required secrets are missing or too short in vault.yml.
|
||||||
|
authelia_jwt_secret (min 64 chars) : openssl rand -base64 64
|
||||||
|
authelia_session_secret (min 64 chars) : openssl rand -base64 64
|
||||||
|
authelia_storage_encryption_key (min 20 chars): openssl rand -base64 32
|
||||||
|
authelia_oidc_hmac_secret (min 32 chars) : openssl rand -base64 48
|
||||||
|
|
||||||
|
- name: Validate admin user password hash is set
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- authelia_user_admin_password_hash is defined
|
||||||
|
- authelia_user_admin_password_hash | length > 0
|
||||||
|
fail_msg: >
|
||||||
|
authelia_user_admin_password_hash is not set in vault.yml.
|
||||||
|
Generate with: docker run authelia/authelia:latest authelia hash-password 'yourpassword'
|
||||||
|
Then paste the $argon2id$... hash into vault.yml
|
||||||
|
|
||||||
|
- name: Validate OIDC client secrets when OIDC is enabled
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- authelia_oidc_secret_gitea is defined and authelia_oidc_secret_gitea | length >= 16
|
||||||
|
- authelia_oidc_secret_grafana is defined and authelia_oidc_secret_grafana | length >= 16
|
||||||
|
fail_msg: >
|
||||||
|
authelia_oidc_secret_gitea and authelia_oidc_secret_grafana must be set in vault.yml.
|
||||||
|
Generate with: openssl rand -hex 32
|
||||||
|
when: authelia_oidc_enabled | bool
|
||||||
|
|
||||||
|
# ── Generate OIDC RSA private key if not provided ────────────────────────────
|
||||||
|
|
||||||
|
- name: Check if OIDC private key is already set
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
_authelia_oidc_key_provided: >-
|
||||||
|
{{ authelia_oidc_private_key is defined and
|
||||||
|
authelia_oidc_private_key | length > 0 }}
|
||||||
|
|
||||||
|
- name: Generate RSA-4096 OIDC private key (if not in vault)
|
||||||
|
ansible.builtin.command: openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096
|
||||||
|
register: _generated_oidc_key
|
||||||
|
changed_when: true
|
||||||
|
no_log: true
|
||||||
|
when:
|
||||||
|
- authelia_oidc_enabled | bool
|
||||||
|
- not _authelia_oidc_key_provided | bool
|
||||||
|
|
||||||
|
- name: Use generated OIDC private key
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
_authelia_oidc_private_key_final: "{{ _generated_oidc_key.stdout }}"
|
||||||
|
no_log: true
|
||||||
|
when:
|
||||||
|
- authelia_oidc_enabled | bool
|
||||||
|
- not _authelia_oidc_key_provided | bool
|
||||||
|
|
||||||
|
- name: Use vault-provided OIDC private key
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
_authelia_oidc_private_key_final: "{{ authelia_oidc_private_key }}"
|
||||||
|
no_log: true
|
||||||
|
when: _authelia_oidc_key_provided | bool
|
||||||
|
|
||||||
|
- name: Set empty OIDC private key (OIDC disabled)
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
_authelia_oidc_private_key_final: ""
|
||||||
|
when: not (authelia_oidc_enabled | bool)
|
||||||
|
|
||||||
|
# ── Create namespace ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
- name: Create authelia namespace
|
||||||
|
ansible.builtin.command: >
|
||||||
|
k3s kubectl create namespace {{ authelia_namespace }}
|
||||||
|
--dry-run=client -o yaml | k3s kubectl apply -f -
|
||||||
|
become: true
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
# ── Copy Helm chart ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
- name: Ensure chart temp directory is clean
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /tmp/authelia-chart
|
||||||
|
state: absent
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Create chart temp directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /tmp/authelia-chart
|
||||||
|
state: directory
|
||||||
|
mode: "0755"
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Copy Helm chart to master
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "{{ role_path }}/chart/"
|
||||||
|
dest: /tmp/authelia-chart/
|
||||||
|
mode: preserve
|
||||||
|
become: true
|
||||||
|
|
||||||
|
# ── Template Helm values ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
- name: Template Helm values
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: values.yaml.j2
|
||||||
|
dest: /tmp/authelia-values.yaml
|
||||||
|
mode: "0600"
|
||||||
|
become: true
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
# ── Lint chart ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
- name: Lint Helm chart
|
||||||
|
ansible.builtin.command: >
|
||||||
|
helm lint /tmp/authelia-chart
|
||||||
|
--values /tmp/authelia-values.yaml
|
||||||
|
become: true
|
||||||
|
changed_when: false
|
||||||
|
register: _helm_lint
|
||||||
|
failed_when: _helm_lint.rc != 0
|
||||||
|
|
||||||
|
# ── Deploy chart ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
- name: Deploy Authelia via Helm
|
||||||
|
ansible.builtin.command: >
|
||||||
|
helm upgrade --install {{ authelia_release_name }}
|
||||||
|
/tmp/authelia-chart
|
||||||
|
--namespace {{ authelia_namespace }}
|
||||||
|
--values /tmp/authelia-values.yaml
|
||||||
|
--atomic
|
||||||
|
--wait
|
||||||
|
--timeout 180s
|
||||||
|
become: true
|
||||||
|
register: _helm_result
|
||||||
|
changed_when: true
|
||||||
|
|
||||||
|
# ── Cleanup ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
- name: Remove temp values file (contains secrets)
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /tmp/authelia-values.yaml
|
||||||
|
state: absent
|
||||||
|
become: true
|
||||||
|
|
||||||
|
# ── Wait for readiness ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
- name: Wait for Authelia pod to be ready
|
||||||
|
ansible.builtin.command: >
|
||||||
|
k3s kubectl -n {{ authelia_namespace }} rollout status
|
||||||
|
deployment/authelia --timeout=120s
|
||||||
|
become: true
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
# ── Get status ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
- name: Get pod status
|
||||||
|
ansible.builtin.command: >
|
||||||
|
k3s kubectl -n {{ authelia_namespace }} get pods,svc,ingress -o wide
|
||||||
|
become: true
|
||||||
|
changed_when: false
|
||||||
|
register: _status
|
||||||
|
|
||||||
|
- name: Get forward-auth annotations reference
|
||||||
|
ansible.builtin.command: >
|
||||||
|
k3s kubectl -n {{ authelia_namespace }} get cm authelia-forward-auth
|
||||||
|
-o jsonpath='{.data.annotations\.yaml}'
|
||||||
|
become: true
|
||||||
|
changed_when: false
|
||||||
|
register: _annotations
|
||||||
|
|
||||||
|
# ── Summary ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
- name: "=== Authelia SSO Ready ==="
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg:
|
||||||
|
- "╔══════════════════════════════════════════════════════════════╗"
|
||||||
|
- "║ Authelia SSO — Deployed ║"
|
||||||
|
- "╚══════════════════════════════════════════════════════════════╝"
|
||||||
|
- ""
|
||||||
|
- " Portal : http{{ 's' if authelia_ingress_tls_enabled else '' }}://{{ authelia_host }}/"
|
||||||
|
- " Namespace : {{ authelia_namespace }}"
|
||||||
|
- " OIDC : {{ 'enabled' if authelia_oidc_enabled else 'disabled' }}"
|
||||||
|
- " Storage : {{ authelia_storage_type }}"
|
||||||
|
- " Redis : {{ 'enabled' if authelia_redis_enabled else 'disabled' }}"
|
||||||
|
- ""
|
||||||
|
- " ── Protect a new service (add to its Ingress) ──"
|
||||||
|
- "{{ _annotations.stdout_lines | to_yaml }}"
|
||||||
|
- ""
|
||||||
|
- " ── OIDC Issuer URL ──"
|
||||||
|
- " http{{ 's' if authelia_ingress_tls_enabled else '' }}://{{ authelia_host }}"
|
||||||
|
- ""
|
||||||
|
- " ── Pods / Services ──"
|
||||||
|
- "{{ _status.stdout_lines | to_yaml }}"
|
||||||
|
- ""
|
||||||
|
- " Login: open http{{ 's' if authelia_ingress_tls_enabled else '' }}://{{ authelia_host }}/"
|
||||||
|
- " user: admin | pass: <your vault plaintext password>"
|
||||||
|
- ""
|
||||||
|
- "{% if not _authelia_oidc_key_provided %}"
|
||||||
|
- " ⚠ OIDC private key was AUTO-GENERATED. Save it to vault.yml for reproducibility:"
|
||||||
|
- " kubectl -n {{ authelia_namespace }} get secret authelia-secrets \\"
|
||||||
|
- " -o jsonpath='{.data.oidc_private_key}' | base64 -d"
|
||||||
|
- "{% endif %}"
|
||||||
154
addons/authelia/role/templates/values.yaml.j2
Normal file
154
addons/authelia/role/templates/values.yaml.j2
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
# Generated by Ansible — do not edit manually.
|
||||||
|
# Configure via: group_vars/all/addons.yml → authelia_* variables
|
||||||
|
# Secrets from: group_vars/all/vault.yml → authelia_* secrets
|
||||||
|
|
||||||
|
domain: {{ authelia_domain | quote }}
|
||||||
|
authHost: {{ authelia_host | quote }}
|
||||||
|
theme: {{ authelia_theme | quote }}
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
jwtSecret: {{ authelia_jwt_secret | quote }}
|
||||||
|
sessionSecret: {{ authelia_session_secret | quote }}
|
||||||
|
storageEncryptionKey: {{ authelia_storage_encryption_key | quote }}
|
||||||
|
oidcHmacSecret: {{ authelia_oidc_hmac_secret | quote }}
|
||||||
|
oidcPrivateKey: {{ _authelia_oidc_private_key_final | quote }}
|
||||||
|
dbPassword: {{ authelia_db_password | default('') | quote }}
|
||||||
|
smtpPassword: {{ authelia_smtp_password | default('') | quote }}
|
||||||
|
|
||||||
|
# Users — passwords are Argon2id hashes from vault.yml
|
||||||
|
users:
|
||||||
|
{% for username, user in authelia_users.items() %}
|
||||||
|
{{ username }}:
|
||||||
|
disabled: false
|
||||||
|
displayname: {{ user.displayname | quote }}
|
||||||
|
password: {{ vars['authelia_user_' + username + '_password_hash'] | default('') | quote }}
|
||||||
|
email: {{ user.email | quote }}
|
||||||
|
groups:
|
||||||
|
{{ user.groups | to_yaml | indent(6, True) }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
totp:
|
||||||
|
issuer: {{ authelia_domain | quote }}
|
||||||
|
period: 30
|
||||||
|
skew: 1
|
||||||
|
|
||||||
|
twoFactor:
|
||||||
|
enabled: {{ authelia_two_factor_enabled | string | lower }}
|
||||||
|
|
||||||
|
session:
|
||||||
|
name: authelia_session
|
||||||
|
domain: {{ authelia_domain | quote }}
|
||||||
|
sameSite: lax
|
||||||
|
expiration: {{ authelia_session_expiration | quote }}
|
||||||
|
inactivity: {{ authelia_session_inactivity | quote }}
|
||||||
|
rememberMeDuration: {{ authelia_session_remember_me | quote }}
|
||||||
|
|
||||||
|
storage:
|
||||||
|
type: {{ authelia_storage_type | quote }}
|
||||||
|
size: {{ authelia_storage_size | quote }}
|
||||||
|
storageClassName: {{ authelia_storage_class | quote }}
|
||||||
|
sqlite:
|
||||||
|
path: /data/db.sqlite3
|
||||||
|
postgresql:
|
||||||
|
host: {{ authelia_db_host | quote }}
|
||||||
|
port: {{ authelia_db_port }}
|
||||||
|
database: {{ authelia_db_name | quote }}
|
||||||
|
username: {{ authelia_db_user | quote }}
|
||||||
|
schema: public
|
||||||
|
|
||||||
|
redis:
|
||||||
|
enabled: {{ authelia_redis_enabled | string | lower }}
|
||||||
|
|
||||||
|
notifier:
|
||||||
|
smtp:
|
||||||
|
enabled: {{ authelia_smtp_enabled | string | lower }}
|
||||||
|
host: {{ authelia_smtp_host | quote }}
|
||||||
|
port: {{ authelia_smtp_port }}
|
||||||
|
username: {{ authelia_smtp_username | quote }}
|
||||||
|
sender: {{ authelia_smtp_sender | quote }}
|
||||||
|
tls:
|
||||||
|
skipVerify: {{ authelia_smtp_tls_skip_verify | string | lower }}
|
||||||
|
|
||||||
|
accessControl:
|
||||||
|
defaultPolicy: deny
|
||||||
|
bypassDomains:
|
||||||
|
{{ authelia_bypass_domains | to_yaml | indent(4, True) }}
|
||||||
|
oidcDomains:
|
||||||
|
{{ authelia_oidc_domains | to_yaml | indent(4, True) }}
|
||||||
|
adminDomains:
|
||||||
|
{{ authelia_admin_domains | to_yaml | indent(4, True) }}
|
||||||
|
protectedDomains:
|
||||||
|
{{ authelia_protected_domains | to_yaml | indent(4, True) }}
|
||||||
|
|
||||||
|
oidc:
|
||||||
|
enabled: {{ authelia_oidc_enabled | string | lower }}
|
||||||
|
accessTokenLifespan: 1h
|
||||||
|
authorizeCodeLifespan: 1m
|
||||||
|
idTokenLifespan: 1h
|
||||||
|
refreshTokenLifespan: 90m
|
||||||
|
clients:
|
||||||
|
gitea:
|
||||||
|
enabled: {{ authelia_oidc_gitea_enabled | string | lower }}
|
||||||
|
id: gitea
|
||||||
|
secret: {{ authelia_oidc_secret_gitea | default('') | quote }}
|
||||||
|
description: "Gitea"
|
||||||
|
redirectUris:
|
||||||
|
- {{ authelia_oidc_gitea_redirect | quote }}
|
||||||
|
scopes: [openid, profile, email, groups]
|
||||||
|
grantTypes: [refresh_token, authorization_code]
|
||||||
|
grafana:
|
||||||
|
enabled: {{ authelia_oidc_grafana_enabled | string | lower }}
|
||||||
|
id: grafana
|
||||||
|
secret: {{ authelia_oidc_secret_grafana | default('') | quote }}
|
||||||
|
description: "Grafana"
|
||||||
|
redirectUris:
|
||||||
|
- {{ authelia_oidc_grafana_redirect | quote }}
|
||||||
|
scopes: [openid, profile, email, groups]
|
||||||
|
grantTypes: [refresh_token, authorization_code]
|
||||||
|
argocd:
|
||||||
|
enabled: {{ authelia_oidc_argocd_enabled | string | lower }}
|
||||||
|
id: argocd
|
||||||
|
secret: {{ authelia_oidc_secret_argocd | default('') | quote }}
|
||||||
|
description: "ArgoCD"
|
||||||
|
redirectUris:
|
||||||
|
- {{ authelia_oidc_argocd_redirect | quote }}
|
||||||
|
scopes: [openid, profile, email, groups]
|
||||||
|
grantTypes: [refresh_token, authorization_code]
|
||||||
|
minio:
|
||||||
|
enabled: {{ authelia_oidc_minio_enabled | string | lower }}
|
||||||
|
id: minio
|
||||||
|
secret: {{ authelia_oidc_secret_minio | default('') | quote }}
|
||||||
|
description: "MinIO"
|
||||||
|
redirectUris:
|
||||||
|
- {{ authelia_oidc_minio_redirect | quote }}
|
||||||
|
scopes: [openid, profile, email]
|
||||||
|
grantTypes: [authorization_code]
|
||||||
|
vault:
|
||||||
|
enabled: {{ authelia_oidc_vault_enabled | string | lower }}
|
||||||
|
id: vault
|
||||||
|
secret: {{ authelia_oidc_secret_vault | default('') | quote }}
|
||||||
|
description: "Vault"
|
||||||
|
redirectUris:
|
||||||
|
- {{ authelia_oidc_vault_redirect_1 | quote }}
|
||||||
|
- {{ authelia_oidc_vault_redirect_2 | quote }}
|
||||||
|
scopes: [openid, profile, email, groups]
|
||||||
|
grantTypes: [refresh_token, authorization_code]
|
||||||
|
nextcloud:
|
||||||
|
enabled: {{ authelia_oidc_nextcloud_enabled | string | lower }}
|
||||||
|
id: nextcloud
|
||||||
|
secret: {{ authelia_oidc_secret_nextcloud | default('') | quote }}
|
||||||
|
description: "Nextcloud"
|
||||||
|
redirectUris:
|
||||||
|
- {{ authelia_oidc_nextcloud_redirect | quote }}
|
||||||
|
scopes: [openid, profile, email, groups]
|
||||||
|
grantTypes: [refresh_token, authorization_code]
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: {{ authelia_ingress_enabled | string | lower }}
|
||||||
|
ingressClass: {{ authelia_ingress_class | quote }}
|
||||||
|
tls:
|
||||||
|
enabled: {{ authelia_ingress_tls_enabled | string | lower }}
|
||||||
|
secretName: {{ authelia_ingress_tls_secret | quote }}
|
||||||
|
certManager:
|
||||||
|
enabled: {{ authelia_ingress_cert_manager_enabled | string | lower }}
|
||||||
|
issuer: {{ authelia_ingress_cert_manager_issuer | quote }}
|
||||||
@@ -45,6 +45,7 @@ addon_ingress_proxypass: false # External Services Ingress Proxy —
|
|||||||
addon_ingress_add_domains: false # Ingress-only — добавить домены к существующим сервисам кластера
|
addon_ingress_add_domains: false # Ingress-only — добавить домены к существующим сервисам кластера
|
||||||
addon_yandex_dns_controller: false # Yandex 360 DNS controller — управление DNS через ConfigMap (safe mode)
|
addon_yandex_dns_controller: false # Yandex 360 DNS controller — управление DNS через ConfigMap (safe mode)
|
||||||
addon_technitium_dns: false # Technitium DNS HA — Primary+Secondary с kube-vip LB, зональный sync
|
addon_technitium_dns: false # Technitium DNS HA — Primary+Secondary с kube-vip LB, зональный sync
|
||||||
|
addon_authelia: false # Authelia SSO — Forward-auth + OIDC provider для всех сервисов
|
||||||
|
|
||||||
# ─── NFS Server ───────────────────────────────────────────────────────────────
|
# ─── NFS Server ───────────────────────────────────────────────────────────────
|
||||||
nfs_exports:
|
nfs_exports:
|
||||||
@@ -381,6 +382,32 @@ minio_api_ingress_host: "s3.example.com"
|
|||||||
# technitium_dns_externaldns_policy: "upsert-only" # sync | upsert-only
|
# technitium_dns_externaldns_policy: "upsert-only" # sync | upsert-only
|
||||||
# technitium_dns_externaldns_txt_owner_id: "k3s-home"
|
# technitium_dns_externaldns_txt_owner_id: "k3s-home"
|
||||||
|
|
||||||
|
# ─── Authelia SSO ────────────────────────────────────────────────────────────
|
||||||
|
# Централизованная аутентификация: forward-auth для ingress-nginx + OIDC provider.
|
||||||
|
# Все секреты — в vault.yml (authelia_jwt_secret, authelia_session_secret, и др.)
|
||||||
|
# authelia_host: "auth.home.local" # URL портала авторизации
|
||||||
|
# authelia_domain: "home.local" # базовый домен (session cookie domain)
|
||||||
|
# authelia_two_factor_enabled: false # включить 2FA для защищённых сервисов
|
||||||
|
# authelia_storage_type: "sqlite" # sqlite | postgresql
|
||||||
|
# authelia_redis_enabled: false # Redis для хранения сессий
|
||||||
|
# authelia_smtp_enabled: false # SMTP для сброса пароля и 2FA email
|
||||||
|
# Домены с защитой (forward-auth):
|
||||||
|
# authelia_protected_domains: [sonarr.home.local, radarr.home.local, ...]
|
||||||
|
# authelia_admin_domains: [argocd.home.local, vault.home.local, ...]
|
||||||
|
# authelia_bypass_domains: [plex.home.local]
|
||||||
|
# OIDC клиенты (включить нужные):
|
||||||
|
# authelia_oidc_gitea_enabled: true # + authelia_oidc_secret_gitea в vault
|
||||||
|
# authelia_oidc_grafana_enabled: true # + authelia_oidc_secret_grafana в vault
|
||||||
|
# authelia_oidc_argocd_enabled: false
|
||||||
|
# authelia_oidc_minio_enabled: false
|
||||||
|
# authelia_oidc_vault_enabled: false
|
||||||
|
# Пользователи (хэши паролей — в vault.yml):
|
||||||
|
# authelia_users:
|
||||||
|
# admin:
|
||||||
|
# displayname: "Administrator"
|
||||||
|
# email: "admin@home.local"
|
||||||
|
# groups: [admins, users]
|
||||||
|
|
||||||
# ─── etcd backup ──────────────────────────────────────────────────────────────
|
# ─── etcd backup ──────────────────────────────────────────────────────────────
|
||||||
etcd_backup_dir: "{{ k3s_data_dir }}/server/db/snapshots"
|
etcd_backup_dir: "{{ k3s_data_dir }}/server/db/snapshots"
|
||||||
etcd_backup_retention: 5 # сколько снимков хранить
|
etcd_backup_retention: 5 # сколько снимков хранить
|
||||||
|
|||||||
@@ -135,3 +135,26 @@ yandex_dns:
|
|||||||
|
|
||||||
# ── Technitium DNS HA ─────────────────────────────────────────────────────────
|
# ── Technitium DNS HA ─────────────────────────────────────────────────────────
|
||||||
technitium_dns_admin_password: "ЗАМЕНИ_НА_ПАРОЛЬ" # минимум 8 символов
|
technitium_dns_admin_password: "ЗАМЕНИ_НА_ПАРОЛЬ" # минимум 8 символов
|
||||||
|
|
||||||
|
# ── Authelia SSO ──────────────────────────────────────────────────────────────
|
||||||
|
# Generate secrets:
|
||||||
|
# openssl rand -base64 64 → jwt_secret, session_secret
|
||||||
|
# openssl rand -base64 32 → storage_encryption_key
|
||||||
|
# openssl rand -base64 48 → oidc_hmac_secret
|
||||||
|
# openssl rand -hex 32 → each OIDC client secret
|
||||||
|
# Generate password hash:
|
||||||
|
# docker run authelia/authelia:latest authelia hash-password 'yourpassword'
|
||||||
|
authelia_jwt_secret: "ЗАМЕНИ_openssl_rand_-base64_64"
|
||||||
|
authelia_session_secret: "ЗАМЕНИ_openssl_rand_-base64_64"
|
||||||
|
authelia_storage_encryption_key: "ЗАМЕНИ_openssl_rand_-base64_32"
|
||||||
|
authelia_oidc_hmac_secret: "ЗАМЕНИ_openssl_rand_-base64_48"
|
||||||
|
authelia_oidc_private_key: "" # оставь пустым — будет сгенерирован автоматически
|
||||||
|
# OIDC client secrets (генерируй для каждого включённого клиента):
|
||||||
|
authelia_oidc_secret_gitea: "ЗАМЕНИ_openssl_rand_-hex_32"
|
||||||
|
authelia_oidc_secret_grafana: "ЗАМЕНИ_openssl_rand_-hex_32"
|
||||||
|
authelia_oidc_secret_argocd: ""
|
||||||
|
authelia_oidc_secret_minio: ""
|
||||||
|
authelia_oidc_secret_vault: ""
|
||||||
|
authelia_oidc_secret_nextcloud: ""
|
||||||
|
# User password hashes (argon2id):
|
||||||
|
authelia_user_admin_password_hash: "ЗАМЕНИ_НА_ARGON2ID_ХЭШ"
|
||||||
|
|||||||
@@ -327,3 +327,11 @@
|
|||||||
when: addon_technitium_dns | default(false) | bool
|
when: addon_technitium_dns | default(false) | bool
|
||||||
roles:
|
roles:
|
||||||
- role: "{{ playbook_dir }}/../addons/technitium-dns/role"
|
- role: "{{ playbook_dir }}/../addons/technitium-dns/role"
|
||||||
|
|
||||||
|
- name: Install Authelia SSO
|
||||||
|
hosts: k3s_master[0]
|
||||||
|
gather_facts: false
|
||||||
|
become: true
|
||||||
|
when: addon_authelia | default(false) | bool
|
||||||
|
roles:
|
||||||
|
- role: "{{ playbook_dir }}/../addons/authelia/role"
|
||||||
|
|||||||
Reference in New Issue
Block a user