In this article, I will demonstrate how workstation users authenticating to Active Directory using the Kerberos protocol can use Simple and Protected GSSAPI Negotiation Mechanism (SPNEGO) tokens with Red Hat's single sign-on (SSO) technology for single sign-on to web applications.
In summary, the authentication flow is as follows:
- The user is authenticated with Active Directory over Kerberos and has a Ticket Granting Ticket (TGT) stored locally on the workstation.
- The user makes a request from the browser to access the web application.
- The web application redirects the browser to Red Hat's SSO.
-
Red Hat's SSO responds with a 401 HTTP header:
WWW-Authenticate: Negotiate
- The browser requests a Service Ticket (ST) from the Ticket Granting Service (TGS) part of the KDC and then responds back to Red Hat's SSO and passes the Authorization Negotiate header containing the SPNEGO token.
- Red Hat's SSO authenticates the user.
- The user is redirected back to the web application and is now allowed access to the protected content.
The source code for this tutorial can be found here: https://github.com/torbjorndahlen/kerberos-keycloak-openshift
(use branch rhblog
) and here https://github.com/torbjorndahlen/keycloak-openshift-demo-nodejs
(use branch rhblog
).
Architecture
Figure 1 shows the architecture used in this example, where 3 hosts are being used:
- Workstation: Contains the kinit client for user authentication to Active Directory and the browser for accessing the secured web application.
- Opentlc.com: A Red Hat OpenShift cluster containing Red Hat's SSO with a kinit client and the secured web application.
- Sso-demo.local: A Windows Server with Active Directory and KDC.
In this example, the user at some point before trying to access the web app, obtains a TGT using Kinit on the workstation to authenticate to Active Directory. When accessing the web application from the browser, the TGT is used to obtain a ST from the TGS to authenticate to Red Hat's SSO.
The secured web application and Red Hat's SSO with a kinit
client are both deployed on OpenShift with in the domain opentlc.com
.
The Windows Server contains Active Directory and the KDC in the domain sso-demo.local
.
Create a user in Active Directory
Active Directory Domain Services are required for default Kerberos implementations within the domain or forest. The KDC is integrated with Windows Server security services that run on the domain controller. The KDC uses the domain's Active Directory Domain Services database as its security account database.
In this example, I'm using the domain sso-demo.local
. A local user called adminuser
will be used to authenticate to Active Directory from the workstation later.
In order for clients on the workstation and on OpenShift to access the KDC, the firewall protecting the Windows Server where Active Directory is deployed needs to allow UDP requests to the port the KDC is running. (The default is port 88; other ports may be specified in the KDC's kdc.conf file.).
Figure 2 shows how to create a user in Active Directory. The user sso-sso-demo
in the domain sso-demo.local
will be representing the host where Red Hat's single sign-on technology is deployed.
Configure encryption types allowed for Kerberos
In order to access Kerberos from the kinit client, the allowed encryption types needs to be configured. This configuration is located in Local Security Policy → Local Policies → Security Options → Network Security → Configure encryption types allowed for Kerberos.
After selecting this configuration property, the allowed encryption types can be configured as is shown in Figure 3.
These settings should match the settings in the configuration file used for kinit
(krb5.conf
) on the workstation and in the SSO container on OpenShift. In this example I've only allowed AES256_HMAC_SHA1
.
Generate a keytab
A Kerberos keytab file is used by Red Hat's SSO to enable Kerberos based user federation. Before the keytab is generated, the Service Principal Name (SPN) for Active Directory User Account must be set. Go back to the Windows Server admin console and run the following command:
C:\> setspn -S HTTP/sso-sso-demo.apps.<your domain>.opentlc.com sso-sso-demo
The Service Principal Name (SPN) must include the protocol (HTTP in this example) and also the full route to Red Hat's SSO, and be mapped to the previously created user in AD.
On Windows Server ktpass.exe
is used to create the keytab. Use ktpass -?
to list all available options.
The SPN together with the Kerberos realm SSO-DEMO.LOCAL
is used as principal when generating the keytab for SSO. Note that the value of the -mapUser
parameter must be the full name of the user as registered in AD.
C:\> ktpass -out sso-sso-demo.keytab -princ HTTP/sso-sso-demo.apps.<your domain>.opentlc.com@SSO-DEMO.LOCAL -mapUser sso -mapOp set -pass my_password -crypto AES256-SHA1 -ptype KRB5_NT_PRINCIPAL
Copy the keytab file (in this example: sso-sso-demo.keytab
) to the workstation from where you will deploy Red Hat's SSO on OpenShift—for example, using Remote Desktop.
On the workstation, after copying, inspect the contents of the keytab file:
% ktutil -k sso-sso-demo.keytab list
sso-sso-demo.keytab:
Vno Type Principal
6 aes256-cts-hmac-sha1-96 HTTP/sso-sso-demo.apps.<your domain>.opentlc.com@SSO-DEMO.LOCAL
Deploy SSO on OpenShift
Create a project to contain the Red Hat SSO instance:
% oc new-project sso-demo
Add the view role to the default service account:
% oc policy add-role-to-user view system:serviceaccount:$(oc project -q):default
To generate an image puller secret to allow OpenShift to pull images from registry.redhat.io
, you need to create a registry server account and the create a secret for OpenShift. The secret will look similar to:
apiVersion: v1
kind: Secret
metadata:
name: 10000000---my--pull-secret
data:
.dockerconfigjson: nnnn....
type: kubernetes.io/dockerconfigjson
Then create the secret in OpenShift:
% oc create -f my_user--secret.yaml -n sso-demo
In order to connect to KDC, Red Hat's SSO needs to be deployed with kinit
running in the same container. To achieve this, I'm creating a custom image for SSO where kinit
and the krb5.conf
file are added. In addition, the previously created keytab is also included in the image.
Figure 4 shows a Dockerfile that was used to build the modified SSO image.
The path to the krb5.conf
configuration file for kinit
is included in the Dockerfile. The file krb5.conf
contains configuration for kinit
and includes the Kerberos realm defined in Active Directory. In this case, the domain in Active Directory is sso-demo.local
and the Kerberos realm is SSO-DEMO.LOCAL
. The allowed encryption types should be listed in krb5.conf
. In the file https://github.com/torbjorndahlen/kerberos-keycloak-openshift/blob/rhblog/krb5.conf
you'll find an example configuration that you should modify to fit your environment.
Also the keytab file generated for Red Hat's SSO in Windows Server is included in the Dockerfile. Finally, the krb5-workstation
tools (kinit
, klist
, ktutils
, etc.) are also included.
Using this Dockerfile, a custom image containing Red Hat's SSO and krb5-workstation
is built to deploy kinit
in the same container as SSO.
% oc new-build https://github.com/torbjorndahlen/kerberos-keycloak-openshift#rhblog \
> --strategy=docker \
> --name='sso76-openshift-rhel8-krb5'
In this example, I'm using one of the standard Red Hat single sign-on templates including support for HTTPS to deploy the custom SSO image. The template is imported to OpenShift as follows:
% oc replace -n openshift --force -f \
> https://raw.githubusercontent.com/jboss-container-images/redhat-sso-7-openshift-image/sso76-dev/templates/reencrypt/ocp-4.x/sso76-ocp4-x509-https.json
Red Hat's SSO is then deployed using the template with the standard image from registry.redhat.io
.
% oc new-app --template=sso76-ocp4-x509-https \
> -p APPLICATION_NAME=sso \
> -p SSO_ADMIN_USERNAME=admin \
> -p SSO_ADMIN_PASSWORD=secret \
> -p IMAGE_STREAM_NAMESPACE=sso-demo
In order to use the custom image, the deployment config is patched as follows:
% oc patch dc/sso --type=json -p '[{"op": "replace", "path": "/spec/triggers/0/imageChangeParams/from/name", "value": "sso76-openshift-rhel8-krb5:latest"}]'
% oc rollout latest dc/sso
Verify that the correct route has been created:
% oc get route
NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD
sso sso-sso-demo.apps.<your domain>.opentlc.com sso <all> reencrypt None
Verify that the hostname for Red Hat's SSO is the same as was used to create the sso-sso-demo SPN in AD.
Configure Red Hat's SSO
Once deployed, Red Hat's SSO needs to be configured to be able to authenticate users stored in Active Directory with Kerberos.
To start with, we create a realm. Open the SSO Admin console and create a new realm sso-demo
. You can also import the realm from https://github.com/torbjorndahlen/kerberos-keycloak-openshift
(use branch rhblog
).
In order to work with Kerberos, Red Hat's SSO needs to have User Federation with Active Directory set up. Figure 5 shows an example how to set up a federation wit h Active Directory.
Since we're using Kerberos, the Kerberos integration also needs to be configured.
Figure 6 shows the configuration with the Kerberos realm as stated in the krb5.conf
file.
The SPN created in Active Directory and the location of the keytab file generated for Red Hat's SSO are also included in the configuration. In this example, the secured web application is a simple Node.js application that is deployed on OpenShift.
Figure 7 shows how to create an OIDC client in Red Hat's SSO for the secured web application.
Finally, because Kerberos authentication is disabled by default in Red Hat's SSO, it needs to be enabled. You'll find the setting for Kerberos under the Authentication menu in the SSO admin console.
Deploy the web application
The web application is a simple Node.js application that has a /public
and a /secured
endpoint.
To configure the Node.js application to use the OIDC client in Red Hat's SSO, create a fork of the git repo in
https://github.com/torbjorndahlen/keycloak-openshift-demo-nodejs
Copy the Installation file from the client configuration page in the SSO admin console created from the Node.js application and replace the existing keycloak.json
file, and push the changes to the Git repo:
% git clone https://github.com/<your_git_user>/keycloak-openshift-demo-nodejs
% git checkout rhblog
Replace the keycloak.json
file and commit the changes:
% git commit -a -m"Updated keycloak.json"
% git push origin rhblog
Build and deploy the Node.js application on OpenShift as follows:
% oc new-app https://github.com/torbjorndahlen/keycloak-openshift-demo-nodejs#rhblog
Then, create a Route to the Node.js app:
% oc expose svc/keycloak-openshift-demo-nodejs
Test the route by calling the public endpoint:
% curl https://keycloak-openshift-demo-nodejs-sso-demo.apps.<your domain>.opentlc.com/public
You should see the response:
{"message":"public"}
Making a call to the secured endpoint should redirect you to Red Hat's SSO:
% curl http://keycloak-openshift-demo-nodejs-sso-demo.apps.<your domain>.opentlc.com/secured
Found. Redirecting to https://sso-sso-demo.apps.<your domain>.opentlc.com/auth/realms/sso-demo/protocol/openid-connect/auth?client_id=service-nodejs&state=35b0f9a0-2e37-483a-84e0-6e421e7bd439&redirect_uri=http%3A%2F%2Fkeycloak-openshift-demo-nodejs-sso-demo.apps.<your domain>.opentlc.com%2Fsecured%3Fauth_callback%3D1&scope=openid&response_type=code
Set up workstation
Finally, the workstation used to authenticate to Active Directory over Kerberos and running the browser to access the secured web application should be configured to send authentication requests to the KDC.
Use the same krb5.conf
file that was deployed in Red Hat's SSO to configure kinit
on the workstation by copying the krb5.conf
file to /etc/krb5.conf
for clients on Linux or Mac and C:\windows\krb5.ini
for clients running on Windows.
Verify that your kinit
set up is correct by logging in to the KDC running on Windows Server:
% kinit adminuser@SSO-DEMO.LOCAL
adminuser@SSO-DEMO.LOCAL's password:
Verify that a Kerberos TGT has been created using klist
:
% klist
Credentials cache: API:C19459DA-A441-41C3-A51D-EFB78F8ED772
Principal: adminuser@SSO-DEMO.LOCAL
Issued Expires Principal
Jul 20 10:00:17 2023 Jul 20 20:00:12 2023 krbtgt/SSO-DEMO.LOCAL@SSO-DEMO.LOCAL
Next, the web browser must be configured to allow SPNEGO to authenticate to the secured web application. Figure 8 shows an example of enabling SPNEGO in Firefox.
The domain where the web application is deployed is listed at network.negotiate-auth.trusted-uris
, starting with a dot and then the domain name. This is a comma separated list and more trusted domains can be added here.
Finally, use the browser to navigate to the /secured
endpoint in the web app, you should see the following response:
{"message":"secured"}
Troubleshooting
- Verify that the
krb5.conf
file is located in the correct place on the workstation and contains the same information as in the SSO container. - Check that Kerberos is enabled as authentication method for the realm in Red Hat's SSO.
- Your
keycloak.json
needs to contain the configuration for your secured web application client in Red Hat's SSO. - Make sure a ticket is actually created on the workstation after
kinit
. Useklist
to verify. - Verify that the
domain_realm
inkrb5.conf
points to the domain where the secured web application is running, both on the workstation and in the SSO container. - The browser should be configured to send SPNEGO ticket to the domain where Red Hat's SSO is running. In Firefox, it's
network.negotiate-auth.trusted-uris = <RHSSO-domain>
. Use[dot][domain-name]
in a comma separated list. - Check the SSO log for unsupported encryption type, you might need to restrict the allowed encryption types in Active Directory and make the corresponding change in
krb5.conf
.
References
- MIT Kerberos Documentation
- Configuring authentication - Configuring Kerberos
- How to Set Up SSO for JBoss EAP with Kerberos - Configuration for Microsoft Windows Domain
- Configuring Red Hat Single Sign-On for OpenShift - Using the Red Hat Single Sign-On for OpenShift Image Streams and application templates
- Using External Storage - Lightweight Directory Access Protocol (LDAP) and Active Directory
- Kerberos Preferences on Mac OS X 10.4 and 10.5 Documentation
- MIT Kerberos documentation - krb5.conf