fix(v02): wire Keycloak OIDC runtime
This commit is contained in:
@@ -155,6 +155,9 @@
|
||||
"HWLAB_BOOTSTRAP_ADMIN_USERNAME": "admin",
|
||||
"HWLAB_BOOTSTRAP_ADMIN_DISPLAY_NAME": "HWLAB v0.2 Admin",
|
||||
"HWLAB_BOOTSTRAP_ADMIN_PASSWORD_HASH": "secretRef:hwlab-v02-bootstrap-admin/password-hash",
|
||||
"HWLAB_KEYCLOAK_ISSUER": "https://auth.74-48-78-17.nip.io/realms/hwlab",
|
||||
"HWLAB_KEYCLOAK_CLIENT_ID": "hwlab-cloud-web",
|
||||
"HWLAB_KEYCLOAK_CLIENT_SECRET": "secretRef:hwlab-cloud-web-client/client-secret",
|
||||
"HWLAB_CODE_AGENT_ADAPTER": "agentrun-v01",
|
||||
"AGENTRUN_MGR_URL": "http://agentrun-mgr.agentrun-v01.svc.cluster.local:8080",
|
||||
"HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID": "G14",
|
||||
|
||||
@@ -1,15 +1,3 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: hwlab-cloud-web-client
|
||||
namespace: keycloak
|
||||
labels:
|
||||
app.kubernetes.io/name: hwlab-cloud-web-client
|
||||
hwlab.pikastech.local/component: identity
|
||||
type: Opaque
|
||||
stringData:
|
||||
client-secret: kc-client-secret-placeholder
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
@@ -19,14 +7,15 @@ metadata:
|
||||
app.kubernetes.io/name: keycloak-bootstrap-realm
|
||||
hwlab.pikastech.local/component: identity
|
||||
spec:
|
||||
backoffLimit: 3
|
||||
backoffLimit: 1
|
||||
activeDeadlineSeconds: 600
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: keycloak-bootstrap-realm
|
||||
hwlab.pikastech.local/component: identity
|
||||
spec:
|
||||
restartPolicy: OnFailure
|
||||
restartPolicy: Never
|
||||
initContainers:
|
||||
- name: wait-for-keycloak
|
||||
image: curlimages/curl:8.10.1
|
||||
@@ -50,7 +39,7 @@ spec:
|
||||
exit 1
|
||||
containers:
|
||||
- name: bootstrap
|
||||
image: curlimages/curl:8.10.1
|
||||
image: quay.io/keycloak/keycloak:25.0
|
||||
env:
|
||||
- name: PASSWORD
|
||||
valueFrom:
|
||||
@@ -62,41 +51,101 @@ spec:
|
||||
secretKeyRef:
|
||||
name: hwlab-cloud-web-client
|
||||
key: client-secret
|
||||
- name: KEYCLOAK_BASE_URL
|
||||
value: http://keycloak.keycloak.svc.cluster.local:8080
|
||||
- name: REALM
|
||||
value: hwlab
|
||||
- name: CLIENT_ID
|
||||
value: hwlab-cloud-web
|
||||
- name: REDIRECT_URI_DEV
|
||||
value: http://74.48.78.17:19667/auth/oidc/callback
|
||||
- name: WEB_ORIGIN_DEV
|
||||
value: http://74.48.78.17:19666
|
||||
- name: ACCESS_TOKEN_LIFESPAN
|
||||
value: "1440"
|
||||
- name: SSO_SESSION_MAX_LIFESPAN
|
||||
value: "86400"
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
set -eu
|
||||
KC=http://keycloak.keycloak.svc.cluster.local:8080
|
||||
REALM=hwlab
|
||||
echo fetching-admin-token
|
||||
curl -sf -X POST $KC/realms/master/protocol/openid-connect/token \
|
||||
-H 'content-type: application/x-www-form-urlencoded' \
|
||||
--data-urlencode 'username=admin' \
|
||||
--data-urlencode "password=$PASSWORD" \
|
||||
--data-urlencode 'grant_type=password' \
|
||||
--data-urlencode 'client_id=admin-cli' > /tmp/token.json
|
||||
TOKEN=$(grep -oE '"access_token":"[^"]+' /tmp/token.json | head -1 | cut -d'"' -f4)
|
||||
if [ -z "$TOKEN" ]; then
|
||||
echo no-token
|
||||
cat /tmp/token.json
|
||||
exit 1
|
||||
fi
|
||||
echo token-ok
|
||||
code=$(curl -s -o /tmp/realm.json -w '%{http_code}' -H "Authorization: Bearer $TOKEN" $KC/admin/realms/$REALM)
|
||||
if [ "$code" = "200" ]; then
|
||||
echo realm-already-exists
|
||||
KC="$KEYCLOAK_BASE_URL"
|
||||
KCADM=/opt/keycloak/bin/kcadm.sh
|
||||
CONFIG=/tmp/kcadm.config
|
||||
echo "fetching-admin-token"
|
||||
"$KCADM" config credentials \
|
||||
--config "$CONFIG" \
|
||||
--server "$KC" \
|
||||
--realm master \
|
||||
--user admin \
|
||||
--password "$PASSWORD" \
|
||||
--client admin-cli >/tmp/kcadm-login.log
|
||||
echo "token-ok"
|
||||
if "$KCADM" get "realms/$REALM" --config "$CONFIG" >/tmp/realm.json 2>/tmp/realm.err; then
|
||||
echo "realm-already-exists"
|
||||
"$KCADM" update "realms/$REALM" \
|
||||
--config "$CONFIG" \
|
||||
-s enabled=true \
|
||||
-s registrationAllowed=true \
|
||||
-s verifyEmail=false \
|
||||
-s loginWithEmailAllowed=true \
|
||||
-s duplicateEmailsAllowed=false \
|
||||
-s resetPasswordAllowed=false \
|
||||
-s editUsernameAllowed=false \
|
||||
-s bruteForceProtected=false \
|
||||
-s accessTokenLifespan="$ACCESS_TOKEN_LIFESPAN" \
|
||||
-s ssoSessionIdleTimeout="$SSO_SESSION_MAX_LIFESPAN" \
|
||||
-s ssoSessionMaxLifespan="$SSO_SESSION_MAX_LIFESPAN"
|
||||
echo "realm-updated"
|
||||
else
|
||||
echo creating-realm
|
||||
curl -sf -X POST $KC/admin/realms -H "Authorization: Bearer $TOKEN" -H 'content-type: application/json' -d '{"realm":"hwlab","enabled":true,"registrationAllowed":true,"verifyEmail":false,"loginWithEmailAllowed":true,"duplicateEmailsAllowed":false,"resetPasswordAllowed":false,"editUsernameAllowed":false,"bruteForceProtected":false,"accessTokenLifespan":1440,"ssoSessionIdleTimeout":86400,"ssoSessionMaxLifespan":86400}'
|
||||
echo realm-created
|
||||
echo "creating-realm"
|
||||
"$KCADM" create realms \
|
||||
--config "$CONFIG" \
|
||||
-s realm="$REALM" \
|
||||
-s enabled=true \
|
||||
-s registrationAllowed=true \
|
||||
-s verifyEmail=false \
|
||||
-s loginWithEmailAllowed=true \
|
||||
-s duplicateEmailsAllowed=false \
|
||||
-s resetPasswordAllowed=false \
|
||||
-s editUsernameAllowed=false \
|
||||
-s bruteForceProtected=false \
|
||||
-s accessTokenLifespan="$ACCESS_TOKEN_LIFESPAN" \
|
||||
-s ssoSessionIdleTimeout="$SSO_SESSION_MAX_LIFESPAN" \
|
||||
-s ssoSessionMaxLifespan="$SSO_SESSION_MAX_LIFESPAN"
|
||||
echo "realm-created"
|
||||
fi
|
||||
client_code=$(curl -s -o /tmp/clients.json -w '%{http_code}' -H "Authorization: Bearer $TOKEN" "$KC/admin/realms/$REALM/clients?clientId=hwlab-cloud-web")
|
||||
if [ "$client_code" = "200" ] && grep -q '"clientId":"hwlab-cloud-web"' /tmp/clients.json; then
|
||||
echo client-already-exists
|
||||
CLIENT_UUID=$("$KCADM" get clients \
|
||||
--config "$CONFIG" \
|
||||
-r "$REALM" \
|
||||
-q clientId="$CLIENT_ID" \
|
||||
--fields id \
|
||||
--format csv \
|
||||
--noquotes | head -1 | tr -d '\r')
|
||||
if [ -n "$CLIENT_UUID" ]; then
|
||||
echo "client-already-exists"
|
||||
"$KCADM" update "clients/$CLIENT_UUID" \
|
||||
--config "$CONFIG" \
|
||||
-r "$REALM" \
|
||||
-s clientId="$CLIENT_ID" \
|
||||
-s secret="$CLIENT_SECRET" \
|
||||
-s 'redirectUris=["'"$REDIRECT_URI_DEV"'"]' \
|
||||
-s 'webOrigins=["'"$WEB_ORIGIN_DEV"'"]' \
|
||||
-s standardFlowEnabled=true \
|
||||
-s directAccessGrantsEnabled=true
|
||||
echo "client-updated"
|
||||
else
|
||||
echo creating-client
|
||||
curl -sf -X POST $KC/admin/realms/$REALM/clients -H "Authorization: Bearer $TOKEN" -H 'content-type: application/json' -d "{\"clientId\":\"hwlab-cloud-web\",\"secret\":\"$CLIENT_SECRET\",\"redirectUris\":[\"http://74.48.78.17:19667/auth/oidc/callback\",\"https://auth.74-48-78-17.nip.io/auth/oidc/callback\"],\"webOrigins\":[\"+\"],\"standardFlowEnabled\":true,\"directAccessGrantsEnabled\":true}"
|
||||
echo client-created
|
||||
echo "creating-client"
|
||||
"$KCADM" create clients \
|
||||
--config "$CONFIG" \
|
||||
-r "$REALM" \
|
||||
-s clientId="$CLIENT_ID" \
|
||||
-s secret="$CLIENT_SECRET" \
|
||||
-s 'redirectUris=["'"$REDIRECT_URI_DEV"'"]' \
|
||||
-s 'webOrigins=["'"$WEB_ORIGIN_DEV"'"]' \
|
||||
-s standardFlowEnabled=true \
|
||||
-s directAccessGrantsEnabled=true
|
||||
echo "client-created"
|
||||
fi
|
||||
echo keycloak-bootstrap-complete
|
||||
echo "keycloak-bootstrap-complete"
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: keycloak-frpc-config
|
||||
namespace: keycloak
|
||||
labels:
|
||||
app.kubernetes.io/name: keycloak-frpc
|
||||
hwlab.pikastech.local/component: identity
|
||||
data:
|
||||
frpc.toml: |
|
||||
serverAddr = "74.48.78.17"
|
||||
serverPort = 7000
|
||||
loginFailExit = true
|
||||
|
||||
[[proxies]]
|
||||
name = "keycloak-public-https"
|
||||
type = "tcp"
|
||||
localIP = "keycloak.keycloak.svc.cluster.local"
|
||||
localPort = 8080
|
||||
remotePort = 28443
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: keycloak-frpc
|
||||
namespace: keycloak
|
||||
labels:
|
||||
app.kubernetes.io/name: keycloak-frpc
|
||||
hwlab.pikastech.local/component: identity
|
||||
spec:
|
||||
replicas: 1
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: keycloak-frpc
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: keycloak-frpc
|
||||
hwlab.pikastech.local/component: identity
|
||||
spec:
|
||||
containers:
|
||||
- name: frpc
|
||||
image: fatedier/frpc:v0.68.1
|
||||
args:
|
||||
- -c
|
||||
- /etc/frp/frpc.toml
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /etc/frp
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: keycloak-frpc-config
|
||||
@@ -6,6 +6,7 @@ resources:
|
||||
- postgres.yaml
|
||||
- keycloak.yaml
|
||||
- keycloak-bootstrap-job.yaml
|
||||
- keycloak-frpc.yaml
|
||||
commonLabels:
|
||||
app.kubernetes.io/part-of: hwlab
|
||||
hwlab.pikastech.local/profile: dev
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
# Caddyfile for auth.74-48-78-17.nip.io (HWLAB Keycloak public HTTPS)
|
||||
# This Caddyfile runs on the master server and reverse-proxies HTTPS to
|
||||
# the G14 keycloak Service via master frps (port 28443).
|
||||
#
|
||||
# Master-side dependency tree:
|
||||
#
|
||||
# client browser
|
||||
# -> 74.48.78.17:443 (Caddy, this file)
|
||||
# -> 127.0.0.1:28443 (master frps remotePort, see frps.dev.toml)
|
||||
# -> G14:/root/hwlab-v02/.worktree/.../deploy/k8s/keycloak/keycloak-frpc.yaml
|
||||
# -> keycloak.keycloak.svc.cluster.local:8080
|
||||
#
|
||||
# Install: download caddy 2.x from https://github.com/caddyserver/caddy/releases
|
||||
# Put binary at /usr/local/bin/caddy and Caddyfile at /etc/caddy/Caddyfile.
|
||||
# The systemd unit caddy.service goes to /etc/systemd/system/caddy.service.
|
||||
# Run `systemctl daemon-reload && systemctl enable --now caddy`.
|
||||
# Caddy will auto-request a Let's Encrypt production cert for the first
|
||||
# domain in the config (auth.74-48-78-17.nip.io).
|
||||
# To validate the chain end-to-end first, point acme_ca to staging:
|
||||
#
|
||||
# acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
|
||||
#
|
||||
# Then remove the line to switch to production.
|
||||
|
||||
{
|
||||
email ops@pikas.tech
|
||||
}
|
||||
|
||||
auth.74-48-78-17.nip.io {
|
||||
encode zstd gzip
|
||||
reverse_proxy 127.0.0.1:28443 {
|
||||
header_up Host {host}
|
||||
header_up X-Real-IP {remote_host}
|
||||
transport http {
|
||||
dial_timeout 5s
|
||||
response_header_timeout 30s
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
[Unit]
|
||||
Description=Caddy (HWLAB Keycloak public HTTPS reverse proxy)
|
||||
Documentation=https://caddyserver.com/docs/
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
ExecStart=/usr/local/bin/caddy run --environ --config /etc/caddy/Caddyfile --adapter caddyfile
|
||||
ExecReload=/usr/local/bin/caddy reload --config /etc/caddy/Caddyfile --adapter caddyfile
|
||||
TimeoutStopSec=5s
|
||||
LimitNOFILE=1048576
|
||||
PrivateDevices=yes
|
||||
PrivateTmp=yes
|
||||
ProtectSystem=full
|
||||
ProtectHome=read-only
|
||||
ReadWritePaths=/var/lib/caddy /var/log/caddy /root/.local/share/caddy
|
||||
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||
NoNewPrivileges=yes
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,18 @@
|
||||
# Master-side frps container launch equivalent.
|
||||
# The actual running container is `hwlab-frps-dev` (fatedier/frps:v0.68.1)
|
||||
# started by the existing flow with restart policy `unless-stopped`.
|
||||
# It bind-mounts /opt/hwlab-frp/frps.dev.toml -> /etc/frp/frps.toml (ro).
|
||||
# To recreate from scratch:
|
||||
#
|
||||
# mkdir -p /opt/hwlab-frp
|
||||
# cp deploy/master/frp/frps.dev.toml /opt/hwlab-frp/
|
||||
# docker run -d --name hwlab-frps-dev --restart unless-stopped \
|
||||
# -v /opt/hwlab-frp/frps.dev.toml:/etc/frp/frps.toml:ro \
|
||||
# -p 7000:7000 \
|
||||
# -p 16666:16666 -p 16667:16667 \
|
||||
# -p 17666:17666 -p 17667:17667 \
|
||||
# -p 18666:18666 -p 18667:18667 \
|
||||
# -p 19666:19666 -p 19667:19667 \
|
||||
# -p 7402:7402 \
|
||||
# -p 28443:28443 \
|
||||
# fatedier/frps:v0.68.1 -c /etc/frp/frps.toml
|
||||
@@ -0,0 +1,41 @@
|
||||
bindPort = 7000
|
||||
|
||||
[[allowPorts]]
|
||||
start = 16666
|
||||
end = 16666
|
||||
|
||||
[[allowPorts]]
|
||||
start = 16667
|
||||
end = 16667
|
||||
|
||||
[[allowPorts]]
|
||||
start = 17666
|
||||
end = 17666
|
||||
|
||||
[[allowPorts]]
|
||||
start = 17667
|
||||
end = 17667
|
||||
|
||||
[[allowPorts]]
|
||||
start = 18666
|
||||
end = 18666
|
||||
|
||||
[[allowPorts]]
|
||||
start = 18667
|
||||
end = 18667
|
||||
|
||||
[[allowPorts]]
|
||||
start = 19666
|
||||
end = 19666
|
||||
|
||||
[[allowPorts]]
|
||||
start = 19667
|
||||
end = 19667
|
||||
|
||||
[[allowPorts]]
|
||||
start = 7402
|
||||
end = 7402
|
||||
|
||||
[[allowPorts]]
|
||||
start = 28443
|
||||
end = 28443
|
||||
Reference in New Issue
Block a user