## Introduction Learn how to deploy Keycloak as an Identity and Access Management (IAM) solution using Terraform on Atlas Cloud. This guide provides a complete infrastructure-as-code (IaC) approach for automated, repeatable deployments. ## Prerequisites Before you begin, ensure you have: - Terraform installed on your local machine - Atlas Cloud account with API access - CloudStack API credentials (API key and secret key) - Basic understanding of Terraform concepts ## Terraform Overview The provided Terraform configuration creates: - A Virtual Machine with Ubuntu 24.04 LTS - PostgreSQL database - Keycloak server with automated setup - Complete network configuration with public IP, port forwarding, and firewall rules ## Step 1: Set Up Your Working Directory Create a new directory for your Keycloak deployment: ```bash mkdir keycloak-deployment cd keycloak-deployment ``` Create the configuration files as shown below. The complete code is provided - no external file downloads needed. ## Step 2: Get Your Atlas API Credentials Before configuring Terraform, you need your Atlas Cloud Platform API credentials: 1. Log in to [alpha.runatlas.is](https://alpha.runatlas.is) 2. Click your profile in the top-right corner 3. Wait 10 seconds for your API keys to appear in the user card 4. If no keys appear, click "Generate new API/Secret keys" 5. Copy the API Key and Secret Key from the UI ## Step 3: Create Terraform Configuration Files Create the following files in your project directory: ### `main.tf` ```hcl terraform { required_providers { cloudstack = { source = "cloudstack/cloudstack" version = "0.6.0-rc3" } } } provider "cloudstack" { api_url = var.cloudstack_api_url api_key = var.cloudstack_api_key secret_key = var.cloudstack_secret_key } # Create a network for Keycloak resource "cloudstack_network" "keycloak_network" { name = "keycloak-network" display_text = "Network for Keycloak IAM Server" cidr = "10.1.0.0/24" network_offering = var.network_offering zone = var.zone } # Create a virtual machine for Keycloak resource "cloudstack_instance" "keycloak" { name = "keycloak-server" display_name = "Keycloak IAM Server" service_offering = var.instance_service_offering template = var.instance_template zone = var.zone network = cloudstack_network.keycloak_network.name # User data script for initial setup user_data = templatefile("${path.module}/cloud-init.yaml", { admin_password = var.keycloak_admin_password db_password = var.keycloak_db_password }) tags = { Name = "keycloak-server" Environment = var.environment Purpose = "IAM" } } # Associate public IP address resource "cloudstack_ipaddress" "keycloak_ip" { network = cloudstack_network.keycloak_network.name } # Create port forwarding rules for Keycloak resource "cloudstack_port_forward" "keycloak_http" { ip_address_id = cloudstack_ipaddress.keycloak_ip.id forward { protocol = "tcp" publicport = 80 privateport = 8080 virtualmachine = cloudstack_instance.keycloak.id } } resource "cloudstack_port_forward" "keycloak_https" { ip_address_id = cloudstack_ipaddress.keycloak_ip.id forward { protocol = "tcp" publicport = 443 privateport = 8443 virtualmachine = cloudstack_instance.keycloak.id } } # Create firewall rules resource "cloudstack_firewall" "keycloak_firewall" { ip_address_id = cloudstack_ipaddress.keycloak_ip.id rule { protocol = "tcp" start_port = 80 end_port = 80 cidr_list = ["0.0.0.0/0"] } rule { protocol = "tcp" start_port = 443 end_port = 443 cidr_list = ["0.0.0.0/0"] } rule { protocol = "tcp" start_port = 22 end_port = 22 cidr_list = ["0.0.0.0/0"] } } # Output the public IP and access information output "keycloak_public_ip" { description = "Public IP address of the Keycloak server" value = cloudstack_ipaddress.keycloak_ip.ip_address } output "keycloak_admin_url" { description = "URL for Keycloak admin console" value = "http://${cloudstack_ipaddress.keycloak_ip.ip_address}/admin" } output "keycloak_login_url" { description = "URL for Keycloak login page" value = "http://${cloudstack_ipaddress.keycloak_ip.ip_address}/" } ``` ### `variables.tf` ```hcl variable "cloudstack_api_url" { description = "CloudStack API URL" type = string sensitive = true } variable "cloudstack_api_key" { description = "CloudStack API key" type = string sensitive = true } variable "cloudstack_secret_key" { description = "CloudStack secret key" type = string sensitive = true } variable "zone" { description = "CloudStack zone name" type = string default = "Atlas-alpha" } variable "instance_service_offering" { description = "Instance service offering (CPU, memory configuration)" type = string default = "Medium Instance" } variable "instance_template" { description = "Instance template (OS image)" type = string default = "Ubuntu 24.04 LTS" } variable "network_offering" { description = "Network offering for the Keycloak network" type = string default = "DefaultSharedNetworkOffering" } variable "environment" { description = "Environment tag for resources" type = string default = "production" } variable "keycloak_admin_password" { description = "Password for Keycloak admin user" type = string sensitive = true } variable "keycloak_db_password" { description = "Password for Keycloak PostgreSQL database" type = string sensitive = true } ``` ### `cloud-init.yaml` ```yaml #cloud-config package_update: true package_upgrade: true packages: - openjdk-21-jdk - postgresql - postgresql-contrib - wget - unzip - nginx runcmd: # Create keycloak user - useradd -r -s /bin/false keycloak # Download and install Keycloak - cd /tmp - wget -q https://github.com/keycloak/keycloak/releases/download/23.0.0/keycloak-23.0.0.tar.gz - tar -xzf keycloak-23.0.0.tar.gz - mv keycloak-23.0.0 /opt/keycloak - chown -R keycloak:keycloak /opt/keycloak # Configure PostgreSQL - sudo -u postgres psql -c "CREATE USER keycloak WITH PASSWORD '${db_password}';" - sudo -u postgres psql -c "CREATE DATABASE keycloak OWNER keycloak;" - sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE keycloak TO keycloak;" # Configure PostgreSQL for Keycloak - echo "listen_addresses = 'localhost'" >> /etc/postgresql/16/main/postgresql.conf - systemctl restart postgresql # Create Keycloak configuration - cat > /opt/keycloak/conf/keycloak.conf << EOF db=postgres db-url=jdbc:postgresql://localhost:5432/keycloak db-username=keycloak db-password=${db_password} http-port=8080 https-port=8443 hostname=localhost production-mode=true EOF # Create systemd service for Keycloak - cat > /etc/systemd/system/keycloak.service << 'EOF' [Unit] Description=Keycloak Server After=network.target postgresql.service [Service] Type=idle User=keycloak Group=keycloak ExecStart=/opt/keycloak/bin/kc.sh start TimeoutStartSec=600 TimeoutStopSec=600 Restart=always RestartSec=10 [Install] WantedBy=multi-user.target EOF # Enable and start services - systemctl daemon-reload - systemctl enable keycloak - systemctl start keycloak - systemctl enable postgresql # Wait for Keycloak to start and create admin user - sleep 30 - /opt/keycloak/bin/add-user-keycloak.sh -u admin -p '${admin_password}' --realm master # Restart Keycloak to apply admin user - systemctl restart keycloak final_message: "Keycloak IAM server has been successfully configured!" ``` ### `terraform.tfvars` ```hcl # CloudStack Configuration cloudstack_api_url = "https://alpha.runatlas.is/client/api" cloudstack_api_key = "your-copied-api-key" cloudstack_secret_key = "your-copied-secret-key" # Infrastructure Configuration zone = "Atlas-alpha" instance_service_offering = "Medium Instance" instance_template = "Ubuntu 24.04 LTS" network_offering = "DefaultSharedNetworkOffering" environment = "production" # Keycloak Configuration keycloak_admin_password = "YourSecureAdminPassword123!" keycloak_db_password = "YourSecureDBPassword456!" ``` **Important**: Replace the placeholder values with your actual Atlas Cloud Platform configuration. For additional examples and advanced configurations, see the [RunAtlas Terraform Examples](https://github.com/RunAtlas/examples-terraform) repository (coming soon). ## Step 4: Initialize Terraform Initialize the Terraform working directory: ```bash terraform init ``` This will download the CloudStack provider plugin and prepare the environment. ## Step 5: Review the Deployment Plan Generate and review the execution plan: ```bash terraform plan ``` Terraform will show you what resources will be created: - `cloudstack_network.keycloak_network` - Network for the Keycloak server - `cloudstack_instance.keycloak` - The Keycloak virtual machine - `cloudstack_ipaddress.keycloak_ip` - Public IP address - `cloudstack_port_forward.keycloak_http` - HTTP port forwarding rule - `cloudstack_port_forward.keycloak_https` - HTTPS port forwarding rule - `cloudstack_firewall.keycloak_firewall` - Firewall rules for security ## Step 6: Deploy the Infrastructure Apply the configuration to create the resources: ```bash terraform apply ``` Type `yes` when prompted to confirm the deployment. Terraform will: 1. Create the network infrastructure 2. Provision the virtual machine with Keycloak 3. Assign a public IP address 4. Configure port forwarding and firewall rules 5. Execute the cloud-init script for automated setup The deployment typically takes 5-10 minutes to complete. ## Step 7: Access Your Keycloak Server Once Terraform completes the deployment: ### Access the Admin Console Once deployment completes, Terraform will output the access information: ```toml keycloak_public_ip = "203.0.113.123" keycloak_admin_url = "http://203.0.113.123/admin" keycloak_login_url = "http://203.0.113.123/" ``` 1. Open your web browser and navigate to the admin URL from the output 2. Log in with: - **Username**: `admin` - **Password**: The password you set in `terraform.tfvars` ### Verify the Setup 1. Check that you can access the Keycloak admin console 2. Verify the server status in the admin panel 3. Test creating a test realm and user ## Understanding the Configuration ### Main Components **Virtual Machine Configuration** (`main.tf`): ```hcl resource "cloudstack_instance" "keycloak" { name = "keycloak-server" display_name = "Keycloak IAM Server" service_offering = var.instance_service_offering template = var.instance_template zone = var.zone user_data = templatefile("${path.module}/cloud-init.yaml", {...}) tags = { Name = "keycloak-server" Environment = var.environment Purpose = "IAM" } } ``` **Note**: All network configuration including public IP, port forwarding, and firewall rules is handled automatically by Terraform. **Network Setup**: ```hcl resource "cloudstack_network" "keycloak_network" { name = "keycloak-network" display_text = "Network for Keycloak IAM Server" cidr = "10.1.0.0/24" network_offering = var.network_offering zone = var.zone } ``` **Port Forwarding**: ```hcl resource "cloudstack_port_forward" "keycloak_http" { ip_address_id = cloudstack_ipaddress.keycloak_ip.id forward { protocol = "tcp" publicport = 80 privateport = 8080 virtualmachine = cloudstack_instance.keycloak.id } } ``` ### Cloud-Init Automation The `cloud-init.yaml` script handles: - Package installation (Java, PostgreSQL, Keycloak) - Database setup and configuration - Keycloak service configuration - Admin user creation - Nginx reverse proxy setup ## Customization Options ### Scaling Resources Modify the `terraform.tfvars` file to adjust resources: ```hcl # For higher performance instance_service_offering = "Large Instance" # More CPU/RAM ``` ### Custom Domain To use a custom domain, update the cloud-init script: ```yaml # In cloud-init.yaml hostname=your-domain.com ``` ### SSL/TLS Configuration For production deployments, configure HTTPS: 1. Obtain SSL certificates 2. Update Nginx configuration 3. Modify Keycloak to use HTTPS ## Managing Your Deployment ### Check Status ```bash # Check Terraform state terraform show # List all resources terraform state list ``` ### Update Configuration 1. Modify your `.tf` files or `terraform.tfvars` 2. Run `terraform plan` to see changes 3. Apply updates with `terraform apply` ### Backup and Restore **Backup Terraform State**: ```bash cp terraform.tfstate terraform.tfstate.backup ``` **Backup Keycloak Data**: ```bash # SSH into the server ssh ubuntu@<your-public-ip> # Backup PostgreSQL sudo -u postgres pg_dump keycloak > keycloak_backup.sql ``` ## Cleanup To remove all resources and avoid charges: ```bash terraform destroy ``` Type `yes` to confirm the destruction of all created resources. ## Best Practices 1. **Version Control**: Store your Terraform code in Git 2. **State Management**: Use remote state storage for team collaboration 3. **Security**: Use environment variables for sensitive data 4. **Monitoring**: Set up monitoring for your Keycloak instance 5. **Backups**: Regularly backup both Terraform state and Keycloak data Congratulations! You've successfully deployed Keycloak using Terraform on Atlas Cloud 🎉