-
Notifications
You must be signed in to change notification settings - Fork 786
Description
🧪 LitmusChaos (ChaosCenter) + Authentik via Dex
💡 Goal: Integrate LitmusChaos with Authentik as an IdP using Dex as an OIDC broker, replicating the same working pattern already used by Argo CD.
⚙️ Environment Architecture
Main Components
flowchart TB
%% EXTERNAL
subgraph External
direction TB
User@{icon:"fa:user", form:"circle", label:"User"}
F5@{icon:"fa:cloud", form:"circle", label:"F5 Load Balancer"}
Authentik@{icon:"fa:lock", form:"circle", label:"Authentik IdP"}
end
%% KUBERNETES CLUSTER
subgraph "Kubernetes Cluster"
direction TB
subgraph "Istio Service Mesh"
direction TB
VS@{icon:"fa:globe", form:"rounded", label:"VirtualService\nlitmus.example.com"}
subgraph "Litmus Namespace"
direction TB
Frontend@{icon:"fa:desktop", form:"rect", label:"Litmus Frontend\n:9091"}
AuthServer@{icon:"fa:key", form:"rect", label:"Auth Server\n:3000"}
Dex@{icon:"fa:arrows-to-circle", form:"rect", label:"Dex\n:5556"}
end
end
end
%% FLUXO
User -- HTTPS --> F5
F5 -- Istio Gateway --> VS
VS -- "/ (UI)" --> Frontend
VS -- "/auth/dex/*" --> Dex
VS -- "/auth/dex/callback" --> AuthServer
Frontend -.->|SSO Button Click| Dex
AuthServer -->|Validates Token| Dex
Dex <--> Authentik
%% ESTILOS
classDef dexStyle fill:#f9f,stroke:#333,stroke-width:4px;
classDef idpStyle fill:#bbf,stroke:#333,stroke-width:2px;
classDef frontendStyle fill:#bfb,stroke:#333,stroke-width:2px;
class Dex dexStyle;
class Authentik idpStyle;
class Frontend frontendStyle;
📦 Technology Stack
Component Version Port
Kubernetes 1.29 -
Istio - -
LitmusChaos 3.22.0 9091/3000
Dex 2.41.1 5556
Authentik - 443
📚 Two Operating Modes
The configuration has been organized into two distinct patterns:
1️⃣ Dedicated Dex Mode
ℹ️ Separate host: Dex has its own domain
sequenceDiagram
participant U as User
participant L as litmus.example.com
participant D as dex.litmus.example.com
participant A as Authentik
U->>L: Clicks "Login with SSO"
L->>D: Redirect to /auth
D->>A: OIDC Authorization
A->>U: Login Form
U->>A: Credentials
A->>D: Authorization Code
D->>L: Callback with Code
L->>U: Authenticated ✓
Configuration:
Dex Issuer: https://dex.litmus.example.com
Callback: https://litmus.example.com/auth/dex/callback
VirtualServices: Two separate ones (Litmus + Dex)
2️⃣ Embedded Dex Mode
:::warning
sequenceDiagram
participant U as User
participant L as litmus.example.com
participant D as litmus.example.com/auth/dex
participant A as Authentik
U->>L: Clicks "Login with SSO"
L->>D: Redirect (same host)
Note over L,D: :x: Frontend does not send<br/>client_id, redirect_uri, etc.
D-->>L: Invalid client_id ("")
Configuration:
Dex Issuer: https://litmus.example.com/auth/dex
Callback: https://litmus.example.com/auth/dex/callback
VirtualService: Single resource routing all paths
:::
🔧 Detailed Implementation
1. Click to view full Dex configuration
apiVersion: apps/v1
kind: Deployment
metadata:
name: litmus-dex
namespace: litmus
spec:
replicas: 1
template:
spec:
serviceAccountName: dex-server-account
initContainers:
- name: wait-for-authentik
image: curlimages/curl:latest
command: ['/bin/sh', '-c']
args:
- |
until curl -f https://authentik.example.com/application/o/httpslitmusexamplecom/.well-known/openid-configuration; do
echo "Waiting for Authentik...";
sleep 5;
done
containers:
- name: dex
image: ghcr.io/dexidp/dex:v2.41.1
command: ["/usr/local/bin/dex"]
args: ["serve", "/etc/dex/cfg/config.yaml"]
ports:
- containerPort: 5556
name: http
volumeMounts:
- name: config
mountPath: /etc/dex/cfg
livenessProbe:
tcpSocket:
port: 5556
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
tcpSocket:
port: 5556
initialDelaySeconds: 20
periodSeconds: 5
volumes:
- name: config
configMap:
name: litmus-dex-config
ConfigMap (litmus-dex-config)
apiVersion: v1
kind: ConfigMap
metadata:
name: litmus-dex-config
namespace: litmus
data:
config.yaml: |
# Embedded type
issuer: https://litmus.example.com/auth/dex
# Dedicated (alternative)
# issuer: https://dex.litmus.example.com
storage:
type: memory
web:
http: 0.0.0.0:5556
staticClients:
- id: LitmusPortalAuthBackend
redirectURIs:
- https://litmus.example.com/auth/dex/callback
- http://localhost:8080/auth/dex/callback
name: 'Litmus Portal'
secret: <your-secret>
connectors:
- type: oidc
id: authentik
name: Authentik
config:
issuer: https://authentik.example.com/application/o/httpslitmusexamplecom/
clientID: <authentik-client-id>
clientSecret: <authentik-client-secret>
redirectURI: https://litmus.example.com/auth/dex/callback
scopes:
- openid
- profile
- email
- groups
claimMapping:
email: email
preferred_username: preferred_username
groups: groups
2. Click to view full Auth Server Configuration
✅ Critical environment variables required to enable Dex
apiVersion: apps/v1
kind: Deployment
metadata:
name: chaos-litmus-auth-server
spec:
template:
spec:
containers:
- name: auth-server
env:
# Habilitar Dex
- name: DEX_ENABLED
value: "true"
# Embedded
- name: OIDC_ISSUER
value: "https://litmus.example.com/auth/dex"
# Dedicated (alternative)
# - name: OIDC_ISSUER
# value: "https://dex.litmus.example.com"
# Callback (same for both methods)
- name: DEX_OAUTH_CALLBACK_URL
value: "https://litmus.example.com/auth/dex/callback"
# Client Configuration
- name: DEX_OAUTH_CLIENT_ID
value: "LitmusPortalAuthBackend"
- name: DEX_OAUTH_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: chaos-litmus-admin-secret
key: OIDC_CLIENT_SECRET
3. Authentik Configuration
🔒OIDC Provider configured specifically for Dex/Litmus
Provider settings in Authentik:
Field Value
Name Litmus Dex Integration
Client Type Confidential
Redirect URIs https://litmus.example.com/auth/dex/callback
https://dex.litmus.example.com/callback (dedicated mode)
Scopes openid, email, profile, groups
Subject Mode Based on User’s Email
Claim Mappings:
email → User Email
preferred_username → User Username
groups → User Groups
4. Click to view Embedded Mode – Single VirtualService
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: litmus
namespace: litmus
spec:
hosts:
- litmus.example.com
gateways:
- litmus-gateway
http:
# Temporary workaround for /auth/dex/login
- match:
- uri:
exact: /auth/dex/login
redirect:
uri: /auth/dex/auth
# Dex routes
- match:
- uri:
prefix: /auth/dex/
route:
- destination:
host: litmus-dex.litmus.svc.internal
port:
number: 5556
# Litmus frontend
- match:
- uri:
prefix: /
route:
- destination:
host: chaos-litmus-frontend-service.litmus.svc.internal
port:
number: 9091
Click to view Dedicated Mode – Two VirtualServices
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: litmus
namespace: litmus
spec:
hosts:
- litmus.example.com
gateways:
- litmus-gateway
http:
# Dex callback
- match:
- uri:
prefix: /auth/dex/callback
route:
- destination:
host: chaos-litmus-auth-server-service.litmus.internal.local
port:
number: 3000
# Litmus frontend
- match:
- uri:
prefix: /
route:
- destination:
host: chaos-litmus-frontend-service.litmus.internal
port:
number: 9091
VirtualService for Dex:
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: litmus-dex-vs
namespace: litmus
spec:
hosts:
- dex.litmus.example.com
gateways:
- litmus-dex-gateway
http:
- match:
- uri:
prefix: /
route:
- destination:
host: litmus-dex.litmus.internal
port:
number: 5556
🐛 Issues Found and Fixes
- Initial Dex CrashLoop
🔥 Error: Dex pod continuously restarting.
Root Cause:
storage.type: kubernetes without the required CRDs installed
Insufficient RBAC to access Kubernetes resources
Fix – ConfigMap change:
# Change in Dex config
storage:
type: memory # ✅ Instead of 'kubernetes'
Fix – Required RBAC:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: dex-server
rules:
- apiGroups: ["apiextensions.k8s.io"]
resources: ["customresourcedefinitions"]
verbs: ["list", "create"]
- apiGroups: [""]
resources: ["secrets", "configmaps"]
verbs: ["get", "list", "watch", "create", "update"]
2. HTTP Probes Failing (404)
Problem:
# Istio logs
no healthy upstream for /auth/dex/.well-known/openid-configuration
# Original probes (did not work)
livenessProbe:
httpGet:
path: /healthz/live
port: 5556
# Returned 404
Fix – Use TCP Socket instead of HTTP:
livenessProbe:
tcpSocket:
port: 5556
initialDelaySeconds: 30 # ⏱️ Increased delay
periodSeconds: 10
readinessProbe:
tcpSocket:
port: 5556
initialDelaySeconds: 20
periodSeconds: 5
- ConfigMap vs Secret Mismatch
🔥 Problem: Deployment mounting the wrong resource.
Cause:
Multiple ConfigMaps/Secrets with conflicting configurations
Deployment referencing the wrong resource
Fix – Single authoritative ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: litmus-dex-config # Consistent name
namespace: litmus
data:
config.yaml: |
# ... full Dex configuration here
---
# Deployment must reference exactly this ConfigMap
volumes:
- name: config
configMap:
name: litmus-dex-config # ✅ Same name
- Endpoint Discovery Working
✅ After fixes, both endpoints return HTTP 200.
Embedded Mode:
curl https://litmus.example.com/auth/dex/.well-known/openid-configuration
# ✅ HTTP 200 OK
Dedicated Mode:
curl https://dex.litmus.example.com/.well-known/openid-configuration
# ✅ HTTP 200 OK
❌ Main Problem: Litmus Frontend
🔍 Behaviour Analysis
✅ Manual OIDC Flow (Works)
When we test the full OIDC flow manually:
# Correctly formed URL
curl -L "https://litmus.example.com/auth/dex/auth?\
client_id=LitmusPortalAuthBackend&\
redirect_uri=https://litmus.example.com/auth/dex/callback&\
response_type=code&\
scope=openid+profile+email+groups&\
state=random_state"
Result:
sequenceDiagram
participant C as cURL/Browser
participant D as Dex
participant A as Authentik
C->>D: GET /auth with OIDC params ✓
D->>A: Redirect to Authentik
A->>C: Login form
C->>A: Credentials
A->>D: Authorization Code ✓
D->>C: Redirect to callback ✓
Note over C,A: ✅ Full OIDC flow works
❌ Litmus Frontend Flow (Does NOT work)
When the user clicks "Login With Single Sign-On", the frontend does:
// What the Litmus frontend currently does (INCORRECT)
window.location = "https://litmus.example.com/auth/dex/auth/authentik";
// ❌ No client_id
// ❌ No redirect_uri
// ❌ No response_type
// ❌ No scope
// ❌ No state
Dex responds with:
{
"error": "invalid_request",
"error_description": "Not Found - Invalid client_id (\"\")"
}
Problem Diagram:
sequenceDiagram
participant U as User
participant F as Litmus Frontend
participant D as Dex
U->>F: Clicks "Login with SSO"
rect rgb(255, 200, 200)
Note over F: ❌ Builds incorrect URL
F->>D: GET /auth/dex/auth/authentik<br/>(without OIDC params)
D-->>F: Invalid client_id ("")
end
Note over U,D: Flow is interrupted
💡 Comparison with Argo CD
Argo CD, using the same infrastructure (Dex + Authentik), works correctly because its frontend builds the OIDC URL properly:
// Argo CD Frontend (CORRECT) ✅
const authUrl = new URL('https://argocd.example.com/auth/dex/auth');
authUrl.searchParams.set('client_id', 'argocd-client');
authUrl.searchParams.set('redirect_uri', 'https://argocd.example.com/auth/callback');
authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('scope', 'openid profile email groups');
authUrl.searchParams.set('state', generateRandomState());
window.location = authUrl.toString();
🚀 Improvement Proposal
For the Litmus Community
ℹ️ Validation: Dex, Authentik, Istio, callbacks, and issuer configuration are all correct and tested. The bottleneck is only how the Litmus frontend initiates the SSO flow.
- Required Changes in the Frontend
Option A: Frontend builds the OIDC URL correctly
// Suggested implementation in the frontend
function initiateSSO() {
const authUrl = new URL(`${OIDC_ISSUER}/auth`);
authUrl.searchParams.set('client_id', DEX_OAUTH_CLIENT_ID);
authUrl.searchParams.set('redirect_uri', DEX_OAUTH_CALLBACK_URL);
authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('scope', 'openid profile email groups');
authUrl.searchParams.set('state', generateSecureRandomString());
window.location.href = authUrl.toString();
}
Option B: Backend exposes a “start SSO” endpoint
// Frontend just redirects to the backend
function initiateSSO() {
window.location.href = '/auth/login/sso';
}
// Backend (auth-server) then returns the proper redirect
// with all required OIDC parameters
- Official Documentation Needed
📝 Missing: Official documentation for the “Litmus → Dex → external IdP” setup.
Suggested content for docs:
Full example of staticClients and connectors for Dex
Explanation of env vars: DEX_ENABLED, OIDC_ISSUER, DEX_OAUTH_*
Guide for embedded mode (Dex behind the Litmus host via Ingress/Istio)
Troubleshooting common problems (CrashLoop, probes, RBAC)
Comparison: when to use dedicated vs embedded mode
- Current Workaround
Until these frontend changes are implemented:
✅ Recommendation: Use Dedicated Dex Mode
graph LR
A[Litmus Frontend<br/>litmus.example.com] -->|OIDC Flow| B[Dedicated Dex<br/>dex.litmus.example.com]
B --> C[Authentik IdP]
style B fill:#9f9,stroke:#333,stroke-width:3px
style A fill:#bbf
style C fill:#fbb
Advantages:
✅ Same pattern as Argo CD (already proven to work)
✅ Clear separation of responsibilities
✅ Easier debugging (isolated logs)
✅ Does not depend on Litmus frontend code changes
Configuration:
# Auth Server (example)
env:
- name: OIDC_ISSUER
value: "https://dex.litmus.example.com" # ← dedicated host
📋 Validation Checklist
Before reporting similar issues, check:
✅ Dex is running and the pod is Ready
✅ Probes are configured as tcpSocket (not HTTP)
✅ .well-known/openid-configuration returns HTTP 200
✅ A single, consistent ConfigMap is mounted in the Deployment
✅ RBAC allows access to secrets/configmaps
✅ storage.type: memory is configured
✅ Authentik has correct redirect URIs
✅ VirtualService correctly routes traffic to Dex
✅ Auth Server has DEX_ENABLED=true
✅ Callback URL is consistent everywhere
⬜ Frontend sends full OIDC parameters ← ❌ current problem
📚 References
Resource Link
Dex Documentation https://dexidp.io/docs/
OIDC Spec https://openid.net/specs/openid-connect-core-1_0.html
Argo CD + Dex https://argo-cd.readthedocs.io/en/stable/operator-manual/user-management/
Litmus Docs https://docs.litmuschaos.io/
💭 Conclusion
The Litmus ↔ Dex ↔ Authentik integration is completely viable from an infrastructure perspective. We have successfully validated:
✅ Full manual OIDC flow
✅ Dex endpoint discovery
✅ Authentication in Authentik
✅ Token generation
✅ Callbacks working
The only blocker is how the Litmus frontend starts the SSO flow. A relatively small change in the frontend (or an abstraction in the backend) would fully unlock the embedded mode.
In the meantime, the Dedicated Dex Mode works perfectly and is our recommendation for production environments.
Feedback and contributions are very welcome! 💬