Red Hat's single sign-on tool has long been a trusted solution for securing web applications and providing centralized identity management. However, with the introduction of the Red Hat build of Keycloak, a next-generation option has emerged. This article will guide you through how to migrate from Red Hat's single sign-on to Red Hat build of Keycloak, highlighting the benefits and considerations involved in this strategic move.
We'll delve into the key advantages of Red Hat build of Keycloak, such as its cloud-native architecture, enhanced performance, and streamlined configuration. Additionally, we'll provide a step-by-step approach to the migration process, ensuring a smooth transition with minimal disruption to your existing infrastructure. Whether you're seeking improved scalability, cost efficiency, or a more modern security posture, migrating to Red Hat build of Keycloak offers a compelling path forward.
Refer to the Red Hat build of Keycloak documentation for up-to-date product information.
Prerequisites
To start this demonstration, you will need the following:
- Red Hat OpenShift cluster
- Admin user
- Git (download for macOS, Linux/Fedora)
- Red Hat OpenShift 4.14 (download for macOS, Linux/Fedora)
- Argo CD command-line interface (CLI) (download for macOS, Linux/Fedora)
Technical overview
Red Hat single sign-on and Red Hat build of Keycloak are both identity and access management (IAM) solutions offered by Red Hat, but there are key differences between the two.
Red Hat single sign-on:
- Origin: Based on Red Hat JBoss Enterprise Application Platform (JBoss EAP) and the community project, Keycloak is a legacy product built and maintained by Red Hat.
- Technology: Uses a Java EE stack, making it potentially less cloud-native and more resource-intensive.
- Features: Feature set is more limited compared to Keycloak, with some features reaching end-of-life or not being actively developed.
Red Hat build of Keycloak:
- Origin: Based on the fast-growing open source Keycloak project, but with additional features and support from Red Hat.
- Technology: Built with a modern architecture designed for cloud deployments and containers.
- Features:
- Single sign-on (SSO): Enables users to sign in once and access multiple applications securely.
- User federation: Integrates with various user directories like LDAP, Active Directory, and social login providers.
- Access control: Granular control over user access to applications and resources based on roles and permissions.
- Multi-factor authentication (MFA): Adds an extra layer of security for logins.
- OpenID Connect (OIDC) and SAML Support: Industry-standard protocols for secure authentication and authorization.
- Self-service management: Users can manage their profiles, passwords, and security settings.
- Account linking: Allows users to connect accounts from different identity providers.
- WebAuthn support: Enables passwordless login using hardware security keys.
- Client registration: Developers can easily register their applications with Keycloak.
- Permissions by attribute: Control access based on user attributes retrieved from directories.
- Token store integration: Integrates with external token stores for scalability and redundancy.
- Fine-grained authorization: Granular control over access to specific resources within applications.
Let's get to it!
For the scope of this article, we are going to use the following Git repository:
git clone https://github.com/Everything-is-Code/red_hat-build_of_keycloak
cd red_hat-build_of_keycloak
Now we have to install the OpenShift GitOps Operator and Argo CD instance. Let's take a look at the files first:
$ oc apply -k ./bootstrrap/argo
Wait until it is installed.
$ watch oc get pods -n openshift-gitops
Every 2.0s: oc get pods -n openshift-gitops
NAME READY STATUS RESTARTS AGE
cluster-84c744d68d-jkvkj 1/1 Running 0 39m
kam-67b754468-q66ng 1/1 Running 0 39m
openshift-gitops-application-controller-0 1/1 Running 0 39m
openshift-gitops-applicationset-controller-84ddbb9469-l9vvc 1/1 Running 0 39m
openshift-gitops-dex-server-b9fd89b78-92tpx 1/1 Running 0 39m
openshift-gitops-redis-5684c6fc5b-g542b 1/1 Running 0 39m
openshift-gitops-repo-server-774f57885c-ct2vn 1/1 Running 0 39m
openshift-gitops-server-76cf7bd6c8-zzwkt 1/1 Running 0 39m
Next, apply the base bootstrap folder:
$ oc apply -k ./bootstrrap/deploy/01_keycloak-development
After few minutes we should see the elements of Red Hat build of Keycloak in OpenShift GitOps (Figure 1).
Explaining elements
The elements we will see in the following section are in the resources/keycloak-development
folder on the root of repo.
We have the namespace YAML, just namespace definition for OpenShift:
cat 00_keycloak-namespace.yaml
kind: Project
apiVersion: project.openshift.io/v1
metadata:
annotations:
argocd.argoproj.io/sync-wave: "0"
name: keycloak
spec:
finalizers:
- kubernetes
The following two are the definitions to install the operator:
cat 01_keycloak-operatorgroup.yaml
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
annotations:
olm.providedAPIs: 'Keycloak.v2alpha1.k8s.keycloak.org,KeycloakRealmImport.v2alpha1.k8s.keycloak.org'
argocd.argoproj.io/sync-wave: "1"
name: keycloak-operatorgroup
namespace: keycloak
spec:
targetNamespaces:
- keycloak
upgradeStrategy: Default
cat 02_keycloak-subscription.yaml
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
annotations:
argocd.argoproj.io/sync-wave: "2"
labels:
operators.coreos.com/rhbk-operator.keycloak: ''
name: rhbk-operator
namespace: keycloak
spec:
channel: stable-v22
installPlanApproval: Automatic
name: rhbk-operator
source: redhat-operators
sourceNamespace: openshift-marketplace
Up to this point, these elements do not require explanation. We are simply creating a namespace where we are going to create the operator and the operator group that uses the subscription to install the same.
Now we are going to explain the files inside the keycloak-development
folder that you use later.
03_pgsql-db.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
annotations:
argocd.argoproj.io/sync-wave: "0"
name: postgresql-db
namespace: keycloak
spec:
serviceName: postgresql-db-service
selector:
matchLabels:
app: postgresql-db
replicas: 1
template:
metadata:
labels:
app: postgresql-db
spec:
containers:
- name: postgresql-db
image: postgres:latest
volumeMounts:
- mountPath: /data
name: cache-volume
env:
- name: POSTGRES_PASSWORD
value: pgsqlpassword
- name: POSTGRES_USERNAME
value: pgsqladmin
- name: PGDATA
value: /data/pgdata
- name: POSTGRES_DB
value: keycloak
volumes:
- name: cache-volume
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: postgres-db
namespace: keycloak
spec:
selector:
app: postgresql-db
type: LoadBalancer
ports:
- port: 5432
targetPort: 5432
postgres-db
definitions and the port are required to run the container.
We need to create secrets to be used in Red Hat build of Keycloak with the TLS definition. To achieve this, we need to run:
openssl req -subj '/CN=development.keycloak.org/O=Test Keycloak./C=US' -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem
cat 01_secrets.yaml
---
apiVersion: v1
kind: Secret
metadata:
annotations:
argocd.argoproj.io/sync-wave: "1"
name: keycloak-tls
namespace: keycloak
type: Opaque
stringData:
tls.crt: |
"-----BEGIN CERTIFICATE-----
MIIDczCCAlugAwIBAgIUecg6til+Ew9HvDvC1gCqlXJduZswDQYJKoZIhvcNAQEL
BQAwSTEhMB8GA1UEAwwYZGV2ZWxvcG1lbnQua2V5Y2xvYWsub3JnMRcwFQYDVQQK
DA5UZXN0IEtleWNsb2FrLjELMAkGA1UEBhMCVVMwHhcNMjQwNDEwMTU0MDMyWhcN
MjUwNDEwMTU0MDMyWjBJMSEwHwYDVQQDDBhkZXZlbG9wbWVudC5rZXljbG9hay5v
cmcxFzAVBgNVBAoMDlRlc3QgS2V5Y2xvYWsuMQswCQYDVQQGEwJVUzCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKqbxgFSc84s2yu1QF9RGsFQechxe+ss
wcD0fE49fKTPAh9u7TMU+Z4z5cGPhdftfSYZI8z96K9xXUVwb7s4L8/4NxJ6lJUF
2Nq+UBfLbnbQTrIrS18zdrc3eTESCrrONz6q153o9tyxlDas4fg9JF+iSDHP+Hhp
/OLaEwRXQEZ/2ouCxOghW157loT/3Y9DpX82Tpcgg+cdEa44TKd2Ej8ob7Oj+EfP
Pb9uCeOSwTJh520CA7CtVWbA17eXfaYpJCPl1NenHWXd9rhPItS4yC4oXt9ZxRLa
0K2aKjnKlUehCHkO5pr0ngWF7nIhMEZVdWsHfpbE9RKzcjHXQrbUh+ECAwEAAaNT
MFEwHQYDVR0OBBYEFMKRq3W0xwWyK2pCyVAPuJlgYtNmMB8GA1UdIwQYMBaAFMKR
q3W0xwWyK2pCyVAPuJlgYtNmMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
BQADggEBAAPxwuG8AVwfDPfOeztKKLSUQLM9WZSFkXGqlSqiQxZWzsN8q1AmT+7P
jHc/kgLKVjAVbN2jr7TKibVpbGPn/cyEy4pDItCf82NH/aqAfPUUnBbOm1ytyQPW
s09vqYQ+t+ARjPIDLffin7OYD5EXpscpCBSFkKcNErYt3XoBaHDjYf5o4yI9wsGW
7jCjG2lYebHnB4hXAYlde2GC9LdQ2EwXVzSgBxaS+eaNwHYz7WS566nURCOPYOk7
Sjq+jLZ9zXsL4PnIQwE6lv1OVi9+ZTaIwr7O30MD/NovTjaXHcJE+gledZC7qoka
iAC81/s8QmX+d7kEq9klueqbrlztXQ0=
-----END CERTIFICATE-----"
tls.key: |
"-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCqm8YBUnPOLNsr
tUBfURrBUHnIcXvrLMHA9HxOPXykzwIfbu0zFPmeM+XBj4XX7X0mGSPM/eivcV1F
cG+7OC/P+DcSepSVBdjavlAXy2520E6yK0tfM3a3N3kxEgq6zjc+qted6PbcsZQ2
rOH4PSRfokgxz/h4afzi2hMEV0BGf9qLgsToIVtee5aE/92PQ6V/Nk6XIIPnHRGu
OEyndhI/KG+zo/hHzz2/bgnjksEyYedtAgOwrVVmwNe3l32mKSQj5dTXpx1l3fa4
TyLUuMguKF7fWcUS2tCtmio5ypVHoQh5Duaa9J4Fhe5yITBGVXVrB36WxPUSs3Ix
10K21IfhAgMBAAECggEABF/vMVx8ZLaIvjOtHWSWg4t9O/MRAuRIaZq7T0RLXGyE
eOrewTcR+YkKJK759yH7Wg09+kUugMUu55ds/geATlxmiR5EjheyylUj96A7Smeo
BPCQQ7YtnqAZBvWX+ddM2loGImH1Zo5VJxvCxZtHwf4GzOQw0mGhXu3JnAxitQwK
g1f0T5kqAqOI21XFhBVf1Fv+q/CInzrZf40HVyXnOqrGNVWMfVHGWMDrEQw7bbS4
GxHzDYodVroejxRqReSlG7lAIodjIhIzNxr3ruHIbvdSNYzlqVL5KV5n7VKZVfea
FuURA1vD173RvXhKHVungPzOYuS9gisfTSl2CypzWQKBgQDa7xE5r97abHzc/bkz
vLRPigshU7iNKK9RkWVagf0bwMpER0RfU5zT4G3vUthHhNcfUAlBw1nE723RfKZJ
Oz2zPjMn+Wo+ZdwSw9zQC4Jg2tthaTji21pnh79HJHSGxRgIQix773hG0qZ1rbf9
ykLGXAaR6OUiOWSK5DRCei3ArQKBgQDHfjW6gw90aFpa8qcw0F4lBblNHId86VDF
nKEmEN694+Yl7DhSXc0pRsbaXG6KI7tnywG6Ad3AUtinwHfkUX381mjj5RbqM/qv
4r9v+y8LH9lDtS3gR2Zwj2nPF7GClF4vl12ElA9QV7amCwOTk33fes9bxxEK/5nH
9Hr7RETmhQKBgQC6gM/Gubh5j9OqmoXrugRMgcdLg7uCnLcFIHwb5wJMYyarlZ58
Kok9wUFFj+hovJRZu1+3YwgVCPYfcDVjyxCbohAILKPCNhmM7scrf7J4edhLGkz4
jG5uJajfnQGbUUlQt7aXeX+XrZlaRDup+mR6ACkkoSaYyhWJcC/ItbZGHQKBgQCz
l2xZHxmvqy4EiER5TmwimjeKMu/KROTBMdNlSHStsFgFtdWyWN2UljH4bJPa6nYQ
55IDWSC/vhVrV3rXYYGxN3iwCRIK/4ZkBxZegluEgUR/jsDhEoYnOQSBOgxEyLrN
z0+SRhRPONemPW4X0gTURmQcdGZkZ1ySxQZd48S/XQKBgHykwMU3SwztY4bICztP
SUoBGw3opBxafuhWeeTqivl+D4IG9USuhmeM8AKXoaPXnz0cLZeVONRjgw+LAFjD
YTT/4zL/cfPwlY8Z2qutX2igCvmbI2K2CkTVTR/FqJAJgEAK1sSSfhgpqVaj3ccS
mwlT0lXTQltEif3cDkEfo7f9
-----END PRIVATE KEY-----"
---
apiVersion: v1
kind: Secret
metadata:
annotations:
argocd.argoproj.io/sync-wave: "1"
name: keycloak-db-secret
namespace: keycloak
type: Opaque
stringData:
username: pgsqladmin
password: pgsqlpassword
The previous secret will be used by the operator to configure the instance.
05_keycloak-development.yaml
apiVersion: k8s.keycloak.org/v2alpha1
kind: Keycloak
metadata:
annotations:
argocd.argoproj.io/sync-wave: "2"
name: keycloak-development
spec:
instances: 2 #number of instances we will require
db: #dbtype
vendor: postgres
host: postgres-db
usernameSecret:
name: keycloak-db-secret
key: username
passwordSecret:
name: keycloak-db-secret
key: password
http:
httpEnabled: true
tlsSecret: keycloak-tls
hostname:
hostname: development.keycloak.org
Route definition:
cat 06_keycloak-route.yaml
kind: Route
apiVersion: route.openshift.io/v1
metadata:
name: keycloak
namespace: keycloak
annotations:
argocd.argoproj.io/sync-wave: "7"
labels:
app: keycloak
app.kubernetes.io/instance: keycloak-development
app.kubernetes.io/managed-by: keycloak-operator
spec:
to:
kind: Service
name: keycloak-development-service
tls:
termination: passthrough
insecureEdgeTerminationPolicy: Redirect
certificate: ''
key: ''
caCertificate: ''
destinationCACertificate: ''
port:
targetPort: https
In our case, we will install Open LDAP just for demo:
cat 07_open-ldap.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
argocd.argoproj.io/sync-wave: "8"
name: openldap
namespace: keycloak
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
annotations:
argocd.argoproj.io/sync-wave: "9"
name: anyrole
namespace: keycloak
subjects:
- kind: ServiceAccount
name: openldap
namespace: keycloak
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: 'system:openshift:scc:anyuid'
---
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
argocd.argoproj.io/sync-wave: "10"
namespace: keycloak
name: ldap
spec:
serviceAccount: openldap
selector:
matchLabels:
app: ldap
replicas: 1
template:
metadata:
labels:
app: ldap
spec:
serviceAccount: openldap
containers:
- name: container
image: rroemhild/test-openldap
ports:
- containerPort: 8080
protocol: TCP
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
---
apiVersion: v1
kind: Service
metadata:
annotations:
argocd.argoproj.io/sync-wave: "11"
name: openldap
namespace: keycloak
spec:
selector:
app: ldap
ports:
- protocol: TCP
port: 10389
targetPort: 10389
Applying Red Hat build of Keycloak instance
oc apply -k bootstrap/deploy/01_keycloak-development/01_keycoak-development.yaml
application.argoproj.io/keycloak-db configured
application.argoproj.io/keycloak-development configured
application.argoproj.io/rhsso-development configured
This application will create a CustomResourceDefinition related to the Red Hat build of Keycloak instance.
In addition to this, we have the 02_rhsso-production.yaml
file only for demo purposes; we will not apply it in this case. For more details of the SSO installation, see this article: How to deploy Single Sign-On as code using GitOps
After few minutes, we can verify the installation and login.
Retrieve admin password (Figure 2):
oc get secret keycloak-development-initial-admin -o jsonpath="{.data.password}" | base64 -d
445858b041ca445c8e02770d042c96a5
Migrating data from Red Hat's SSO to Red Hat build of Keycloak
First, we will create some data in in Red Hat's SSO to migrate to the new one.
Then log in to your instance and go to user Federation -> add user federation provider.
Complete the data as you can see in Figure 3:
You will need your LDAP credentials and distinguished name (DN) from your LDAP (you can copy from image if you use our data) and after you complete the fields, click sync all users.
As you can see now in our old instance, we have data.
Now we will to generate a dump for old database (postgres
from Red Hat single sign-on) to the new one.
First, we need to recover the pod name to generate the database dump:
oc get pods
oc NAME READY STATUS RESTARTS AGE
keycloak-0 1/1 Running 0 61m
keycloak-1 1/1 Running 0 60m
keycloak-postgresql-5dd8cbb447-dx794 1/1 Running 0 61m
rhsso-operator-58599c66b7-nnr7q 1/1 Running 0 62m
To achieve the dump generation we should run:
oc rsh keycloak-postgresql-5dd8cbb447-dx794
pg_dump root > rhsso.sql
Info alert: Note
If you check the Keycloak secret, notice the database name is root
.
Then we need to copy the generated file to our local machine to later restore the dump in new Red Hat build of Keycloak:
oc rsync keycloak-postgresql-5dd8cbb447-dx794:/tmp/rhsso.sql ./
receiving file list ... done
rhsso.sql
sent 38 bytes received 289638 bytes 82764.57 bytes/sec
total size is 289480 speedup is 1.00
oc rsync ./rhsso/ postgresql-db-0:/tmp/
WARNING: cannot use rsync: rsync not available in container
rhsso.sql
And now we will import the dump:
psql --username=postgres keycloak < /tmp/rhsso.sql
After that, check Red Hat build of Keycloak to see if federation data from the old user already exists in the existing one (Figure 4, Figure 5).
Mission accomplished: you have successfully migrated from Red Hat's single sign-on to Red Hat build of Keycloak!
Refer to the Red Hat build of Keycloak documentation for the latest information.
Last updated: September 12, 2024