## 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 🎉