WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit b3eca80

Browse files
committed
adding keycloak terrafrom setup
1 parent 4a7cf54 commit b3eca80

File tree

4 files changed

+285
-13
lines changed

4 files changed

+285
-13
lines changed

README.md

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# MinIO Azure Container App
22

3-
This repo deploys a MinIO Container to an **Azure Container Group** with Azure Application Gateway for SSL termination, IP restrictions, and Coraza WAF for comprehensive security protection.
3+
This repo deploys a MinIO Container to an **Azure Container Group** with Azure Application Gateway for SSL termination, IP restrictions, Coraza WAF for comprehensive security protection, and Keycloak for SSO authentication.
44

55
---
66

@@ -9,18 +9,24 @@ This repo deploys a MinIO Container to an **Azure Container Group** with Azure A
99
```mermaid
1010
flowchart TD
1111
subgraph External
12-
A[External Traffic<br>HTTPS:443 / 8443<br>IP Restricted]
12+
A[External Traffic<br>HTTPS:443 / 8443 / 8444<br>IP Restricted]
1313
end
1414
1515
A --> B[Azure Application Gateway<br>SSL Termination & Load Balancing<br>IP Restrictions via NSG]
1616
17-
B --> C[Coraza WAF Container<br>Ports: 8080, 8081<br>OWASP CRS + Rate Limiting]
17+
B --> C[Coraza WAF Container<br>Ports: 8080, 8081, 8082<br>OWASP CRS + Rate Limiting]
1818
1919
C -->|Port 8080| E[MinIO UI<br>Port 9001]
2020
C -->|Port 8081| F[MinIO API<br>Port 9000]
21+
C -->|Port 8082| K[Keycloak<br>Port 8080]
2122
2223
E --> G[Azure File Share / Storage Account]
2324
F --> G
25+
K --> H[PostgreSQL<br>Port 5432]
26+
K --> I[Azure File Share<br>Keycloak Data]
27+
H --> J[Azure File Share<br>Postgres Data]
28+
29+
E -.OIDC Auth.-> K
2430
2531
subgraph "Azure Virtual Network"
2632
subgraph "Application Gateway Subnet"
@@ -30,6 +36,8 @@ flowchart TD
3036
C
3137
E
3238
F
39+
K
40+
H
3341
end
3442
end
3543
```
@@ -38,11 +46,13 @@ flowchart TD
3846

3947
## Components
4048

41-
* **MinIO Container**: Runs the object storage service (ports 9000/9001 - internal only)
42-
* **Azure Application Gateway**: Provides SSL termination, load balancing, and IP restrictions (ports 443/8443 - externally exposed)
43-
* **Coraza WAF Container**: Modern WAF with OWASP Core Rule Set protecting both UI (8080) and API (8081)
49+
* **MinIO Container**: Runs the object storage service with OIDC authentication (ports 9000/9001 - internal only)
50+
* **Keycloak Container**: Identity provider for SSO authentication (port 8080 - internal, exposed via port 8444 externally)
51+
* **PostgreSQL Container**: Database backend for Keycloak (port 5432 - internal only)
52+
* **Azure Application Gateway**: Provides SSL termination, load balancing, and IP restrictions (ports 443/8443/8444 - externally exposed)
53+
* **Coraza WAF Container**: Modern WAF with OWASP Core Rule Set protecting MinIO UI (8080), API (8081), and Keycloak (8082)
4454
* **Network Security Group**: Controls inbound traffic with IP-based access restrictions
45-
* **Storage**: Uses Azure File Share for persistent data storage
55+
* **Storage**: Uses Azure File Shares for persistent data storage (MinIO data, Postgres data, Keycloak data)
4656
* **Virtual Network**: Isolates components with dedicated subnets for Application Gateway and Container Instances
4757

4858
---
@@ -52,6 +62,7 @@ flowchart TD
5262
* Azure Subscription
5363
* Azure Resource Group
5464
* SSL Certificate (.pfx file) for HTTPS traffic
65+
* Credentials for PostgreSQL and Keycloak (provided as Terraform variables)
5566

5667
---
5768

