generated from coulomb/repo-seed
bootstrapping guidance ui and missing stuff
This commit is contained in:
@@ -2,13 +2,16 @@
|
||||
# encrypt-secrets.sh — encrypt secrets/ directory to secrets.enc/ using age
|
||||
#
|
||||
# Usage:
|
||||
# ./encrypt-secrets.sh [SECRETS_DIR] [AGE_KEY_FILE]
|
||||
# ./encrypt-secrets.sh [SECRETS_DIR] [AGE_RECIPIENT_OR_KEY_FILE]
|
||||
#
|
||||
# SECRETS_DIR plaintext secrets directory (default: ./secrets)
|
||||
# AGE_KEY_FILE age private key file (default: ~/.config/net-kingdom/age.key)
|
||||
# SECRETS_DIR plaintext secrets directory (default: ./secrets)
|
||||
# AGE_RECIPIENT_OR_KEY_FILE age public key, public-key file, or private-key
|
||||
# file with public-key comment
|
||||
# (default: ~/.config/net-kingdom/age.key)
|
||||
#
|
||||
# Reads the public key from the age key file and encrypts each *.env file
|
||||
# (and pi.enc if present) to secrets.enc/<component>/<filename>.age.
|
||||
# Encrypts each *.env file (and pi.enc if present) to
|
||||
# secrets.enc/<component>/<filename>.age. Prefer passing a public age recipient
|
||||
# for normal bootstrap; the private key is needed only for decrypt/apply.
|
||||
#
|
||||
# After a successful encrypt, shreds the plaintext secrets directory unless
|
||||
# --no-shred is passed.
|
||||
@@ -19,7 +22,7 @@
|
||||
set -euo pipefail
|
||||
|
||||
SECRETS_DIR="${1:-./secrets}"
|
||||
AGE_KEY="${2:-$HOME/.config/net-kingdom/age.key}"
|
||||
AGE_RECIPIENT_OR_KEY="${2:-$HOME/.config/net-kingdom/age.key}"
|
||||
NO_SHRED=false
|
||||
for arg in "$@"; do [[ "$arg" == "--no-shred" ]] && NO_SHRED=true; done
|
||||
|
||||
@@ -29,18 +32,40 @@ if [[ ! -d "$SECRETS_DIR" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$AGE_KEY" ]]; then
|
||||
echo "ERROR: age key not found: $AGE_KEY" >&2
|
||||
echo "Generate with: age-keygen -o $AGE_KEY" >&2
|
||||
exit 1
|
||||
fi
|
||||
resolve_recipient() {
|
||||
local source="$1"
|
||||
if [[ "$source" == age1* ]]; then
|
||||
printf '%s\n' "$source"
|
||||
return 0
|
||||
fi
|
||||
if [[ ! -f "$source" ]]; then
|
||||
echo "ERROR: age recipient/key file not found: $source" >&2
|
||||
echo "Pass an age public recipient such as age1... or a file containing it." >&2
|
||||
return 1
|
||||
fi
|
||||
local recipient
|
||||
recipient=$(grep -m1 '^age1' "$source" || true)
|
||||
if [[ -n "$recipient" ]]; then
|
||||
printf '%s\n' "$recipient"
|
||||
return 0
|
||||
fi
|
||||
recipient=$(grep -m1 'public key:' "$source" | awk '{print $NF}' || true)
|
||||
if [[ -n "$recipient" ]]; then
|
||||
printf '%s\n' "$recipient"
|
||||
return 0
|
||||
fi
|
||||
if grep -q 'AGE-SECRET-KEY-1' "$source"; then
|
||||
recipient=$(age-keygen -y "$source" 2>/dev/null || true)
|
||||
if [[ -n "$recipient" ]]; then
|
||||
printf '%s\n' "$recipient"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
echo "ERROR: could not resolve an age public recipient from $source" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
# Extract public key from the private key file
|
||||
PUBKEY=$(grep 'public key:' "$AGE_KEY" | awk '{print $NF}')
|
||||
if [[ -z "$PUBKEY" ]]; then
|
||||
echo "ERROR: could not read public key from $AGE_KEY" >&2
|
||||
exit 1
|
||||
fi
|
||||
PUBKEY=$(resolve_recipient "$AGE_RECIPIENT_OR_KEY")
|
||||
|
||||
ENC_DIR="$(dirname "$SECRETS_DIR")/secrets.enc"
|
||||
mkdir -p "$ENC_DIR"
|
||||
|
||||
@@ -12,6 +12,12 @@ the full authentication flow:
|
||||
KeyCape is stateless — all state lives in Authelia (sessions), LLDAP (users), and
|
||||
privacyIDEA (MFA tokens). No PVC is required.
|
||||
|
||||
The Authelia `baseURL` in `create-secrets.sh` must be the browser-facing
|
||||
`https://auth.coulomb.social` URL. KeyCape uses it to build the redirect sent
|
||||
to the user's browser during `/authorize`; a cluster-internal service URL or
|
||||
relative Authelia path will make the public OIDC login flow land on a 404 even
|
||||
when discovery and health checks are working.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- T04 complete (privacyIDEA is Running and bootstrapped — admin account + enckey done)
|
||||
@@ -114,6 +120,25 @@ clients:
|
||||
clientType: "public"
|
||||
```
|
||||
|
||||
For the local NetKingdom bootstrap console login check, keep the dedicated
|
||||
bootstrap client registered with exact local callback URIs:
|
||||
|
||||
```yaml
|
||||
clients:
|
||||
- clientId: "netkingdom-bootstrap-console"
|
||||
displayName: "NetKingdom Bootstrap Console"
|
||||
redirectUris:
|
||||
- "http://127.0.0.1:8876/oidc/callback"
|
||||
- "http://localhost:8876/oidc/callback"
|
||||
allowedScopes: ["openid", "profile", "email", "groups"]
|
||||
grantTypes: ["authorization_code"]
|
||||
clientType: "public"
|
||||
```
|
||||
|
||||
The local callback page exchanges the authorization code and displays only
|
||||
non-secret claims. KeyCape presents a browser OTP challenge between Authelia
|
||||
password login and the final OIDC redirect whenever privacyIDEA requires MFA.
|
||||
|
||||
## Secrets managed
|
||||
|
||||
| Secret name | Keys | Purpose |
|
||||
@@ -142,4 +167,9 @@ curl -s https://kc.coulomb.social/.well-known/openid-configuration | jq .
|
||||
# Check issuer matches CP-NK-004
|
||||
curl -s https://kc.coulomb.social/.well-known/openid-configuration \
|
||||
| jq -r .issuer # should be: https://kc.coulomb.social
|
||||
|
||||
# Browser login redirect should start at KeyCape and then leave the kc host for
|
||||
# Authelia. If it redirects to /api/oidc/authorization on kc.coulomb.social,
|
||||
# regenerate keycape-config and restart KeyCape after confirming the Authelia
|
||||
# browserBaseURL above.
|
||||
```
|
||||
|
||||
@@ -80,7 +80,13 @@ lldap:
|
||||
baseDN: "dc=netkingdom,dc=local"
|
||||
|
||||
authelia:
|
||||
# Cluster-internal URL for server-side token exchange.
|
||||
baseURL: "http://authelia.sso.svc.cluster.local:9091"
|
||||
# Browser-facing URL. KeyCape redirects the user's browser here for the
|
||||
# upstream Authelia password step, so this must not be the cluster-internal
|
||||
# service URL.
|
||||
browserBaseURL: "https://auth.coulomb.social"
|
||||
tokenBaseURL: "http://authelia.sso.svc.cluster.local:9091"
|
||||
clientId: "keycape"
|
||||
clientSecret: "${AUTHELIA_CLIENT_SECRET}"
|
||||
redirectURI: "https://kc.coulomb.social/authorize/callback"
|
||||
@@ -98,10 +104,20 @@ clients:
|
||||
displayName: "Demo Application"
|
||||
redirectUris:
|
||||
- "http://localhost:3000/callback"
|
||||
- "http://127.0.0.1:8876/oidc/callback"
|
||||
- "http://localhost:8876/oidc/callback"
|
||||
- "https://demo.coulomb.social/callback"
|
||||
allowedScopes: ["openid", "profile", "email", "groups"]
|
||||
grantTypes: ["authorization_code"]
|
||||
clientType: "public"
|
||||
- clientId: "netkingdom-bootstrap-console"
|
||||
displayName: "NetKingdom Bootstrap Console"
|
||||
redirectUris:
|
||||
- "http://127.0.0.1:8876/oidc/callback"
|
||||
- "http://localhost:8876/oidc/callback"
|
||||
allowedScopes: ["openid", "profile", "email", "groups"]
|
||||
grantTypes: ["authorization_code"]
|
||||
clientType: "public"
|
||||
EOF
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user