Often when you want to implement authenticaiton/identity provider in your system, you turn to a well tested solution that is already on the market. Writting a good full OAuth2/OIDC/Federation IdP Provider is not a simple task, and if you start from scratch - you can consider it 3-6 months with good size pizza team, that is experienced in the technologies - to go through the whole implementation cycle. There are plenty of solutions out there, and quite a good ones - Auth0, Google OAuth, Github OAuth, AWS Cognito. Those are all external indentity providers that you can hook into your product, and rely on them. The problem usually is that mojority of Enterprises would like to keep the solution inhouse. They are even not ready to do federation through the public internet.

Here comes one of the solutions for such enterprises - RedHat Keycloak is for quite some while on the market and offers a very decent set of features that one can expect from IdP.

I am not going to go into detail and explain what Keycloak is - feel free to check it out at the official site.

Well from Operations point of view, especially if you are running on Kubernetes, intallation of Keycloak is traight forward using this Helm Chart

When we do that for our customers, we even wrap the helm installation in terraform code, so that we can automate all the infrastructure and component deployment, and to keep them as code (Infrastructure as code is a main principle of ZestLabs)

All said, what we need left is a way to configure our Keycloak Installation, once it is up and running. This can include:

Luckyly keycloak is entirely API Driven, and basicly everything that you have in the nice UI Console, you can achieve using API Calls.

There is an open source provider for keycloak, that can be found on Github, capable of handling all those configurations, that utilizes the API interface.

Using the provider in your project

Start by introducing the provider in your project. All the follow up snippets are done and tested on Terraform 0.13+.

terraform {
  required_providers {
    keycloak = {
      source = "mrparkers/keycloak"
      version = ">= 2.0.0"
    }
  }
}

One important note here is - if you are creating a module that will do the job of configuring Keycloak, and then you will use this module in your infrastructure terraform scripts, make sure to include the same snippet to the module itself - this is something introduced since terraform 0.13 and without it, you will start seeing messages like:

Cannot initialize keycloak provider at: hashicorp/keycloak

Configuring your provider agains your Keycloak installation

If your keycloak is freshly installed, most probably you will need to use the admin account that was initially created using password grant:

provider "keycloak" {
    client_id     = "admin-cli"
    username      = "keycloak"
    password      = "password"
    url           = "http://localhost:8080"
}

Replace in the snippet the url, username and password with the once specified in your helm installation. If you need some more flexibility, e.g. providing those credentials from secure provider on execution, then a solution with Terragrunt can be considered. Anyway this will be a topic for another article.

Creating your Realm

If you are wandering what Realm is - feel free to visit the Getting started guide

resource "keycloak_realm" "my_realm" {
  realm             = "my-realm"
  enabled           = true
  display_name_html = "<h1>My Org Realm</h1>"
  login_with_email_allowed = true
}

for more details on the realm config - refer to the provider realm doc resource “keycloak_realm”

Supply a default root user for the realm

// Create default user root with the same password as the admin one in master realm
resource "keycloak_user" "root" {
  realm_id = keycloak_realm.my_realm.id
  username = var.root_username
  enabled  = true

  email          = var.root_email
  first_name     = var.root_firstname
  last_name      = var.root_lastname
  email_verified = true

  attributes = {
  }

  initial_password {
    value     = var.keycloak_password
    temporary = true
  }
}

Create OIDC Clients

Mobile realm with clientId: mobile, clientSecret: ${var.oidc_secret_mobile} and mobile oauth schema: my-mobile-app-schema

resource "keycloak_openid_client" "mobile" {
  realm_id  = keycloak_realm.my_realm.id
  client_id = "mobile"

  enabled = true

  access_type           = "CONFIDENTIAL"
  standard_flow_enabled = true
  valid_redirect_uris = [
    "my-mobile-app-schema:/callback"
  ]
  root_url    = "$${authBaseUrl}"
  admin_url   = "$${authBaseUrl}"
  web_origins = ["+"]

  client_secret = var.oidc_secret_mobile
}

Applying the configuration

What was left is just executing the infrastructure/configuration scripts using terraform:

terraform init
terraform apply

After the second step, terraform will present the plan of execution and ask for confirmation.

~Enjoy