feat(openclaw): add shopping, supermarket deals, geizhals, and ebay MCP tools
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
# Machine & AI Assistant Authentication Guide
|
||||
|
||||
This guide describes how to configure programmatic, machine-to-machine, and AI assistant authentication across services protected by **Authentik** and **Traefik ForwardAuth**.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Use Case
|
||||
When an AI assistant (or automation script, CLI tool, or cron job) needs to:
|
||||
* Inspect Zigbee2MQTT logs or device states via `https://zigbee2mqtt.moritzgraf.de`
|
||||
* Scrape or query metrics from `https://prometheus.haumdaucher.de`
|
||||
* Trigger or query APIs protected behind the Traefik ForwardAuth gateway
|
||||
|
||||
Instead of interactive browser logins or hardcoding static basic auth credentials into individual ingress configs, Authentik supports **Service Accounts & API Tokens**.
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Setup Instructions
|
||||
|
||||
### 1. Create a Service Account in Authentik
|
||||
1. Navigate to **Directory > Users** in Authentik (`https://auth.haumdaucher.de`).
|
||||
2. Click **Create Service Account**:
|
||||
* **Username**: `ai-assistant` (or `mopbot`, `cli-agent`)
|
||||
* **Create API Token**: Check this box.
|
||||
* **Token Expiration**: Set to never expire (or desired TTL).
|
||||
3. Copy the generated **Token Secret** (e.g. `ak_tok_xxxx...`).
|
||||
|
||||
### 2. Grant Access Permissions
|
||||
1. Go to **Directory > Groups**.
|
||||
2. Add the `ai-assistant` service account to the appropriate group (e.g. `infra-admins` or `zigbee-readers`).
|
||||
3. Ensure the Application/Proxy Provider policy allows this group.
|
||||
|
||||
---
|
||||
|
||||
## 💻 Making Authenticated API Calls
|
||||
|
||||
### HTTP Bearer Token (Recommended)
|
||||
Pass the API token in the `Authorization` header:
|
||||
|
||||
```bash
|
||||
curl -H "Authorization: Bearer <your-authentik-token>" \
|
||||
https://zigbee2mqtt.moritzgraf.de/api/bridge/info
|
||||
```
|
||||
|
||||
When Traefik ForwardAuth queries Authentik with this header, Authentik detects the Bearer token, authenticates the `ai-assistant` service account, checks permissions, and responds with HTTP `200 OK`. Traefik then proxies the request directly to the backend.
|
||||
|
||||
### Python / Scripting Example
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
AUTH_TOKEN = "your-authentik-token"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {AUTH_TOKEN}",
|
||||
"Accept": "application/json"
|
||||
}
|
||||
|
||||
response = requests.get("https://zigbee2mqtt.moritzgraf.de/api/bridge/devices", headers=headers)
|
||||
print(response.json())
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Rotating & Revoking Tokens
|
||||
* To rotate a token, navigate to **Directory > Tokens and App passwords**.
|
||||
* You can view active tokens, inspect last-used timestamps, and revoke compromised tokens instantly with one click without restarting any Kubernetes pods or modifying ingress secrets.
|
||||
@@ -0,0 +1,188 @@
|
||||
# Authentik Identity & Access Management (SSO)
|
||||
|
||||
Centralized authentication and identity provider for the `haumdaucher` Kubernetes cluster.
|
||||
|
||||
* **Domain**: `https://auth.haumdaucher.de`
|
||||
* **Helm Chart**: `authentik/authentik` (Version 2026.8.0)
|
||||
* **Database**: CloudNative-PG (`cnpg`) PostgreSQL cluster (`authentik-db`)
|
||||
* **Ingress**: Traefik with Let's Encrypt TLS certificate (`auth-haumdaucher-de`)
|
||||
* **Capabilities**: OIDC/OAuth2 Provider, Traefik ForwardAuth, 2FA (WebAuthn/Passkey, TOTP), User Invitations, Machine/AI Service Accounts.
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Architecture Layout
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
Client[Browser / User] -->|HTTPS| Traefik[Traefik Ingress]
|
||||
AI[AI Assistant / CLI Script] -->|HTTPS + Bearer Token| Traefik
|
||||
|
||||
subgraph "ForwardAuth Ingresses"
|
||||
Traefik -->|ForwardAuth Check| ForwardAuthMW[Traefik ForwardAuth Middleware]
|
||||
ForwardAuthMW -->|Verify Session or Token| AuthServer[Authentik Server]
|
||||
Traefik -->|Allow| Z2M[Zigbee2MQTT]
|
||||
Traefik -->|Allow| Prom[Prometheus & Alertmanager]
|
||||
Traefik -->|Allow| PMA[phpMyAdmin]
|
||||
Traefik -->|Allow| OC[OpenClaw]
|
||||
Traefik -->|Allow| N8N[n8n Web UI]
|
||||
end
|
||||
|
||||
subgraph "Native OIDC Workloads"
|
||||
Grafana[Grafana] -->|OIDC Auth Code Flow| AuthServer
|
||||
Coder[Coder v2] -->|OIDC Auth| AuthServer
|
||||
Gitea[Gitea] -->|OIDC Auth| AuthServer
|
||||
Nextcloud[Nextcloud user_oidc] -->|OIDC Auth| AuthServer
|
||||
MinIO[MinIO Console] -->|OIDC Auth| AuthServer
|
||||
end
|
||||
|
||||
subgraph "auth Namespace"
|
||||
AuthServer --> DB[(CNPG Postgres: authentik-db)]
|
||||
AuthWorker[Authentik Worker] --> DB
|
||||
end
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Deployment Instructions
|
||||
|
||||
### 1. Create Namespace & Provision CNPG Database
|
||||
|
||||
```bash
|
||||
# Create auth namespace
|
||||
kubectl create namespace auth
|
||||
|
||||
# Apply CNPG PostgreSQL cluster
|
||||
kubectl apply -f k8s/auth/authentik-db.yaml
|
||||
|
||||
# Verify PostgreSQL cluster is ready (Status: Cluster in healthy state)
|
||||
kubectl get cluster -n auth authentik-db
|
||||
```
|
||||
|
||||
### 2. Deploy Authentik via Helm
|
||||
|
||||
```bash
|
||||
# Add Authentik repository
|
||||
helm repo add authentik https://charts.goauthentik.io
|
||||
helm repo update
|
||||
|
||||
# Install or upgrade Authentik release
|
||||
helm upgrade --install authentik authentik/authentik \
|
||||
--namespace auth \
|
||||
-f k8s/auth/authentik.secret.values.yaml
|
||||
```
|
||||
|
||||
### 3. Deploy Traefik ForwardAuth Middleware
|
||||
|
||||
```bash
|
||||
kubectl apply -f k8s/auth/traefik-forwardauth-middleware.yaml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔑 Initial Setup & Admin Onboarding
|
||||
|
||||
1. Open your browser and navigate to:
|
||||
```
|
||||
https://auth.haumdaucher.de/if/flow/initial-setup/
|
||||
```
|
||||
2. Set a secure password for the default `akadmin` account.
|
||||
3. Configure your admin user profile and optionally enroll a WebAuthn / Passkey / TOTP 2FA device.
|
||||
|
||||
---
|
||||
|
||||
## 👥 User Management & Invitations
|
||||
|
||||
### Creating Users & Sending Invites
|
||||
1. Navigate to **Directory > Users** in the Authentik Admin interface.
|
||||
2. You can create users manually or upload/provision users in batches.
|
||||
3. To send enrollment links, go to **Directory > Invitations**:
|
||||
* Click **Create**.
|
||||
* Set the target email and assign user groups (e.g. `family`, `friends`, `admins`).
|
||||
* Copy the generated invitation URL or send it to the user.
|
||||
|
||||
### Group Permissions
|
||||
* `authentik Admins`: Full administrative control over Authentik.
|
||||
* `infra-admins`: Access to infrastructure tools (Prometheus, Alertmanager, phpMyAdmin, Zigbee2MQTT).
|
||||
* `users`: Standard user group with access to shared web services (Grafana dashboards, Coder, Nextcloud, Gitea).
|
||||
|
||||
👉 **For the complete guide on Terraform user management, bulk Excel/CSV imports, custom email templates, and RBAC/PBAC access limiting, see [USER_MANAGEMENT.md](./USER_MANAGEMENT.md).**
|
||||
|
||||
---
|
||||
|
||||
## 🤖 Machine & AI Agent Access (Programmatic Authentication)
|
||||
|
||||
For automated tools, scripts, or AI assistants that need to inspect protected applications (e.g. querying Zigbee2MQTT API/logs or Prometheus metrics):
|
||||
|
||||
1. **Create a Service Account**:
|
||||
* In Authentik Admin, navigate to **Directory > Users**.
|
||||
* Click **Create Service Account** (e.g. `ai-agent` or `automation-bot`).
|
||||
* Create a permanent API token for the service account.
|
||||
2. **Accessing Protected Endpoints**:
|
||||
* Pass the token in the HTTP `Authorization` header:
|
||||
```bash
|
||||
curl -H "Authorization: Bearer <your-authentik-token>" https://zigbee2mqtt.moritzgraf.de/api/...
|
||||
```
|
||||
* Authentik's ForwardAuth middleware validates the Bearer token and allows the request without redirecting to a web login page.
|
||||
|
||||
See [MACHINE_AUTH.md](./MACHINE_AUTH.md) for full details.
|
||||
|
||||
---
|
||||
|
||||
## 🔒 Protecting Applications (Rollout Guide)
|
||||
|
||||
### Pattern 1: Traefik ForwardAuth (Proxy Protection)
|
||||
Use this for applications without native OIDC (e.g. Zigbee2MQTT, Prometheus, phpMyAdmin, OpenClaw).
|
||||
|
||||
1. In Authentik Admin, go to **Applications > Providers**:
|
||||
* Create a **Proxy Provider**.
|
||||
* Name: `<App Name> Proxy` (e.g. `Zigbee2MQTT Proxy`).
|
||||
* Mode: `Forward auth (single application)`.
|
||||
* External Host: `https://<app-domain>` (e.g. `https://zigbee2mqtt.moritzgraf.de`).
|
||||
2. Go to **Applications > Applications**:
|
||||
* Create Application, link the Provider, and set access policies/groups.
|
||||
3. Add the middleware annotation to the application's Kubernetes Ingress:
|
||||
```yaml
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.middlewares: auth-authentik-forwardauth@kubernetescrd
|
||||
```
|
||||
|
||||
### Pattern 2: Native OIDC SSO
|
||||
Use this for applications supporting OpenID Connect (Grafana, Coder, Gitea, Nextcloud).
|
||||
|
||||
1. In Authentik Admin, create an **OAuth2/OpenID Provider**:
|
||||
* Name: `<App Name> OIDC`
|
||||
* Client Type: `Confidential`
|
||||
* Redirect URI: e.g. `https://grafana.haumdaucher.de/login/generic_oauth`
|
||||
2. Create an **Application** in Authentik and assign it to the Provider.
|
||||
3. Configure the client credentials (`client_id` and `client_secret`) in the application's Helm values / ConfigMap.
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Branding & Haumdaucher UI Theme
|
||||
|
||||
The Authentik login screen is customized with a **Haumdaucher** glassmorphism theme matching `haumdaucher.de`.
|
||||
|
||||
* **Styling Highlights**:
|
||||
* **Glassmorphic Card**: Frosted glass panel (`backdrop-filter: blur(20px)`), smooth rounded corners (`24px`), and elegant ambient background aura.
|
||||
* **Typography**: Clean, modern typography using Google Font **Outfit**.
|
||||
* **Logo & Entrance Animation**: Dynamic 3D scale-and-fade entry animation for the Haumdaucher crest logo (`https://haumdaucher.de/images/logo_classic.png`).
|
||||
* **Dual Light & Dark Theme**: Automatic adaptation with dark mode styling featuring obsidian surfaces, gold accents (`#d4af37`), and glowing tactile buttons.
|
||||
* **Branded Footer**: "HAUMDAUCHER Wurst und Spezialitäten n.e.V." subtle watermark.
|
||||
|
||||
### Managing Theme via Terraform
|
||||
Branding is provisioned via the `authentik_brand` resource in `terraform/authentik.tf` using the stylesheet `terraform/haumdaucher-theme.css`:
|
||||
|
||||
```bash
|
||||
cd terraform
|
||||
terraform apply -target=authentik_brand.haumdaucher
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💾 Backup & Disaster Recovery
|
||||
|
||||
* **Database**: Managed by CloudNative-PG on `openebs-hostpath` persistent storage.
|
||||
* **Velero Integration**: The `auth` namespace is backed up during daily/weekly Velero schedules:
|
||||
```bash
|
||||
velero backup create auth-backup-$(date +%Y%m%d) --include-namespaces auth --wait
|
||||
```
|
||||
@@ -0,0 +1,629 @@
|
||||
# Authentik User Management: Complete Roundup & Operations Guide
|
||||
|
||||
This guide covers everything you need to know about managing users in Authentik for the **Haumdaucher** infrastructure (`https://auth.haumdaucher.de`): from manual creation and invitation workflows to Terraform IaC, custom email branding, fine-grained access control, handling custom attributes (e.g., Vereins-Mitgliedsnummer, second email), and bulk-importing users from an Excel / CSV spreadsheet.
|
||||
|
||||
---
|
||||
|
||||
## 📑 Table of Contents
|
||||
|
||||
1. [Executive Summary: Quick Answers](#-executive-summary-quick-answers)
|
||||
2. [Method 1: Manual Web UI & Invitation Links](#-method-1-manual-web-ui--invitation-links)
|
||||
3. [Method 2: User Provisioning via Terraform](#-method-2-user-provisioning-via-terraform)
|
||||
4. [Method 3: Bulk Import from Excel / CSV (Python Script)](#-method-3-bulk-import-from-excel--csv-python-script)
|
||||
5. [Customizing Registration & Onboarding Emails](#-customizing-registration--onboarding-emails)
|
||||
6. [Access Control & Authorization Policies (Limiting App Access)](#-access-control--authorization-policies-limiting-app-access)
|
||||
7. [Custom Attributes & OIDC Claim Mappings](#-custom-attributes--oidc-claim-mappings)
|
||||
8. [Production Checklist & Best Practices](#-production-checklist--best-practices)
|
||||
|
||||
---
|
||||
|
||||
## ⚡ Executive Summary: Quick Answers
|
||||
|
||||
| Question | Answer & Key Mechanism |
|
||||
| :--- | :--- |
|
||||
| **How to add new users?** | **4 Ways**: (1) Admin Web UI (`Directory > Users`), (2) **Invitations flow** (`Directory > Invitations` - recommended for self-service), (3) **Terraform** (`authentik_user` resource), or (4) **REST API / Python script** for bulk imports. |
|
||||
| **Can this be done in Terraform?** | **Yes.** Use `resource "authentik_user"` in `terraform/authentik.tf`. Supports custom attributes via `jsonencode()`, group assignments, and active status. |
|
||||
| **Can I change the email sent to the user?** | **Yes.** Configured in **Flows & Stages > Stages > Email Stage**. You can customize the subject line, token expiration, and HTML template (written in Django template syntax with access to user fields and custom attributes). |
|
||||
| **Can I limit what a user has access to?** | **Yes.** Through **Policy Bindings** attached to Applications: Group Membership Policies (e.g., `infra-admins` vs `users`), IP/Geo Policies, or Python Expression Policies checking custom attributes (e.g., only active club members). |
|
||||
| **How to handle Excel tables with custom attributes?** | Authentik stores arbitrary key-value pairs in `user.attributes` (JSON). You can import an Excel/CSV file with a Python script or Terraform `csvdecode()`, map fields like `haumdaucher_mitgliedsnummer` or `second_email`, and expose them to downstream apps (Nextcloud, Grafana, Gitea) via OIDC Scope Mappings. |
|
||||
|
||||
---
|
||||
|
||||
## 👤 Method 1: Manual Web UI & Invitation Links
|
||||
|
||||
Authentik offers two UI methods to onboard users:
|
||||
|
||||
### Option A: Direct User Creation (Admin sets password or triggers reset)
|
||||
1. Go to `https://auth.haumdaucher.de` and log in with your admin account.
|
||||
2. Navigate to **Directory > Users** and click **Create**.
|
||||
3. Fill in:
|
||||
* **Username**: `max.mustermann`
|
||||
* **Name**: `Max Mustermann`
|
||||
* **Email**: `max@example.com`
|
||||
* **Type**: `Internal`
|
||||
* **Groups**: Select groups (e.g., `users`, `verein-mitglieder`).
|
||||
* **Attributes (YAML/JSON)**:
|
||||
```json
|
||||
{
|
||||
"second_email": "max.privat@gmail.com",
|
||||
"haumdaucher_mitgliedsnummer": "HM-2024-042",
|
||||
"phone": "+49 170 1234567"
|
||||
}
|
||||
```
|
||||
4. Click **Create**.
|
||||
5. To set credentials: Click on the user -> **Actions** -> **Set Password** (or **Explicitly trigger password reset flow** so the user receives a link via email).
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Troubleshooting: "Flow does not apply to current user"
|
||||
|
||||
If you encounter this screen when opening an invite link:
|
||||
|
||||
> **"Flow does not apply to current user."**
|
||||
|
||||
### Why this happens:
|
||||
1. **Wrong Flow Selected (`default-source-enrollment`)**:
|
||||
In your URL (`/if/flow/default-source-enrollment/?itoken=...`), the flow used was `default-source-enrollment`. That flow is strictly designed for external identity providers (OAuth/SAML like Google/GitHub) and binds a policy that checks for an active external source in the context. When accessed directly with an `?itoken=...`, Authentik evaluates this policy, fails, and displays this error.
|
||||
2. **Missing Invitation Stage**:
|
||||
Standard enrollment flows reject direct token access unless an **`Invitation Stage`** is bound to the beginning of the flow to validate `?itoken=...`.
|
||||
3. **Active Admin Session**:
|
||||
If an administrator is currently logged in to the browser and clicks the enrollment link, flows with an "unauthenticated-only" policy will reject the session. Always test invitation URLs in an **Incognito / Private window**.
|
||||
|
||||
---
|
||||
|
||||
### Solution: The Haumdaucher Custom Invitation Flow (`haumdaucher-invitation-flow`)
|
||||
|
||||
We provision a dedicated, streamlined flow in `terraform/authentik.tf`:
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
Link[Invite Link with ?itoken=...] --> Stage1[1. Invitation Stage<br/>Validates Token]
|
||||
Stage1 --> Stage2[2. Prompt Stage<br/>User inputs Username, Name, Password]
|
||||
Stage2 --> Stage3[3. User Write Stage<br/>Writes to DB & assigns Groups]
|
||||
Stage3 --> Stage4[4. User Login Stage<br/>Logs user into session]
|
||||
Stage4 --> Stage5[5. Redirect Stage<br/>Redirects to haumdaucher.de]
|
||||
```
|
||||
|
||||
#### Flow Behavior (Tailored to your setup):
|
||||
* **User Inputs**: Prompts the user to choose their preferred **Username**, **Full Name**, and **Password** (with confirmation).
|
||||
* **Email & Custom Attributes**: Pre-filled from the admin invitation (e.g. `haumdaucher_mitgliedsnummer`, `second_email`).
|
||||
* **MFA / 2FA**: Optional. The user registers immediately with their password and can enroll Passkeys/TOTP anytime in their profile settings.
|
||||
* **Automatic Redirect**: Upon completing registration, the user is automatically logged in and redirected to **`https://haumdaucher.de`**.
|
||||
|
||||
---
|
||||
|
||||
### How to Create an Invitation using the Custom Flow
|
||||
|
||||
1. Go to `https://auth.haumdaucher.de` > **Directory > Invitations**.
|
||||
2. Click **Create** (or **New Invitation**).
|
||||
3. Set the fields:
|
||||
* **Name**: `Invite - Max Mustermann`
|
||||
* **Expires**: Set expiration (e.g., 7 days).
|
||||
* **Flow**: Select **`Haumdaucher Invitation Flow`** (`haumdaucher-invitation-flow`).
|
||||
* **Single use**: Checked (`true`).
|
||||
* **Fixed Data / Attributes (JSON)**:
|
||||
```json
|
||||
{
|
||||
"email": "max@example.com",
|
||||
"haumdaucher_mitgliedsnummer": "HM-2024-042",
|
||||
"second_email": "max.privat@gmail.com"
|
||||
}
|
||||
```
|
||||
4. Click **Create**.
|
||||
5. Copy the generated URL:
|
||||
```
|
||||
https://auth.haumdaucher.de/if/flow/haumdaucher-invitation-flow/?itoken=<generated-token>
|
||||
```
|
||||
6. Send the link to the user. When they open it, they will see the branded Haumdaucher registration form asking for their Username, Name, and Password!
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Method 2: User Provisioning via Terraform
|
||||
|
||||
You can manage users, groups, and permissions directly in `terraform/authentik.tf`.
|
||||
|
||||
### 1. Single User Definition
|
||||
```hcl
|
||||
# Group for club members
|
||||
resource "authentik_group" "verein_mitglieder" {
|
||||
name = "verein-mitglieder"
|
||||
is_superuser = false
|
||||
}
|
||||
|
||||
# User with custom attributes
|
||||
resource "authentik_user" "max_mustermann" {
|
||||
username = "max.mustermann"
|
||||
name = "Max Mustermann"
|
||||
email = "max@example.com"
|
||||
type = "internal"
|
||||
is_active = true
|
||||
groups = [
|
||||
authentik_group.users.id,
|
||||
authentik_group.verein_mitglieder.id
|
||||
]
|
||||
attributes = jsonencode({
|
||||
"second_email" = "max.privat@gmail.com",
|
||||
"haumdaucher_mitgliedsnummer" = "HM-2024-042",
|
||||
"eintrittsdatum" = "2024-01-15",
|
||||
"status" = "aktiv"
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Batch Provisioning from CSV in Terraform
|
||||
If you maintain users in a CSV file (`terraform/users.csv`):
|
||||
|
||||
```csv
|
||||
username,name,email,second_email,mitgliedsnummer,is_admin
|
||||
max.mustermann,Max Mustermann,max@example.com,max.privat@gmail.com,HM-2024-042,false
|
||||
anna.schmidt,Anna Schmidt,anna@example.com,anna.work@company.de,HM-2024-043,true
|
||||
```
|
||||
|
||||
In `terraform/authentik.tf`:
|
||||
```hcl
|
||||
locals {
|
||||
csv_users = csvdecode(file("${path.module}/users.csv"))
|
||||
}
|
||||
|
||||
resource "authentik_user" "csv_members" {
|
||||
for_each = { for u in local.csv_users : u.username => u }
|
||||
|
||||
username = each.value.username
|
||||
name = each.value.name
|
||||
email = each.value.email
|
||||
type = "internal"
|
||||
is_active = true
|
||||
groups = compact([
|
||||
authentik_group.users.id,
|
||||
authentik_group.verein_mitglieder.id,
|
||||
each.value.is_admin == "true" ? authentik_group.infra_admins.id : null
|
||||
])
|
||||
attributes = jsonencode({
|
||||
"second_email" = each.value.second_email,
|
||||
"haumdaucher_mitgliedsnummer" = each.value.mitgliedsnummer
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### ⚖️ Trade-offs: When to use Terraform for Users
|
||||
* **Pros**: Version-controlled in Git, declarative, reproducible, ideal for admins and service accounts (`ai_assistant`).
|
||||
* **Cons / Considerations**: Terraform cannot trigger interactive password onboarding emails out of the box; passwords must be set via recovery flow or first login reset.
|
||||
|
||||
---
|
||||
|
||||
## 📊 Method 3: Bulk Import from Excel / CSV (Python Script)
|
||||
|
||||
If you have an Excel file (`mitglieder.xlsx`) or CSV, using Authentik's REST API is the cleanest approach because it can **create users, attach custom attributes, and automatically email them an invitation link to set their own password**.
|
||||
|
||||
### Ready-to-Run Python Import Script
|
||||
Save this script (e.g. `k8s/auth/scripts/import_users_excel.py`):
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Bulk User Importer for Authentik (auth.haumdaucher.de)
|
||||
Reads an Excel (.xlsx) or CSV file and creates users with custom attributes and invitation links.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import requests
|
||||
import pandas as pd
|
||||
|
||||
# Configuration
|
||||
AUTHENTIK_URL = os.getenv("AUTHENTIK_URL", "https://auth.haumdaucher.de")
|
||||
AUTHENTIK_TOKEN = os.getenv("AUTHENTIK_TOKEN") # API Token (e.g. ai_assistant_token)
|
||||
|
||||
if not AUTHENTIK_TOKEN:
|
||||
print("❌ Error: AUTHENTIK_TOKEN environment variable is required.")
|
||||
sys.exit(1)
|
||||
|
||||
HEADERS = {
|
||||
"Authorization": f"Bearer {AUTHENTIK_TOKEN}",
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json"
|
||||
}
|
||||
|
||||
def get_or_create_group(group_name: str) -> str:
|
||||
"""Fetch group ID or create if it doesn't exist."""
|
||||
res = requests.get(f"{AUTHENTIK_URL}/api/v3/core/groups/?name={group_name}", headers=HEADERS)
|
||||
res.raise_for_status()
|
||||
results = res.json().get("results", [])
|
||||
if results:
|
||||
return results[0]["pk"]
|
||||
|
||||
# Create group
|
||||
create_res = requests.post(f"{AUTHENTIK_URL}/api/v3/core/groups/", headers=HEADERS, json={"name": group_name})
|
||||
create_res.raise_for_status()
|
||||
return create_res.json()["pk"]
|
||||
|
||||
def import_users_from_file(file_path: str, send_invitation: bool = True):
|
||||
# Read Excel or CSV
|
||||
if file_path.endswith((".xlsx", ".xls")):
|
||||
df = pd.read_excel(file_path)
|
||||
else:
|
||||
df = pd.read_csv(file_path)
|
||||
|
||||
# Standardize column names (lowercase & stripped)
|
||||
df.columns = [c.strip().lower() for c in df.columns]
|
||||
|
||||
print(f"📋 Found {len(df)} rows to process.")
|
||||
|
||||
users_group_pk = get_or_create_group("users")
|
||||
verein_group_pk = get_or_create_group("verein-mitglieder")
|
||||
|
||||
for idx, row in df.iterrows():
|
||||
name = str(row.get("name", "")).strip()
|
||||
email = str(row.get("email", "")).strip()
|
||||
username = str(row.get("username", "")).strip() or email.split("@")[0].lower()
|
||||
second_email = str(row.get("second_email", row.get("zweite_email", ""))).strip()
|
||||
mitgliedsnummer = str(row.get("mitgliedsnummer", row.get("verein_mitgliedsnummer", ""))).strip()
|
||||
|
||||
if not email or email == "nan":
|
||||
print(f"⚠️ Skipping row {idx+1}: missing email")
|
||||
continue
|
||||
|
||||
# Prepare user payload with custom attributes
|
||||
user_payload = {
|
||||
"username": username,
|
||||
"name": name if name != "nan" else username,
|
||||
"email": email,
|
||||
"type": "internal",
|
||||
"is_active": True,
|
||||
"groups": [users_group_pk, verein_group_pk],
|
||||
"attributes": {
|
||||
"second_email": second_email if second_email != "nan" else "",
|
||||
"haumdaucher_mitgliedsnummer": mitgliedsnummer if mitgliedsnummer != "nan" else "",
|
||||
"source": "excel_import"
|
||||
}
|
||||
}
|
||||
|
||||
# 1. Create or Update User in Authentik
|
||||
res = requests.get(f"{AUTHENTIK_URL}/api/v3/core/users/?username={username}", headers=HEADERS)
|
||||
res.raise_for_status()
|
||||
existing = res.json().get("results", [])
|
||||
|
||||
if existing:
|
||||
user_pk = existing[0]["pk"]
|
||||
patch_res = requests.patch(f"{AUTHENTIK_URL}/api/v3/core/users/{user_pk}/", headers=HEADERS, json=user_payload)
|
||||
patch_res.raise_for_status()
|
||||
print(f"🔄 Updated existing user: {username} ({email})")
|
||||
else:
|
||||
create_res = requests.post(f"{AUTHENTIK_URL}/api/v3/core/users/", headers=HEADERS, json=user_payload)
|
||||
if not create_res.ok:
|
||||
print(f"❌ Failed to create {username}: {create_res.text}")
|
||||
continue
|
||||
user_pk = create_res.json()["pk"]
|
||||
print(f"✅ Created user: {username} ({email}) [ID: {user_pk}]")
|
||||
|
||||
# 2. Generate Invitation / Password Reset Link
|
||||
if send_invitation:
|
||||
invitation_payload = {
|
||||
"name": f"Onboarding {username}",
|
||||
"single_use": True,
|
||||
"fixed_data": {
|
||||
"email": email,
|
||||
"username": username
|
||||
}
|
||||
}
|
||||
inv_res = requests.post(f"{AUTHENTIK_URL}/api/v3/stages/invitation/invitations/", headers=HEADERS, json=invitation_payload)
|
||||
if inv_res.ok:
|
||||
inv_key = inv_res.json()["pk"]
|
||||
link = f"{AUTHENTIK_URL}/if/flow/default-enrollment-flow/?itoken={inv_key}"
|
||||
print(f" ✉️ Invitation Link: {link}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python3 import_users_excel.py <path-to-excel-or-csv>")
|
||||
sys.exit(1)
|
||||
import_users_from_file(sys.argv[1])
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✉️ Customizing Registration & Onboarding Emails
|
||||
|
||||
When an admin creates a user or triggers an enrollment/password recovery, Authentik sends transactional emails. You can customize their sender address, subject line, and full HTML appearance.
|
||||
|
||||
### 1. SMTP & Sender Settings
|
||||
Authentik sends emails using the SMTP configuration defined in `k8s/auth/authentik.secret.values.yaml` or global environment variables:
|
||||
* `AUTHENTIK_EMAIL__HOST`: `smtp.gmail.com` (or Google Workspace / OVH relay)
|
||||
* `AUTHENTIK_EMAIL__PORT`: `587`
|
||||
* `AUTHENTIK_EMAIL__USE_TLS`: `true`
|
||||
* `AUTHENTIK_EMAIL__USERNAME`: `service@haumdaucher.de`
|
||||
* `AUTHENTIK_EMAIL__PASSWORD`: `<app-password>`
|
||||
* `AUTHENTIK_EMAIL__FROM`: `HAUMDAUCHER Identity <service@haumdaucher.de>`
|
||||
|
||||
---
|
||||
|
||||
### 2. Customizing Email Stages in Authentik
|
||||
Authentik controls outgoing emails via **Email Stages**:
|
||||
1. Open Admin UI: **Flows & Stages > Stages**.
|
||||
2. Locate the relevant email stage:
|
||||
* `default-password-reset-email` (for password recovery & manual user activation)
|
||||
* `default-enrollment-email` / `invitation-email` (for new user invitations)
|
||||
* `default-user-settings-password-reset-email`
|
||||
3. Click **Edit** on the stage:
|
||||
* **Subject**: `Willkommen bei Haumdaucher e.V. – Aktiviere deinen Zugang`
|
||||
* **Token Expiry**: `Minutes=1440` (24 hours) or `Minutes=10080` (7 days)
|
||||
* **Template**: Select standard template or your custom template path.
|
||||
|
||||
---
|
||||
|
||||
### 3. Customizing the HTML Email Template (Django Syntax)
|
||||
Authentik email templates use Django template syntax. Available variables in email templates include:
|
||||
* `{{ user.name }}` / `{{ user.username }}` / `{{ user.email }}`
|
||||
* `{{ user.attributes.haumdaucher_mitgliedsnummer }}`
|
||||
* `{{ url }}` (The activation / password reset link)
|
||||
* `{{ token_expires }}` (Expiry timestamp)
|
||||
* `{{ brand.branding_title }}` (`HAUMDAUCHER`)
|
||||
|
||||
#### Example Custom Haumdaucher Welcome Template
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body { font-family: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background-color: #0d0d12; color: #f0f0f5; margin: 0; padding: 40px; }
|
||||
.card { background: #181824; border: 1px solid rgba(212, 175, 55, 0.3); border-radius: 16px; max-width: 540px; margin: 0 auto; padding: 32px; box-shadow: 0 12px 30px rgba(0,0,0,0.5); }
|
||||
.header { text-align: center; margin-bottom: 24px; }
|
||||
.logo { height: 60px; }
|
||||
h1 { color: #d4af37; font-size: 22px; margin-top: 12px; }
|
||||
p { color: #c0c0d0; line-height: 1.6; font-size: 15px; }
|
||||
.btn { display: block; text-align: center; background: linear-gradient(135deg, #d4af37, #aa8520); color: #000; font-weight: bold; text-decoration: none; padding: 14px 24px; border-radius: 10px; margin: 28px 0; }
|
||||
.meta { background: rgba(255,255,255,0.05); border-radius: 8px; padding: 12px 16px; font-size: 13px; color: #a0a0b0; }
|
||||
.footer { text-align: center; font-size: 12px; color: #606070; margin-top: 30px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="card">
|
||||
<div class="header">
|
||||
<img class="logo" src="https://haumdaucher.de/images/logo_classic.png" alt="Haumdaucher Logo" />
|
||||
<h1>Willkommen beim Haumdaucher e.V.</h1>
|
||||
</div>
|
||||
|
||||
<p>Hallo <strong>{{ user.name }}</strong>,</p>
|
||||
<p>dein zentraler Zugang für die Haumdaucher Cloud & Services wurde eingerichtet.</p>
|
||||
|
||||
{% if user.attributes.haumdaucher_mitgliedsnummer %}
|
||||
<div class="meta">
|
||||
<strong>Mitgliedsnummer:</strong> {{ user.attributes.haumdaucher_mitgliedsnummer }}<br/>
|
||||
<strong>Benutzername:</strong> {{ user.username }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<p>Klicke auf den Button unten, um dein Passwort festzulegen und deinen Zugang zu aktivieren:</p>
|
||||
|
||||
<a class="btn" href="{{ url }}">Zugang aktivieren & Passwort setzen</a>
|
||||
|
||||
<p style="font-size: 12px; color: #888;">Dieser Link ist 7 Tage lang gültig. Falls du die Registrierung nicht angefordert hast, kannst du diese E-Mail ignorieren.</p>
|
||||
|
||||
<div class="footer">
|
||||
HAUMDAUCHER e.V. • <a href="https://haumdaucher.de" style="color: #d4af37;">haumdaucher.de</a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔒 Access Control & Authorization Policies (Limiting App Access)
|
||||
|
||||
By default, an application without an attached policy allows **any authenticated user** to access it. Authentik provides fine-grained Access Control (RBAC & PBAC) to restrict access per application.
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph "Authentik Directory Groups"
|
||||
Admin["👑 <b>infra-admins</b><br/>(Moritz & Wife / Full Admin)"]
|
||||
Verein["🍺 <b>verein-mitglieder</b><br/>(Club Members)"]
|
||||
Normal["👤 <b>users</b><br/>(Normal Authenticated Users)"]
|
||||
end
|
||||
|
||||
subgraph "Tier 1: Admin & Ops Tools (ForwardAuth / OIDC)"
|
||||
Z2M["Zigbee2MQTT"]
|
||||
Prom["Prometheus & Alertmanager"]
|
||||
PMA["phpMyAdmin (Nextcloud & Gitea)"]
|
||||
N8N["n8n Automation"]
|
||||
MinIO["MinIO Console"]
|
||||
Coder["Coder v2"]
|
||||
OpenClaw["OpenClaw Engine"]
|
||||
end
|
||||
|
||||
subgraph "Tier 2: Daily Shared Services (OIDC)"
|
||||
HASS["Home Assistant"]
|
||||
Grafana["Grafana Dashboards"]
|
||||
Nextcloud["Nextcloud Cloud"]
|
||||
Gitea["Gitea Git Platform"]
|
||||
ClubWeb["haumdaucher.de"]
|
||||
end
|
||||
|
||||
%% Admin Links (Full Superadmin access everywhere)
|
||||
Admin ==>|Full Access| Z2M
|
||||
Admin ==>|Full Access| OpenClaw
|
||||
Admin ==>|Admin| HASS
|
||||
Admin ==>|Admin| Grafana
|
||||
Admin ==>|Admin| Nextcloud
|
||||
Admin ==>|Admin| Gitea
|
||||
Admin ==>|Admin| ClubWeb
|
||||
|
||||
%% Normal User Links (Restricted)
|
||||
Normal -->|Viewer (Read-Only)| Grafana
|
||||
Normal -->|Dashboard View| HASS
|
||||
Normal -->|Standard User| Nextcloud
|
||||
Normal -->|Developer| Gitea
|
||||
|
||||
%% Club Members Links
|
||||
Verein -->|Member Portal| ClubWeb
|
||||
Verein -->|Club Shared Folder| Nextcloud
|
||||
Verein -->|Viewer (Read-Only)| Grafana
|
||||
```
|
||||
|
||||
### Master Permission Matrix
|
||||
|
||||
| Application | Domain | Auth Type | `infra-admins` (Moritz & Wife) | `verein-mitglieder` (Club) | `users` (Normal Users) |
|
||||
| :--- | :--- | :--- | :---: | :---: | :---: |
|
||||
| **OpenClaw** | `openclaw.haumdaucher.de` | ForwardAuth | **Full Access** ✅ | ❌ *Denied* | ❌ *Denied* |
|
||||
| **Zigbee2MQTT** | `zigbee2mqtt.moritzgraf.de` | ForwardAuth | **Full Access** ✅ | ❌ *Denied* | ❌ *Denied* |
|
||||
| **Prometheus / Alertmanager** | `prometheus.haumdaucher.de` | ForwardAuth | **Full Access** ✅ | ❌ *Denied* | ❌ *Denied* |
|
||||
| **phpMyAdmin (All DBs)** | `*.phpmyadmin.haumdaucher.de` | ForwardAuth | **Full Access** ✅ | ❌ *Denied* | ❌ *Denied* |
|
||||
| **n8n** | `n8n.moritzgraf.de` | ForwardAuth | **Full Access** ✅ | ❌ *Denied* | ❌ *Denied* |
|
||||
| **MinIO Console** | `minio-console.haumdaucher.de` | Native OIDC | **`consoleAdmin`** ✅ | ❌ *Denied* | ❌ *Denied* |
|
||||
| **Coder v2** | `coder.moritzgraf.de` | Native OIDC | **`Owner / Admin`** ✅ | ❌ *Denied* | ❌ *Denied* |
|
||||
| **Home Assistant** | `hass.moritzgraf.de` | Native OIDC | **`Administrator`** ✅ | ❌ *Denied* | **`Standard User`** |
|
||||
| **Grafana** | `grafana.haumdaucher.de` | Native OIDC | **`Admin`** ✅ | **`Viewer` (Read-Only)** | **`Viewer` (Read-Only)** |
|
||||
| **Nextcloud** | `cloud.haumdaucher.de` | Native OIDC | **`Admin`** ✅ | **`User` (Club Folder)** | **`User` (Standard)** |
|
||||
| **Gitea** | `git.moritzgraf.de` | Native OIDC | **`Admin`** ✅ | ❌ / Member | **`Developer`** |
|
||||
| **haumdaucher.de** | `haumdaucher.de` | ForwardAuth / OIDC | **`Admin`** ✅ | **`Member Access`** ✅ | ❌ *Denied* |
|
||||
|
||||
### Policy Bindings in Terraform
|
||||
All policy bindings are enforced directly in `terraform/authentik.tf`:
|
||||
|
||||
```hcl
|
||||
# 1. Admin-Only Tools (Restricted strictly to infra-admins)
|
||||
resource "authentik_policy_binding" "openclaw_admin_only" {
|
||||
target = authentik_application.openclaw.uuid
|
||||
group = authentik_group.infra_admins.id
|
||||
order = 0
|
||||
}
|
||||
|
||||
resource "authentik_policy_binding" "zigbee2mqtt_admin_only" {
|
||||
target = authentik_application.zigbee2mqtt.uuid
|
||||
group = authentik_group.infra_admins.id
|
||||
order = 0
|
||||
}
|
||||
|
||||
# 2. Shared & Member Applications (Accessible to users group)
|
||||
resource "authentik_policy_binding" "grafana_users" {
|
||||
target = authentik_application.grafana.uuid
|
||||
group = authentik_group.users.id
|
||||
order = 0
|
||||
}
|
||||
|
||||
resource "authentik_policy_binding" "nextcloud_users" {
|
||||
target = authentik_application.nextcloud.uuid
|
||||
group = authentik_group.users.id
|
||||
order = 0
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. Attribute-Based Policy (Python Expression Policy)
|
||||
You can write Python expressions that evaluate custom user attributes dynamically:
|
||||
|
||||
```hcl
|
||||
resource "authentik_policy_expression" "require_active_membership" {
|
||||
name = "require-active-haumdaucher-membership"
|
||||
expression = <<EOF
|
||||
# Must have a valid Mitgliedsnummer and active status
|
||||
mitgliedsnummer = request.user.attributes.get('haumdaucher_mitgliedsnummer')
|
||||
status = request.user.attributes.get('status', 'aktiv')
|
||||
|
||||
if not mitgliedsnummer or not mitgliedsnummer.startswith('HM-'):
|
||||
ak_message("Keine gültige Haumdaucher Mitgliedsnummer hinterlegt.")
|
||||
return False
|
||||
|
||||
if status != 'aktiv':
|
||||
ak_message("Deine Mitgliedschaft ist derzeit nicht aktiv.")
|
||||
return False
|
||||
|
||||
return True
|
||||
EOF
|
||||
}
|
||||
|
||||
# Attach policy to Nextcloud application
|
||||
resource "authentik_policy_binding" "nextcloud_active_members" {
|
||||
target = authentik_application.nextcloud.uuid
|
||||
policy = authentik_policy_expression.require_active_membership.id
|
||||
order = 1
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🏷️ Custom Attributes & OIDC Claim Mappings
|
||||
|
||||
Authentik allows storing any arbitrary JSON object inside `user.attributes`.
|
||||
|
||||
### 1. Recommended Attribute Schema for Haumdaucher
|
||||
```json
|
||||
{
|
||||
"haumdaucher_mitgliedsnummer": "HM-2024-042",
|
||||
"second_email": "max.privat@gmail.com",
|
||||
"eintrittsdatum": "2024-01-15",
|
||||
"verein_rolle": "Vorstand / Kassenwart / Mitglied",
|
||||
"phone": "+49 170 1234567",
|
||||
"telegram_handle": "@max_mustermann"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. Exposing Custom Attributes via OIDC Claims (Terraform)
|
||||
To pass `haumdaucher_mitgliedsnummer` or `second_email` to downstream applications like **Nextcloud**, **Grafana**, or **Gitea**:
|
||||
|
||||
```hcl
|
||||
# Define a custom Scope Mapping in Terraform
|
||||
resource "authentik_property_mapping_provider_scope" "haumdaucher_profile" {
|
||||
name = "Haumdaucher Extended Profile"
|
||||
scope_name = "haumdaucher_profile"
|
||||
description = "Provides Vereins-Mitgliedsnummer and secondary email to OIDC clients"
|
||||
expression = <<EOF
|
||||
return {
|
||||
"haumdaucher_mitgliedsnummer": request.user.attributes.get("haumdaucher_mitgliedsnummer", ""),
|
||||
"second_email": request.user.attributes.get("second_email", ""),
|
||||
"verein_rolle": request.user.attributes.get("verein_rolle", "Mitglied")
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
# Add this mapping to the OAuth2 provider (e.g. Nextcloud or Grafana)
|
||||
resource "authentik_provider_oauth2" "nextcloud" {
|
||||
name = "Nextcloud"
|
||||
client_id = "nextcloud"
|
||||
client_secret = random_password.nextcloud_oauth_client_secret.result
|
||||
client_type = "confidential"
|
||||
authorization_flow = data.authentik_flow.default_authorization_flow.id
|
||||
invalidation_flow = data.authentik_flow.default_invalidation_flow.id
|
||||
signing_key = data.authentik_certificate_key_pair.generated.id
|
||||
|
||||
property_mappings = [
|
||||
data.authentik_property_mapping_provider_scope.openid.id,
|
||||
data.authentik_property_mapping_provider_scope.email.id,
|
||||
data.authentik_property_mapping_provider_scope.profile.id,
|
||||
authentik_property_mapping_provider_scope.haumdaucher_profile.id, # <-- Custom scope
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ Production Checklist & Best Practices
|
||||
|
||||
When managing users in production, keep the following considerations in mind:
|
||||
|
||||
### 1. Passwordless & Multi-Factor Authentication (MFA / 2FA)
|
||||
* Enforce **WebAuthn / Passkeys (FIDO2)** or **TOTP (Authenticator App)** for users in the `infra-admins` group.
|
||||
* In Authentik, this is done by binding an Authenticator Validation Stage to the default authentication flow or creating an Admin Authorization Flow.
|
||||
|
||||
### 2. User Self-Service & Attribute Editing
|
||||
* Authentik provides a self-service portal at `https://auth.haumdaucher.de/if/user/#/settings`.
|
||||
* Users can change their password, register Passkeys, and edit user profile fields.
|
||||
* **Security Rule**: Keep administrative attributes (like `haumdaucher_mitgliedsnummer`) read-only by not exposing them to the user edit flow, while allowing users to freely edit personal contact details like `second_email` or `phone`.
|
||||
|
||||
### 3. Offboarding & Member Deactivation
|
||||
* If a member leaves the club:
|
||||
1. Set `is_active = false` (or remove from `verein-mitglieder` group).
|
||||
2. Authentik immediately terminates active sessions and revokes ForwardAuth access and OIDC refresh tokens.
|
||||
3. No need to manually reset passwords on Nextcloud, Grafana, or Gitea—SSO handles deprovisioning instantly.
|
||||
|
||||
### 4. GDPR / DSGVO & Privacy
|
||||
* Store only necessary data in user attributes.
|
||||
* If a member requests account deletion, deleting the user in Authentik cascades identity termination across all connected services.
|
||||
|
||||
### 5. Backups & Audit Logs
|
||||
* User database changes are stored in the PostgreSQL cluster (`authentik-db`) and backed up with daily Velero snapshot schedules.
|
||||
* Authentik logs all login attempts, failed logins, and administrative modifications under **Events > Logs**.
|
||||
@@ -0,0 +1,24 @@
|
||||
apiVersion: postgresql.cnpg.io/v1
|
||||
kind: Cluster
|
||||
metadata:
|
||||
name: authentik-db
|
||||
namespace: auth
|
||||
spec:
|
||||
instances: 1
|
||||
bootstrap:
|
||||
initdb:
|
||||
database: authentik
|
||||
owner: authentik
|
||||
postgresql:
|
||||
parameters:
|
||||
shared_buffers: "128MB"
|
||||
max_connections: "100"
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 512Mi
|
||||
limits:
|
||||
memory: 2Gi
|
||||
storage:
|
||||
storageClass: openebs-hostpath
|
||||
size: 5Gi
|
||||
@@ -0,0 +1,62 @@
|
||||
# --- Authentik Helm Configuration ---
|
||||
# Uses CloudNative-PG cluster (authentik-db) for PostgreSQL
|
||||
|
||||
global:
|
||||
env:
|
||||
- name: AUTHENTIK_POSTGRESQL__HOST
|
||||
value: "authentik-db-rw.auth.svc.cluster.local"
|
||||
- name: AUTHENTIK_POSTGRESQL__NAME
|
||||
value: "authentik"
|
||||
- name: AUTHENTIK_POSTGRESQL__USER
|
||||
value: "authentik"
|
||||
- name: AUTHENTIK_POSTGRESQL__PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: authentik-db-app
|
||||
key: password
|
||||
|
||||
authentik:
|
||||
# Secret key for cookie signing and session encryption
|
||||
secret_key: "gU2ohe8eighaiph4quaeCh1ieM3iechoh2ohNg5yahz6eephoh"
|
||||
error_reporting:
|
||||
enabled: false
|
||||
log_level: info
|
||||
|
||||
server:
|
||||
replicas: 1
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 384Mi
|
||||
limits:
|
||||
memory: 768Mi
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
ingressClassName: "traefik"
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: "traefik"
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
kubernetes.io/tls-acme: "true"
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: "0"
|
||||
hosts:
|
||||
- auth.haumdaucher.de
|
||||
tls:
|
||||
- hosts:
|
||||
- auth.haumdaucher.de
|
||||
secretName: auth-haumdaucher-de
|
||||
|
||||
worker:
|
||||
replicas: 1
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 384Mi
|
||||
limits:
|
||||
memory: 768Mi
|
||||
|
||||
# Disable bundled subchart databases (managed by CNPG)
|
||||
postgresql:
|
||||
enabled: false
|
||||
@@ -1,25 +0,0 @@
|
||||
# # status: removed again
|
||||
|
||||
# apiVersion: helm.fluxcd.io/v1
|
||||
# kind: HelmRelease
|
||||
# metadata:
|
||||
# name: helm-phpldapadmin
|
||||
# namespace: flux
|
||||
# spec:
|
||||
# releaseName: phpldapadmin
|
||||
# targetNamespace: auth
|
||||
# chart:
|
||||
# repository: https://cetic.github.io/helm-charts
|
||||
# version: 0.1.3
|
||||
# name: phpldapadmin
|
||||
# values:
|
||||
# service:
|
||||
# type: ClusterIP
|
||||
# ingress:
|
||||
# enabled: true
|
||||
# hosts:
|
||||
# - "ldap.haumdaucher.de"
|
||||
# annotations:
|
||||
# cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
# tls:
|
||||
# - ldap-haumdaucher-de
|
||||
@@ -0,0 +1,26 @@
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: authentik-forwardauth
|
||||
namespace: auth
|
||||
spec:
|
||||
forwardAuth:
|
||||
address: http://authentik-server.auth.svc.cluster.local/outpost.goauthentik.io/auth/traefik
|
||||
trustForwardHeader: true
|
||||
authRequestHeaders:
|
||||
- Authorization
|
||||
- Cookie
|
||||
- Accept
|
||||
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
|
||||
- authorization
|
||||
Reference in New Issue
Block a user