EKS Anywhere., Creating a simple KeyCloak server for various use-cases

Ambar Hassani
11 min readJul 26, 2022

--

This article is part of the series EKS Anywhere, extending the Hybrid cloud momentum | by Ambar Hassani | Apr, 2022 | Medium

In this article., we will create a KeyCloak server running on a docker host. To ease things, we will use our existing EKS-Anywhere Administrative machine to host the dockerized KeyCloak server

Before starting ensure that there is a DNS entry for the intended FQDN of the KeyCloak server. For my setup, the KeyCloak server’s FQDN is keycloak.thecloudgarage.com and is mapped to host IP of 172.24.165.50

Note: The admin username and password for the KeyCloak server will be

  • username: admin
  • password: admin@12345678

For the SSO users (user-admin, user-dev, user-view-only), the password is same as the username

SSH into the EKS-Anywhere Administrative machine

mkdir -p $HOME/eks-anywhere/oidc/keycloak-data
source $HOME/eks-anywhere/oidc/new-keycloak-server.sh
source $HOME/eks-anywhere/oidc/create-oidc-users-groups.sh

What will the above scripts execute:

  • new-keycloak-server.sh script will instantiate a dockerized instance of KeyCloak via the docker-compose file rendered in the same directory. We do not need to worry about any of those files as the script will take care of everything via the input variables
  • create-oidc-users-groups.sh script will use the KeyCloak terraform provider to configure the KeyCloak server. You will need to just provide for the input variables and everything else will be automatically configured by the script itself.
  • Since Terraform is already installed on the EKS Anywhere Administrative machine, the script will simply collect the input variables and pass them as terraform variables. Thereafter it will use the terraform configurations to create the appropriate users (user-admin, user-dev, user-view-only) and the groups (kube-dev, kube-admin, kube-view-only).
  • In addition, it will create the appropriate KeyCloak clients, scopes, user to group mappings and other important parameters required for the purpose of the exercises contained in this saga series

Once the above scripts are executed, you can browse via https to the FQDN of your KeyCloak server and verify realms/clients/scopes/users/groups, etc.

Example screenshots:

Click on Administration console
Click on the client named kube and observe it settings

The callback URLs have been configured to accommodate various use-cases in this saga series. We will discuss those later.

In addition to the “kube” client, there is a specific client called as “argocdcligrpc”, which we will discuss in later articles while dealing with gitops concepts with ArgoCD.

Let’s observe the actual execution of the above scripts

mkdir -p $HOME/eks-anywhere/oidc/keycloak-datasource eks-anywhere/oidc/new-keycloak-server.sh
fqdnOfKeycloakServer: keycloak.thecloudgarage.com
Generating a RSA private key
....+++++
.............................................................................................+++++
writing new private key to 'tls.key'
-----
Creating network "oidc_default" with the default driver
Creating oidc_keycloak_1 ... done
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fa3cee4618c0 quay.io/keycloak/keycloak:16.1.0 "/opt/jboss/tools/do…" 4 seconds ago Up 3 seconds 0.0.0.0:80->8080/tcp, :::80->8080/tcp, 0.0.0.0:443->8443/tcp, :::443->8443/tcp oidc_keycloak_1

Now that KeyCloak is up and running, we will use the second script to configure KeyCloak.

