Discussion

Pegasystems Inc.
JP
Last activity: 20 Mar 2023 22:39 EDT
How to get OpenID Connect / SAML 2.0 to work on SSL offloading environment
Hi,
Some customers prefer enabling and offloading SSL at load balancer instead of Pega app nodes. With this solution, called "SSL offloading" or "SSL termination", client and LB communicates with SSL, and LB and server communicates without SSL. Encryption or decryption is CPU-intensive and consumes the resources to a large extent. The SSL offloading concept was introduced to relieve a web server of the processing burden and make the backend work faster. Another benefit is you need certificate only for LB and you don't need it for every app node.
Recently, customer reported to me that Single Sign On process using OpenID Connect does not work with LB that enables SSL offloading. To investigate this issue, we've set up a PoC environment as below and figured a solution. In this post, I'll summarize how we got this to work.
1. Install nginx
First of all, we've set up a load balancer using nginx-1.13.7 on CentOS 7. I'll skip the detailed steps here but basically we configured cookie stickiness by installing an additional module (nginx-sticky-module-ng-1.2.6) and specified "sticky" in the nginx.conf as below.
SSL is offloaded by forwarding requests to backend servers by HTTP as below.
Using browser from different terminals, make sure two HTTPS requests to LB (i.e. https:// Proprietary information hidden:8443/prweb) are forwarded to AP #1 and AP #2 respectively. Be noted, the strings on browser URL field still shows "https:// Proprietary information hidden:8443/prweb/..." even after forwarded. It won't be replaced with "http:// Proprietary information hidden:8080/prweb/..." or "http:// Proprietary information hidden:8080/prweb/...". You can validate that HTTP is used from Tomcat access log.
2. Install Keycloak
We installed Keycloak on Windows PC for OpenID Connect server. I'll skip the detailed step here but basically you need to set up "Realm", "User", and "Client" from Keycloak Admin Console. Pega serves as RP (Relying Party) and Keycloak serves as OP (OpenID Provider) in this scenario.
3. Configure Authentication Service
Create a Data-Admin-AuthService instance for OpenID Connect. Import metadata as below to fulfill all the necessary fields such as Authentication endpoint. This will also generate a Data-Admin-Security-Keystore instance.
Once metadata is imported, fill in Client ID and Client Secret. These can be obtained from Keycloak Admin Console. Then check on "Enable operator provisioning using model operator" and specify an existing model operator.
* Be noted, Login URL (http://backend/...) or Redirect URI (http://backend/...) on the rule form are varied based on how you log in. For example, if you log in from http:// Proprietary information hidden:8080/prweb, then it shows http:// Proprietary information hidden:8080/prweb/... Do not misunderstand that this string is a fixed value generated by this rule that you should use. This is just for informational purpose only.
- Keystore
You can create this on your own but if you import metadata, system will generate it automatically for you.
4. Configure Redirect URI at OpenID Provider
You need to configure Redirect URI at Keycloak. Since LB resides in front of app node, you should specify LB URI with SSL. In our case, this will be https:// Proprietary information hidden:8443/prweb/PRAuth.
Issue:
Now let's test. From browser, access "https:// Proprietary information hidden:8443/prweb/PRAuth/KeyCloakAuth". Unfortunately, with above settings, you'll face below error.
Keycloak logs below error.
2021-07-05 15:46:42,576 WARN [org.keycloak.events] (default task-46) type=LOGIN_ERROR, realmId=Demo, clientId=account, userId=null, ipAddress= Proprietary information hidden, error=invalid_redirect_uri, redirect_uri=http://backend/prweb/PRAuth
This is because the URI parameter passed from HTTP header (http://backend/prweb/PRAuth) and the URI registered at Keycloak (https:// Proprietary information hidden:8443/prweb/PRAuth) don't match. They have to be identical.
Solution:
There are two approaches how to fix this issue. Let me outline both steps in detail and my recommendation at the end.
Approach A: Configure the load balancer to set context
1. Create a Dynamic System Settings (prconfig/Initialization/ContextRewriteEnabled/default)
Create below DSS and set the value to "true". This DSS is required for both Approach A and Approach B. After creation, restart Tomcat or it won't take effect.
- Owning Ruleset: Pega-Engine
- Setting Purpose: prconfig/Initialization/ContextRewriteEnabled/default
2. Configure LB to tell Pega Platform which URI context to use
When LB receives a request from a client workstation, add a correct load balancer URI information to the HTTP header.
PegaRULES-SetContextURI: https:// Proprietary information hidden:8443/prweb
Approach B: Configure Pega Platform to set context
1. Create a Dynamic System Settings (prconfig/Initialization/ContextRewriteEnabled/default)
This is the same DSS as Approach A. Create one and restart Tomcat.
2. Create a Dynamic System Settings (prconfig/Initialization/SetBaseHTMLContext/default)
Create below DSS and set the value to "https:// Proprietary information hidden:8443/prweb". Restart Tomcat after creation.
- Owning Ruleset: Pega-Engine
- Setting Purpose: prconfig/Initialization/SetBaseHTMLContext/default
After configuration (Approach A or B), test it to see if authentication now works.
1. From browser, access "https:// Proprietary information hidden:8443/prweb/PRAuth/KeyCloakAuth". It is redirected to Keycloak and below screen is displayed properly. Type username and password that you register at Keycloak.
2. User is successfully created on-the-fly in Pega database and able to log in.
Recommendation:
Now, we verified both Approach A and B solves the issue. Are there any differences? This is my personal opinion but I would recommend Approach A, because context is independently added outside of Pega upfront. For example, if you take Approach B, and if you access app node directly (ex. http:// Proprietary information hidden:8080/prweb/PRAuth/KeyCloakAuth), Pega still tries to push the request back to LB. As long as LB is alive it works but if LB is down, you'll see below error.
On the other hand, if you are taking Approach A, and if you access app node directly, the context wouldn't be added. That means it won't push back to LB and Pega still works independently from LB. OpenID Connect authentication can even work as long as you add Redirect URIs for AP #1 and AP #2 at OP (see below for Keycloak configuration).
- Reference
https://community.pega.com/knowledgebase/articles/reverse-proxy-server-configuration
Thanks,