diff --git a/.github/workflows/terraform-ci.yml b/.github/workflows/terraform-ci.yml
deleted file mode 100644
index cf3f91c..0000000
--- a/.github/workflows/terraform-ci.yml
+++ /dev/null
@@ -1,104 +0,0 @@
-name: 'Terraform Module CI'
-
-on:
- push:
- branches:
- - main
- paths:
- - '**/*.tf'
- pull_request:
- branches:
- - main
- paths:
- - '**/*.tf'
- workflow_dispatch:
-
-permissions:
- contents: read
- pull-requests: write
-
-jobs:
- validate:
- name: 'Validate Module'
- runs-on: self-hosted
-
- steps:
- - name: Checkout
- uses: actions/checkout@v3
-
- - name: Setup Terraform
- uses: hashicorp/setup-terraform@v2
- with:
- terraform_version: 1.5.0
-
- - name: Terraform Init
- run: |
- terraform init -backend=false
-
- - name: Terraform Format
- run: |
- terraform fmt -check
-
- - name: Terraform Validate
- run: |
- terraform validate
-
- - name: Run tflint
- uses: terraform-linters/setup-tflint@v3
- if: github.event_name == 'pull_request'
-
- - name: Lint Terraform
- if: github.event_name == 'pull_request'
- run: |
- tflint --format compact
-
- - name: Run Checkov
- uses: bridgecrewio/checkov-action@master
- with:
- directory: .
- framework: terraform
- skip_check: CKV_AWS_115,CKV_AWS_116
- quiet: true
- soft_fail: true
- output_format: sarif
- output_file: checkov-results.sarif
-
- release:
- name: 'Create Release'
- needs: validate
- if: github.ref == 'refs/heads/main' && github.event_name == 'push'
- runs-on: self-hosted
- permissions:
- contents: write
-
- steps:
- - uses: actions/checkout@v3
- with:
- fetch-depth: 0
-
- - name: Setup Python
- uses: actions/setup-python@v4
- with:
- python-version: '3.9'
-
- - name: Install Commitizen
- run: |
- pip install commitizen
-
- - name: Bump Version and Generate Changelog
- id: cz
- run: |
- cz bump --yes
- echo "new_version=$(cz version --project)" >> $GITHUB_OUTPUT
- echo "changelog=$(cz changelog --dry-run)" >> $GITHUB_OUTPUT
-
- - name: Create Release
- uses: actions/create-release@v1
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- with:
- tag_name: v${{ steps.cz.outputs.new_version }}
- release_name: Release v${{ steps.cz.outputs.new_version }}
- draft: false
- prerelease: false
- body: ${{ steps.cz.outputs.changelog }}
diff --git a/.github/workflows/terraform-release.yaml b/.github/workflows/terraform-release.yaml
new file mode 100644
index 0000000..04b96db
--- /dev/null
+++ b/.github/workflows/terraform-release.yaml
@@ -0,0 +1,40 @@
+name: Terraform CI/CD
+on:
+ workflow_dispatch:
+ pull_request:
+ types: [closed]
+ branches:
+ - main
+jobs:
+ terraform-ci-cd:
+ runs-on: 229685449397
+ permissions:
+ contents: write
+
+ steps:
+ - name: Checkout code
+ uses: CSVD/gh-actions-checkout@v4
+
+ - name: Setup GITHUB Credentials
+ id: github_credentials
+ uses: CSVD/gh-auth@main
+ with:
+ github_app_pem_file: ${{ secrets.GH_APP_PEM_FILE }}
+ github_app_installation_id: ${{ vars.GH_APP_INSTALLATION_ID }}
+ github_app_id: ${{ vars.GH_APP_ID }}
+
+ - name: Setup GitHub CLI
+ run: |
+ # Force manual authentication since setup-git might not work with GitHub Enterprise
+ echo "${{ steps.github_credentials.outputs.github_token }}" > /tmp/token.txt
+ gh auth login --with-token --hostname "github.e.it.census.gov" < /tmp/token.txt
+ rm /tmp/token.txt
+
+ # Test GitHub CLI auth status
+ gh auth status || echo "GitHub CLI authentication failed"
+
+ - name: Run Release Action
+ uses: CSVD/releaser@main
+ with:
+ github-token: ${{ steps.github_credentials.outputs.github_token }}
+ working-directory: '.'
diff --git a/.github/workflows/terraform-validate.yaml b/.github/workflows/terraform-validate.yaml
new file mode 100644
index 0000000..ac349eb
--- /dev/null
+++ b/.github/workflows/terraform-validate.yaml
@@ -0,0 +1,42 @@
+name: Terraform Validate
+on:
+ pull_request:
+ workflow_dispatch:
+
+jobs:
+
+ terraform-validate:
+ runs-on: "229685449397"
+ permissions:
+ contents: write
+ steps:
+ - name: Checkout code
+ uses: CSVD/gh-actions-checkout@v4
+
+ - name: Setup Terraform
+ uses: CSVD/gh-actions-setup-terraform@v2
+ with:
+ terraform_version: '1.10.5'
+
+ - name: Validate Terraform Configuration
+ id: validate
+ uses: CSVD/terraform-validate@main
+
+ - name: Check Validation/Test Results
+ if: always()
+ run: |
+ # Set default values if outputs are empty
+ IS_VALID="${{ steps.validate.outputs.is_valid }}"
+ TESTS_PASSED="${{ steps.validate.outputs.tests_passed }}"
+
+ # If outputs are empty, set them to false
+ [ -z "$IS_VALID" ] && IS_VALID="false"
+ [ -z "$TESTS_PASSED" ] && TESTS_PASSED="false"
+
+ if [[ "$IS_VALID" != "true" || "$TESTS_PASSED" != "true" ]]; then
+ echo "Validation or test errors found:"
+ echo "${{ steps.validate.outputs.stderr }}"
+ exit 1
+ else
+ echo "All validations and tests passed successfully!"
+ fi
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 7d247a5..7ef969f 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -47,7 +47,7 @@ repos:
# Terraform Hooks
- repo: https://github.com/antonbabenko/pre-commit-terraform
- rev: v1.97.3 # Get the latest from: https://github.com/antonbabenko/pre-commit-terraform/releases
+ rev: v1.98.0 # Get the latest from: https://github.com/antonbabenko/pre-commit-terraform/releases
hooks:
- id: terraform_fmt
args:
@@ -104,6 +104,6 @@ repos:
# - --hook-config=--parallelism-ci-cpu-cores=2
- repo: https://github.com/ljnsn/cz-conventional-gitmoji
- rev: v0.6.1
+ rev: v0.7.0
hooks:
- id: conventional-gitmoji
diff --git a/README.md b/README.md
index 9e26efa..95208a2 100644
--- a/README.md
+++ b/README.md
@@ -62,6 +62,7 @@ Common issues and solutions:
| [terraform](#requirement\_terraform) | >= 0.13 |
| [aws](#requirement\_aws) | ~> 5.14 |
| [helm](#requirement\_helm) | ~> 2.11 |
+| [keycloak](#requirement\_keycloak) | >= 5.0.0 |
| [kubernetes](#requirement\_kubernetes) | ~> 2.23 |
| [null](#requirement\_null) | ~> 3.2 |
| [random](#requirement\_random) | ~> 3.6 |
@@ -76,8 +77,8 @@ Common issues and solutions:
| Name | Source | Version |
|------|--------|---------|
-| [images](#module\_images) | git@github.e.it.census.gov:terraform-modules/aws-ecr-copy-images.git/ | tf-upgrade |
-| [ingress\_resources](#module\_ingress\_resources) | git@github.e.it.census.gov:SCT-Engineering/tfmod-istio-service-ingress.git | main |
+| [images](#module\_images) | git::https://github.e.it.census.gov/terraform-modules/aws-ecr-copy-images.git/ | tf-upgrade |
+| [ingress\_resources](#module\_ingress\_resources) | git::https://github.e.it.census.gov/SCT-Engineering/tfmod-istio-service-ingress.git | main |
## Resources
@@ -92,22 +93,27 @@ Common issues and solutions:
| [cluster\_domain](#input\_cluster\_domain) | The domain name used to reference ingresses for the cluster. | `string` | n/a | yes |
| [cluster\_name](#input\_cluster\_name) | EKS cluster name name component used through out the EKS cluster describing its purpose (ex: dice-dev) | `string` | n/a | yes |
| [default\_storage\_class](#input\_default\_storage\_class) | The default storage class to use for persistent volumes | `string` | `"gp3-encrypted"` | no |
-| [keycloak\_database](#input\_keycloak\_database) | The name of the database to create in the RDS instance. | `string` | `"bitnami_keycloak"` | no |
-| [keycloak\_password](#input\_keycloak\_password) | The initial password for the database. | `string` | `"bn_keycloak"` | no |
+| [keycloak\_database](#input\_keycloak\_database) | The name of the database to create in the RDS instance. | `string` | `"keycloak"` | no |
+| [keycloak\_password](#input\_keycloak\_password) | The initial password for the database. | `string` | `"keycloak"` | no |
| [keycloak\_tag](#input\_keycloak\_tag) | The image tag associated with the keycloak\_chart\_version | `string` | `"22.0.1-debian-11-r30"` | no |
-| [keycloak\_user](#input\_keycloak\_user) | The username for the database. | `string` | `"bn_keycloak"` | no |
+| [keycloak\_user](#input\_keycloak\_user) | The username for the database. | `string` | `"keycloak"` | no |
| [namespace](#input\_namespace) | The namespace which will be created and into which keycloak will be deployed. | `string` | `"keycloak"` | no |
| [postgresql\_tag](#input\_postgresql\_tag) | The tag of the postgresql image to use. | `string` | `"17.4.0"` | no |
| [profile](#input\_profile) | AWS config profile used to upload images into ECR | `string` | `""` | no |
-| [service\_name](#input\_service\_name) | The name of the service to be deployed in the EKS cluster. | `string` | `"keycloak-service"` | no |
+| [service\_name](#input\_service\_name) | The name of the service to be deployed in the EKS cluster. | `string` | `"service"` | no |
| [telemetry\_namespace](#input\_telemetry\_namespace) | The namespace used for telemetry. | `string` | `"namespace"` | no |
## Outputs
| Name | Description |
|------|-------------|
+| [admin\_internal\_endpoint](#output\_admin\_internal\_endpoint) | internal endpoint for admin |
+| [client\_id](#output\_client\_id) | The client ID for accessing keycloak. |
+| [client\_secret](#output\_client\_secret) | The client secret for accessing keycloak. |
+| [discovery\_url](#output\_discovery\_url) | The URL for discovering keycloak services. |
| [module\_name](#output\_module\_name) | The name of this module. |
| [module\_version](#output\_module\_version) | The version of this module. |
| [namespace](#output\_namespace) | The namespace in which keycloak gets installed in. |
+| [provider\_config](#output\_provider\_config) | Add provider configuration block for easier consumption |
| [public\_endpoint](#output\_public\_endpoint) | The endpoint at which keycloak can be reached from outside the cluster. |
diff --git a/copy_images.tf b/copy_images.tf
index 86ee348..9ea2ccd 100644
--- a/copy_images.tf
+++ b/copy_images.tf
@@ -36,7 +36,7 @@ locals {
}
module "images" {
- source = "git@github.e.it.census.gov:terraform-modules/aws-ecr-copy-images.git/?ref=tf-upgrade"
+ source = "git::https://github.e.it.census.gov/terraform-modules/aws-ecr-copy-images.git/?ref=tf-upgrade"
profile = var.profile
application_name = var.cluster_name
diff --git a/keycloak-values.yaml.tmpl b/keycloak-values.yaml.tmpl
index beaa0c1..a17a86b 100644
--- a/keycloak-values.yaml.tmpl
+++ b/keycloak-values.yaml.tmpl
@@ -3,45 +3,64 @@ replicaCount: 3
global:
security:
allowInsecureImages: true
- imageRegistry: "${image_registry}"
- defaultStorageClass: "${default_storage_class}"
+ imageRegistry: ${image_registry}
+ defaultStorageClass: ${default_storage_class}
image:
- registry: "${image_registry}"
- repository: "${image_repository}"
- tag: "${image_tag}"
+ registry: ${image_registry}
+ repository: ${image_repository}
+ tag: ${image_tag}
autoscaling:
enabled: true
minReplicas: 1
maxReplicas: 5
- targetCPU: "80"
+ targetCPU: 80
resources:
requests:
cpu: 100m
- memory: 256Mi
+ memory: 512Mi
limits:
cpu: 2000m
- memory: 2Gi
+ memory: 1024Mi
metrics:
enabled: true
serviceMonitor:
enabled: true
+ prometheusRule:
+ enabled: true
service:
- type: "ClusterIP"
+ type: ClusterIP
production: true
-proxy: "edge"
+proxy: edge
+
+# Bootstrap configuration
+auth:
+ adminUser: ${keycloak_user}
+ adminPassword: ${keycloak_password}
+
+# Initial realm configuration
+initConfiguration:
+ createInitialAdmin: true
+ importRealms: false
+
+# Realms import configuration (optional)
+# initConfigurationFile: /configuration/realm-config.json
+# extraVolumes:
+# - name: realm-config
+# configMap:
+# name: keycloak-realm-config
postgresql:
architecture: replication
image:
registry: ${image_registry}
- repository: "${postgresql_image_repository}"
- tag: "${postgresql_image_tag}"
+ repository: ${postgresql_image_repository}
+ tag: ${postgresql_image_tag}
enabled: true
auth:
username: ${keycloak_user}
@@ -51,24 +70,45 @@ postgresql:
resources:
cpu: 100m
memory: 128Mi
+ limits:
+ cpu: 2000m
+ memory: 2Gi
readReplicas:
resources:
cpu: 100m
memory: 128Mi
+ limits:
+ cpu: 2000m
+ memory: 2Gi
metrics:
enabled: true
+tracing:
+ enabled: true
extraEnv: |
- name: JGROUPS_DISCOVERY_PROTOCOL
value: dns.DNS_PING
- name: JGROUPS_DISCOVERY_PROPERTIES
- value: "dns_query=${serviceDnsName}"
+ value: 'dns_query={{ include "keycloak.serviceDnsName" . }}'
- name: CACHE_OWNERS_COUNT
- value: "3"
+ value: 3
- name: CACHE_OWNERS_AUTH_SESSIONS_COUNT
- value: "3"
+ value: 3
- name: PROXY_ADDRESS_FORWARDING
- value: "true"
+ value: true
- name: KC_CONFIG_FILE
- value: "/opt/bitnami/keycloak/kcadm.config"
+ value: /opt/bitnami/keycloak/kcadm.config
+ - name: KEYCLOAK_USER
+ value: ${keycloak_user}
+ - name: KEYCLOAK_PASSWORD
+ value: ${keycloak_password}
+ - name: KEYCLOAK_STATISTICS
+ value: all
+ - name: JAVA_OPTS
+ value: >-
+ -XX:+UseContainerSupport
+ -XX:MaxRAMPercentage=50.0
+ -Djava.net.preferIPv4Stack=true
+ -Djboss.modules.system.pkgs=$JBOSS_MODULES_SYSTEM_PKGS
+ -Djava.awt.headless=true
diff --git a/main.tf b/main.tf
index 0cf5121..1d320cd 100644
--- a/main.tf
+++ b/main.tf
@@ -1,9 +1,7 @@
# main.tf
locals {
- internal_port_number = "80"
- public_domain = var.cluster_domain
-
- service_name = var.service_name
+ internal_port_number = "8080"
+ admin_internal_port_number = "9000"
}
resource "helm_release" "keycloak" {
@@ -11,23 +9,24 @@ resource "helm_release" "keycloak" {
name = var.service_name
repository = "${path.module}/charts"
create_namespace = true
- timeout = 120
+ timeout = 300
wait = true
namespace = var.namespace
values = [templatefile("${path.module}/keycloak-values.yaml.tmpl", {
+ cluster_name = var.cluster_name,
+ default_storage_class = var.default_storage_class,
image_registry = module.images.images[local.keycloak_key].dest_registry,
image_repository = module.images.images[local.keycloak_key].dest_repository,
image_tag = module.images.images[local.keycloak_key].tag,
- default_storage_class = var.default_storage_class,
- serviceDnsName = format("https://%s.%s", var.service_name, local.public_domain),
- telemetry_namespace = var.telemetry_namespace,
+ keycloak_database = var.keycloak_database,
+ keycloak_password = var.keycloak_password,
+ keycloak_user = var.keycloak_user,
postgresql_image_registry = module.images.images[local.postgresql_key].dest_registry,
postgresql_image_repository = module.images.images[local.postgresql_key].dest_repository,
postgresql_image_tag = module.images.images[local.postgresql_key].tag,
- keycloak_database = var.keycloak_database,
- keycloak_user = var.keycloak_user,
- keycloak_password = var.keycloak_password,
+ serviceDnsName = format("https://%s.%s", var.service_name, var.cluster_domain),
+ telemetry_namespace = var.telemetry_namespace,
})]
depends_on = [
@@ -38,10 +37,10 @@ resource "helm_release" "keycloak" {
module "ingress_resources" {
depends_on = [helm_release.keycloak]
# tflint-ignore: terraform_module_pinned_source
- source = "git@github.e.it.census.gov:SCT-Engineering/tfmod-istio-service-ingress.git?ref=main"
- public_hostname = local.service_name
- public_domain = local.public_domain
- service_name = local.service_name
+ source = "git::https://github.e.it.census.gov/SCT-Engineering/tfmod-istio-service-ingress.git?ref=main"
+ public_hostname = var.service_name
+ public_domain = var.cluster_domain
+ service_name = var.service_name
service_namespace = var.namespace
service_port = local.internal_port_number
}
diff --git a/outputs.tf b/outputs.tf
index 9a125f9..998f7a7 100644
--- a/outputs.tf
+++ b/outputs.tf
@@ -3,15 +3,39 @@ output "public_endpoint" {
value = module.ingress_resources.service_url
}
-# output "client_id" {
-# description = "The client ID for accessing keycloak."
-# value = dependency.eks_keycloak.outputs.client_id
-# }
-
-# output "client_secret" {
-# description = "The client secret for accessing keycloak."
-# value = dependency.eks_keycloak.outputs.client_secret
-# }
+output "admin_internal_endpoint" {
+ description = "internal endpoint for admin"
+ value = {
+ hostname = format("%v.%v.svc.cluster.local", var.service_name, var.namespace)
+ port_number = local.admin_internal_port_number
+ url = format("http://%v.%v.svc.cluster.local:%v", var.service_name, var.namespace, local.admin_internal_port_number)
+ }
+}
+
+# Add provider configuration block for easier consumption
+output "provider_config" {
+ value = {
+ url = "${module.ingress_resources.service_url}/auth"
+ realm = "master"
+ client_id = var.keycloak_user
+ }
+ sensitive = true
+}
+
+output "discovery_url" {
+ description = "The URL for discovering keycloak services."
+ value = "${module.ingress_resources.service_url}/auth/realms/master"
+}
+
+output "client_id" {
+ description = "The client ID for accessing keycloak."
+ value = var.keycloak_user
+}
+
+output "client_secret" {
+ description = "The client secret for accessing keycloak."
+ value = var.keycloak_password
+}
output "namespace" {
description = "The namespace in which keycloak gets installed in."
diff --git a/requirements.tf b/requirements.tf
index 9276c48..a9f3181 100644
--- a/requirements.tf
+++ b/requirements.tf
@@ -10,6 +10,10 @@ terraform {
source = "hashicorp/helm"
version = "~> 2.11"
}
+ keycloak = {
+ source = "keycloak/keycloak"
+ version = ">= 5.0.0"
+ }
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.23"
diff --git a/variables.tf b/variables.tf
index c53d4f5..194fdbc 100644
--- a/variables.tf
+++ b/variables.tf
@@ -29,19 +29,19 @@ variable "cluster_domain" {
variable "keycloak_database" {
description = "The name of the database to create in the RDS instance."
type = string
- default = "bitnami_keycloak"
+ default = "keycloak"
}
variable "keycloak_user" {
description = "The username for the database."
type = string
- default = "bn_keycloak"
+ default = "keycloak"
}
variable "keycloak_password" {
description = "The initial password for the database."
type = string
- default = "bn_keycloak"
+ default = "keycloak"
}
variable "default_storage_class" {
@@ -53,7 +53,7 @@ variable "default_storage_class" {
variable "service_name" {
description = "The name of the service to be deployed in the EKS cluster."
type = string
- default = "keycloak-service"
+ default = "service"
}
variable "telemetry_namespace" {