Sanitized single-commit public mirror of recipe-maintainer. - Removed test-ssh/.testenv (live creds); added test-ssh/.testenv.example placeholders. - Removed plans/ and planned-updates/ (deployment-planning docs) so no client/ deployment domains appear in the public repo. - All other secret stores were already gitignored. - docs.coopcloud.tech retained as a submodule (public upstream).
107 lines
3.9 KiB
Python
107 lines
3.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Setup Keycloak OIDC integration for Lichen.
|
|
|
|
Creates a Keycloak realm, OIDC client, and test user, then inserts
|
|
the OIDC secrets and enables the OIDC compose overlay for lichen.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", ".."))
|
|
|
|
from lib.abra import app_secret_insert
|
|
from lib.env import apply_env_overrides, get_abra_env_path, read_env_file
|
|
from lib.keycloak import KeycloakAdmin
|
|
from lib.models import load_default_instance
|
|
from lib.secrets import load_secrets
|
|
|
|
# Configuration
|
|
REALM = "lichen"
|
|
CLIENT_ID = "lichen"
|
|
TEST_USER = "testuser"
|
|
TEST_PASS = "testpass123"
|
|
TEST_EMAIL = f"{TEST_USER}@test.example.com"
|
|
|
|
|
|
def main():
|
|
inst = load_default_instance()
|
|
lichen_domain = inst.default_domain("lichen")
|
|
kc_domain = inst.default_domain("keycloak")
|
|
|
|
# Get Keycloak admin password from synced secrets
|
|
kc_secrets = load_secrets(kc_domain)
|
|
kc_admin_pass = kc_secrets["admin_password"]
|
|
|
|
kc = KeycloakAdmin(f"https://{kc_domain}", "admin", kc_admin_pass)
|
|
|
|
# Step 1: Create realm
|
|
kc.ensure_realm(REALM)
|
|
|
|
# Step 2: Create OIDC client
|
|
_, client_secret = kc.ensure_client(
|
|
REALM, CLIENT_ID,
|
|
redirect_uris=[f"https://{lichen_domain}/*"],
|
|
web_origins=[f"https://{lichen_domain}"],
|
|
)
|
|
|
|
# Step 3: Create test user
|
|
kc.ensure_user(REALM, TEST_USER, TEST_EMAIL, TEST_PASS)
|
|
|
|
# Step 4: Insert OIDC secrets via abra
|
|
print("=== Insert OIDC secrets into Lichen ===", flush=True)
|
|
issuer_url = f"https://{kc_domain}/realms/{REALM}"
|
|
|
|
app_secret_insert(lichen_domain, "oidc_issuer_url", "v1", issuer_url)
|
|
app_secret_insert(lichen_domain, "oidc_client_id", "v1", CLIENT_ID)
|
|
app_secret_insert(lichen_domain, "oidc_client_secret", "v1", client_secret)
|
|
|
|
# Step 5: Update lichen env with OIDC compose overlay
|
|
print("=== Update Lichen env with OIDC overlay ===", flush=True)
|
|
env_path = get_abra_env_path(inst.server, lichen_domain)
|
|
apply_env_overrides(env_path, {
|
|
"COMPOSE_FILE": '"compose.yml:compose.oidc.yml"',
|
|
"SECRET_OIDC_ISSUER_URL_VERSION": "v1",
|
|
"SECRET_OIDC_CLIENT_ID_VERSION": "v1",
|
|
"SECRET_OIDC_CLIENT_SECRET_VERSION": "v1",
|
|
"LICHEN_TOML_VERSION": "v1",
|
|
})
|
|
|
|
# Step 6: Write credentials file
|
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
creds_file = os.path.join(script_dir, f"keycloak-test-credentials.{inst.domain_suffix}.toml")
|
|
print(f"=== Write credentials to {creds_file} ===", flush=True)
|
|
with open(creds_file, "w") as f:
|
|
f.write(f'# Keycloak OIDC credentials for lichen test instance\n')
|
|
f.write(f'#\n')
|
|
f.write(f'# Keycloak instance: {kc_domain}\n')
|
|
f.write(f'# Realm: {REALM}\n')
|
|
f.write(f'# Created by: setup_keycloak_integration.py\n')
|
|
f.write(f'\n')
|
|
f.write(f'# Keycloak admin (master realm)\n')
|
|
f.write(f'kc_admin_user = "admin"\n')
|
|
f.write(f'kc_admin_pass = "{kc_admin_pass}"\n')
|
|
f.write(f'\n')
|
|
f.write(f'# OIDC client\n')
|
|
f.write(f'kc_realm = "{REALM}"\n')
|
|
f.write(f'kc_client_id = "{CLIENT_ID}"\n')
|
|
f.write(f'kc_client_secret = "{client_secret}"\n')
|
|
f.write(f'kc_issuer_url = "{issuer_url}"\n')
|
|
f.write(f'\n')
|
|
f.write(f'# Test user (in {REALM} realm)\n')
|
|
f.write(f'kc_test_user = "{TEST_USER}"\n')
|
|
f.write(f'kc_test_pass = "{TEST_PASS}"\n')
|
|
f.write(f'kc_test_email = "{TEST_EMAIL}"\n')
|
|
print(f" Written to {creds_file}", flush=True)
|
|
|
|
print("", flush=True)
|
|
print("=== Keycloak integration setup complete ===", flush=True)
|
|
print("", flush=True)
|
|
print("Next steps:", flush=True)
|
|
print(f" 1. Redeploy lichen: abra app deploy {lichen_domain} --chaos --force --no-input", flush=True)
|
|
print(f" 2. Run OIDC test: python3 recipe-info/lichen/tests/oidc_integration.py", flush=True)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|