BookmarkSubscribeRSS Feed

SAS Viya 2021.2 OIDC with Multi-Tenancy

Started ‎01-22-2022 by
Modified ‎01-22-2022 by
Views 3,531

Application multi-tenancy is supported from the SAS Viya LTS 2021.2 release. In this article we will look at configuring OpenID Connect (OIDC) authentication in a multi-tenant (M-T) environment. We will examine some general concepts and dive into the details of how the authentication mechanism can be configured. For the discussions our SAS Viya environment will have the M-T provider and two tenants: a marketing tenant and a sales tenant.

 

General Concepts

The SAS Viya configuration of OIDC authentication could be performed in the M-T provider and apply to all tenants or could be configured in one or more individual tenants and only apply to that tenant. For our discussions here we will configure ODIC for the M-T provider and the marketing tenant.

 

The third-party OIDC Identity Provider, such as Azure Active Directory, has three key properties. These are:

 

  1. The Relying Party ID or Client ID – which is a unique name for the SAS Viya instance in the third-party OIDC Identity Provider.
  2. The Relying Party Secret or Client Secret – which is a shared secret between the SAS Viya instance and the third-party OIDC Identity Provider used to authenticate SAS Viya to the OIDC Identity Provider.
  3. One or more Redirect URIs – these are normally fully qualified URLs registered with the third-party OIDC Identity Provider. Only authentication requests coming from these registered URLs are valid.

So, if we configure our M-T provider for OIDC and expect the M-T provider, marketing tenant, and sales tenant to be able to authenticate we must register three Redirect URIs. If the name of the configuration in SAS Viya is oidc_azure, these Redirect URIs would be:

 

  1. https://{{INGRESS_NAME}}/SASLogon/login/callback/oidc_azure
  2. https://marketing.{{INGRESS_NAME}}/SASLogon/login/callback/oidc_azure
  3. https://sales.{{INGRESS_NAME}}/SASLogon/login/callback/oidc_azure

 

With SAS Viya 2021.2 (and later) to be able to specify the specific tenant which we want to apply the configuration to, we must use the SAS Viya CLI. With the SAS Viya CLI you can create a separate profile for the provider and each tenant. For example, to create a profile for the marketing tenant you would use the following:

 

INGRESS_URL=https://marketing.{{INGRESS_NAME}} ;\
/opt/sas/viya/home/bin/sas-viya --profile marketing profile set-endpoint "${INGRESS_URL}" 
/opt/sas/viya/home/bin/sas-viya --profile marketing profile toggle-color true 
/opt/sas/viya/home/bin/sas-viya --profile marketing profile set-output fulljson

 

In the examples that follow the default SAS Viya CLI profile will target the M-T provider, and the two tenants marketing, and sales, will have their own profiles.

 

Configuring OIDC

For the example configuration provided in this article we will use RedHat Keycloak as the third-party OpenID Connect Identity Provider. In our case Keycloak has been configured with two OIDC client registrations. The first with the Client ID = OIDC_Viya has all three valid Redirect URIs registered, which means that Keycloak will be able to authenticate end-users from the M-T provider or any tenants using this client. The second with the Client ID = OIDC_Marketing only has the Redirect URI registered for the marketing tenant, so only end-users from the marketing tenant can be authenticated with this client.

 

To configure the SAS Viya multi-tenant provider, we will create a JSON configuration file which we will then apply with the SAS Viya CLI. For example, we can create the JSON configuration file with the following:

 

    mkdir -p $deploy/site-config/JSON
    tee  $deploy/site-config/JSON/OIDC_Provider.json > /dev/null << EOF
    {
      "name": "addOIDC",
      "items": [
        {
          "version": 1,
          "metadata": {
            "allowUserProperties": true,
            "services": ["SASLogon","credentials"],
            "isDefault": false,
            "tenant": "provider",
            "mediaType": "application/vnd.sas.configuration.config.sas.logon.oauth.providers+json;version=1"
          },
          "addShadowUserOnLogin": true,
          "attributeMappings.user_name": "preferred_username",
          "authUrl": "https://gellabdc1.gellab.net/auth/realms/GELRealm/protocol/openid-connect/auth",
          "clientAuthInBody": false,
          "discoveryUrl": "https://gellabdc1.gellab.net/auth/realms/GELRealm/.well-known/openid-configuration",
          "emailDomain": "gellab.net",
          "linkText": "Provider OIDC",
          "name": "oidc_provider",
          "relyingPartyId": "OIDC_Viya",
          "relyingPartySecret": "{{clientSecret}}",
          "scopes": "openid",
          "showLinkText": true,
          "tokenUrl": "https://gellabdc1.gellab.net/auth/realms/GELRealm/protocol/openid-connect/token"
        }
      ]
    }
    EOF

 

