diff options
Diffstat (limited to 'ops/keycloak')
-rw-r--r-- | ops/keycloak/.gitignore | 3 | ||||
-rw-r--r-- | ops/keycloak/README.md | 18 | ||||
-rw-r--r-- | ops/keycloak/clients.tf | 85 | ||||
-rw-r--r-- | ops/keycloak/default.nix | 14 | ||||
-rw-r--r-- | ops/keycloak/main.tf | 53 | ||||
-rw-r--r-- | ops/keycloak/user_sources.tf | 51 |
6 files changed, 224 insertions, 0 deletions
diff --git a/ops/keycloak/.gitignore b/ops/keycloak/.gitignore new file mode 100644 index 000000000000..017878c614d0 --- /dev/null +++ b/ops/keycloak/.gitignore @@ -0,0 +1,3 @@ +.terraform* +*.tfstate* +.envrc diff --git a/ops/keycloak/README.md b/ops/keycloak/README.md new file mode 100644 index 000000000000..fd72daa87d25 --- /dev/null +++ b/ops/keycloak/README.md @@ -0,0 +1,18 @@ +Terraform for Keycloak +====================== + +This contains the Terraform configuration for deploying TVL's Keycloak +instance (which lives at `auth.tvl.fyi`). + +Secrets are needed for applying this. The encrypted file +`//ops/secrets/tf-keycloak.age` contains `export` calls which should +be sourced, for example via `direnv`, by users with the appropriate +credentials. + +An example `direnv` configuration used by tazjin is this: + +``` +# //ops/keycloak/.envrc +source_up +eval $(age --decrypt -i ~/.ssh/id_ed25519 $(git rev-parse --show-toplevel)/ops/secrets/tf-keycloak.age) +``` diff --git a/ops/keycloak/clients.tf b/ops/keycloak/clients.tf new file mode 100644 index 000000000000..178971ae3678 --- /dev/null +++ b/ops/keycloak/clients.tf @@ -0,0 +1,85 @@ +# All Keycloak clients, that is applications which authenticate +# through Keycloak. +# +# Includes first-party (i.e. TVL-hosted) and third-party clients. + +resource "keycloak_openid_client" "grafana" { + realm_id = keycloak_realm.tvl.id + client_id = "grafana" + name = "Grafana" + enabled = true + access_type = "CONFIDENTIAL" + standard_flow_enabled = true + base_url = "https://status.tvl.su" + + valid_redirect_uris = [ + "https://status.tvl.su/*", + ] +} + +resource "keycloak_openid_client" "gerrit" { + realm_id = keycloak_realm.tvl.id + client_id = "gerrit" + name = "TVL Gerrit" + enabled = true + access_type = "CONFIDENTIAL" + standard_flow_enabled = true + base_url = "https://cl.tvl.fyi" + description = "TVL's code review tool" + direct_access_grants_enabled = true + exclude_session_state_from_auth_response = false + + valid_redirect_uris = [ + "https://cl.tvl.fyi/*", + ] + + web_origins = [ + "https://cl.tvl.fyi", + ] +} + +resource "keycloak_saml_client" "buildkite" { + realm_id = keycloak_realm.tvl.id + client_id = "https://buildkite.com" + name = "Buildkite" + base_url = "https://buildkite.com/sso/tvl" + + client_signature_required = false + assertion_consumer_post_url = "https://buildkite.com/sso/~/1531aca5-f49c-4151-8832-a451e758af4c/saml/consume" + + valid_redirect_uris = [ + "https://buildkite.com/sso/~/1531aca5-f49c-4151-8832-a451e758af4c/saml/consume" + ] +} + +resource "keycloak_saml_user_attribute_protocol_mapper" "buildkite_email" { + realm_id = keycloak_realm.tvl.id + client_id = keycloak_saml_client.buildkite.id + name = "buildkite-email-mapper" + user_attribute = "email" + saml_attribute_name = "email" + saml_attribute_name_format = "Unspecified" +} + +resource "keycloak_saml_user_attribute_protocol_mapper" "buildkite_name" { + realm_id = keycloak_realm.tvl.id + client_id = keycloak_saml_client.buildkite.id + name = "buildkite-name-mapper" + user_attribute = "displayName" + saml_attribute_name = "name" + saml_attribute_name_format = "Unspecified" +} + +resource "keycloak_openid_client" "panettone" { + realm_id = keycloak_realm.tvl.id + client_id = "panettone" + name = "Panettone" + enabled = true + access_type = "CONFIDENTIAL" + standard_flow_enabled = true + + valid_redirect_uris = [ + "https://b.tvl.fyi/auth", + "http://localhost:6161/auth", + ] +} diff --git a/ops/keycloak/default.nix b/ops/keycloak/default.nix new file mode 100644 index 000000000000..94ed912dc936 --- /dev/null +++ b/ops/keycloak/default.nix @@ -0,0 +1,14 @@ +{ depot, lib, pkgs, ... }: + +depot.nix.readTree.drvTargets rec { + # Provide a Terraform wrapper with the right provider installed. + terraform = pkgs.terraform.withPlugins (p: [ + p.keycloak + ]); + + validate = depot.tools.checks.validateTerraform { + inherit terraform; + name = "keycloak"; + src = lib.cleanSource ./.; + }; +} diff --git a/ops/keycloak/main.tf b/ops/keycloak/main.tf new file mode 100644 index 000000000000..d5698700ce58 --- /dev/null +++ b/ops/keycloak/main.tf @@ -0,0 +1,53 @@ +# Configure TVL Keycloak instance. +# +# TODO(tazjin): Configure GitLab IDP + +terraform { + required_providers { + keycloak = { + source = "mrparkers/keycloak" + } + } + + backend "s3" { + endpoints = { + s3 = "https://objects.dc-sto1.glesys.net" + } + bucket = "tvl-state" + key = "terraform/tvl-keycloak" + region = "glesys" + + skip_credentials_validation = true + skip_region_validation = true + skip_metadata_api_check = true + skip_requesting_account_id = true + skip_s3_checksum = true + } +} + +provider "keycloak" { + client_id = "terraform" + url = "https://auth.tvl.fyi" + # NOTE: Docs mention this applies to "users of the legacy distribution of keycloak". + # However, we get a "failed to perform initial login to Keycloak: error + # sending POST request to https://auth.tvl.fyi/realms/master/protocol/openid-connect/token: 404 Not Found" + # if we don't set this. + base_path = "/auth" +} + +resource "keycloak_realm" "tvl" { + realm = "TVL" + enabled = true + display_name = "The Virus Lounge" + default_signature_algorithm = "RS256" + + smtp_server { + from = "tvlbot@tazj.in" + from_display_name = "The Virus Lounge" + host = "127.0.0.1" + port = "25" + reply_to = "depot@tvl.su" + ssl = false + starttls = false + } +} diff --git a/ops/keycloak/user_sources.tf b/ops/keycloak/user_sources.tf new file mode 100644 index 000000000000..7fa71e36fbb2 --- /dev/null +++ b/ops/keycloak/user_sources.tf @@ -0,0 +1,51 @@ +# All user sources, that is services from which Keycloak gets user +# information (either by accessing a system like LDAP or integration +# through protocols like OIDC). + +variable "github_client_secret" { + type = string +} + +resource "keycloak_ldap_user_federation" "tvl_ldap" { + name = "tvl-ldap" + realm_id = keycloak_realm.tvl.id + enabled = true + connection_url = "ldap://localhost" + users_dn = "ou=users,dc=tvl,dc=fyi" + username_ldap_attribute = "cn" + uuid_ldap_attribute = "cn" + rdn_ldap_attribute = "cn" + full_sync_period = 86400 + trust_email = true + + user_object_classes = [ + "inetOrgPerson", + "organizationalPerson", + ] + + lifecycle { + # Without this, terraform wants to recreate the resource. + ignore_changes = [ + delete_default_mappers + ] + } +} + +# keycloak_oidc_identity_provider.github will be destroyed +# (because keycloak_oidc_identity_provider.github is not in configuration) +resource "keycloak_oidc_identity_provider" "github" { + alias = "github" + provider_id = "github" + client_id = "Iv23liXfGNIr7InMg5Uo" + client_secret = var.github_client_secret + realm = keycloak_realm.tvl.id + backchannel_supported = false + gui_order = "1" + store_token = false + sync_mode = "IMPORT" + trust_email = true + + # These default to built-in values for the `github` provider_id. + authorization_url = "" + token_url = "" +} |