@@ -65,12 +76,28 @@ flowchart TD
6576
https://your-domain.region.azurecontainer.io/
6677
```
6778

79+
You can log in using:
80+
- **Root credentials**: MinIO root user/password (configured via Terraform variables)
81+
- **SSO**: Click "Login with SSO" to authenticate via Keycloak
82+
6883
**S3 API (for applications/tools):**
6984

7085
```
7186
https://your-domain.region.azurecontainer.io:8443/
7287
```
7388

89+
### Accessing Keycloak
90+
91+
**Admin Console:**
92+
93+
```
94+
https://your-domain.region.azurecontainer.io:8444/
95+
```
96+
97+
Default realm: `minio_realm`
98+
- Pre-configured with OpenID client `minio-client`
99+
- Test user: `testuser` with role `readonly` (credentials in `keycloak-minio-docker/minio-realm-config.json`)
100+
74101
### Using MinIO Client (mc)
75102

76103
1. **Install MinIO Client:**
@@ -109,12 +136,12 @@ aws s3 ls --endpoint-url https://your-domain.region.azurecontainer.io:8443 --no-
109136

110137
## Resources Created
111138

112-
* **Application Gateway**: Provides SSL termination, load balancing, and public access
139+
* **Application Gateway**: Provides SSL termination, load balancing, and public access (ports 443, 8443, 8444)
113140
* **Virtual Network**: Network isolation with dedicated subnets
114141
* **Network Security Group**: IP-based access restrictions
115-
* **Container Group**: Hosts MinIO and Coraza WAF containers
142+
* **Container Group**: Hosts MinIO, Keycloak, PostgreSQL, and Coraza WAF containers
116143
* **Storage Account**: Provides persistent storage
117-
* **Storage Share**: Azure File Share for MinIO data
144+
* **Storage Shares**: Azure File Shares for MinIO data, PostgreSQL data, and Keycloak data
118145
* **Key Vault**: Stores SSL certificates securely
119146
* **Log Analytics Workspace**: For monitoring and logs
120147

main.tf

Lines changed: 196 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,18 @@ resource "azurerm_storage_share" "minio_share" {
7171
quota = var.storage_share_size
7272
}
7373

74+
resource "azurerm_storage_share" "postgres_share" {
75+
name = "postgresstorageshare"
76+
storage_account_id = azurerm_storage_account.minio_storage_account.id
77+
quota = 10
78+
}
79+
80+
resource "azurerm_storage_share" "keycloak_share" {
81+
name = "keycloakstorageshare"
82+
storage_account_id = azurerm_storage_account.minio_storage_account.id
83+
quota = 10
84+
}
85+
7486
data "azurerm_client_config" "current" {}
7587

7688
resource "azurerm_key_vault" "minio_kv" {
@@ -184,6 +196,21 @@ resource "azurerm_network_security_rule" "allow_https_api" {
184196
network_security_group_name = azurerm_network_security_group.agw_nsg.name
185197
}
186198

199+
resource "azurerm_network_security_rule" "allow_https_keycloak" {
200+
count = length(local.allowed_ips_list)
201+
name = "AllowHTTPS-Keycloak-${count.index}"
202+
priority = 250 + count.index
203+
direction = "Inbound"
204+
access = "Allow"
205+
protocol = "Tcp"
206+
source_port_range = "*"
207+
destination_port_range = "8444"
208+
source_address_prefix = local.allowed_ips_list[count.index]
209+
destination_address_prefix = "*"
210+
resource_group_name = azurerm_resource_group.minio_rg.name
211+
network_security_group_name = azurerm_network_security_group.agw_nsg.name
212+
}
213+
187214
resource "azurerm_network_security_rule" "allow_agw_management" {
188215
name = "AllowApplicationGatewayManagement"
189216
priority = 300
@@ -262,6 +289,11 @@ resource "azurerm_application_gateway" "minio_agw" {
262289
port = 8443
263290
}
264291

292+
frontend_port {
293+
name = "https-keycloak"
294+
port = 8444
295+
}
296+
265297
ssl_certificate {
266298
name = "minio-cert"
267299
key_vault_secret_id = azurerm_key_vault_certificate.minio_cert.secret_id
@@ -296,6 +328,18 @@ resource "azurerm_application_gateway" "minio_agw" {
296328
pick_host_name_from_backend_http_settings = false
297329
}
298330

331+
probe {
332+
name = "keycloak-health-probe"
333+
protocol = "Http"
334+
path = "/health/ready"
335+
host = azurerm_container_group.minio_aci_container_group.ip_address
336+
interval = 30
337+
timeout = 20
338+
unhealthy_threshold = 3
339+
port = 8082
340+
pick_host_name_from_backend_http_settings = false
341+
}
342+
299343
backend_http_settings {
300344
name = "ui-http"
301345
port = 8080
@@ -327,6 +371,21 @@ resource "azurerm_application_gateway" "minio_agw" {
327371

328372
}
329373

374+
backend_http_settings {
375+
name = "keycloak-http"
376+
port = 8082
377+
protocol = "Http"
378+
request_timeout = 300
379+
pick_host_name_from_backend_address = false
380+
cookie_based_affinity = "Disabled"
381+
probe_name = "keycloak-health-probe"
382+
connection_draining {
383+
enabled = true
384+
drain_timeout_sec = 300
385+
}
386+
387+
}
388+
330389
http_listener {
331390
name = "listener-ui"
332391
frontend_ip_configuration_name = "public-ip"
@@ -343,6 +402,14 @@ resource "azurerm_application_gateway" "minio_agw" {
343402
ssl_certificate_name = "minio-cert"
344403
}
345404

405+
http_listener {
406+
name = "listener-keycloak"
407+
frontend_ip_configuration_name = "public-ip"
408+
frontend_port_name = "https-keycloak"
409+
protocol = "Https"
410+
ssl_certificate_name = "minio-cert"
411+
}
412+
346413
request_routing_rule {
347414
name = "rule-ui"
348415
rule_type = "Basic"
@@ -361,6 +428,15 @@ resource "azurerm_application_gateway" "minio_agw" {
361428
priority = 20
362429
}
363430

431+
request_routing_rule {
432+
name = "rule-keycloak"
433+
rule_type = "Basic"
434+
http_listener_name = "listener-keycloak"
435+
backend_address_pool_name = "coraza-backend-pool"
436+
backend_http_settings_name = "keycloak-http"
437+
priority = 30
438+
}
439+
364440
identity {
365441
type = "UserAssigned"
366442
identity_ids = [azurerm_user_assigned_identity.agw_identity.id]
@@ -388,6 +464,116 @@ resource "azurerm_container_group" "minio_aci_container_group" {
388464
}
389465
}
390466

467+
container {
468+
name = "postgres"
469+
image = "postgres:16-alpine"
470+
cpu = "0.5"
471+
memory = "1.0"
472+
cpu_limit = 1.0
473+
memory_limit = 1.5
474+
475+
environment_variables = {
476+
POSTGRES_DB = var.postgres_db
477+
POSTGRES_USER = var.postgres_user
478+
POSTGRES_PASSWORD = var.postgres_password
479+
}
480+
481+
ports {
482+
port = 5432
483+
protocol = "TCP"
484+
}
485+
486+
volume {
487+
name = "postgres-data"
488+
mount_path = "/var/lib/postgresql/data"
489+
read_only = false
490+
storage_account_name = azurerm_storage_account.minio_storage_account.name
491+
storage_account_key = azurerm_storage_account.minio_storage_account.primary_access_key
492+
share_name = azurerm_storage_share.postgres_share.name
493+
}
494+
495+
liveness_probe {
496+
exec = ["pg_isready", "-U", var.postgres_user, "-d", var.postgres_db]
497+
498+
initial_delay_seconds = 30
499+
period_seconds = 10
500+
timeout_seconds = 5
501+
failure_threshold = 3
502+
}
503+
}
504+
505+
container {
506+
name = "keycloak"
507+
image = "quay.io/keycloak/keycloak:latest"
508+
cpu = "1.0"
509+
memory = "2.0"
510+
cpu_limit = 1.0
511+
memory_limit = 2.5
512+
513+
environment_variables = {
514+
KC_BOOTSTRAP_ADMIN_USERNAME = var.keycloak_admin_user
515+
KC_BOOTSTRAP_ADMIN_PASSWORD = var.keycloak_admin_password
516+
KC_HTTP_ENABLED = "true"
517+
KC_HOSTNAME_STRICT = "false"
518+
KC_PROXY_HEADERS = "xforwarded"
519+
KEYCLOAK_IMPORT = "/opt/keycloak/data/import/realm-config.json"
520+
KC_DB = "postgres"
521+
KC_DB_URL = "jdbc:postgresql://localhost/${var.postgres_db}"
522+
KC_DB_USERNAME = var.postgres_user
523+
KC_DB_PASSWORD = var.postgres_password
524+
}
525+
526+
ports {
527+
port = 8080
528+
protocol = "TCP"
529+
}
530+
531+
volume {
532+
name = "keycloak-realm-config"
533+
mount_path = "/opt/keycloak/data/import"
534+
read_only = true
535+
536+
secret = {
537+
"minio-realm-config.json" = filebase64("${path.module}/keycloak-minio-docker/minio-realm-config.json")
538+
}
539+
}
540+
541+
volume {
542+
name = "keycloak-data"
543+
mount_path = "/opt/keycloak/data/h2"
544+
read_only = false
545+
storage_account_name = azurerm_storage_account.minio_storage_account.name
546+
storage_account_key = azurerm_storage_account.minio_storage_account.primary_access_key
547+
share_name = azurerm_storage_share.keycloak_share.name
548+
}
549+
550+
commands = ["start", "--import-realm"]
551+
552+
liveness_probe {
553+
http_get {
554+
path = "/health/live"
555+
port = 8080
556+
scheme = "http"
557+
}
558+
initial_delay_seconds = 120
559+
period_seconds = 30
560+
timeout_seconds = 10
561+
failure_threshold = 3
562+
}
563+
564+
readiness_probe {
565+
http_get {
566+
path = "/health/ready"
567+
port = 8080
568+
scheme = "http"
569+
}
570+
initial_delay_seconds = 60
571+
period_seconds = 10
572+
timeout_seconds = 5
573+
failure_threshold = 3
574+
}
575+
}
576+
391577
container {
392578
name = "minio"
393579
image = var.minio_image
@@ -404,9 +590,16 @@ resource "azurerm_container_group" "minio_aci_container_group" {
404590
protocol = "TCP"
405591
}
406592
environment_variables = {
407-
MINIO_ROOT_USER = var.minio_root_user
408-
MINIO_ROOT_PASSWORD = var.minio_root_password
409-
MINIO_BROWSER_REDIRECT_URL = "https://${azurerm_public_ip.agw_pip.fqdn}"
593+
MINIO_ROOT_USER = var.minio_root_user
594+
MINIO_ROOT_PASSWORD = var.minio_root_password
595+
MINIO_BROWSER_REDIRECT_URL = "https://${azurerm_public_ip.agw_pip.fqdn}"
596+
MINIO_IDENTITY_OPENID_CONFIG_URL = "http://localhost:8082/realms/minio_realm/.well-known/openid-configuration"
597+
MINIO_IDENTITY_OPENID_CLIENT_ID = "minio-client"
598+
MINIO_IDENTITY_OPENID_CLIENT_SECRET = var.keycloak_client_secret
599+
MINIO_IDENTITY_OPENID_CLAIM_NAME = "policy"
600+
MINIO_IDENTITY_OPENID_SCOPES = "openid,profile,email"
601+
MINIO_IDENTITY_OPENID_REDIRECT_URI = "https://${azurerm_public_ip.agw_pip.fqdn}/oauth_callback"
602+
MINIO_IDENTITY_OPENID_DISPLAY_NAME = "Login with SSO"
410603
}
411604

412605
volume {

outputs.tf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ output "s3_api_url" {
88
value = "https://${azurerm_public_ip.agw_pip.fqdn}:8443"
99
}
1010

11+
output "keycloak_url" {
12+
description = "Keycloak admin console URL"
13+
value = "https://${azurerm_public_ip.agw_pip.fqdn}:8444"
14+
}
15+
1116
output "fqdn" {
1217
description = "Fully qualified domain name"
1318
value = azurerm_public_ip.agw_pip.fqdn

0 commit comments

Comments
 (0)