# Sso Using Keycloak

## Installing and Configuring SSO Using Keycloak on Platform9 Managed Kubernetes

In this article, we discuss the implementation of SSO using Keycloak on PMK. PMK can be configured to use any SAML2 provider, including KeyCloak as a specific implementation of the SAML2 IdP.

### What is Keycloak?

Keycloak is an open-source Identity and Access Management (IAM) solution committed to improving secure access to applications and services. Keycloak authenticates users across a unified environment rather than single applications. Once the user is logged in to Keycloak, it delegates the authenticated validation to all affiliated applications. Keycloak also affords a single-sign-out service that specifies that once users log out of Keycloak, their access is revoked across all applications. Keycloak also authenticates individuals using active OpenID Connect or SAML 2.0 Identity Providers. The document describes how to set up keycloak as an IdP for the platform9 on-premise management plane.

## Prerequisites

* Keycloak REALM with a SAML 2.0 Endpoint.

## Configuration

#### Settings within Keycloak

First, log in to the Keycloak UI and choose your realm to create the Platform9 service provider. In this example, we will use a realm named Master. Next, save the SAML 2.0 Identity Provider Metadata in an XML file by clicking on the SAML 2.0 link in the Endpoints section of the Realm Settings. Throughout this document, this XML file will be referenced as metadata.xml. Now, click Realm Settings and choose “SAML 2.0 identity Provider Metadata’ in the Endpoints section. Finally, download the page employing an XML format and save it as metadata.xml.

<figure><img src="https://584068516-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtZryvDiHvZIhOZofYOWU%2Fuploads%2Fgit-blob-9dc24608504b57cfd62d826f487af2e84af8207f%2F1629142360.png?alt=media" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**Info**

The following .xml file include a blank line after the comment section. Users can delete this blank line from the metadata.xml file permissions.
{% endhint %}

{% tabs %}
{% tab title="metadata.xml" %}

```xml
?xml version="1.0" encoding="UTF-8"?>
<!--
  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
  ~ and other contributors as indicated by the @author tags.
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~ http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->
```

{% endtab %}
{% endtabs %}

Now, in the UI, create a platform9 SAML 2.0 client by clicking on ‘Clients’ followed by clicking on 'Create'

<figure><img src="https://584068516-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtZryvDiHvZIhOZofYOWU%2Fuploads%2Fgit-blob-1727028b810762ef7514cefb35f5e0a143a9289a%2F1629142440.png?alt=media" alt=""><figcaption></figcaption></figure>