Notice that in the metadata block of the JSON we have the property tenant: provider. This will define the configuration as being for the specified tenant. Also, the name property needs to be unique across all environments, so the provider and tenants. If the name is not unique, we will have unexpected behaviour, which we will discuss later.

 

This configuration can then be simply applied using the SAS Viya CLI:

 

/opt/sas/viya/home/bin/sas-viya auth login -u sasboot
/opt/sas/viya/home/bin/sas-viya configuration configurations create \
--file $deploy/site-config/JSON/OIDC_Provider.json
/opt/sas/viya/home/bin/sas-viya auth logout

 

Which will prompt for the sasboot user’s password.

 

If we review the logs for SAS Logon Manager after applying this configuration, we will see:

 

INFO  2022-01-05 06:27:47.894 +0000 [sas-logon-app] - Refresh keys changed: [tenants.provider.sas.logon.oauth.providers.oidc_provider.tokenUrl, sas.logon.oauth.providers.oidc_provider.tokenUrl, 
sas.logon.oauth.providers.oidc_provider.authUrl, sas.logon.oauth.providers.oidc_provider.showLinkText, tenants.provider.sas.logon.oauth.providers.oidc_provider.showLinkText, 
sas.logon.oauth.providers.oidc_provider.clientAuthInBody, sas.logon.oauth.providers.oidc_provider.linkText, sas.logon.oauth.providers.oidc_provider.attributeMappings.user_name, 
tenants.provider.sas.logon.oauth.providers.oidc_provider.relyingPartyId, tenants.provider.sas.logon.oauth.providers.oidc_provider.scopes, tenants.provider.sas.logon.oauth.providers.oidc_provider.addShadowUserOnLogin, 
tenants.provider.sas.logon.oauth.providers.oidc_provider.clientAuthInBody, tenants.provider.sas.logon.oauth.providers.oidc_provider.authUrl, sas.logon.oauth.providers.oidc_provider.scopes, 
tenants.provider.sas.logon.oauth.providers.oidc_provider.attributeMappings.user_name, tenants.provider.sas.logon.oauth.providers.oidc_provider.emailDomain, tenants.provider.sas.logon.oauth.providers.oidc_provider.discoveryUrl, 
sas.logon.oauth.providers.oidc_provider.addShadowUserOnLogin, tenants.provider.sas.logon.oauth.providers.oidc_provider.responseType, tenants.provider.sas.logon.oauth.providers.oidc_provider.relyingPartySecret, 
sas.logon.oauth.providers.oidc_provider.relyingPartyId, sas.logon.oauth.providers.oidc_provider.responseType, tenants.provider.sas.logon.oauth.providers.oidc_provider.linkText, 
sas.logon.oauth.providers.oidc_provider.discoveryUrl, sas.logon.oauth.providers.oidc_provider.emailDomain, sas.logon.oauth.providers.oidc_provider.relyingPartySecret]

 

This shows that the configuration properties we have set using the SAS Viya CLI have been picked up by SAS Logon Manager. Notice that although we specified "tenant": "provider" when SAS Logon Manager reads the M-T provider settings it also makes those available as service wide properties. Each property is prefixed by tenants.provider.sas.logon.oauth.providers.oidc_provider and sas.logon.oauth.providers.oidc_provider. This means that the settings will apply to the M-T provider and all tenants.

 

However, at this stage the link to authenticate with OIDC will only be displayed on the SAS Logon Manager page for the M-T provider. Only after restarting SAS Logon Manager will the link appear on the pages for the marketing and sales tenants.

 

Next, we will create the ODIC configuration for the marketing tenant. For example, we can create the JSON configuration file with the following:

 

    mkdir -p $deploy/site-config/JSON
    tee  $deploy/site-config/JSON/OIDC_Marketing.json > /dev/null << EOF
    {
      "name": "addOIDC",
      "items": [
        {
          "version": 1,
          "metadata": {
            "allowUserProperties": true,
            "services": ["SASLogon","credentials"],
            "isDefault": false,
            "tenant": "marketing",
            "mediaType": "application/vnd.sas.configuration.config.sas.logon.oauth.providers+json;version=1"
          },
          "addShadowUserOnLogin": true,
          "attributeMappings.user_name": "preferred_username",
          "authUrl": "https://gellabdc1.gellab.net/auth/realms/GELRealm/protocol/openid-connect/auth",
          "clientAuthInBody": false,
          "discoveryUrl": "https://gellabdc1.gellab.net/auth/realms/GELRealm/.well-known/openid-configuration",
          "emailDomain": "gellab.net",
          "linkText": "Marketing OIDC",
          "name": "oidc_marketing",
          "relyingPartyId": "OIDC_Marketing",
          "relyingPartySecret": "{{clientSecret}}",
          "scopes": "openid",
          "showLinkText": true,
          "tokenUrl": "https://gellabdc1.gellab.net/auth/realms/GELRealm/protocol/openid-connect/token"
        }
      ]
    }
    EOF

 

