docs auth
This commit is contained in:
35
README.md
35
README.md
@@ -70,6 +70,7 @@ This repository contains the complete GitOps configuration for our Kubernetes cl
|
|||||||
✅ **Self-Healing**: Manual cluster changes are reverted
|
✅ **Self-Healing**: Manual cluster changes are reverted
|
||||||
✅ **Multi-Source**: Separate chart templates from configuration
|
✅ **Multi-Source**: Separate chart templates from configuration
|
||||||
✅ **Policy Enforcement**: Kyverno ensures security and compliance
|
✅ **Policy Enforcement**: Kyverno ensures security and compliance
|
||||||
|
✅ **Authentication**: Automatic sidecar injection (token & OIDC support)
|
||||||
✅ **TLS Everywhere**: Automatic Let's Encrypt certificates
|
✅ **TLS Everywhere**: Automatic Let's Encrypt certificates
|
||||||
✅ **Full Observability**: Prometheus, Grafana, Loki integration
|
✅ **Full Observability**: Prometheus, Grafana, Loki integration
|
||||||
|
|
||||||
@@ -189,6 +190,40 @@ git commit -m "Add myapp credentials"
|
|||||||
git push
|
git push
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Enable Authentication
|
||||||
|
|
||||||
|
**See detailed guide**: [Developer Guide - Enabling Authentication](docs/DEVELOPER-GUIDE.md#enabling-authentication-for-applications)
|
||||||
|
|
||||||
|
**Quick version**:
|
||||||
|
```yaml
|
||||||
|
# In helm-values/myapp/values.yaml
|
||||||
|
|
||||||
|
# Token-based auth (simple)
|
||||||
|
auth:
|
||||||
|
enabled: true
|
||||||
|
type: token
|
||||||
|
tokens:
|
||||||
|
- your-secret-token-here
|
||||||
|
|
||||||
|
# OIDC auth (SSO)
|
||||||
|
auth:
|
||||||
|
enabled: true
|
||||||
|
type: oidc
|
||||||
|
oidc:
|
||||||
|
authority: https://auth.example.com/realms/master
|
||||||
|
clientId: myapp
|
||||||
|
```
|
||||||
|
|
||||||
|
Then create OIDC secret (if using OIDC):
|
||||||
|
```bash
|
||||||
|
kubectl create secret generic auth-oidc \
|
||||||
|
--from-literal=client-secret=your-oidc-secret \
|
||||||
|
--from-literal=cookie-secret=$(openssl rand -hex 32) \
|
||||||
|
--namespace=myapp | \
|
||||||
|
kubeseal --format=yaml --cert=pub-cert.pem --namespace=myapp | \
|
||||||
|
kubectl apply -f -
|
||||||
|
```
|
||||||
|
|
||||||
### Bootstrap Cluster
|
### Bootstrap Cluster
|
||||||
|
|
||||||
**See detailed guide**: [Operations Runbook - Cluster Bootstrap](docs/OPERATIONS-RUNBOOK.md#cluster-bootstrap)
|
**See detailed guide**: [Operations Runbook - Cluster Bootstrap](docs/OPERATIONS-RUNBOOK.md#cluster-bootstrap)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
- [Deploying Your First Application](#deploying-your-first-application)
|
- [Deploying Your First Application](#deploying-your-first-application)
|
||||||
- [Updating an Existing Application](#updating-an-existing-application)
|
- [Updating an Existing Application](#updating-an-existing-application)
|
||||||
- [Working with Secrets](#working-with-secrets)
|
- [Working with Secrets](#working-with-secrets)
|
||||||
|
- [Enabling Authentication for Applications](#enabling-authentication-for-applications)
|
||||||
- [Troubleshooting](#troubleshooting)
|
- [Troubleshooting](#troubleshooting)
|
||||||
- [Best Practices](#best-practices)
|
- [Best Practices](#best-practices)
|
||||||
|
|
||||||
@@ -754,6 +755,457 @@ kubectl rollout restart deployment myapp -n myapp
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Enabling Authentication for Applications
|
||||||
|
|
||||||
|
The cluster supports automatic authentication sidecar injection for applications via Kyverno policies. This allows you to add authentication to your applications without modifying application code.
|
||||||
|
|
||||||
|
### How It Works
|
||||||
|
|
||||||
|
When you enable authentication in your Helm values, the Kyverno policy automatically:
|
||||||
|
1. ✅ Injects an authentication sidecar container into your pod
|
||||||
|
2. ✅ Routes all incoming traffic through the auth sidecar (port 8080)
|
||||||
|
3. ✅ Validates credentials before forwarding requests to your application
|
||||||
|
4. ✅ Creates necessary secrets (if they don't exist)
|
||||||
|
5. ✅ Adds a NetworkPolicy to restrict ingress
|
||||||
|
|
||||||
|
**Architecture**:
|
||||||
|
```
|
||||||
|
Internet → Traefik → Service:8080 → Auth Sidecar:8080 → localhost → Your App:3000
|
||||||
|
│
|
||||||
|
├─ Validates credentials
|
||||||
|
└─ Forwards if valid
|
||||||
|
```
|
||||||
|
|
||||||
|
### Authentication Modes
|
||||||
|
|
||||||
|
Two authentication modes are supported:
|
||||||
|
1. **Token-based**: Static tokens (simple, good for service-to-service or internal apps)
|
||||||
|
2. **OIDC**: OpenID Connect (full SSO, good for user-facing apps)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Token-Based Authentication
|
||||||
|
|
||||||
|
#### Step 1: Configure Helm Values
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# In helm-values/myapp/values.yaml
|
||||||
|
auth:
|
||||||
|
enabled: true
|
||||||
|
type: token # Token mode (default)
|
||||||
|
tokens:
|
||||||
|
- d4f88f6d9292c10cc3e21c4aad56d2be485db532b54fe961d738e1137d247823
|
||||||
|
- 8803f621acc3898df1d7a8f514bc3602551a0681a8f747bd4e43c3c5849d57a7
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 2: Generate Token (if needed)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Generate a secure random token
|
||||||
|
openssl rand -hex 32
|
||||||
|
|
||||||
|
# Or using Python
|
||||||
|
python3 -c "import secrets; print(secrets.token_hex(32))"
|
||||||
|
|
||||||
|
# Example output:
|
||||||
|
# d4f88f6d9292c10cc3e21c4aad56d2be485db532b54fe961d738e1137d247823
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 3: Deploy Application
|
||||||
|
|
||||||
|
Commit and push your changes:
|
||||||
|
```bash
|
||||||
|
cd ~/dev/k8s/helm-prod-values
|
||||||
|
git add myapp/values.yaml
|
||||||
|
git commit -m "Enable token auth for myapp"
|
||||||
|
git push
|
||||||
|
```
|
||||||
|
|
||||||
|
ArgoCD will sync, and the Kyverno policy will:
|
||||||
|
- Inject the auth sidecar container
|
||||||
|
- Create an `auth-tokens` Secret with your tokens
|
||||||
|
- Configure the sidecar to validate against these tokens
|
||||||
|
|
||||||
|
#### Step 4: Access Application
|
||||||
|
|
||||||
|
Use your token in the `Authorization` header:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Access application with token
|
||||||
|
curl -H "Authorization: Bearer d4f88f6d9292c10cc3e21c4aad56d2be485db532b54fe961d738e1137d247823" \
|
||||||
|
https://myapp.forteapps.net/api/data
|
||||||
|
|
||||||
|
# Without token (will be rejected)
|
||||||
|
curl https://myapp.forteapps.net/api/data
|
||||||
|
# Response: 401 Unauthorized
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Advanced: Custom Secret Name
|
||||||
|
|
||||||
|
To use a different secret for tokens:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# In Helm values
|
||||||
|
auth:
|
||||||
|
enabled: true
|
||||||
|
type: token
|
||||||
|
tokens: [] # Empty - using external secret
|
||||||
|
|
||||||
|
# Tokens will be read from custom secret
|
||||||
|
```
|
||||||
|
|
||||||
|
Then reference it via annotation (configured by Helm chart automatically):
|
||||||
|
```yaml
|
||||||
|
# Helm chart sets this annotation:
|
||||||
|
policies.forteapps.io/auth-token-secret-name: "myapp-auth-tokens"
|
||||||
|
```
|
||||||
|
|
||||||
|
Create the secret manually:
|
||||||
|
```bash
|
||||||
|
kubectl create secret generic myapp-auth-tokens \
|
||||||
|
--from-file=tokens=tokens.txt \
|
||||||
|
--namespace=myapp
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### OIDC Authentication
|
||||||
|
|
||||||
|
OIDC mode integrates with identity providers like Keycloak, Okta, Auth0, Azure AD, etc.
|
||||||
|
|
||||||
|
#### Step 1: Configure Identity Provider
|
||||||
|
|
||||||
|
In your identity provider (e.g., Keycloak):
|
||||||
|
1. Create a new client (e.g., `myapp`)
|
||||||
|
2. Set redirect URI: `https://myapp.forteapps.net/auth/callback`
|
||||||
|
3. Note the **Client ID** and **Client Secret**
|
||||||
|
4. Note the **Authority URL** (e.g., `https://keycloak.forteapps.net/realms/master`)
|
||||||
|
|
||||||
|
#### Step 2: Create OIDC Secret
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create plain secret
|
||||||
|
kubectl create secret generic auth-oidc \
|
||||||
|
--from-literal=client-secret=your-oidc-client-secret \
|
||||||
|
--from-literal=cookie-secret=$(openssl rand -hex 32) \
|
||||||
|
--namespace=myapp \
|
||||||
|
--dry-run=client -o yaml > private/myapp-auth-oidc.yaml
|
||||||
|
|
||||||
|
# Seal it
|
||||||
|
kubeseal --format=yaml \
|
||||||
|
--cert=pub-cert.pem \
|
||||||
|
--namespace=myapp \
|
||||||
|
< private/myapp-auth-oidc.yaml \
|
||||||
|
> secrets/myapp-auth-oidc-sealed.yaml
|
||||||
|
|
||||||
|
# Commit sealed secret
|
||||||
|
cd ~/dev/k8s/launchpad
|
||||||
|
git add secrets/myapp-auth-oidc-sealed.yaml
|
||||||
|
git commit -m "Add OIDC secrets for myapp"
|
||||||
|
git push
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm private/myapp-auth-oidc.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 3: Configure Helm Values
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# In helm-values/myapp/values.yaml
|
||||||
|
auth:
|
||||||
|
enabled: true
|
||||||
|
type: oidc # OIDC mode
|
||||||
|
oidc:
|
||||||
|
authority: https://keycloak.forteapps.net/realms/master
|
||||||
|
clientId: myapp
|
||||||
|
scopes: "openid,profile,email"
|
||||||
|
callbackPath: /auth/callback
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 4: Deploy Application
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/dev/k8s/helm-prod-values
|
||||||
|
git add myapp/values.yaml
|
||||||
|
git commit -m "Enable OIDC auth for myapp"
|
||||||
|
git push
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 5: Access Application
|
||||||
|
|
||||||
|
When users access `https://myapp.forteapps.net`:
|
||||||
|
1. They're redirected to the identity provider login page
|
||||||
|
2. After successful login, redirected back to `/auth/callback`
|
||||||
|
3. Session cookie is set
|
||||||
|
4. Subsequent requests are authenticated via cookie
|
||||||
|
|
||||||
|
**User flow**:
|
||||||
|
```
|
||||||
|
User → https://myapp.forteapps.net
|
||||||
|
↓
|
||||||
|
Redirect → https://keycloak.forteapps.net/login
|
||||||
|
↓
|
||||||
|
Login successful → Redirect with auth code
|
||||||
|
↓
|
||||||
|
https://myapp.forteapps.net/auth/callback?code=xyz
|
||||||
|
↓
|
||||||
|
Auth sidecar exchanges code for tokens
|
||||||
|
↓
|
||||||
|
Sets session cookie
|
||||||
|
↓
|
||||||
|
Redirects to application → https://myapp.forteapps.net
|
||||||
|
↓
|
||||||
|
User sees application (authenticated)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Authentication Configuration Reference
|
||||||
|
|
||||||
|
#### Helm Values Schema
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
auth:
|
||||||
|
enabled: false # Enable/disable authentication
|
||||||
|
type: token # "token" or "oidc"
|
||||||
|
|
||||||
|
# Token mode configuration
|
||||||
|
tokens: [] # List of valid bearer tokens
|
||||||
|
# - token1
|
||||||
|
# - token2
|
||||||
|
|
||||||
|
# OIDC mode configuration
|
||||||
|
oidc:
|
||||||
|
authority: "" # OIDC provider URL (required for OIDC)
|
||||||
|
clientId: "" # OIDC client ID (required for OIDC)
|
||||||
|
scopes: "openid,profile,email" # OIDC scopes (optional)
|
||||||
|
callbackPath: /auth/callback # OAuth callback path (optional)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Annotations Set by Helm Chart
|
||||||
|
|
||||||
|
When `auth.enabled: true`, the Helm chart sets these pod annotations:
|
||||||
|
|
||||||
|
**Token mode**:
|
||||||
|
```yaml
|
||||||
|
policies.forteapps.io/auth: "true"
|
||||||
|
policies.forteapps.io/auth-type: "token"
|
||||||
|
policies.forteapps.io/auth-token-secret-name: "auth-tokens"
|
||||||
|
policies.forteapps.io/auth-upstream-url: "http://localhost:3000"
|
||||||
|
```
|
||||||
|
|
||||||
|
**OIDC mode**:
|
||||||
|
```yaml
|
||||||
|
policies.forteapps.io/auth: "true"
|
||||||
|
policies.forteapps.io/auth-type: "oidc"
|
||||||
|
policies.forteapps.io/auth-oidc-authority: "https://keycloak.forteapps.net/realms/master"
|
||||||
|
policies.forteapps.io/auth-oidc-client-id: "myapp"
|
||||||
|
policies.forteapps.io/auth-oidc-scopes: "openid,profile,email"
|
||||||
|
policies.forteapps.io/auth-oidc-callback-path: "/auth/callback"
|
||||||
|
policies.forteapps.io/auth-upstream-url: "http://localhost:3000"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Sidecar Configuration
|
||||||
|
|
||||||
|
The auth sidecar container:
|
||||||
|
- **Image**: `ghcr.io/snothub/stunning-memory:latest`
|
||||||
|
- **Port**: 8080
|
||||||
|
- **Resources**: 10m CPU / 32Mi memory (requests), 50m CPU / 64Mi memory (limits)
|
||||||
|
- **Health checks**: `/healthz` endpoint
|
||||||
|
- **Security**: Read-only root filesystem, no privilege escalation
|
||||||
|
|
||||||
|
#### Advanced: Custom Sidecar Image
|
||||||
|
|
||||||
|
To use a different auth sidecar image:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# These annotations can be set in the Helm chart template if needed
|
||||||
|
policies.forteapps.io/auth-image: "your-registry/your-auth-proxy"
|
||||||
|
policies.forteapps.io/auth-image-version: "v1.2.3"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Authentication Examples
|
||||||
|
|
||||||
|
#### Example 1: Internal API with Token Auth
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# helm-values/internal-api/values.yaml
|
||||||
|
app:
|
||||||
|
image:
|
||||||
|
repository: ghcr.io/company/internal-api
|
||||||
|
tag: v1.0.0
|
||||||
|
|
||||||
|
auth:
|
||||||
|
enabled: true
|
||||||
|
type: token
|
||||||
|
tokens:
|
||||||
|
- d4f88f6d9292c10cc3e21c4aad56d2be485db532b54fe961d738e1137d247823 # Service A
|
||||||
|
- 8803f621acc3898df1d7a8f514bc3602551a0681a8f747bd4e43c3c5849d57a7 # Service B
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
host: internal-api.forteapps.net
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage**:
|
||||||
|
```bash
|
||||||
|
# Service A calls API
|
||||||
|
curl -H "Authorization: Bearer d4f88f..." \
|
||||||
|
https://internal-api.forteapps.net/api/endpoint
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Example 2: User-Facing App with OIDC
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# helm-values/web-app/values.yaml
|
||||||
|
app:
|
||||||
|
image:
|
||||||
|
repository: ghcr.io/company/web-app
|
||||||
|
tag: v2.1.0
|
||||||
|
|
||||||
|
auth:
|
||||||
|
enabled: true
|
||||||
|
type: oidc
|
||||||
|
oidc:
|
||||||
|
authority: https://auth.company.com/realms/employees
|
||||||
|
clientId: web-app-prod
|
||||||
|
scopes: "openid,profile,email,groups"
|
||||||
|
callbackPath: /auth/callback
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
host: web-app.forteapps.net
|
||||||
|
```
|
||||||
|
|
||||||
|
**With sealed OIDC secret**:
|
||||||
|
```bash
|
||||||
|
# Create and seal secret
|
||||||
|
kubectl create secret generic auth-oidc \
|
||||||
|
--from-literal=client-secret=super-secret-value \
|
||||||
|
--from-literal=cookie-secret=$(openssl rand -hex 32) \
|
||||||
|
--namespace=web-app \
|
||||||
|
--dry-run=client -o yaml | \
|
||||||
|
kubeseal --format=yaml --cert=pub-cert.pem --namespace=web-app \
|
||||||
|
> secrets/web-app-auth-oidc-sealed.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Example 3: Disabling Authentication
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# helm-values/public-api/values.yaml
|
||||||
|
auth:
|
||||||
|
enabled: false # No authentication
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
host: public-api.forteapps.net
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Troubleshooting Authentication
|
||||||
|
|
||||||
|
#### Issue: 401 Unauthorized (Token Mode)
|
||||||
|
|
||||||
|
**Check token validity**:
|
||||||
|
```bash
|
||||||
|
# Get auth-tokens secret
|
||||||
|
kubectl get secret auth-tokens -n myapp -o yaml
|
||||||
|
|
||||||
|
# Decode tokens
|
||||||
|
kubectl get secret auth-tokens -n myapp \
|
||||||
|
-o jsonpath='{.data.tokens}' | base64 -d
|
||||||
|
|
||||||
|
# Verify your token is in the list
|
||||||
|
```
|
||||||
|
|
||||||
|
**Test with different token**:
|
||||||
|
```bash
|
||||||
|
curl -v -H "Authorization: Bearer YOUR-TOKEN-HERE" \
|
||||||
|
https://myapp.forteapps.net/
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Issue: OIDC Login Loop
|
||||||
|
|
||||||
|
**Check OIDC configuration**:
|
||||||
|
```bash
|
||||||
|
# Verify auth-oidc secret exists
|
||||||
|
kubectl get secret auth-oidc -n myapp
|
||||||
|
|
||||||
|
# Check sidecar logs
|
||||||
|
kubectl logs -n myapp <pod-name> -c authn
|
||||||
|
|
||||||
|
# Common issues:
|
||||||
|
# - Wrong authority URL
|
||||||
|
# - Wrong client ID
|
||||||
|
# - Missing client-secret in auth-oidc Secret
|
||||||
|
# - Redirect URI not configured in identity provider
|
||||||
|
```
|
||||||
|
|
||||||
|
**Verify redirect URI** in your identity provider matches:
|
||||||
|
```
|
||||||
|
https://<your-app-domain>/auth/callback
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Issue: Auth Sidecar Not Injected
|
||||||
|
|
||||||
|
**Check pod annotations**:
|
||||||
|
```bash
|
||||||
|
kubectl get pod -n myapp <pod-name> -o yaml | grep policies.forteapps.io
|
||||||
|
|
||||||
|
# Should show:
|
||||||
|
# policies.forteapps.io/auth: "true"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Check Kyverno policy**:
|
||||||
|
```bash
|
||||||
|
kubectl get clusterpolicy inject-auth-sidecar
|
||||||
|
kubectl describe clusterpolicy inject-auth-sidecar
|
||||||
|
```
|
||||||
|
|
||||||
|
**Check Kyverno logs**:
|
||||||
|
```bash
|
||||||
|
kubectl logs -n kyverno deployment/kyverno | grep inject-auth
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Issue: Auth Sidecar Crashes
|
||||||
|
|
||||||
|
**Check sidecar logs**:
|
||||||
|
```bash
|
||||||
|
kubectl logs -n myapp <pod-name> -c authn
|
||||||
|
```
|
||||||
|
|
||||||
|
**Common causes**:
|
||||||
|
- Missing secret (auth-tokens or auth-oidc)
|
||||||
|
- Invalid OIDC configuration
|
||||||
|
- Can't reach OIDC authority URL
|
||||||
|
- Network policy blocking outbound OIDC requests
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Authentication Best Practices
|
||||||
|
|
||||||
|
✅ **DO**:
|
||||||
|
- Use OIDC for user-facing applications
|
||||||
|
- Use token auth for service-to-service communication
|
||||||
|
- Rotate tokens and secrets regularly
|
||||||
|
- Use strong random tokens (32+ bytes)
|
||||||
|
- Store client secrets in SealedSecrets
|
||||||
|
- Test authentication before deploying to production
|
||||||
|
- Document which tokens/users have access
|
||||||
|
|
||||||
|
❌ **DON'T**:
|
||||||
|
- Share tokens between environments
|
||||||
|
- Commit tokens to application code
|
||||||
|
- Use predictable tokens
|
||||||
|
- Reuse tokens across multiple applications
|
||||||
|
- Disable authentication on sensitive APIs
|
||||||
|
- Log tokens or secrets
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
### Application Not Deploying
|
### Application Not Deploying
|
||||||
|
|||||||
@@ -496,6 +496,122 @@ data:
|
|||||||
|
|
||||||
When a new namespace is created, Kyverno automatically copies this secret.
|
When a new namespace is created, Kyverno automatically copies this secret.
|
||||||
|
|
||||||
|
### Authentication Secrets
|
||||||
|
|
||||||
|
Applications using the authentication sidecar require specific secrets depending on the auth mode.
|
||||||
|
|
||||||
|
#### Token Mode Secrets
|
||||||
|
|
||||||
|
Token-based auth uses an `auth-tokens` Secret:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Method 1: From Helm values (automatic)
|
||||||
|
# Tokens specified in values.yaml are automatically created
|
||||||
|
|
||||||
|
# Method 2: Manual creation
|
||||||
|
kubectl create secret generic auth-tokens \
|
||||||
|
--from-literal=tokens="token1
|
||||||
|
token2
|
||||||
|
token3" \
|
||||||
|
--namespace=myapp
|
||||||
|
|
||||||
|
# Method 3: From file
|
||||||
|
echo "d4f88f6d9292c10cc3e21c4aad56d2be485db532b54fe961d738e1137d247823" > tokens.txt
|
||||||
|
echo "8803f621acc3898df1d7a8f514bc3602551a0681a8f747bd4e43c3c5849d57a7" >> tokens.txt
|
||||||
|
kubectl create secret generic auth-tokens \
|
||||||
|
--from-file=tokens=tokens.txt \
|
||||||
|
--namespace=myapp
|
||||||
|
rm tokens.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
#### OIDC Mode Secrets
|
||||||
|
|
||||||
|
OIDC auth requires an `auth-oidc` Secret with two keys:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Generate secrets
|
||||||
|
CLIENT_SECRET="your-oidc-client-secret-from-provider"
|
||||||
|
COOKIE_SECRET=$(openssl rand -hex 32)
|
||||||
|
|
||||||
|
# Create plain secret
|
||||||
|
kubectl create secret generic auth-oidc \
|
||||||
|
--from-literal=client-secret=$CLIENT_SECRET \
|
||||||
|
--from-literal=cookie-secret=$COOKIE_SECRET \
|
||||||
|
--namespace=myapp \
|
||||||
|
--dry-run=client -o yaml > private/myapp-auth-oidc.yaml
|
||||||
|
|
||||||
|
# Seal it
|
||||||
|
kubeseal --format=yaml \
|
||||||
|
--cert=pub-cert.pem \
|
||||||
|
--namespace=myapp \
|
||||||
|
< private/myapp-auth-oidc.yaml \
|
||||||
|
> secrets/myapp-auth-oidc-sealed.yaml
|
||||||
|
|
||||||
|
# Apply sealed secret
|
||||||
|
kubectl apply -f secrets/myapp-auth-oidc-sealed.yaml
|
||||||
|
|
||||||
|
# Commit to Git
|
||||||
|
git add secrets/myapp-auth-oidc-sealed.yaml
|
||||||
|
git commit -m "Add OIDC secrets for myapp"
|
||||||
|
git push
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm private/myapp-auth-oidc.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Rotating Authentication Secrets
|
||||||
|
|
||||||
|
**Token Rotation**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Generate new token
|
||||||
|
NEW_TOKEN=$(openssl rand -hex 32)
|
||||||
|
|
||||||
|
# Get current tokens
|
||||||
|
kubectl get secret auth-tokens -n myapp -o yaml > /tmp/tokens.yaml
|
||||||
|
|
||||||
|
# Edit tokens (add new, optionally remove old)
|
||||||
|
# Then re-seal and apply
|
||||||
|
|
||||||
|
# Restart pods to use new tokens
|
||||||
|
kubectl rollout restart deployment myapp -n myapp
|
||||||
|
```
|
||||||
|
|
||||||
|
**OIDC Secret Rotation**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Rotate cookie secret (safe - invalidates existing sessions)
|
||||||
|
NEW_COOKIE_SECRET=$(openssl rand -hex 32)
|
||||||
|
|
||||||
|
# Recreate secret
|
||||||
|
kubectl create secret generic auth-oidc \
|
||||||
|
--from-literal=client-secret=$CLIENT_SECRET \
|
||||||
|
--from-literal=cookie-secret=$NEW_COOKIE_SECRET \
|
||||||
|
--namespace=myapp \
|
||||||
|
--dry-run=client -o yaml | \
|
||||||
|
kubeseal --format=yaml --cert=pub-cert.pem --namespace=myapp | \
|
||||||
|
kubectl apply -f -
|
||||||
|
|
||||||
|
# Restart to pick up new secret
|
||||||
|
kubectl rollout restart deployment myapp -n myapp
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Viewing Authentication Secrets
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List auth-related secrets
|
||||||
|
kubectl get secrets -n myapp | grep auth
|
||||||
|
|
||||||
|
# View token secret (tokens are in plain text in the Secret)
|
||||||
|
kubectl get secret auth-tokens -n myapp -o jsonpath='{.data.tokens}' | base64 -d
|
||||||
|
|
||||||
|
# View OIDC secret keys (values are base64 encoded)
|
||||||
|
kubectl get secret auth-oidc -n myapp -o jsonpath='{.data.client-secret}' | base64 -d
|
||||||
|
kubectl get secret auth-oidc -n myapp -o jsonpath='{.data.cookie-secret}' | base64 -d
|
||||||
|
```
|
||||||
|
|
||||||
|
**See**: [Developer Guide - Enabling Authentication](../docs/DEVELOPER-GUIDE.md#enabling-authentication-for-applications) for complete authentication setup guide.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Monitoring & Alerting
|
## Monitoring & Alerting
|
||||||
|
|||||||
@@ -299,19 +299,27 @@ ingress:
|
|||||||
clusterIssuer: letsencrypt-prod
|
clusterIssuer: letsencrypt-prod
|
||||||
|
|
||||||
auth:
|
auth:
|
||||||
enabled: false
|
enabled: false # Enable authentication sidecar injection
|
||||||
type: token # Options: "token", "oidc"
|
type: token # Authentication mode: "token" or "oidc"
|
||||||
oidc:
|
|
||||||
authority: ""
|
|
||||||
clientId: ""
|
|
||||||
scopes: ""
|
|
||||||
callbackPath: /auth/callback
|
|
||||||
tokens: []
|
|
||||||
# - token1
|
|
||||||
# - token2
|
|
||||||
|
|
||||||
configmap: []
|
# Token-based authentication configuration
|
||||||
|
tokens: [] # List of valid bearer tokens (hex strings, 32+ bytes recommended)
|
||||||
|
# - d4f88f6d9292c10cc3e21c4aad56d2be485db532b54fe961d738e1137d247823
|
||||||
|
# - 8803f621acc3898df1d7a8f514bc3602551a0681a8f747bd4e43c3c5849d57a7
|
||||||
|
|
||||||
|
# OIDC authentication configuration
|
||||||
|
oidc:
|
||||||
|
authority: "" # OIDC provider URL (e.g., https://auth.example.com/realms/master)
|
||||||
|
clientId: "" # OIDC client ID registered with provider
|
||||||
|
scopes: "openid,profile,email" # OAuth scopes (comma-separated)
|
||||||
|
callbackPath: /auth/callback # OAuth callback path (default: /auth/callback)
|
||||||
|
# Note: Client secret must be in 'auth-oidc' Secret (client-secret key)
|
||||||
|
# Cookie secret must be in 'auth-oidc' Secret (cookie-secret key)
|
||||||
|
|
||||||
|
configmap: [] # Application ConfigMap key-value pairs
|
||||||
# KEY: value
|
# KEY: value
|
||||||
|
# DB_HOST: postgres
|
||||||
|
# DB_PORT: "5432"
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -818,35 +826,235 @@ spec:
|
|||||||
|
|
||||||
**File**: `cluster-resources/policies/auth-sidecar-injector.yaml`
|
**File**: `cluster-resources/policies/auth-sidecar-injector.yaml`
|
||||||
|
|
||||||
**Purpose**: Inject authentication sidecar based on pod annotations
|
**Purpose**: Automatically inject authentication sidecar into pods with authentication enabled
|
||||||
|
|
||||||
|
**Rules**: 5 rules in the policy
|
||||||
|
1. `generate-auth-tokens-secret` - Creates Secret for token mode
|
||||||
|
2. `generate-auth-oidc-secret` - Creates Secret for OIDC mode
|
||||||
|
3. `inject-sidecar-token` - Injects auth sidecar for token mode
|
||||||
|
4. `inject-sidecar-oidc` - Injects auth sidecar for OIDC mode
|
||||||
|
5. `generate-auth-network-policy` - Creates NetworkPolicy to restrict ingress
|
||||||
|
|
||||||
|
#### Trigger Annotation
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: kyverno.io/v1
|
policies.forteapps.io/auth: "true"
|
||||||
kind: ClusterPolicy
|
|
||||||
metadata:
|
|
||||||
name: inject-auth-sidecar
|
|
||||||
spec:
|
|
||||||
rules:
|
|
||||||
- name: inject-sidecar
|
|
||||||
match:
|
|
||||||
any:
|
|
||||||
- resources:
|
|
||||||
kinds:
|
|
||||||
- Pod
|
|
||||||
preconditions:
|
|
||||||
all:
|
|
||||||
- key: "{{ request.object.metadata.annotations.\"policies.forteapps.io/auth\" || '' }}"
|
|
||||||
operator: Equals
|
|
||||||
value: "true"
|
|
||||||
mutate:
|
|
||||||
patchStrategicMerge:
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: auth-proxy
|
|
||||||
image: oauth2-proxy/oauth2-proxy:latest
|
|
||||||
# ... additional configuration
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Authentication Modes
|
||||||
|
|
||||||
|
**Token Mode** (default):
|
||||||
|
```yaml
|
||||||
|
# Annotations
|
||||||
|
policies.forteapps.io/auth: "true"
|
||||||
|
policies.forteapps.io/auth-type: "token"
|
||||||
|
policies.forteapps.io/auth-token-secret-name: "auth-tokens"
|
||||||
|
policies.forteapps.io/auth-upstream-url: "http://localhost:3000"
|
||||||
|
|
||||||
|
# Optional customization
|
||||||
|
policies.forteapps.io/auth-image: "ghcr.io/snothub/stunning-memory"
|
||||||
|
policies.forteapps.io/auth-image-version: "latest"
|
||||||
|
```
|
||||||
|
|
||||||
|
**OIDC Mode**:
|
||||||
|
```yaml
|
||||||
|
# Annotations (required)
|
||||||
|
policies.forteapps.io/auth: "true"
|
||||||
|
policies.forteapps.io/auth-type: "oidc"
|
||||||
|
policies.forteapps.io/auth-oidc-authority: "https://auth.example.com/realms/master"
|
||||||
|
policies.forteapps.io/auth-oidc-client-id: "myapp"
|
||||||
|
|
||||||
|
# Optional annotations
|
||||||
|
policies.forteapps.io/auth-oidc-callback-path: "/auth/callback"
|
||||||
|
policies.forteapps.io/auth-oidc-scopes: "openid,profile,email"
|
||||||
|
policies.forteapps.io/auth-upstream-url: "http://localhost:3000"
|
||||||
|
policies.forteapps.io/auth-image: "ghcr.io/snothub/stunning-memory"
|
||||||
|
policies.forteapps.io/auth-image-version: "latest"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Sidecar Container Specification
|
||||||
|
|
||||||
|
**Token Mode**:
|
||||||
|
```yaml
|
||||||
|
name: authn
|
||||||
|
image: ghcr.io/snothub/stunning-memory:latest
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
name: auth
|
||||||
|
protocol: TCP
|
||||||
|
env:
|
||||||
|
- name: AUTH_MODE
|
||||||
|
value: "token"
|
||||||
|
- name: AUTH_LISTEN_ADDR
|
||||||
|
value: ":8080"
|
||||||
|
- name: AUTH_UPSTREAM_URL
|
||||||
|
value: "http://localhost:3000"
|
||||||
|
- name: AUTH_TOKEN_FILE
|
||||||
|
value: "/etc/auth/tokens"
|
||||||
|
volumeMounts:
|
||||||
|
- name: auth-tokens
|
||||||
|
mountPath: /etc/auth
|
||||||
|
readOnly: true
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 32Mi
|
||||||
|
limits:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 64Mi
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
capabilities:
|
||||||
|
drop: [ALL]
|
||||||
|
```
|
||||||
|
|
||||||
|
**OIDC Mode**:
|
||||||
|
```yaml
|
||||||
|
name: authn
|
||||||
|
image: ghcr.io/snothub/stunning-memory:latest
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
name: auth
|
||||||
|
protocol: TCP
|
||||||
|
env:
|
||||||
|
- name: AUTH_MODE
|
||||||
|
value: "oidc"
|
||||||
|
- name: AUTH_LISTEN_ADDR
|
||||||
|
value: ":8080"
|
||||||
|
- name: AUTH_UPSTREAM_URL
|
||||||
|
value: "http://localhost:3000"
|
||||||
|
- name: AUTH_OIDC_AUTHORITY
|
||||||
|
value: "https://auth.example.com/realms/master"
|
||||||
|
- name: AUTH_OIDC_CLIENT_ID
|
||||||
|
value: "myapp"
|
||||||
|
- name: AUTH_OIDC_CALLBACK_PATH
|
||||||
|
value: "/auth/callback"
|
||||||
|
- name: AUTH_OIDC_SCOPES
|
||||||
|
value: "openid,profile,email"
|
||||||
|
- name: AUTH_OIDC_COOKIE_SECRET
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: auth-oidc
|
||||||
|
key: cookie-secret
|
||||||
|
- name: AUTH_OIDC_CLIENT_SECRET
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: auth-oidc
|
||||||
|
key: client-secret
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 32Mi
|
||||||
|
limits:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 64Mi
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
capabilities:
|
||||||
|
drop: [ALL]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Generated Resources
|
||||||
|
|
||||||
|
**Secret (Token Mode)**:
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: auth-tokens
|
||||||
|
namespace: <app-namespace>
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/managed-by: kyverno
|
||||||
|
app.kubernetes.io/created-by: inject-auth-sidecar
|
||||||
|
type: Opaque
|
||||||
|
data: {} # Populated by Helm chart
|
||||||
|
```
|
||||||
|
|
||||||
|
**Secret (OIDC Mode)**:
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: auth-oidc
|
||||||
|
namespace: <app-namespace>
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/managed-by: kyverno
|
||||||
|
app.kubernetes.io/created-by: inject-auth-sidecar
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
client-secret: <base64>
|
||||||
|
cookie-secret: <base64>
|
||||||
|
```
|
||||||
|
|
||||||
|
**NetworkPolicy**:
|
||||||
|
```yaml
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: <pod-name>-auth-ingress
|
||||||
|
namespace: <app-namespace>
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/managed-by: kyverno
|
||||||
|
app.kubernetes.io/created-by: inject-auth-sidecar
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels: <pod-labels>
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
ingress:
|
||||||
|
- ports:
|
||||||
|
- port: 8080
|
||||||
|
protocol: TCP
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Excluded Namespaces
|
||||||
|
|
||||||
|
The policy does NOT apply to:
|
||||||
|
- `kube-system`
|
||||||
|
- `kyverno`
|
||||||
|
- `argocd`
|
||||||
|
- `cert-manager`
|
||||||
|
- `monitoring`
|
||||||
|
|
||||||
|
#### Health Checks
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: 8080
|
||||||
|
initialDelaySeconds: 2
|
||||||
|
periodSeconds: 5
|
||||||
|
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: 8080
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Request Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
External Request → Traefik
|
||||||
|
↓
|
||||||
|
Service (port 8080)
|
||||||
|
↓
|
||||||
|
Pod: Auth Sidecar (port 8080)
|
||||||
|
├─ Validate credentials
|
||||||
|
│ • Token mode: Check Bearer token
|
||||||
|
│ • OIDC mode: Validate session or redirect to IdP
|
||||||
|
↓
|
||||||
|
Forward to Application (localhost:3000)
|
||||||
|
↓
|
||||||
|
Application processes request
|
||||||
|
```
|
||||||
|
|
||||||
|
**See**: [Developer Guide - Enabling Authentication](DEVELOPER-GUIDE.md#enabling-authentication-for-applications) for usage examples.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Configuration Reference
|
## Configuration Reference
|
||||||
|
|||||||
Reference in New Issue
Block a user