Admin stack: Authelia SSO, portal at admin.carr.pub, gated grafana.carr.pub
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1,5 @@
|
||||
configs/node-password.txt
|
||||
.synology-password
|
||||
configs/admin-password.txt
|
||||
configs/authelia-session-secret.txt
|
||||
configs/authelia-jwt-secret.txt
|
||||
|
||||
133
manifests/admin/authelia.yaml
Normal file
133
manifests/admin/authelia.yaml
Normal file
@@ -0,0 +1,133 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: admin
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: authelia-config
|
||||
namespace: admin
|
||||
data:
|
||||
configuration.yml: |
|
||||
server:
|
||||
address: tcp://:9091
|
||||
theme: dark
|
||||
log:
|
||||
level: info
|
||||
authentication_backend:
|
||||
file:
|
||||
path: /config/users_database.yml
|
||||
password_policy:
|
||||
standard:
|
||||
enabled: true
|
||||
min_length: 12
|
||||
session:
|
||||
cookies:
|
||||
- domain: carr.pub
|
||||
authelia_url: https://auth.carr.pub
|
||||
default_redirection_url: https://admin.carr.pub
|
||||
same_site: lax
|
||||
storage:
|
||||
local:
|
||||
path: /config/data/db.sqlite3
|
||||
notifier:
|
||||
filesystem:
|
||||
filename: /config/data/notifications.txt
|
||||
totp:
|
||||
issuer: carr.pub
|
||||
webauthn:
|
||||
disable: true
|
||||
access_control:
|
||||
default_policy: one_factor
|
||||
rules: []
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: authelia-users
|
||||
namespace: admin
|
||||
stringData:
|
||||
users_database.yml: |
|
||||
users:
|
||||
adamcarr:
|
||||
displayname: "Adam Carr"
|
||||
password: "<argon2-hash from configs/admin-password.txt via deploy script>"
|
||||
groups: ["admins"]
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: authelia-secrets
|
||||
namespace: admin
|
||||
stringData:
|
||||
session-secret: <from configs/authelia-session-secret.txt>
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: authelia-data
|
||||
namespace: admin
|
||||
spec:
|
||||
accessModes: [ReadWriteOnce]
|
||||
storageClassName: local-path
|
||||
resources:
|
||||
requests: {storage: 2Gi}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: authelia
|
||||
namespace: admin
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels: {app: authelia}
|
||||
template:
|
||||
metadata:
|
||||
labels: {app: authelia}
|
||||
spec:
|
||||
containers:
|
||||
- name: authelia
|
||||
image: authelia/authelia:v4.39.28
|
||||
args: ["--config", "/config/configuration.yml"]
|
||||
env:
|
||||
- name: AUTHELIA_SESSION_SECRET
|
||||
valueFrom: {secretKeyRef: {name: authelia-secrets, key: session-secret}}
|
||||
ports: [{containerPort: 9091}]
|
||||
resources:
|
||||
requests: {cpu: 50m, memory: 64Mi}
|
||||
limits: {memory: 256Mi}
|
||||
volumeMounts:
|
||||
- {name: config, mountPath: /config/configuration.yml, subPath: configuration.yml}
|
||||
- {name: users, mountPath: /config/users_database.yml, subPath: users_database.yml}
|
||||
- {name: data, mountPath: /config/data}
|
||||
volumes:
|
||||
- name: config
|
||||
configMap: {name: authelia-config}
|
||||
- name: users
|
||||
secret: {secretName: authelia-users}
|
||||
- name: data
|
||||
persistentVolumeClaim: {claimName: authelia-data}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: authelia
|
||||
namespace: admin
|
||||
spec:
|
||||
selector: {app: authelia}
|
||||
ports:
|
||||
- port: 9091
|
||||
targetPort: 9091
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: authelia-auth
|
||||
namespace: admin
|
||||
spec:
|
||||
forwardAuth:
|
||||
address: "http://authelia.admin.svc:9091/api/verify?rd=https://auth.carr.pub"
|
||||
trustForwardHeader: true
|
||||
authResponseHeaders: [Remote-User, Remote-Groups, Remote-Email, Remote-Name]
|
||||
61
manifests/admin/ingresses.yaml
Normal file
61
manifests/admin/ingresses.yaml
Normal file
@@ -0,0 +1,61 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: auth
|
||||
namespace: admin
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
tls:
|
||||
- hosts: [auth.carr.pub]
|
||||
secretName: auth-carr-pub-tls
|
||||
rules:
|
||||
- host: auth.carr.pub
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service: {name: authelia, port: {number: 9091}}
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: admin-portal
|
||||
namespace: admin
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
traefik.ingress.kubernetes.io/router.middlewares: admin-authelia-auth@kubernetescrd
|
||||
spec:
|
||||
tls:
|
||||
- hosts: [admin.carr.pub]
|
||||
secretName: admin-carr-pub-tls
|
||||
rules:
|
||||
- host: admin.carr.pub
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service: {name: portal, port: {number: 80}}
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: grafana
|
||||
namespace: monitoring
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
traefik.ingress.kubernetes.io/router.middlewares: admin-authelia-auth@kubernetescrd
|
||||
spec:
|
||||
tls:
|
||||
- hosts: [grafana.carr.pub]
|
||||
secretName: grafana-carr-pub-tls
|
||||
rules:
|
||||
- host: grafana.carr.pub
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service: {name: grafana, port: {number: 3000}}
|
||||
66
manifests/admin/portal.yaml
Normal file
66
manifests/admin/portal.yaml
Normal file
@@ -0,0 +1,66 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: portal-index
|
||||
namespace: admin
|
||||
data:
|
||||
index.html: |
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head><meta charset="utf-8"><title>planck admin</title>
|
||||
<style>
|
||||
body { font-family: system-ui, sans-serif; background: #111; color: #eee;
|
||||
display: grid; place-items: center; min-height: 100vh; margin: 0; }
|
||||
.card { text-align: center; }
|
||||
h1 { font-size: 2.5rem; margin: 0 0 1.5rem; }
|
||||
a { display: block; margin: 0.6rem auto; padding: 0.8rem 1.5rem;
|
||||
background: #1e1e2e; border: 1px solid #333; border-radius: 10px;
|
||||
color: #8be9fd; text-decoration: none; font-size: 1.1rem; width: 260px; }
|
||||
a:hover { background: #2a2a3e; }
|
||||
p { color: #888; }
|
||||
</style>
|
||||
</head>
|
||||
<body><div class="card">
|
||||
<h1>planck</h1>
|
||||
<a href="https://grafana.carr.pub">Grafana</a>
|
||||
<a href="https://auth.carr.pub">Account & 2FA settings</a>
|
||||
<p>20 nodes · k3s · carr.pub</p>
|
||||
</div></body>
|
||||
</html>
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: portal
|
||||
namespace: admin
|
||||
spec:
|
||||
replicas: 2
|
||||
selector:
|
||||
matchLabels: {app: portal}
|
||||
template:
|
||||
metadata:
|
||||
labels: {app: portal}
|
||||
spec:
|
||||
containers:
|
||||
- name: web
|
||||
image: nginx:1.29-alpine
|
||||
ports: [{containerPort: 80}]
|
||||
resources:
|
||||
requests: {cpu: 10m, memory: 16Mi}
|
||||
limits: {memory: 64Mi}
|
||||
volumeMounts:
|
||||
- {name: html, mountPath: /usr/share/nginx/html}
|
||||
volumes:
|
||||
- name: html
|
||||
configMap: {name: portal-index}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: portal
|
||||
namespace: admin
|
||||
spec:
|
||||
selector: {app: portal}
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 80
|
||||
24
scripts/deploy-admin.sh
Normal file
24
scripts/deploy-admin.sh
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
# Redeploy the admin stack (Authelia SSO + portal). Secrets are regenerated
|
||||
# from the gitignored files in configs/ so nothing sensitive is committed.
|
||||
# First-time setup: run scripts/gen-admin-secrets.sh before this.
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
HASH=$(/tmp/opencode/authelia/authelia crypto hash generate argon2 \
|
||||
--password "$(cat configs/admin-password.txt)" 2>/dev/null | grep -o '\$argon2id\$.*')
|
||||
SESSION=$(cat configs/authelia-session-secret.txt)
|
||||
JWT=$(cat configs/authelia-jwt-secret.txt)
|
||||
ENCKEY=$(openssl rand -base64 24 | tr -d "=+/" | cut -c1-32)
|
||||
|
||||
export HASH SESSION JWT ENCKEY
|
||||
for f in manifests/admin/*.yaml; do
|
||||
envsubst '\$HASH \$SESSION \$JWT \$ENCKEY' < "$f" | kubectl apply -f -
|
||||
done
|
||||
|
||||
kubectl -n admin set env deployment/authelia \
|
||||
AUTHELIA_SESSION_SECRET="$SESSION" \
|
||||
AUTHELIA_STORAGE_ENCRYPTION_KEY="$ENCKEY" \
|
||||
AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET="$JWT" \
|
||||
>/dev/null
|
||||
echo "admin stack deployed"
|
||||
Reference in New Issue
Block a user