infrastructure/keycloak-config.yaml
Infrastructure Admin d770504fa5 Initial infrastructure as code deployment
This commit includes the complete Kubernetes infrastructure deployment for NGE6:

- Crossplane setup with providers (Kubernetes, Helm, Civo)
- Ambassador/Emissary ingress controller with SSL termination
- Cert-manager with Let's Encrypt and Gandi webhook for DNS01 challenges
- ExternalDNS integration with Gandi for automatic DNS management
- Keycloak authentication server with PostgreSQL
- Pomerium identity-aware proxy with OIDC integration
- Forgejo Git server with persistent storage and authentication
- Spire/SPIFFE for secure service communication

All services are deployed using Infrastructure as Code principles with
Crossplane managing Kubernetes and Helm resources declaratively.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-23 08:43:06 -04:00

205 lines
No EOL
6.7 KiB
YAML

# Keycloak realm and client configuration for Pomerium
# First, copy pomerium secrets to auth-system namespace
apiVersion: kubernetes.crossplane.io/v1alpha2
kind: Object
metadata:
name: copy-pomerium-secrets
namespace: crossplane-system
spec:
providerConfigRef:
name: kubernetes-provider
forProvider:
manifest:
apiVersion: batch/v1
kind: Job
metadata:
name: copy-pomerium-secrets
namespace: auth-system
spec:
ttlSecondsAfterFinished: 300
template:
spec:
serviceAccountName: secret-copier
restartPolicy: Never
containers:
- name: secret-copier
image: bitnami/kubectl:latest
command: ["/bin/bash"]
args:
- -c
- |
set -e
echo "Copying pomerium secrets to auth-system namespace..."
# Get the secret from pomerium namespace
kubectl get secret pomerium-secrets -n pomerium -o yaml | \
sed 's/namespace: pomerium/namespace: auth-system/' | \
sed '/resourceVersion/d' | \
sed '/uid:/d' | \
kubectl apply -f -
echo "Secret copied successfully"
---
# ServiceAccount for secret copying
apiVersion: kubernetes.crossplane.io/v1alpha2
kind: Object
metadata:
name: secret-copier-sa
namespace: crossplane-system
spec:
providerConfigRef:
name: kubernetes-provider
forProvider:
manifest:
apiVersion: v1
kind: ServiceAccount
metadata:
name: secret-copier
namespace: auth-system
---
# Role for secret copying
apiVersion: kubernetes.crossplane.io/v1alpha2
kind: Object
metadata:
name: secret-copier-role
namespace: crossplane-system
spec:
providerConfigRef:
name: kubernetes-provider
forProvider:
manifest:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: secret-copier
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "create", "update", "patch"]
---
# RoleBinding for secret copying
apiVersion: kubernetes.crossplane.io/v1alpha2
kind: Object
metadata:
name: secret-copier-binding
namespace: crossplane-system
spec:
providerConfigRef:
name: kubernetes-provider
forProvider:
manifest:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: secret-copier
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: secret-copier
subjects:
- kind: ServiceAccount
name: secret-copier
namespace: auth-system
---
# Create kubernetes-realm
apiVersion: kubernetes.crossplane.io/v1alpha2
kind: Object
metadata:
name: keycloak-kubernetes-realm
namespace: crossplane-system
spec:
providerConfigRef:
name: kubernetes-provider
forProvider:
manifest:
apiVersion: batch/v1
kind: Job
metadata:
name: setup-keycloak-realm
namespace: auth-system
spec:
ttlSecondsAfterFinished: 600
template:
spec:
restartPolicy: Never
containers:
- name: keycloak-setup
image: curlimages/curl:latest
command: ["/bin/sh"]
args:
- -c
- |
set -e
echo "Setting up Keycloak realm and client..."
# Wait for Keycloak to be ready
until curl -f http://keycloak-http:80/realms/master; do
echo "Waiting for Keycloak..."
sleep 10
done
# Get admin token
TOKEN=$(curl -s -X POST http://keycloak-http:80/realms/master/protocol/openid-connect/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d "username=admin&password=${KEYCLOAK_ADMIN_PASSWORD}&grant_type=password&client_id=admin-cli" | \
grep -o '"access_token":"[^"]*' | cut -d'"' -f4)
if [ -z "$TOKEN" ]; then
echo "Failed to get admin token"
exit 1
fi
echo "Got admin token, creating realm..."
# Create kubernetes-realm
curl -s -X POST http://keycloak-http:80/admin/realms \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"realm": "kubernetes-realm",
"enabled": true,
"displayName": "Kubernetes Realm",
"accessTokenLifespan": 1800,
"sslRequired": "none"
}' || echo "Realm might already exist"
echo "Creating Pomerium OIDC client..."
# Create pomerium client
curl -s -X POST http://keycloak-http:80/admin/realms/kubernetes-realm/clients \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"clientId": "pomerium",
"enabled": true,
"clientAuthenticatorType": "client-secret",
"secret": "'${POMERIUM_CLIENT_SECRET}'",
"redirectUris": [
"https://authenticate.nge6.com/oauth2/callback"
],
"webOrigins": [
"https://authenticate.nge6.com",
"https://keycloak.nge6.com"
],
"protocol": "openid-connect",
"publicClient": false,
"bearerOnly": false,
"consentRequired": false,
"standardFlowEnabled": true,
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": false,
"serviceAccountsEnabled": false
}'
echo "Keycloak setup completed successfully"
env:
- name: KEYCLOAK_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: keycloak-admin-creds
key: password
- name: POMERIUM_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: pomerium-secrets
key: idp_client_secret