Notice that we target the marketing tenant since the metadata sections contains "tenant": "marketing". Also notice that the name and relyingPartyId are oidc_marketing and OIDC_Marketing respectively. Remember we must have the name property as a unique value for the provider and all tenants.

 

Now when we use the SAS Viya CLI to load this configuration we must leverage the marketing profile we setup earlier. Also, we must authenticate as the sasprovider user and not sasboot.

 

 

/opt/sas/viya/home/bin/sas-viya --profile marketing auth login -u sasprovider 
/opt/sas/viya/home/bin/sas-viya --profile marketing configuration configurations create \
--file $deploy/site-config/JSON/OIDC_Marketing.json
/opt/sas/viya/home/bin/sas-viya --profile marketing auth logout

 

Again, reviewing the log for SAS Logon Manager, you will see the configuration apply with the following:

 

INFO  2022-01-05 06:43:56.254 +0000 [sas-logon-app] - Refresh keys changed: [tenants.marketing.sas.logon.oauth.providers.oidc_marketing.emailDomain, tenants.marketing.sas.logon.oauth.providers.oidc_marketing.discoveryUrl, 
tenants.marketing.sas.logon.oauth.providers.oidc_marketing.attributeMappings.user_name, tenants.marketing.sas.logon.oauth.providers.oidc_marketing.scopes, 
tenants.marketing.sas.logon.oauth.providers.oidc_marketing.relyingPartySecret, tenants.marketing.sas.logon.oauth.providers.oidc_marketing.clientAuthInBody, 
tenants.marketing.sas.logon.oauth.providers.oidc_marketing.responseType, tenants.marketing.sas.logon.oauth.providers.oidc_marketing.relyingPartyId, tenants.marketing.sas.logon.oauth.providers.oidc_marketing.tokenUrl, 
tenants.marketing.sas.logon.oauth.providers.oidc_marketing.addShadowUserOnLogin, tenants.marketing.sas.logon.oauth.providers.oidc_marketing.linkText, tenants.marketing.sas.logon.oauth.providers.oidc_marketing.authUrl, 
tenants.marketing.sas.logon.oauth.providers.oidc_marketing.showLinkText]

 

So, in this case, the configuration is applied only to the marketing tenant. Notice that each property is only prefaced with tenants.marketing.sas.logon.oauth.providers.oidc_marketing.

 

With these two sets of configurations loaded into the SAS Viya multi-tenant environment we will have:

 

  • Provider login page shows only the link for the M-T provider OIDC configuration
  • Marketing tenant login page shows both links; one for the M-T provider OIDC configuration and one for the marketing tenant OIDC configuration
  • Sales tenant login page shows only the link for the M-T provider OIDC configuration

 

sr_1_OIDC_MT_LogonForm.png

 

Select any image to see a larger version.
Mobile users: To view the images, select the "Full" version at the bottom of the page.


 

One way to prevent the marketing tenant from displaying the M-T provider OIDC link is to ensure the configuration within the marketing tenant has the same name as the configuration within the M-T provider. Which is why we stated earlier the name should be unique. This means in the OIDC_Marketing.json file changing the value "name": "oidc_marketing" to "name": "oidc_provider" to match the value we used in the OIDC_Provider.json file. To do this you will need to first remove the OIDC configuration within the marketing tenant.

 

Removing Tenant OIDC Configuration

We need to remove the existing oidc_marketing configuration from the marketing tenant. This involves both removing the configuration using the SAS Viya CLI and cleaning up one of the database tables used by SAS Logon Manager. You could attempt to clean-up the database table directly; a better approach is to use the SAS Logon Manager API to perform this clean-up.

 

In a future release we expect that removing the configuration with the SAS Viya CLI will be sufficient and no other clean-up will be required.

 

You can use the following commands to delete the existing OIDC configuration from the marketing tenant using the SAS Viya CLI:

 

