diff options
| author | Franck Cuny <franck@fcuny.net> | 2025-09-01 12:38:41 -0700 |
|---|---|---|
| committer | Franck Cuny <franck@fcuny.net> | 2025-09-01 12:38:41 -0700 |
| commit | 6b3de6a99ddd810eacdfb4d9f2109ad6fd310592 (patch) | |
| tree | 10ece53c00f999a0781cf5c5f04524fc7f0ec367 | |
| parent | clean up flake and .envrc (diff) | |
| download | infra-6b3de6a99ddd810eacdfb4d9f2109ad6fd310592.tar.gz | |
configure keycloak with terraform
| -rw-r--r-- | docs/keycloak.org | 20 | ||||
| -rw-r--r-- | flake/terraform.nix | 2 | ||||
| -rw-r--r-- | terraform/admin/base.nix | 8 | ||||
| -rw-r--r-- | terraform/admin/default.nix | 1 | ||||
| -rw-r--r-- | terraform/admin/keycloak.nix | 162 |
5 files changed, 193 insertions, 0 deletions
diff --git a/docs/keycloak.org b/docs/keycloak.org index e29350f..c8760ff 100644 --- a/docs/keycloak.org +++ b/docs/keycloak.org @@ -22,3 +22,23 @@ There's an admin user in 1password. - the client ID is =forgejo= - the client secret is in the =credentials= tab in forgejo for the client - select =skip local 2FA= +** Managing with terranix +Ultimately we want to manage it with terranix. + +First, we need a client ID and a secret. The client can be created in the UI: +- https://id.fcuny.net/admin/master/console/#/master/clients +- create a new client (use =terranix= if possible, so that it's descriptive) +- =Standard Flow Enabled= should be disabled +- =Direct Access Grants Enabled= should be disabled +- =Service Accounts Enabled= should be enabled + +The go to "Service account roles" for the newly created client, and ensure it has =admin= role (assign role -> filter by realm roles -> admin). + +Export the secret with =KEYCLOAK_CLIENT_SECRET=. + +To import resources: +#+begin_src bash +nix run .#tf -- import keycloak_realm.master master +nix run .#tf -- import keycloak_user.fcuny master/d0fdbc04-8f6c-4558-8fd6-ebf7d9e23e6f +... +#+end_src diff --git a/flake/terraform.nix b/flake/terraform.nix index 23cc6d3..d593b98 100644 --- a/flake/terraform.nix +++ b/flake/terraform.nix @@ -31,8 +31,10 @@ p.digitalocean p.external p.google + p.keycloak p.null p.random + p.secret ]; }; }; diff --git a/terraform/admin/base.nix b/terraform/admin/base.nix index 7221742..97cf738 100644 --- a/terraform/admin/base.nix +++ b/terraform/admin/base.nix @@ -11,6 +11,10 @@ prefix = "admin"; }; required_providers = { + secret = { + version = "~> 1.2.1"; + source = "numtide/secret"; + }; google = { source = "hashicorp/google"; }; @@ -25,6 +29,10 @@ source = "hashicorp/random"; version = "~> 3.1"; }; + keycloak = { + source = "keycloak/keycloak"; + version = "~> 5.0"; + }; }; }; } diff --git a/terraform/admin/default.nix b/terraform/admin/default.nix index 0cbbe12..0b06e25 100644 --- a/terraform/admin/default.nix +++ b/terraform/admin/default.nix @@ -4,6 +4,7 @@ ./base.nix ./dns.nix ./droplet-proxy.nix + ./keycloak.nix ./variables.nix ]; } diff --git a/terraform/admin/keycloak.nix b/terraform/admin/keycloak.nix new file mode 100644 index 0000000..4c1af8b --- /dev/null +++ b/terraform/admin/keycloak.nix @@ -0,0 +1,162 @@ +{ lib, ... }: +let + mkUser = + { + enable ? true, + first_name, + last_name, + username, + email, + initial_password ? null, + }: + { + realm_id = lib.tf.ref "keycloak_realm.fcuny.id"; + enabled = enable; + inherit + username + email + first_name + last_name + ; + email_verified = true; + + required_actions = [ + "Update password" + "Configure OTP" + ]; + + initial_password = { + value = email; + temporary = true; + }; + }; + +in +{ + provider.keycloak = { + client_id = "terranix"; + url = "https://id.fcuny.net"; + realm = "master"; + }; + + resource.secret_resource.keycloak_smtp_password.lifecycle.prevent_destroy = true; + + resource.keycloak_realm."fcuny" = { + enabled = true; + realm = "fcuny.net"; + display_name = "Keycloak for fcuny.net"; + login_theme = "keycloak"; + access_code_lifespan = "1h"; + + reset_password_allowed = true; + remember_me = true; + login_with_email_allowed = true; + + smtp_server = { + from = "noreply@fcuny.net"; + from_display_name = "fcuny.net identity services"; + host = "smtp.fastmail.com"; + port = 465; + ssl = true; + starttls = true; + + auth = { + username = "franck@fcuny.net"; + # nix run .#tf -- import secret_resource.keycloak_smtp_password SMPT_PASSWORD + # https://github.com/numtide/terraform-provider-secret?tab=readme-ov-file#usage + password = lib.tf.ref "resource.secret_resource.keycloak_smtp_password.value"; + }; + }; + + default_signature_algorithm = "RS256"; + }; + + resource.keycloak_user = { + fcuny = mkUser { + username = "fcuny"; + first_name = "Franck"; + last_name = "Cuny"; + email = "franck@fcuny.net"; + }; + }; + + data.keycloak_openid_client.realm_management_client = { + realm_id = lib.tf.ref "keycloak_realm.fcuny.id"; + client_id = "realm-management"; + }; + + data.keycloak_role.admin = { + realm_id = lib.tf.ref "keycloak_realm.fcuny.id"; + client_id = lib.tf.ref "data.keycloak_openid_client.realm_management_client.id"; + name = "realm-admin"; + }; + + resource.keycloak_role = { + forgejo_admin = { + realm_id = lib.tf.ref "keycloak_realm.fcuny.id"; + client_id = lib.tf.ref "keycloak_openid_client.forgejo.id"; + name = "Forgejo Admin"; + description = "Forgejo's site admin"; + }; + }; + + resource.keycloak_openid_user_client_role_protocol_mapper = { + forgejo_role_mapper = { + name = "forgejo_roles_mapper"; + realm_id = lib.tf.ref "keycloak_realm.fcuny.id"; + client_id = lib.tf.ref "keycloak_openid_client.forgejo.id"; + + claim_name = "forgejo_roles"; + claim_value_type = "String"; + add_to_id_token = true; + add_to_access_token = true; + multivalued = true; + client_id_for_role_mappings = lib.tf.ref "keycloak_openid_client.forgejo.client_id"; + }; + }; + + resource.keycloak_user_roles = + let + superadminRoles = { + exhaustive = false; + + realm_id = lib.tf.ref "keycloak_realm.fcuny.id"; + + role_ids = [ + (lib.tf.ref "data.keycloak_role.admin.id") + (lib.tf.ref "keycloak_role.forgejo_admin.id") + ]; + }; + in + { + fcuny_roles = superadminRoles // { + user_id = lib.tf.ref "keycloak_user.fcuny.id"; + }; + }; + + resource.keycloak_openid_client = { + forgejo = { + realm_id = lib.tf.ref "keycloak_realm.fcuny.id"; + client_id = "forgejo"; + name = "Forgejo [fcuny.net]"; + enabled = true; + access_type = "CONFIDENTIAL"; + standard_flow_enabled = true; + oauth2_device_authorization_grant_enabled = true; + base_url = "https://code.fcuny.net"; + description = "fcuny.net's Forgejo instance"; + direct_access_grants_enabled = true; + exclude_session_state_from_auth_response = false; + service_accounts_enabled = false; + full_scope_allowed = false; + + valid_redirect_uris = [ + "https://code.fcuny.net/*" + ]; + + web_origins = [ + "https://code.fcuny.net" + ]; + }; + }; +} |
