From 7204114fa010a67d13e48c87a0ff6b6e47560a76 Mon Sep 17 00:00:00 2001 From: Diamantis Sellis Date: Wed, 4 Mar 2026 12:02:39 +0100 Subject: [PATCH] feat: migrate automation client from old modules --- modules/cicd/README.md | 42 +++++++++++++ modules/cicd/main.tf | 59 +++++++++++++++++++ .../cicd/tests/config/tenant-test-realm.json | 12 ++++ modules/cicd/tests/docker-compose.yml | 21 +++++++ modules/cicd/tests/keycloak.local.tfvars | 7 +++ modules/cicd/tests/keycloak.tftest.hcl | 26 ++++++++ modules/cicd/variables.tf | 37 ++++++++++++ 7 files changed, 204 insertions(+) create mode 100644 modules/cicd/README.md create mode 100644 modules/cicd/main.tf create mode 100644 modules/cicd/tests/config/tenant-test-realm.json create mode 100644 modules/cicd/tests/docker-compose.yml create mode 100644 modules/cicd/tests/keycloak.local.tfvars create mode 100644 modules/cicd/tests/keycloak.tftest.hcl create mode 100644 modules/cicd/variables.tf diff --git a/modules/cicd/README.md b/modules/cicd/README.md new file mode 100644 index 0000000..499bb93 --- /dev/null +++ b/modules/cicd/README.md @@ -0,0 +1,42 @@ +# CICD Keycloak Automation Client Submodule + +This submodule creates a Keycloak OpenID client named `automation-client` in an existing realm. It does not require admin access to a Kubernetes cluster with the downside of requiring configuring the keycloak variables. + +## Module Input Variables + +- Cosmotech Platform specific variables + - `tenant`: CosmoTech platform tenant name + - `cluster_domain`: The cluster location +- Variables for keycloak + - `keycloak_url` Keycloak server URL + - `keycloak_client_id` Keycloak client id (with admin rights) + - `keycloak_username` Keycloak admin username + - `keycloak_password` Keycloak admin password + - `keycloak_realm` Keycloak realm name + +## Usage +``` +module "cicd" { + source = "./modules/cicd" + + tenant = "tenant-test" + cluster_domain = "localhost" + keycloak_url = "http://localhost:8080" + keycloak_client_id = "admin-cli" + keycloak_username = "admin" + keycloak_password = "admin" + keycloak_realm = "master" +} +``` + +## Testing +Start the keycloak container +```shell +cd tests +docker compose up -d +``` +A keycloak instance will start and will be configured with a realm and roles loaded. +Run the terraform test: +```shell +terraform test --var-file keycloak.local.tfvars +``` \ No newline at end of file diff --git a/modules/cicd/main.tf b/modules/cicd/main.tf new file mode 100644 index 0000000..df2e9b1 --- /dev/null +++ b/modules/cicd/main.tf @@ -0,0 +1,59 @@ +terraform { + required_providers { + keycloak = { + source = "keycloak/keycloak" + version = "5.7.0" + } + } +} + +provider "keycloak" { + url = var.keycloak_url + client_id = var.keycloak_client_id + username = var.keycloak_username + password = var.keycloak_password + realm = var.keycloak_realm +} + + +# get realm for current tenant +data "keycloak_realm" "realm" { + realm = var.tenant +} + +# automation client +resource "keycloak_openid_client" "automation-client" { + realm_id = data.keycloak_realm.realm.id + client_id = "automation-client" + name = "automation-client" + enabled = true + standard_flow_enabled = false + access_type = "CONFIDENTIAL" + service_accounts_enabled = true + login_theme = "keycloak" + root_url = "https://${var.cluster_domain}" + full_scope_allowed = true +} + +resource "keycloak_generic_protocol_mapper" "automation_realm_roles_mapper" { + realm_id = data.keycloak_realm.realm.id + client_id = keycloak_openid_client.automation-client.id + name = "realm roles" + protocol = "openid-connect" + protocol_mapper = "oidc-usermodel-realm-role-mapper" + config = { + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "userRoles", + "jsonType.label" : "String", + "multivalued" : "true", + "userinfo.token.claim" : "true", + "introspection.token.claim" : "true" + } +} + +resource "keycloak_openid_client_service_account_realm_role" "automation_client_service_account_role" { + realm_id = data.keycloak_realm.realm.id + service_account_user_id = keycloak_openid_client.automation-client.service_account_user_id + role = "Platform.Admin" +} diff --git a/modules/cicd/tests/config/tenant-test-realm.json b/modules/cicd/tests/config/tenant-test-realm.json new file mode 100644 index 0000000..0d573c5 --- /dev/null +++ b/modules/cicd/tests/config/tenant-test-realm.json @@ -0,0 +1,12 @@ +{ + "realm": "tenant-test", + "enabled": true, + "roles": { + "realm": [ + { + "name": "Platform.Admin", + "description": "Administration role" + } + ] + } +} \ No newline at end of file diff --git a/modules/cicd/tests/docker-compose.yml b/modules/cicd/tests/docker-compose.yml new file mode 100644 index 0000000..693b163 --- /dev/null +++ b/modules/cicd/tests/docker-compose.yml @@ -0,0 +1,21 @@ +services: + keycloak: + image: keycloak/keycloak:26.5 + environment: + KC_BOOTSTRAP_ADMIN_USERNAME: "admin" + KC_BOOTSTRAP_ADMIN_PASSWORD: "admin" + KC_HTTP_ENABLED: "true" + KC_HOSTNAME_STRICT: "false" + ports: + - "8080:8080" + volumes: + - ./config/:/opt/keycloak/data/import/ + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8080/health/ready"] + interval: 10s + timeout: 5s + retries: 5 + command: + - start-dev + - --import-realm + - --verbose \ No newline at end of file diff --git a/modules/cicd/tests/keycloak.local.tfvars b/modules/cicd/tests/keycloak.local.tfvars new file mode 100644 index 0000000..237cc8e --- /dev/null +++ b/modules/cicd/tests/keycloak.local.tfvars @@ -0,0 +1,7 @@ +keycloak_url = "http://localhost:8080" +keycloak_client_id = "admin-cli" +keycloak_username = "admin" +keycloak_password = "admin" +keycloak_realm = "master" +tenant = "tenant-test" +cluster_domain = "localhost" diff --git a/modules/cicd/tests/keycloak.tftest.hcl b/modules/cicd/tests/keycloak.tftest.hcl new file mode 100644 index 0000000..14bb101 --- /dev/null +++ b/modules/cicd/tests/keycloak.tftest.hcl @@ -0,0 +1,26 @@ +provider "keycloak" { + url = "http://localhost:8080" + username = "admin" + password = "admin" + initial_login = true + client_id = "admin-cli" + realm = "master" + tls_insecure_skip_verify = true +} + +variables { + tenant = "tenant-test" + cluster_domain = "localhost" +} + +run "verify_automation_client_creation" { + command = plan + variables { + tenant = var.tenant + cluster_domain = var.cluster_domain + } + assert { + condition = keycloak_openid_client.automation-client.client_id == "automation-client" + error_message = "Keycloak automation client should be created" + } +} diff --git a/modules/cicd/variables.tf b/modules/cicd/variables.tf new file mode 100644 index 0000000..c66c488 --- /dev/null +++ b/modules/cicd/variables.tf @@ -0,0 +1,37 @@ +## CosmoTech Platform specifics +variable "tenant" { + description = "CosmoTech platform tenant name (e.g. tenant-sphinx)" + type = string +} + +variable "cluster_domain" { + description = "The DNS name of the API, e.g. cluster.azure.platform.cosmotech.com" + type = string +} + +## General variables +variable "keycloak_url" { + description = "Keycloak server URL" + type = string +} + +variable "keycloak_client_id" { + description = "Keycloak client ID" + type = string +} + +variable "keycloak_username" { + description = "Keycloak admin username" + type = string +} + +variable "keycloak_password" { + description = "Keycloak admin password" + type = string + sensitive = true +} + +variable "keycloak_realm" { + description = "Keycloak realm name" + type = string +}