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.tf106
-rw-r--r--ops/keycloak/default.nix8
-rw-r--r--ops/keycloak/main.tf34
-rw-r--r--ops/keycloak/user_sources.tf21
6 files changed, 190 insertions, 0 deletions
diff --git a/ops/keycloak/.gitignore b/ops/keycloak/.gitignore
new file mode 100644
index 0000000000..017878c614
--- /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 0000000000..e8ffd700b5
--- /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/secrets/.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 0000000000..9506bd4aa0
--- /dev/null
+++ b/ops/keycloak/clients.tf
@@ -0,0 +1,106 @@
+# 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" "oauth2_proxy" {
+  realm_id              = keycloak_realm.tvl.id
+  client_id             = "oauth2-proxy"
+  name                  = "TVL OAuth2 Proxy"
+  enabled               = true
+  access_type           = "CONFIDENTIAL"
+  standard_flow_enabled = true
+
+  valid_redirect_uris = [
+    "https://login.tvl.fyi/oauth2/callback",
+    "http://localhost:4774/oauth2/callback",
+  ]
+}
+
+resource "keycloak_openid_audience_protocol_mapper" "oauth2_proxy_audience" {
+  realm_id                 = keycloak_realm.tvl.id
+  client_id                = keycloak_openid_client.oauth2_proxy.id
+  name                     = "oauth2-proxy-audience"
+  included_custom_audience = keycloak_openid_client.oauth2_proxy.client_id
+}
+
+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 0000000000..5757debd1a
--- /dev/null
+++ b/ops/keycloak/default.nix
@@ -0,0 +1,8 @@
+{ depot, pkgs, ... }:
+
+depot.nix.readTree.drvTargets {
+  # Provide a Terraform wrapper with the right provider installed.
+  terraform = pkgs.terraform.withPlugins (p: [
+    p.keycloak
+  ]);
+}
diff --git a/ops/keycloak/main.tf b/ops/keycloak/main.tf
new file mode 100644
index 0000000000..819267ff96
--- /dev/null
+++ b/ops/keycloak/main.tf
@@ -0,0 +1,34 @@
+# Configure TVL Keycloak instance.
+#
+# TODO(tazjin): Configure GitHub/GitLab IDP
+
+terraform {
+  required_providers {
+    keycloak = {
+      source = "mrparkers/keycloak"
+    }
+  }
+
+  backend "s3" {
+    endpoint = "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
+  }
+}
+
+provider "keycloak" {
+  client_id = "terraform"
+  url       = "https://auth.tvl.fyi"
+}
+
+resource "keycloak_realm" "tvl" {
+  realm                       = "TVL"
+  enabled                     = true
+  display_name                = "The Virus Lounge"
+  default_signature_algorithm = "RS256"
+}
diff --git a/ops/keycloak/user_sources.tf b/ops/keycloak/user_sources.tf
new file mode 100644
index 0000000000..3fde6e07cc
--- /dev/null
+++ b/ops/keycloak/user_sources.tf
@@ -0,0 +1,21 @@
+# 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).
+
+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",
+  ]
+}