source $HOME/eks-anywhere/oidc/create-oidc-users-groups.sh
fqdnOfKeycloakServer: keycloak.thecloudgarage.com
emailDomainName: thecloudgarage.com
Initializing the backend...Initializing provider plugins...
- Finding mrparkers/keycloak versions matching "3.6.0"...
- Installing mrparkers/keycloak v3.6.0...
- Installed mrparkers/keycloak v3.6.0 (self-signed, key ID C50867915E116CD2)
Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html
Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.
Terraform has been successfully initialized!You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:# keycloak_group.groups["kube-admin"] will be created
+ resource "keycloak_group" "groups" {
+ id = (known after apply)
+ name = "kube-admin"
+ path = (known after apply)
+ realm_id = "master"
}
# keycloak_group.groups["kube-dev"] will be created
+ resource "keycloak_group" "groups" {
+ id = (known after apply)
+ name = "kube-dev"
+ path = (known after apply)
+ realm_id = "master"
}
# keycloak_group.groups["kube-view-only"] will be created
+ resource "keycloak_group" "groups" {
+ id = (known after apply)
+ name = "kube-view-only"
+ path = (known after apply)
+ realm_id = "master"
}
# keycloak_openid_client.argocdcligrpc will be created
+ resource "keycloak_openid_client" "argocdcligrpc" {
+ access_type = "PUBLIC"
+ backchannel_logout_session_required = true
+ client_id = "argocdcligrpc"
+ client_secret = (sensitive value)
+ consent_required = false
+ direct_access_grants_enabled = false
+ enabled = true
+ exclude_session_state_from_auth_response = false
+ full_scope_allowed = true
+ id = (known after apply)
+ implicit_flow_enabled = false
+ name = "argocdcligrpc"
+ pkce_code_challenge_method = "S256"
+ realm_id = "master"
+ resource_server_id = (known after apply)
+ service_account_user_id = (known after apply)
+ service_accounts_enabled = false
+ standard_flow_enabled = true
+ use_refresh_tokens = true
+ valid_redirect_uris = [
+ "http://localhost:8085/*",
]
}
# keycloak_openid_client.kube will be created
+ resource "keycloak_openid_client" "kube" {
+ access_type = "CONFIDENTIAL"
+ backchannel_logout_session_required = true
+ client_id = "kube"
+ client_secret = (sensitive value)
+ consent_required = false
+ direct_access_grants_enabled = true
+ enabled = true
+ exclude_session_state_from_auth_response = false
+ full_scope_allowed = true
+ id = (known after apply)
+ implicit_flow_enabled = false
+ name = "kube"
+ realm_id = "master"
+ resource_server_id = (known after apply)
+ service_account_user_id = (known after apply)
+ service_accounts_enabled = true
+ standard_flow_enabled = true
+ use_refresh_tokens = true
+ valid_redirect_uris = [
+ "http://localhost:8000/*",
+ "http://localhost:8085/*",
+ "https://argocd.oidc.thecloudgarage.com:/*",
+ "https://gitlab.oidc.thecloudgarage.com:10443/*",
+ "https://portainer.oidc.thecloudgarage.com:11443/*",
]
}
# keycloak_openid_client_default_scopes.argocdcligrpc will be created
+ resource "keycloak_openid_client_default_scopes" "argocdcligrpc" {
+ client_id = (known after apply)
+ default_scopes = [
+ "email",
+ "groups",
+ "profile",
+ "roles",
+ "web-origins",
]
+ id = (known after apply)
+ realm_id = "master"
}
# keycloak_openid_client_default_scopes.kube will be created
+ resource "keycloak_openid_client_default_scopes" "kube" {
+ client_id = (known after apply)
+ default_scopes = [
+ "email",
+ "groups",
+ "profile",
+ "roles",
+ "web-origins",
]
+ id = (known after apply)
+ realm_id = "master"
}
# keycloak_openid_client_scope.groups will be created
+ resource "keycloak_openid_client_scope" "groups" {
+ gui_order = 1
+ id = (known after apply)
+ include_in_token_scope = true
+ name = "groups"
+ realm_id = "master"
}
# keycloak_openid_group_membership_protocol_mapper.groups will be created
+ resource "keycloak_openid_group_membership_protocol_mapper" "groups" {
+ add_to_access_token = true
+ add_to_id_token = true
+ add_to_userinfo = true
+ claim_name = "groups"
+ client_scope_id = (known after apply)
+ full_path = false
+ id = (known after apply)
+ name = "groups"
+ realm_id = "master"
}
# keycloak_user.users["user-admin"] will be created
+ resource "keycloak_user" "users" {
+ email = "user-admin@emailDomainName"
+ email_verified = true
+ enabled = true
+ first_name = "user-admin"
+ id = (known after apply)
+ last_name = "user-admin"
+ realm_id = "master"
+ username = "user-admin"
+ initial_password {
+ temporary = false
+ value = (sensitive value)
}
}
# keycloak_user.users["user-dev"] will be created
+ resource "keycloak_user" "users" {
+ email = "user-dev@emailDomainName"
+ email_verified = true
+ enabled = true
+ first_name = "user-dev"
+ id = (known after apply)
+ last_name = "user-dev"
+ realm_id = "master"
+ username = "user-dev"
+ initial_password {
+ temporary = false
+ value = (sensitive value)
}
}
# keycloak_user.users["user-view-only"] will be created
+ resource "keycloak_user" "users" {
+ email = "user-view-only@emailDomainName"
+ email_verified = true
+ enabled = true
+ first_name = "user-view-only"
+ id = (known after apply)
+ last_name = "user-view-only"
+ realm_id = "master"
+ username = "user-view-only"
+ initial_password {
+ temporary = false
+ value = (sensitive value)
}
}
# keycloak_user_groups.user_groups["user-admin"] will be created
+ resource "keycloak_user_groups" "user_groups" {
+ exhaustive = true
+ group_ids = (known after apply)
+ id = (known after apply)
+ realm_id = "master"
+ user_id = (known after apply)
}
# keycloak_user_groups.user_groups["user-dev"] will be created
+ resource "keycloak_user_groups" "user_groups" {
+ exhaustive = true
+ group_ids = (known after apply)
+ id = (known after apply)
+ realm_id = "master"
+ user_id = (known after apply)
}
# keycloak_user_groups.user_groups["user-view-only"] will be created
+ resource "keycloak_user_groups" "user_groups" {
+ exhaustive = true
+ group_ids = (known after apply)
+ id = (known after apply)
+ realm_id = "master"
+ user_id = (known after apply)
}
Plan: 15 to add, 0 to change, 0 to destroy.Changes to Outputs:
+ client-secret = (sensitive value)
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:# keycloak_group.groups["kube-admin"] will be created
+ resource "keycloak_group" "groups" {
+ id = (known after apply)
+ name = "kube-admin"
+ path = (known after apply)
+ realm_id = "master"
}
# keycloak_group.groups["kube-dev"] will be created
+ resource "keycloak_group" "groups" {
+ id = (known after apply)
+ name = "kube-dev"
+ path = (known after apply)
+ realm_id = "master"
}
# keycloak_group.groups["kube-view-only"] will be created
+ resource "keycloak_group" "groups" {
+ id = (known after apply)
+ name = "kube-view-only"
+ path = (known after apply)
+ realm_id = "master"
}
# keycloak_openid_client.argocdcligrpc will be created
+ resource "keycloak_openid_client" "argocdcligrpc" {
+ access_type = "PUBLIC"
+ backchannel_logout_session_required = true
+ client_id = "argocdcligrpc"
+ client_secret = (sensitive value)
+ consent_required = false
+ direct_access_grants_enabled = false
+ enabled = true
+ exclude_session_state_from_auth_response = false
+ full_scope_allowed = true
+ id = (known after apply)
+ implicit_flow_enabled = false
+ name = "argocdcligrpc"
+ pkce_code_challenge_method = "S256"
+ realm_id = "master"
+ resource_server_id = (known after apply)
+ service_account_user_id = (known after apply)
+ service_accounts_enabled = false
+ standard_flow_enabled = true
+ use_refresh_tokens = true
+ valid_redirect_uris = [
+ "http://localhost:8085/*",
]
}
# keycloak_openid_client.kube will be created
+ resource "keycloak_openid_client" "kube" {
+ access_type = "CONFIDENTIAL"
+ backchannel_logout_session_required = true
+ client_id = "kube"
+ client_secret = (sensitive value)
+ consent_required = false
+ direct_access_grants_enabled = true
+ enabled = true
+ exclude_session_state_from_auth_response = false
+ full_scope_allowed = true
+ id = (known after apply)
+ implicit_flow_enabled = false
+ name = "kube"
+ realm_id = "master"
+ resource_server_id = (known after apply)
+ service_account_user_id = (known after apply)
+ service_accounts_enabled = true
+ standard_flow_enabled = true
+ use_refresh_tokens = true
+ valid_redirect_uris = [
+ "http://localhost:8000/*",
+ "http://localhost:8085/*",
+ "https://argocd.oidc.thecloudgarage.com:/*",
+ "https://gitlab.oidc.thecloudgarage.com:10443/*",
+ "https://portainer.oidc.thecloudgarage.com:11443/*",
]
}
# keycloak_openid_client_default_scopes.argocdcligrpc will be created
+ resource "keycloak_openid_client_default_scopes" "argocdcligrpc" {
+ client_id = (known after apply)
+ default_scopes = [
+ "email",
+ "groups",
+ "profile",
+ "roles",
+ "web-origins",
]
+ id = (known after apply)
+ realm_id = "master"
}
# keycloak_openid_client_default_scopes.kube will be created
+ resource "keycloak_openid_client_default_scopes" "kube" {
+ client_id = (known after apply)
+ default_scopes = [
+ "email",
+ "groups",
+ "profile",
+ "roles",
+ "web-origins",
]
+ id = (known after apply)
+ realm_id = "master"
}
# keycloak_openid_client_scope.groups will be created
+ resource "keycloak_openid_client_scope" "groups" {
+ gui_order = 1
+ id = (known after apply)
+ include_in_token_scope = true
+ name = "groups"
+ realm_id = "master"
}
# keycloak_openid_group_membership_protocol_mapper.groups will be created
+ resource "keycloak_openid_group_membership_protocol_mapper" "groups" {
+ add_to_access_token = true
+ add_to_id_token = true
+ add_to_userinfo = true
+ claim_name = "groups"
+ client_scope_id = (known after apply)
+ full_path = false
+ id = (known after apply)
+ name = "groups"
+ realm_id = "master"
}
# keycloak_user.users["user-admin"] will be created
+ resource "keycloak_user" "users" {
+ email = "user-admin@emailDomainName"
+ email_verified = true
+ enabled = true
+ first_name = "user-admin"
+ id = (known after apply)
+ last_name = "user-admin"
+ realm_id = "master"
+ username = "user-admin"
+ initial_password {
+ temporary = false
+ value = (sensitive value)
}
}
# keycloak_user.users["user-dev"] will be created
+ resource "keycloak_user" "users" {
+ email = "user-dev@emailDomainName"
+ email_verified = true
+ enabled = true
+ first_name = "user-dev"
+ id = (known after apply)
+ last_name = "user-dev"
+ realm_id = "master"
+ username = "user-dev"
+ initial_password {
+ temporary = false
+ value = (sensitive value)
}
}
# keycloak_user.users["user-view-only"] will be created
+ resource "keycloak_user" "users" {
+ email = "user-view-only@emailDomainName"
+ email_verified = true
+ enabled = true
+ first_name = "user-view-only"
+ id = (known after apply)
+ last_name = "user-view-only"
+ realm_id = "master"
+ username = "user-view-only"
+ initial_password {
+ temporary = false
+ value = (sensitive value)
}
}
# keycloak_user_groups.user_groups["user-admin"] will be created
+ resource "keycloak_user_groups" "user_groups" {
+ exhaustive = true
+ group_ids = (known after apply)
+ id = (known after apply)
+ realm_id = "master"
+ user_id = (known after apply)
}
# keycloak_user_groups.user_groups["user-dev"] will be created
+ resource "keycloak_user_groups" "user_groups" {
+ exhaustive = true
+ group_ids = (known after apply)
+ id = (known after apply)
+ realm_id = "master"
+ user_id = (known after apply)
}
# keycloak_user_groups.user_groups["user-view-only"] will be created
+ resource "keycloak_user_groups" "user_groups" {
+ exhaustive = true
+ group_ids = (known after apply)
+ id = (known after apply)
+ realm_id = "master"
+ user_id = (known after apply)
}
Plan: 15 to add, 0 to change, 0 to destroy.Changes to Outputs:
+ client-secret = (sensitive value)
keycloak_group.groups["kube-view-only"]: Creating...
keycloak_user.users["user-dev"]: Creating...
keycloak_openid_client_scope.groups: Creating...
keycloak_group.groups["kube-dev"]: Creating...
keycloak_user.users["user-admin"]: Creating...
keycloak_openid_client.argocdcligrpc: Creating...
keycloak_user.users["user-view-only"]: Creating...
keycloak_group.groups["kube-admin"]: Creating...
keycloak_openid_client.kube: Creating...
keycloak_group.groups["kube-admin"]: Creation complete after 0s [id=2814ac7f-1c7e-4424-8b53-d0331ec5b400]
keycloak_group.groups["kube-dev"]: Creation complete after 0s [id=2de2ebec-3c04-4e73-910e-8c4bdb1ad83b]
keycloak_group.groups["kube-view-only"]: Creation complete after 0s [id=a8641171-cd74-46d8-8e50-fffe954a7f76]
keycloak_openid_client_scope.groups: Creation complete after 0s [id=6272b3ae-633d-4338-b098-1dcdb8ee54ea]
keycloak_openid_group_membership_protocol_mapper.groups: Creating...
keycloak_openid_client.argocdcligrpc: Creation complete after 1s [id=8ade07c6-add2-4683-b8c9-aba8200c1c03]
keycloak_openid_client_default_scopes.argocdcligrpc: Creating...
keycloak_openid_group_membership_protocol_mapper.groups: Creation complete after 1s [id=587bb283-2762-4c2a-8a1c-a7d2cc5a960d]
keycloak_user.users["user-admin"]: Creation complete after 1s [id=55129602-4c61-4005-8f39-512c6d1630e3]
keycloak_openid_client.kube: Creation complete after 1s [id=2b8cd01c-828c-4c08-897c-5df1c76b71f4]
keycloak_openid_client_default_scopes.kube: Creating...
keycloak_user.users["user-dev"]: Creation complete after 1s [id=7fb9a768-c065-4414-bc82-d94e325831c0]
keycloak_openid_client_default_scopes.argocdcligrpc: Creation complete after 0s [id=master/8ade07c6-add2-4683-b8c9-aba8200c1c03]
keycloak_user.users["user-view-only"]: Creation complete after 1s [id=641b6e63-ee26-4455-9c0f-63fbe2608ea5]
keycloak_user_groups.user_groups["user-admin"]: Creating...
keycloak_user_groups.user_groups["user-dev"]: Creating...
keycloak_user_groups.user_groups["user-view-only"]: Creating...
keycloak_openid_client_default_scopes.kube: Creation complete after 0s [id=master/2b8cd01c-828c-4c08-897c-5df1c76b71f4]
keycloak_user_groups.user_groups["user-dev"]: Creation complete after 0s [id=master/7fb9a768-c065-4414-bc82-d94e325831c0]
keycloak_user_groups.user_groups["user-admin"]: Creation complete after 0s [id=master/55129602-4c61-4005-8f39-512c6d1630e3]
keycloak_user_groups.user_groups["user-view-only"]: Creation complete after 0s [id=master/641b6e63-ee26-4455-9c0f-63fbe2608ea5]
Apply complete! Resources: 15 added, 0 changed, 0 destroyed.Outputs:client-secret = <sensitive>

That’s it., our KeyCloak server is configured and ready for use in the EKS-Anywhere series.

cheers.

Ambar@thecloudgarage

#iwork4dell

--

--

Ambar Hassani
Ambar Hassani

Written by Ambar Hassani

24+ years of blended experience of technology & people leadership, startup management and disruptive acceleration/adoption of next-gen technologies

No responses yet