Type the on-premises DU’s keystone URL, e.g. ‘[https://airctl-4.pf9.localnet/keystone’](https://airctl-4.pf9.localnet/keystone%E2%80%99), then select SAML from the Client Protocol dropdown and click Save.

<figure><img src="https://584068516-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtZryvDiHvZIhOZofYOWU%2Fuploads%2Fgit-blob-ac25124b821e0b41e2e7b8dd2be7810fd2ebb4e3%2F1629142469.png?alt=media" alt=""><figcaption></figcaption></figure>

Next, edit the client settings: Click Clients ⇾ <https://airctl-4.pf9.localnet/keystone> ⇾ Settings and add the following information to the configurations.

{% hint style="info" %}
**Info**

Replace the DU name with the name of your own DU (management plane)
{% endhint %}

{% tabs %}
{% tab title="Bash" %}

```bash
Valid Redirect URIs: https://airctl-4.pf9.localnet/*
Assertion Consumer POST Binding URL: https://airctl-4.pf9.localnet/Shibboleth.sso/SAML2/POST
Assertion Consumer Service Redirect Binding URl: https://airctl-4.pf9.localnet/keystone
```

{% endtab %}
{% endtabs %}

Screenshots of the Client Settings:

<figure><img src="https://584068516-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtZryvDiHvZIhOZofYOWU%2Fuploads%2Fgit-blob-51c99b0d4176a931bf77f5cc1ccbd0ad96d40a46%2F1629142917.png?alt=media" alt=""><figcaption></figcaption></figure>

***

<figure><img src="https://584068516-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtZryvDiHvZIhOZofYOWU%2Fuploads%2Fgit-blob-9d29b997991471bb712a062e798f1c45f90ead4f%2F1629142953.png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://584068516-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtZryvDiHvZIhOZofYOWU%2Fuploads%2Fgit-blob-c194c03b3d8261b31caa86b8838bfc424ae64267%2F1629143053.png?alt=media" alt=""><figcaption></figcaption></figure>

#### Add mappers

In this section, we create mappers using the *FirstName*, *LastName*, *Email*, and *memberOf* attributes of the keycloak user.

<figure><img src="https://584068516-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtZryvDiHvZIhOZofYOWU%2Fuploads%2Fgit-blob-3323968370b056b1605ed6d3c027cb3c56133128%2F1629143153.png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://584068516-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtZryvDiHvZIhOZofYOWU%2Fuploads%2Fgit-blob-0cec60d4b6ba0d4c2ba7c65983e2dd0bdc74f480%2F1629143169.png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://584068516-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtZryvDiHvZIhOZofYOWU%2Fuploads%2Fgit-blob-ca6f1c2e50758e6044325b8005e43af96eaf8718%2F1629143200.png?alt=media" alt=""><figcaption></figcaption></figure>

Finally, create the mappers for the *Email* and *LastName* attributes similarly. In the end, the final mappers view will look like below:

<figure><img src="https://584068516-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtZryvDiHvZIhOZofYOWU%2Fuploads%2Fgit-blob-7979eb8fc933ebb8075f57e8a714024f7e0ce42d%2F1629143221.png?alt=media" alt=""><figcaption></figcaption></figure>

### Appendix A

User properties in keycloak

<figure><img src="https://584068516-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtZryvDiHvZIhOZofYOWU%2Fuploads%2Fgit-blob-e5c85a870e3b85dd9ec23f1951e366d2cf026b28%2F1629144747.png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://584068516-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtZryvDiHvZIhOZofYOWU%2Fuploads%2Fgit-blob-d44a7b77a4b09d56a9a9487865faa46980d09d37%2F1629144760.png?alt=media" alt=""><figcaption></figcaption></figure>

### Appendix B

Reference: export of the client.

{% tabs %}
{% tab title="Bash" %}

```bash
{
    "clientId": "https://airctl-4.pf9.localnet/keystone",
    "baseUrl": "",
    "surrogateAuthRequired": false,
    "enabled": true,
    "alwaysDisplayInConsole": false,
    "clientAuthenticatorType": "client-secret",
    "redirectUris": [
        "https://airctl-4.pf9.localnet/*"
    ],
    "webOrigins": [],
    "notBefore": 0,
    "bearerOnly": false,
    "consentRequired": false,
    "standardFlowEnabled": true,
    "implicitFlowEnabled": false,
    "directAccessGrantsEnabled": false,
    "serviceAccountsEnabled": false,
    "publicClient": false,
    "frontchannelLogout": true,
    "protocol": "saml",
    "attributes": {
        "saml.assertion.signature": "false",
        "saml_assertion_consumer_url_redirect": "https://airctl-4.pf9.localnet/keystone",
        "saml.force.post.binding": "true",
        "saml.multivalued.roles": "false",
        "saml.encrypt": "false",
        "saml_assertion_consumer_url_post": "https://airctl-4.pf9.localnet/Shibboleth.sso/SAML2/POST",
        "saml.server.signature": "true",
        "saml.server.signature.keyinfo.ext": "false",
        "exclude.session.state.from.auth.response": "false",
        "saml.signing.certificate": "MIIC2zCCAcMCBgF4EEPAHzANBgkqhkiG9w0BAQsFADAxMS8wLQYDVQQDDCZodHRwczovL2FpcmN0bC03LnBmOS5sb2NhbG5ldC9rZXlzdG9uZTAeFw0yMTAzMDgwNTE0MzhaFw0zMTAzMDgwNTE2MThaMDExLzAtBgNVBAMMJmh0dHBzOi8vYWlyY3RsLTcucGY5LmxvY2FsbmV0L2tleXN0b25lMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAg4UAoLDMCtQA3n7psSSDcNrIjeNU9+fcd2sTUUq9D8euFc5E8ZJ+RxPdq47eYbdMKdXNEGJYlCrErRxK+BWZ+WkI1tda9K66lTQ+PdnVKz21p18AzIJ2IlrORfVGeyhO7DjKTwT+fk/kaEoG0r+Yzj8pyduI7dJSe0qsyZb2TrxhE0iywpWbBXvEtIFylLNqmGsxatXtB62/7Xy3RQplUZmdRJ8sr24qr9UDcLqI41U0juW2EhKFVJgi15m8URm2H9C6rtAKbahTvDlSZj8boNmM/pAn9d6skPkT77rWJMvotokCWjyp345ph3wppbgDYkVebqWGTenuRBSjFpUv0wIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQA8BPR3NWU7E+Q/J8d9vfCnx9mQSgf50LFuoLeyGeRib3DDBPmhiPGDKcBep3GHT4MzMrCHQJk4YWqil4C1LaJF2MY321hm8HAB1hDf+/TeF+fRCOee5fv4+cuSfRp7HhXqE4xZATYZtqdkQhOl4Id3oyTybVm8bDG9iBHFMVDFwsuedb0HzeJOJJ3q7AvY5RybtVPWWT/Dki7T4or0ZQ28k+xVtaTif2QBQnRZOcMGF4rqTs1fkA6wnp/sH1/ycOQcxrhaMNfGnorRvBgKcexfbk1xu3DK0xudN4EObsrqeYUtnGWNuoDtQ+Ra+i6KPJ9xV8ENOfRsH/uXJMMPVDPb",
        "saml.signature.algorithm": "RSA_SHA256",
        "saml_force_name_id_format": "false",
        "saml.client.signature": "false",
        "tls.client.certificate.bound.access.tokens": "false",
        "saml.authnstatement": "true",
        "display.on.consent.screen": "false",
        "saml.signing.private.key": "MIIEpAIBAAKCAQEAg4UAoLDMCtQA3n7psSSDcNrIjeNU9+fcd2sTUUq9D8euFc5E8ZJ+RxPdq47eYbdMKdXNEGJYlCrErRxK+BWZ+WkI1tda9K66lTQ+PdnVKz21p18AzIJ2IlrORfVGeyhO7DjKTwT+fk/kaEoG0r+Yzj8pyduI7dJSe0qsyZb2TrxhE0iywpWbBXvEtIFylLNqmGsxatXtB62/7Xy3RQplUZmdRJ8sr24qr9UDcLqI41U0juW2EhKFVJgi15m8URm2H9C6rtAKbahTvDlSZj8boNmM/pAn9d6skPkT77rWJMvotokCWjyp345ph3wppbgDYkVebqWGTenuRBSjFpUv0wIDAQABAoIBAAylE/tfJC8CVRcPQq6qYQzPrCqgKcIwA61jmRbexbCntSAZld1YBVYWHeDpuo3Qjr0S9kVV/0g3mHNAXiDeCtDE/XmSeQc/aWcA/974e5tNspJl+vCutmb1LhHh1CXxKS1jBGh2hXVlfwNb4q4Oh8WEoyLqPY8IArAh7Nzw67uEE1brm85LyuoxUaK9j+bxqZzrjYtrf3esuomZEJXhFR2rzBosKxx0ndKG77FkJtIbE9rM3HCCEgM4Q+VmfLglyWSt7XgRjBZ+xLW5vWHYHnoeikSwbGNjij2J3BifkdbvFhh5TlbQ82HT3O7NQoc+4B6JMCYtm1DWSP0E3kZ9LvkCgYEA2MOVshhCHBan6K+b5EQZ5lJncTXR0OoIyfRoKcqmnM0I9g9ngs2d0BDNHNi4hnKcKyKwIV5EZdpJJQXEKjqQwtLeu0SEuXatMFWn5d8+MSBcEHqQO57/xcjY2w7qVV57ZM+Fb/YlCQ37X+sG9HVWYEokQidy7SVKlzZKUGaCqrcCgYEAm1NbnzOV38qzCeLh9FpeQfwazxQGJVTZuoUu9CYEl0lAQjTsCuClj5hL3P3921hj9l92qG7MHGs5X1dyG3e9A51BN5rDaF1zrLRvQEJcmfdzHEHo4jsAo2A8G6/ztYfUuBZUbhrTz6wa3kYyHeNqJ3xY5/lx1jSK85+nAUD5t8UCgYEAsJ4UX+tiGm7fWzmTBNf0XnVwMY9PqTC3/o21PbAQN5zcm1kL10lgN8MozUNMfsfttTvrVRTxGChXBuJ+5oWXpBabQuzeVBt9m+9/AU735qFeQlMLKHkyIF65SywJBYwZcJeiOwrNPGZ3Fr1yikb9HTHr/zcTbmS/NRwYSxBrkVsCgYA3S6ard27cm8m/NEEif2Vc8kYNAGDru1hDuZQsoLgzr4UrzLFXcgAeraYcR2OvSblUhUm1zrPlThq/oV7i/m6QsdP82qDEL7i1fAq7AqT6vwgAwEoK99xTTTg41xvYvUFyQ6jNBcnv/aIXDUBcOZCZ+/+encPz8QKilmya2qnLzQKBgQDHrydZAwBR07V2GNEhLW418jdU/6dyw5+OZo7VGDCLZDPDKjAxirfn1u2Y48bpXvnePwp+iq2y83tC5TwxHhRzkSDel7O4SAEHA2+3/VW3Zfsvaqp2cFWTFOv9KeEUe07wq7tPE2prQbnsyLnemjjwXt6PXADTQwKyoA72KDyFGw==",
        "saml_name_id_format": "username",
        "saml.onetimeuse.condition": "false",
        "saml_signature_canonicalization_method": "http://www.w3.org/2001/10/xml-exc-c14n#"
    },
    "authenticationFlowBindingOverrides": {},
    "fullScopeAllowed": true,
    "nodeReRegistrationTimeout": -1,
    "protocolMappers": [
        {
            "name": "FirstName",
            "protocol": "saml",
            "protocolMapper": "saml-user-property-mapper",
            "consentRequired": false,
            "config": {
                "attribute.nameformat": "Basic",
                "user.attribute": "FirstName",
                "friendly.name": "FirstName",
                "attribute.name": "FirstName"
            }
        },
        {
            "name": "Email",
            "protocol": "saml",
            "protocolMapper": "saml-user-property-mapper",
            "consentRequired": false,
            "config": {
                "attribute.nameformat": "Basic",
                "user.attribute": "Email",
                "friendly.name": "Email",
                "attribute.name": "Email"
            }
        },
        {
            "name": "LastName",
            "protocol": "saml",
            "protocolMapper": "saml-user-property-mapper",
            "consentRequired": false,
            "config": {
                "attribute.nameformat": "Basic",
                "user.attribute": "LastName",
                "friendly.name": "LastName",
                "attribute.name": "LastName"
            }
        },
        {
            "name": "username",
            "protocol": "saml",
            "protocolMapper": "saml-user-property-mapper",
            "consentRequired": false,
            "config": {
                "attribute.nameformat": "Basic",
                "user.attribute": "username",
                "friendly.name": "username",
                "attribute.name": "username"
            }
        },
        {
            "name": "groups",
            "protocol": "saml",
            "protocolMapper": "saml-group-membership-mapper",
            "consentRequired": false,
            "config": {
                "single": "true",
                "attribute.nameformat": "Basic",
                "full.path": "false",
                "friendly.name": "groups",
                "attribute.name": "memberOf"
            }
        }
    ],
    "defaultClientScopes": [
        "web-origins",
        "role_list",
        "profile",
        "roles",
        "email"
    ],
    "optionalClientScopes": [
        "address",
        "phone",
        "offline_access",
        "microprofile-jwt"
    ],
    "access": {
        "view": true,
        "configure": true,
        "manage": true
    }
```

{% endtab %}
{% endtabs %}