/opt/sas/viya/home/bin/sas-viya --profile marketing auth login -u sasprovider 
my_id=`/opt/sas/viya/home/bin/sas-viya --profile marketing configuration configurations list |grep -A 1 sas.logon.oauth| awk -F\" '{print $4}'|tail -1`
/opt/sas/viya/home/bin/sas-viya --profile marketing configuration configurations delete --id ${my_id}
/opt/sas/viya/home/bin/sas-viya --profile marketing auth logout

 

Then use the following commands to use the SAS Logon Manager API to remove the oidc_marketing internal reference:

 

/opt/sas/viya/home/bin/sas-viya auth login -u sasboot 
myToken=`cat ~/.sas/credentials.json |jq -r '.Default."access-token"'`
myTenant="marketing"
myHost={{INGRESS_NAME}}
myID=`curl https://${myHost}/SASLogon/identity-providers \
     -H "Content-Type: application/json" \
     -H "Authorization: Bearer ${myToken}" \
     -H "X-Identity-Zone-Id: ${myTenant}" | jq -r '.[] | select(.originKey == "oidc_marketing ").id'`
curl -X DELETE https://${myHost}/SASLogon/identity-providers/${myID} \
     -H "Content-Type: application/json" \
     -H "Authorization: Bearer ${myToken}" \
     -H "X-Identity-Zone-Id: ${myTenant}"
/opt/sas/viya/home/bin/sas-viya auth logout

 

Notice that we are using the SAS Viya CLI to authenticate to the M-T provider as the sasboot user. We then use the internal token that this authentication provides to call the SAS Logon Manager API. But when we call the /identity-providers API we include the X-Identity-Zone-Id header that identifies the marketing tenant. First, we use the /identity-providers API to find the ID of the oidc_marketing definition. Then we use the DELETE method of the /identity-providers API to remove that specific ID.

 

With these two steps complete, SAS Logon Manager should be restarted. Once SAS Logon Manager has been restarted the OIDC configuration can be loaded for the marketing tenant using the SAS Viya CLI. However, this time the name of the configuration will be oidc_provider.

 

Since the name of the configuration loaded to the marketing tenant matches the name loaded to the M-T provider the values from the marketing tenant will supersede those from the M-T provider. This means that the marketing tenant SAS Logon Manager login form will now only display a single link.

 

Preventing a Tenant Displaying the Provider Configuration

Our desired configuration of the SAS Viya multi-tenant environment is almost complete. The M-T provider only uses the M-T provider configuration, and the marketing tenant now only uses the marketing tenant configuration. However, the sales tenant is still using the M-T provider configuration. This might be a desired outcome if we want to share the OIDC configuration between the M-T provider and the sales tenant.

 

Instead, let’s look at how we can prevent the sales tenant using the M-T provider OIDC configuration. This will leave the sales tenant displaying the standard login form with no additional authentication options. Again, we can leverage the SAS Logon Manager API. We will use the SAS Logon Manager API to set the propagated M-T provider configuration as not active in the sales tenant.

 

Use the following commands to update the propagated configuration in the sales tenant using the SAS Logon Manager API:

 

/opt/sas/viya/home/bin/sas-viya auth login -u sasboot 
myToken=`cat ~/.sas/credentials.json |jq -r '.Default."access-token"'`
myTenant="sales"
myHost={{INGRESS_NAME}}
myID=`curl https://${myHost}/SASLogon/identity-providers \
     -H "Content-Type: application/json" \
     -H "Authorization: Bearer ${myToken}" \
     -H "X-Identity-Zone-Id: ${myTenant}" | jq -r '.[] | select(.originKey == "oidc_provider").id'`
myConf=`curl https://${myHost}/SASLogon/identity-providers/${myID} \
     -H "Content-Type: application/json" \
     -H "Authorization: Bearer ${myToken}" \
     -H "X-Identity-Zone-Id: ${myTenant}"`;\
myConf=`echo $myConf|sed 's/"active":true/"active":false/'`
curl -X PUT https://${myHost}/SASLogon/identity-providers/${myID} \
     -H "Content-Type: application/json" \
     -H "Authorization: Bearer ${myToken}" \
     -H "X-Identity-Zone-Id: ${myTenant}" \
     -d "${myConf}"
/opt/sas/viya/home/bin/sas-viya auth logout

 

As before, we authenticate using the SAS Viya CLI as sasboot in the M-T provider. The header X-Identity-Zone-Id then identifies which tenant we are operating in.

 

These commands are using the SAS Logon Manager API to find the ID for the OIDC configuration internally in SAS Logon Manager for the sales tenant. Next we fetch that configuration and update the value "active":true to "active":false. Finally, the updated configuration is uploaded using the SAS Logon Manager API. Setting "active":false within the sales tenant will prevent the configuration being used.

 

