Terraform — это инструмент, который позволяет управлять инфраструктурой как кодом (IaC). С помощью Terraform вы можете определить вашу инфраструктуру в простых конфигурационных файлах, и сервис автоматически создаст вашу инфраструктуру в соответствии с этими конфигурациями.
Terragrunt — это легкая обертка для Terraform, которая предоставляет дополнительные инструменты для поддержания ваших конфигураций в DRY (Don't Repeat Yourself) стиле, управления удаленным состоянием и работы с несколькими модулями Terraform. Terragrunt помогает поддерживать чистоту и повторяемость кода Terraform, обеспечивая дополнительный функционал и лучшие практики.
В паре эти инструменты дают такие преимущества:
Инструкции по установке можно найти в официальной документации:
Ниже приведена структура, наиболее подходящая для организации компонентов, концепций и настройки Keycloak.
.
├── README.md                 <- The project overview
├── .tool-versions            <- Used tools versions (managed by asdf. see https://asdf-vm.com) 
├── README.md                 <- The project overview
├── modules                   <- Terraform modules
|   └── common
│       ├── provider.tf
│       └── variables.tf
│       └── output.tf
│       └── main.tf
│       └── README.md
│       └── docs/
|   └── clients
│       ├── provider.tf
│       └── variables.tf
│       └── output.tf
│       └── main.tf
│       └── README.md
│       └── docs/
|   └── my-realm
│       ├── provider.tf
│       └── variables.tf
│       └── output.tf
│       └── main.tf
│       └── README.md
│       └── docs/
|   └── other
│       ├── provider.tf
│       └── variables.tf
│       └── output.tf
│       └── main.tf
│       └── README.md
│       └── docs/
└── how-to                    <- Documentation
└── stage                     <- Terraform for environment stage
    ├── .terraform.lock.hcl   <- Terraform lock file
    └── terragrunt.hcl        <- Terragrunt file
    └── env.yaml              <- environment related variables
    └── main.tf               <- environment modules
└── prod                      <- Terraform for environment prod
    ├── .terraform.lock.hcl   <- Terraform lock file
    └── terragrunt.hcl        <- Terragrunt file
    └── env.yaml              <- environment related variables
    └── main.tf               <- environment modules
└── local                     <- Terraform for environment local
    ├── .terraform.lock.hcl   <- Terraform lock file
    └── terragrunt.hcl        <- Terragrunt file
    └── env.yaml              <- environment related variables
    └── main.tf               <- environment modules Каждый модуль включает файл main.tf, инкапсулирующий ресурсы модуля, а также файлы input.tf, output.tf, и variable.tfдля легкой настройки в разных средах.
Common-модуль
Предположим, что в common модуле мы настраиваем события реального времени, используя слушатель событий jboss-logging с некоторыми нестандартными конфигурациями. Ниже приведен пример того, как может выглядеть файл main.tf:
resource "keycloak_realm_events" "realm_events" {
  realm_id                     = var.realm_id
  events_enabled               = true
  events_expiration            = 1800
  admin_events_enabled         = true
  admin_events_details_enabled = true
  ]
  events_listeners = [
    "jboss-logging"
  ]
} Чтобы включить переменную realm_id, ее необходимо определить в variables.tf, как показано ниже:
variable "realm_id" {
  description = "Realm ID"
  type        = string
} Также стоит настроить используемые провайдеры в нашем модуле. В этом случае provider.tf будет выглядеть так:
terraform {
  required_providers {
    keycloak = {
      source = "mrparkers/keycloak"
    }
  }
} Модуль Master Realm
В realm-master модуле main.tf должен ссылаться на common. Вот пример того, как main.tf может выглядеть:
data "keycloak_realm" "master" {
  realm = "master"
}
module "realm-master" {
  source = "../../modules/common"
  realm_id = data.keycloak_realm.master.id
} Файл provider.tf настраиваем аналогично:
terraform {
  required_providers {
    keycloak = {
      source = "mrparkers/keycloak"
    }
  }
} Local environment
В main.tf нам необходимо определить главную область, чтобы ссылаться на realm-master модуль в нашем проекте.
# Define master realm
module "realm-master" {
  source = "../modules/realm-master"
} В каждой среде (например, prod, stage и local) есть env.yaml, содержащий все переменные, специфичные для этой среды.
Например, env.yaml для локальной среды может выглядеть так:
---
environment: local
url: http://localhost:8080/keycloak И, конечно же, не забудьте включить файл terragrunt-local.hcl, который должен быть определен в родительском модуле.
include "root" {
  path = find_in_parent_folders("terragrunt-local.hcl")
} Terragrunt очень полезен для сохранения конфигурации Don't Repeat Yourself (DRY). Например, файл terragrunt.hcl может выглядеть так:
# Generates the backend for all modules.
remote_state {
  backend = "s3"
  config  = {
    encrypt        = true
    key            = "keycloak/${path_relative_to_include()}/terraform.tfstate"
    region         = "<AWS REGION>"
    bucket         = "terraform-states"
    dynamodb_table = "terraform-lock"
  }
}
# Read the local "env.yaml" in every environment.
locals {
  vars        = yamldecode(file("${path_relative_to_include()}/env.yaml"))
  environment = local.vars.environment
  url         = local.vars.url
}
# Generate the "provider.tf" file for every module.
generate "provider" {
  path      = "provider.tf"
  if_exists = "overwrite"
  contents  = <<EOF
terraform {
  required_providers {
    keycloak = {
      source  = "mrparkers/keycloak"
      version = "4.4.0"
    }
    http = {
      source  = "hashicorp/http"
      version = "3.2.1"
    }
  }
}
data "http" "config" {
  url = "<INTERNAL CONFIGURATION URL>"
}
provider "keycloak" {
  client_id     = jsondecode(data.http.config.response_body).terraform-client-id
  client_secret = jsondecode(data.http.config.response_body).terraform-client-secret
  url           = "${local.url}"
}
EOF
}
# Generate the "backend.tf" file for every module.
generate "backend" {
  path      = "backend.tf"
  if_exists = "overwrite"
  contents  = <<EOF
terraform {
  backend "s3" {}
}
EOF
} В remote_state мы используем AWS S3 для хранения состояния наших конфигураций среды. Кроме того, мы генерируем backend и providerдля каждой среды.
Блок locals в основном используется для чтения env.yaml и назначения переменных.
Наконец, http config отвечает за выполнение HTTP-вызова туда, где вы безопасно храните конфигурации своей среды (по крайней мере, идентификатор клиента Terraform и секрет), для передачи их провайдеру keycloak.
Файл terragrunt-local.hcl похож на terragrunt.hcl, за исключением конфигурации удаленного состояния, которая в данном случае не нужна. Файл local в первую очередь предназначен для локального тестирования конфигурации.
Мы используем Docker Compose для запуска кластера Keycloak, что позволяет нам беспрепятственно запускать наши локальные конфигурации Terraform на нем.
version: '3'
volumes:
  postgres_data:
      driver: local
services:
  postgres:
      image: postgres
      volumes:
        - postgres_data:/var/lib/postgresql/data
      environment:
        POSTGRES_DB: keycloak
        POSTGRES_USER: keycloak
        POSTGRES_PASSWORD: password
      ports:
        - "5432:5432"
  keycloak:
      image: quay.io/keycloak/keycloak:23.0.6
      environment:
        KC_DB_USERNAME: keycloak
        KC_DB_PASSWORD: password
        KC_DB_URL_HOST: postgres
        KC_DB: postgres
        KC_DB_SCHEMA: public
        KC_HTTP_RELATIVE_PATH: /keycloak
        KC_HOSTNAME_ADMIN: 127.0.0.1
        KC_HOSTNAME: localhost
        KEYCLOAK_ADMIN: admin
        KEYCLOAK_ADMIN_PASSWORD: admin
      command:
        - start-dev
      ports:
        - "8080:8080"
        - "8787:8787"
      depends_on:
        - postgres
  config_keycloak:
    image: ubuntu
    volumes:
      - ./keycloak-docker-config.sh:/opt/keycloak-docker-config.sh
    command: ./opt/keycloak-docker-config.sh
    depends_on:
      - keycloak Скрипт keycloak-docker-config.sh в основном используется для настройки клиента с привилегиями админа, которые Terraform будет использовать во время своей работы.
#!/bin/bash
apt update -y && apt -y install jq curl
until $(curl --output /dev/null --silent --head --fail http://keycloak:8080/keycloak); do
    printf '.'
    sleep 5
done
# Get access token
TOKEN=$( \
  curl -X POST \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d "client_id=admin-cli" \
    -d "username=admin" \
    -d "password=admin" \
    -d "grant_type=password" \
    "http://keycloak:8080/keycloak/realms/master/protocol/openid-connect/token" | jq -r '.access_token')
# Create Terraform client (terraform/terraform)
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${TOKEN}" \
  -d '{"clientId": "terraform", "name": "terraform", "enabled": true, "publicClient": false, "secret": "terraform", "serviceAccountsEnabled": true}' \
  "http://keycloak:8080/keycloak/admin/realms/master/clients"
# Get the Terraform service account user ID
USER_ID=$( \
  curl -X GET \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer ${TOKEN}" \
    "http://keycloak:8080/keycloak/admin/realms/master/users?username=service-account-terraform" | jq -r '.[0].id')
# Get the admin role ID
ROLE_ID=$( \
  curl -X GET \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer ${TOKEN}" \
    "http://keycloak:8080/keycloak/admin/realms/master/roles" | jq -r '.[] | select(.name == "admin") | .id')
# Add the admin role to the Terraform service account user
curl -kv -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${TOKEN}" \
  -d '[{"id":"'"${ROLE_ID}"'", "name":"admin"}]' \
  "http://keycloak:8080/keycloak/admin/realms/master/users/$USER_ID/role-mappings/realm" Чтобы запустить его, откройте terminal и выполните следующую команду docker compose:
docker-compose up --build После того, как контейнеры docker-compose будут запущены, перейдите на http://localhost:8080/keycloak и войдите в систему, используя учетные данные admin/admin. Убедитесь, что клиент Terraform настроен в пределах главной области.
 Теперь пришло время запустить ваши локальные конфигурации Terraform. Откройте терминал и выполните следующие команды:
# Navigate to the local environment
$ cd local 
# Ensure that Terraform-related files, including the auto-generated backend.tf and provider.tf, are removed
$ rm -r backend.tf provider.tf terraform.tfstate terraform.tfstate.backup .terraform.lock.hcl .terraform 
# Initialize Terraform to create all necessary files
$ terragrunt init --terragrunt-config terragrunt-local.hcl 
# Apply the Terraform configurations
$ terragrunt apply --terragrunt-config terragrunt-local.hcl  Управление конфигурациями Keycloak с помощью Terraform может значительно упростить процесс разработки. Следуя шагам, описанным в этом руководстве, вы сможете настраивать и поддерживать среды Keycloak, обеспечивая согласованность и масштабируемость в своих проектах.
Узнайте об услуге devops support и закажите звонок у наших менеджеров. Поможем с любой задачей
Узнать больше