about summary refs log tree commit diff
path: root/ops/keycloak
diff options
context:
space:
mode:
Diffstat (limited to 'ops/keycloak')
-rw-r--r--ops/keycloak/.gitignore3
-rw-r--r--ops/keycloak/README.md18
-rw-r--r--ops/keycloak/clients.tf85
-rw-r--r--ops/keycloak/default.nix14
-rw-r--r--ops/keycloak/main.tf53
-rw-r--r--ops/keycloak/user_sources.tf51
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         = ""
+}