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>
205 lines
No EOL
6.7 KiB
YAML
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 |