Bypassing SAS Logon Manager for an Individual Tenant

Our SAS Viya multi-tenant environment is now showing what we expect on the SAS Logon Manager login form for the M-T provider and the two tenants. The M-T provider page has a link to use the M-T provider configured OIDC, the marketing tenant also has a link but to use the marketing configured OIDC, and the sales tenant does not display any additional links.

 

But what if we want our end-users of the marketing tenant to be automatically redirected to the third-party OIDC provider. So, we don’t want to display the SAS Logon Manager login page for just the marketing tenant. Obviously, the end-users accessing the sales tenant must be able to still access the SAS Logon Manager login page as they have no other way to authenticate.

 

SAS already provides a sample transformer that enables automatic redirect of sign-ins to the configured third-party OIDC provider. This can be found in your deployment assets in the directory $deploy/sas-bases/examples/sas-logon-app/. We will just change the provided sample slightly to target the marketing tenant.

 

You can either copy the sample and edit it or use the following to create the YAML file with the required content:

 

tee $deploy/site-config/sas-logon-app/marketing-login-hint-transformer.yaml > /dev/null << 'EOF'
---
apiVersion: builtin
kind: PatchTransformer
metadata:
  name: sas-ingress-login-hint-transformer
patch: |-
  kind: Ingress
  metadata:
    name: sas-logon-app
    annotations:
      nginx.ingress.kubernetes.io/server-snippet: |
          large_client_header_buffers 4 32k;
          if ( $args !~ "login_hint" ) { set $test A; }
          if ( $uri = "/SASLogon/oauth/authorize" ) { set $test "${test}B"; }
          if ( $request_method = "GET" ) { set $test "${test}C"; }
          if ( $host ~ "marketing." ) { set $test "${test}D"; }
          if ($test = ABCD ) { set $args $args&login_hint=gellab.net; rewrite $uri uri?$args; }
target:
  kind: Ingress
  name: sas-logon-app
EOF

 

These annotations that are added to the Ingress rule for SAS Logon Manager do the following:

 

  1. Check the arguments of the request for an existing `login_hint`parameter, if it is not there set the variable $test to A.
  2. Check the URI of the request to ensure it is `/SASLogon/oauth/authorize`, if is set the variable $test to AB.
  3. Check the HTTP method to see if it is a GET request, if is set the variable $test to ABC
  4. Check the hostname of the request to see if it contains the tenant’s name marketing if it does set the variable $test to ABCD.
  5. Finally, only if the variable `$test` equals ABCD insert the `login_hint=gellab.net` into the request and resubmit the request. Notice, this matches the emailDomain property in the OIDC configuration loaded to the marketing tenant.

 

This means if the GET request to `/SASLogon/oauth/authorize` on the marketing tenant does not have a `login_hint` it will be added. While if the request is not a GET, or already has a `login_hint`, or is not to `/SASLogon/oauth/authorize` on the marketing tenant nothing will happen. Remember the login_hint value is just used as a string match against the text in the emailDomain property and does not have to be an actual email address domain.

 

Next you need to add the reference to the file site-config/sas-logon-app/marketing-login-hint-transformer.yaml to your kustomization.yaml in the transformers section. Then follow the documented commands to rebuild your site.yaml and apply the updated site.yaml.

 

Once this is complete there will be no change in behaviour for the M-T provider or the sales tenant. However, for the marketing tenant when end-users access a web application like SAS Drive, they will no-longer see SAS Logon Manager. If the end-user already has a session with the third-party OIDC Identity Provider, they will just be logged into SAS Drive. Alternatively, if they don’t have a current session with the third-party OIDC Identity Provider they will be presented with the OIDC Identity Provider’s login form.

 

Conclusion

In this article we’ve shown the details of how OIDC configuration is applied to the M-T provider and individual tenants in SAS Viya 2021.2 (and later). Through the examples we’ve shown how the M-T provider configuration is propagated to the tenants. We have shown how this might be a target architecture that you want to have, but also provided a couple of ways to deal with this propagation if you want different configuration in the tenants.



Find more articles from SAS Global Enablement and Learning here.

Version history
Last update:
‎01-22-2022 04:31 AM
Updated by:
Contributors

sas-innovate-2024.png

Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.

 

Register now!

Free course: Data Literacy Essentials

Data Literacy is for all, even absolute beginners. Jump on board with this free e-learning  and boost your career prospects.

Get Started

Article Tags