Agent skill
opentofu-keycloak-explorer
Explore and manage Keycloak identity and access management resources using OpenTofu/Terraform
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/opentofu-keycloak-explorer
Metadata
Additional technical details for this skill
- audience
- developers
- workflow
- identity-management
SKILL.md
OpenTofu Keycloak Explorer
What I do
I guide you through managing Keycloak identity and access management (IAM) resources using the Keycloak provider for OpenTofu/Terraform. I help you:
- Realm Management: Create and configure Keycloak realms
- Client Configuration: Setup OAuth2/OpenID Connect clients
- User and Role Management: Manage users, groups, and roles
- Authentication Flows: Configure authentication flows and mappers
- Best Practices: Follow Keycloak provider documentation patterns
When to use me
Use this skill when you need to:
- Automate Keycloak infrastructure as code
- Manage identity providers (GitHub, Google, Azure AD, etc.)
- Setup authentication and authorization flows
- Manage users, groups, and roles programmatically
- Configure client applications with OAuth2/OpenID Connect
- Implement fine-grained access control
Note: OpenTofu and Terraform are used interchangeably throughout this skill. OpenTofu is an open-source implementation of Terraform and maintains full compatibility with Terraform providers.
Prerequisites
- OpenTofu CLI installed: Install from https://opentofu.org/docs/intro/install/
- Keycloak Server: Running Keycloak instance (managed or self-hosted)
- Keycloak Admin Account: Credentials with admin privileges
- Basic IAM Knowledge: Understanding of OAuth2, OpenID Connect, and SAML
Provider Documentation
- Terraform Registry: https://registry.terraform.io/providers/keycloak/keycloak/latest/docs
- Latest Provider Version: keycloak/keycloak ~> 5.0.0
- Provider Source: https://github.com/mrparkers/terraform-provider-keycloak
Steps
Step 1: Install and Configure OpenTofu
# Verify OpenTofu installation
tofu version
# Initialize project
mkdir keycloak-terraform
cd keycloak-terraform
tofu init
Step 2: Configure Keycloak Provider
Create versions.tf:
terraform {
required_providers {
keycloak = {
source = "keycloak/keycloak"
version = "~> 5.0.0"
}
}
required_version = ">= 1.0"
}
# State backend configuration
backend "s3" {
bucket = "keycloak-state"
key = "terraform.tfstate"
region = "us-east-1"
}
Step 3: Configure Provider Connection
Create provider.tf:
provider "keycloak" {
# Method 1: Direct URL (local development)
url = "http://localhost:8080"
client_id = "admin-cli"
username = "admin"
password = "admin"
# Method 2: Managed Keycloak (e.g., Red Hat SSO)
url = "https://sso.example.com/auth"
client_id = "terraform"
username = var.keycloak_admin_username
password = var.keycloak_admin_password
# Method 3: Client Credentials (recommended for production)
url = "https://keycloak.example.com"
client_id = "terraform"
# Read from environment variable: KEYCLOAK_CLIENT_SECRET
}
Step 4: Configure Environment Variables
# For production usage, use environment variables
export KEYCLOAK_CLIENT_SECRET="your-client-secret"
# Or use variable file
cat > terraform.tfvars <<EOF
keycloak_admin_username = "admin"
keycloak_admin_password = "secure-password"
EOF
Step 5: Create Keycloak Realm
Create realm.tf:
resource "keycloak_realm" "example" {
realm = "example"
enabled = true
# Display settings
display_name = "Example Realm"
display_name_html = "<div class='kc-logo-text'><span>Example</span></div>"
# Security settings
ssl_required = "external"
# User registration
registration_allowed = true
registration_email_as_username = true
# Reset password
reset_password_allowed = true
edit_username_allowed = true
brute_force_protected = true
# Internationalization
internationalization_enabled = true
supported_locales = ["en", "es", "fr"]
default_locale = "en"
# Login theme
login_theme = "keycloak"
account_theme = "keycloak"
# SMTP settings (optional)
smtp_server {
host = "smtp.gmail.com"
port = 587
from = "noreply@example.com"
starttls = true
ssl = false
auth {
username = var.smtp_username
password = var.smtp_password
}
}
# Browser security headers
browser_security_headers {
content_security_policy_report_only = false
x_content_type_options = "nosniff"
x_robots_tag = "none"
x_frame_options = "SAMEORIGIN"
content_security_policy = "frame-src 'self'; frame-ancestors 'self'; object-src 'none';"
x_xss_protection = "1; mode=block"
strict_transport_security = "max-age=31536000; includeSubDomains"
}
}
Step 6: Create Identity Providers
Create identity_providers.tf:
# GitHub OAuth2
resource "keycloak_identity_provider" "github" {
realm = keycloak_realm.example.realm
alias = "github"
display_name = "GitHub"
provider_id = "github"
enabled = true
trust_email = true
first_broker_login_flow_alias = keycloak_authentication_flow.github.id
store_token = true
add_read_token_role_on_create = false
config {
client_id = var.github_client_id
client_secret = var.github_client_secret
use_jwks_url = true
}
}
# Google OAuth2
resource "keycloak_identity_provider" "google" {
realm = keycloak_realm.example.realm
alias = "google"
display_name = "Google"
provider_id = "google"
enabled = true
store_token = false
trust_email = true
first_broker_login_flow_alias = keycloak_authentication_flow.google.id
config {
client_id = var.google_client_id
client_secret = var.google_client_secret
hosted_domain = "example.com"
use_jwks_url = true
}
}
# Azure AD / Microsoft
resource "keycloak_identity_provider" "azure" {
realm = keycloak_realm.example.realm
alias = "azure"
display_name = "Microsoft"
provider_id = "azure"
enabled = true
trust_email = true
config {
client_id = var.azure_client_id
client_secret = var.azure_client_secret
tenant_id = var.azure_tenant_id
gui_order = 10
hide_on_login_page = false
}
}
Step 7: Create Authentication Flows
Create authentication.tf:
# Browser flow
resource "keycloak_authentication_flow" "browser" {
realm_id = keycloak_realm.example.id
alias = "browser"
description = "Browser based authentication"
provider_id = "basic-flow"
top_level = true
}
# GitHub flow
resource "keycloak_authentication_flow" "github" {
realm_id = keycloak_realm.example.id
alias = "github"
description = "GitHub authentication"
provider_id = "basic-flow"
top_level = true
}
# Reset credentials flow
resource "keycloak_authentication_flow" "reset_credentials" {
realm_id = keycloak_realm.example.id
alias = "reset credentials"
description = "Reset credentials for a user if they forgot their password or something"
provider_id = "basic-flow"
top_level = true
}
Step 8: Create User and Group
Create users.tf:
# Group
resource "keycloak_group" "developers" {
realm_id = keycloak_realm.example.id
name = "developers"
attributes = {
department = "engineering"
team = "platform"
}
}
# Subgroup
resource "keycloak_group" "frontend" {
realm_id = keycloak_realm.example.id
parent_id = keycloak_group.developers.id
name = "frontend"
}
# Role
resource "keycloak_role" "developer" {
realm_id = keycloak_realm.example.id
name = "developer"
description = "Developer role with API access"
attributes = {
access_level = "full"
}
}
# User
resource "keycloak_user" "admin_user" {
realm_id = keycloak_realm.example.id
username = "johndoe"
enabled = true
email = "john.doe@example.com"
first_name = "John"
last_name = "Doe"
# User attributes
attributes = {
job_title = "Senior Developer"
department = "Engineering"
}
# Initial password
initial_password {
value = var.user_password
temporary = false
}
# Add user to group
groups = [
keycloak_group.developers.id
]
# Assign roles
realm_roles = [
keycloak_role.developer.name
]
}
# Role mapping
resource "keycloak_group_roles" "developers_roles" {
realm_id = keycloak_realm.example.id
group_id = keycloak_group.developers.id
realm_roles = [
keycloak_role.developer.name
]
}
Step 9: Create Client Application
Create clients.tf:
# Web application (confidential client)
resource "keycloak_openid_client" "web_app" {
realm_id = keycloak_realm.example.id
client_id = "my-web-app"
name = "My Web Application"
enabled = true
# Access type
access_type = "CONFIDENTIAL"
client_authenticator_type = "client-secret"
standard_flow_enabled = true
direct_access_grants_enabled = true
service_accounts_enabled = true
valid_redirect_uris = [
"https://app.example.com/callback",
"https://app.example.com/silent-callback"
]
web_origins = ["https://app.example.com"]
# Logout settings
frontchannel_logout = true
frontchannel_logout_url = "https://app.example.com/logout"
backchannel_logout_url = "https://app.example.com/backchannel-logout"
# Token settings
access_token_lifespan = "3600"
client_session_idle = "1800"
client_session_max = "3600"
# Fine grain OpenID Connect configuration
consent_required = false
# Protocol mappers
protocol_mappers {
name = "username"
protocol = "openid-connect"
protocol_mapper = "user-attribute-mapper"
user_attribute = "username"
claim_name = "preferred_username"
json_type_label = "String"
add_to_id_token = true
add_to_access_token = true
}
protocol_mappers {
name = "email"
protocol = "openid-connect"
protocol_mapper = "user-attribute-mapper"
user_attribute = "email"
claim_name = "email"
json_type_label = "String"
add_to_id_token = true
add_to_access_token = true
}
}
# SPA application (public client)
resource "keycloak_openid_client" "spa_app" {
realm_id = keycloak_realm.example.id
client_id = "my-spa-app"
name = "My SPA Application"
enabled = true
access_type = "PUBLIC"
standard_flow_enabled = true
implicit_flow_enabled = false
direct_access_grants_enabled = false
service_accounts_enabled = false
# SPA settings
web_origins = ["+"]
valid_redirect_uris = [
"https://spa.example.com/callback"
]
# PKCE settings (recommended for SPAs)
pkce_code_challenge_method = "S256"
}
# Machine-to-Machine client
resource "keycloak_openid_client" "api_service" {
realm_id = keycloak_realm.example.id
client_id = "api-service"
name = "API Service"
enabled = true
access_type = "CONFIDENTIAL"
service_accounts_enabled = true
client_authenticator_type = "client-secret"
# No user interaction
standard_flow_enabled = false
direct_access_grants_enabled = false
}
Step 10: Configure Client Scopes
Create scopes.tf:
# Custom scope
resource "keycloak_openid_client_scope" "api_scope" {
realm_id = keycloak_realm.example.id
name = "api:read"
description = "API read access scope"
}
# Protocol mapper in scope
resource "keycloak_generic_protocol_mapper" "api_scope_mapper" {
realm_id = keycloak_realm.example.id
name = "api-read-mapper"
protocol = "openid-connect"
protocol_mapper = "user-attribute-mapper"
# Scope configuration
add_to_id_token = true
add_to_access_token = true
claim_name = "api_read"
user_attribute = "api_read"
# Add to scope
client_scope_id = keycloak_openid_client_scope.api_scope.id
}
Step 11: Define Variables
Create variables.tf:
variable "keycloak_admin_username" {
description = "Keycloak admin username"
type = string
sensitive = true
}
variable "keycloak_admin_password" {
description = "Keycloak admin password"
type = string
sensitive = true
}
variable "github_client_id" {
description = "GitHub OAuth2 client ID"
type = string
sensitive = true
}
variable "github_client_secret" {
description = "GitHub OAuth2 client secret"
type = string
sensitive = true
}
variable "google_client_id" {
description = "Google OAuth2 client ID"
type = string
sensitive = true
}
variable "google_client_secret" {
description = "Google OAuth2 client secret"
type = string
sensitive = true
}
variable "smtp_username" {
description = "SMTP username"
type = string
sensitive = true
}
variable "smtp_password" {
description = "SMTP password"
type = string
sensitive = true
}
Step 12: Initialize and Apply
# Initialize providers
tofu init
# Plan changes
tofu plan -out=tfplan
# Apply changes
tofu apply tfplan
Best Practices
Security
- Use Service Accounts: For production, use service account credentials instead of admin credentials
- Least Privilege: Grant only necessary permissions to service accounts
- Secure Secrets: Store sensitive data in environment variables or secret managers
- Enable SSL/TLS: Always use HTTPS in production environments
- Session Management: Set appropriate session timeouts
Organization
- Modular Configuration: Split resources into logical files (realm.tf, clients.tf, users.tf)
- Terraform Modules: Create reusable modules for common patterns
- State Management: Use remote backend with encryption and locking
- Environment Separation: Use workspaces or separate state files for dev/staging/prod
Authentication Flows
- Customize for Your Needs: Modify authentication flows based on requirements
- Multi-Factor Authentication: Enable MFA for sensitive applications
- Social Login: Configure identity providers (GitHub, Google, etc.)
- Password Policies: Set strong password policies
Client Configuration
- Use PKCE for SPAs: Recommended security practice for single-page applications
- Set Appropriate Scopes: Only request necessary scopes
- Configure Redirect URIs: Only allow trusted redirect URIs
- Logout Configuration: Implement proper logout flows (frontchannel and backchannel)
Common Issues
Issue: Provider Connection Failed
Symptom: Error Error: Failed to GET: http://localhost:8080/auth/realms/master/protocol/openid-connect/token
Solution:
# Verify Keycloak is running
curl http://localhost:8080/health/ready
# Check provider configuration
# Ensure URL includes /auth/ for Keycloak < 18
# Omit /auth/ for Keycloak >= 18
# Test credentials manually
curl -X POST http://localhost:8080/auth/realms/master/protocol/openid-connect/token \
-d "client_id=admin-cli" \
-d "username=admin" \
-d "password=admin" \
-d "grant_type=password"
Issue: Authentication Flow Not Found
Symptom: Error Error: Could not execute: Authentication flow not found
Solution:
# Ensure authentication flow is created before assigning
# Check flow existence:
tofu state list | grep authentication_flow
# Verify flow alias matches exactly
Issue: Client Registration Fails
Symptom: Error Error: Error creating client: HTTP 409 Conflict
Solution:
# Check if client already exists
tofu import keycloak_openid_client.web_app my-realm/my-web-app
# Or use import block in configuration
import {
to = keycloak_openid_client.web_app
id = "my-realm/my-web-app"
}
Issue: Identity Provider Configuration
Symptom: Error Error: Failed to configure identity provider
Solution:
# Verify OAuth2 credentials
# Check client ID and secret from provider console
# Ensure redirect URI matches in Keycloak
# Reference provider documentation:
# GitHub: https://docs.github.com/en/developers/apps/building-oauth-apps
# Google: https://developers.google.com/identity/protocols/oauth2
# Azure: https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow
Issue: User Creation with Password
Symptom: Password not set or temporary password not working
Solution:
# Ensure initial_password block is correctly configured
resource "keycloak_user" "user" {
username = "testuser"
enabled = true
initial_password {
value = "SecurePassword123!"
temporary = false
}
}
Issue: Protocol Mapper Not Working
Symptom: Claims not appearing in token
Solution:
# Check mapper configuration
# Verify claim_name and user_attribute match
# Ensure add_to_id_token or add_to_access_token is true
protocol_mappers {
name = "email"
protocol = "openid-connect"
protocol_mapper = "user-attribute-mapper"
user_attribute = "email"
claim_name = "email"
add_to_id_token = true
add_to_access_token = true
}
Reference Documentation
- Terraform Registry (Keycloak Provider): https://registry.terraform.io/providers/keycloak/keycloak/latest/docs
- Provider GitHub: https://github.com/mrparkers/terraform-provider-keycloak
- Keycloak Documentation: https://www.keycloak.org/documentation.html
- OpenTofu Documentation: https://opentofu.org/docs/
- OAuth2 Best Practices: https://datatracker.ietf.org/doc/html/rfc6749
Examples
Complete Realm Setup
# versions.tf
terraform {
required_providers {
keycloak = {
source = "keycloak/keycloak"
version = "~> 5.0.0"
}
}
}
# provider.tf
provider "keycloak" {
url = "https://keycloak.example.com"
client_id = "terraform"
client_secret = var.keycloak_client_secret
}
# realm.tf
resource "keycloak_realm" "production" {
realm = "production"
enabled = true
ssl_required = "external"
smtp_server {
host = "smtp.example.com"
port = 587
from = "noreply@example.com"
starttls = true
}
}
# clients.tf
resource "keycloak_openid_client" "dashboard" {
realm_id = keycloak_realm.production.id
client_id = "dashboard"
name = "Dashboard Application"
enabled = true
access_type = "PUBLIC"
standard_flow_enabled = true
valid_redirect_uris = ["https://dashboard.example.com/callback"]
web_origins = ["https://dashboard.example.com"]
protocol_mappers {
name = "email"
protocol = "openid-connect"
protocol_mapper = "user-attribute-mapper"
user_attribute = "email"
claim_name = "email"
add_to_id_token = true
add_to_access_token = true
}
}
Social Login Setup
# identity_providers.tf
resource "keycloak_identity_provider" "github" {
realm = keycloak_realm.production.id
alias = "github"
provider_id = "github"
enabled = true
config {
client_id = var.github_client_id
client_secret = var.github_client_secret
}
}
resource "keycloak_identity_provider" "google" {
realm = keycloak_realm.production.id
alias = "google"
provider_id = "google"
enabled = true
config {
client_id = var.google_client_id
client_secret = var.google_client_secret
}
}
User and Role Management
# users.tf
resource "keycloak_group" "admins" {
realm_id = keycloak_realm.production.id
name = "admins"
}
resource "keycloak_role" "admin" {
realm_id = keycloak_realm.production.id
name = "admin"
}
resource "keycloak_user" "alice" {
realm_id = keycloak_realm.production.id
username = "alice"
enabled = true
email = "alice@example.com"
initial_password {
value = "SecurePassword!"
temporary = false
}
realm_roles = [keycloak_role.admin.name]
groups = [keycloak_group.admins.id]
}
Tips and Tricks
- Use tofu import: Import existing Keycloak resources into state
- Validate Configuration: Run
tofu validatebefore applying - Use Workspaces: Manage multiple environments (dev, staging, prod)
- Backup State: Regularly backup Terraform state
- Monitor Changes: Use
tofu planto review changes before applying - Use Modules: Create reusable modules for common patterns
Next Steps
After mastering Keycloak provider, explore:
- opentofu-aws-explorer: AWS cloud provider
- opentofu-kubernetes-explorer: Kubernetes deployment provider
- Keycloak Admin Console: Learn more about Keycloak features
- Advanced Authentication: Configure advanced authentication flows and MFA
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?