Authentication onboarding and single sign-on

You can onboard workloads to Identity and Access Management (IAM) and configure single sign-on (SSO).

Onboarding is the configuration of workloads in IBM Cloud Private IAM. You can configure your workloads to obtain the authentication and authorization service requirements. As part of this process, the workloads must make themselves be known to IAM as a service by registering themselves with the authentication and the authorization services.

Customizing the authentication URL

Default configuration of OpenID Connect (OIDC) in IBM Cloud Private uses <cluster_lb_address>:8443 in the authentication endpoints, which are used to authenticate users to Kubernetes. However, in the issuerURL, an internal or local host IP address is used. This configuration of the issuerURL is required in a VMware NSX-T environment. In environments where NSX-T is not configured, the internal or local host IP address that is used in the issuerURL might cause authentication errors. As a workaround, you can change the issuerURL endpoint to use a hostname or external IP address for Kubernetes authentication by completing the following configurations. You must use the same hostname or external IP address, and port in all the following updates:

  1. Add the external IP address and port in the platform-auth-idp configmap.

    a. Edit the platform-auth-idp configmap. You need kubectl to run the command. For more information about installing kubectl, see Installing the Kubernetes CLI (kubectl).

     kubectl -n kube-system edit cm platform-auth-idp
    

    b. Update the OIDC_ISSUER_URL parameter value with the external IP address and port. The external IP address is the cluster_lb_address that you configure in the config.yaml file during installation. For more information, see Cluster access settings.
    If you enabled SSO in your cluster, you must first complete the following steps. After you complete the steps, you can re-enable SSO.

    1. Back up the Security Assertion Markup Language (SAML) Identity Provider (IDP) metadata file.
    2. Disable SSO. You need the IBM Cloud Private CLI to run the command. For more information about installing the IBM Cloud Private CLI, see Installing the IBM Cloud Private CLI.
      cloudctl iam saml-disable
      
    3. Get the MongoDB pod name.
      kubectl get pods | grep mongodb
      
    4. Log in to the MongoDB container.
      kubectl exec -it <MongoDB pod name> /bin/bash -n kube-system
      
    5. Connect MondoDB client with MongoDB. Use the cluster administrator credentials.
      mongo --host rs0/mongodb:27017 --username $ADMIN_USER --password $ADMIN_PASSWORD --authenticationDatabase admin --ssl --sslCAFile /data/configdb/tls.crt --sslPEMKeyFile /work-dir/mongo.pem
      
    6. Run the following commands to delete the saml collection entry in the samlDB database:

      1. Show all databases.

        show databases
        
      2. Select the SAML database.

        use samlDB
        
      3. Drop the SAML database that has the old configuration.

        db.saml.drop()
        
      4. Exit the MongoDB shell.

        exit
        
      5. Exit the MongoDB container.

        exit
        
    7. Update the OIDC_ISSUER_URL parameter value with the external IP address and port.
    8. Enable SAML.
      cloudctl iam saml-enable
      

    c. Save the changes.

    d. Get the auth-idp pod name.

     kubectl get pods | grep auth-idp
    

    e. Delete the auth-idp pod to restart it.

     kubectl delete pod <auth-idp-pod-name>
    

    f. Upload the SAML IDP metadata file that you backed up.

     cloudctl iam saml-upload-metadata --file <metadata_file>
    
  2. Add the external IP address and port to the clusterrolebinding resource.

    a. Get the clusterrolebinding resource name.

     kubectl get clusterrolebinding | grep oidc
    

    Following is a sample output:

     oidc-admin-binding                       30d
    

    b. Open the clusterrolebinding resource for editing.

     kubectl -n kube-system edit clusterrolebinding oidc-admin-binding
    

    c. Change the URL in the subjects.name parameter.

      subjects:
      - apiGroup: rbac.authorization.k8s.io
        kind: User
        name: https://127.0.0.1:9443/oidc/endpoint/OP#admin
    

    Change name: https://127.0.0.1:9443/oidc/endpoint/OP#admin to name: https://<cluster_lb_address>:8443/oidc/endpoint/OP#admin.

    d. Save the changes.

  3. Add external IP address and port to the master.json file.

    a. Change directory to where the master.json file is located.

     cd /etc/cfc/pods/
    

    b. Open the master.json file for editing.

     vi master.json
    

    c. Locate the apiserver section.

    d. Change the "--oidc-issuer-url=https://127.0.0.1:9443/oidc/endpoint/OP" value to "--oidc-issuer-url=https://<cluster_lb_address>:8443/oidc/endpoint/OP" or https://<cluster_lb_address>:8443/idauth/oidc/endpoint/OP.

    e. Save and exit the master.json file.

    f. Restart the API server by moving out the master.json file from the /etc/cfc/pods/ directory and then moving it back.

Onboarding a workload

The first step towards onboarding the workload to the authentication service of IBM Cloud Private is to register itself as a client of the authentication service based on Liberty. The registration is an important step because it is through this registration that the IBM Cloud Private authentication service knows the following information about the workload:

Most of the content workloads have a login page of their own and would want to redirect to their service-specific dashboard page after a successful login.

The OpenID Connect (OIDC) Client Registration process requires access to a secret that is in the kube-system namespace. You can view the OAUTH2_CLIENT_REGISTRATION_SECRET from the Kubernetes secret platform-oidc-credentials. The following methods are available for obtaining the OAuth secret and for automatic registration:

To manually onboard, that is obtain the secret and register the client, use the cloudctl or IAM.

Onboard by using cloudctl

For more information about the cloudctl IAM commands, see IBM Cloud Private CLI iam commands (iam).

  1. Install cloudctl. For more information, see Installing the IBM Cloud Private CLI.

  2. Construct the client registration payload.
    Following is a sample content from the registration.json file:

      {
      "token_endpoint_auth_method":"client_secret_basic",
      "client_id": "<WLP_CLIENT_ID>",
      "client_secret": "<WLP_CLIENT_SECRET>",
      "scope":"openid profile email",
      "grant_types":[
         "authorization_code",
         "client_credentials",
         "password",
         "implicit",
         "refresh_token",
         "urn:ietf:params:oauth:grant-type:jwt-bearer"
      ],
      "response_types":[
         "code",
         "token",
         "id_token token"
      ],
      "application_type":"web",
      "subject_type":"public",
      "post_logout_redirect_uris":[
         "https://<ICP_PROXY_IP>:<PORT_WHERE_SERVICE_RUNS>"   ],
      "preauthorized_scope":"openid profile email general",
      "introspect_tokens":true,
      "trusted_uri_prefixes":[
         "https://<ICP_ENDPOINT>:<port>", "https://<ICP_PROXY_IP>"    ],
      "redirect_uris":["https://<ICP_PROXY_IP>:<PORT_WHERE_SERVICE_RUNS>/auth/liberty/callback"]
      }
    
  3. Create the customized version of your regisration.json content by editing the sample content.
    The wlp_client_id and wlp_client_secret can be generated by the content service. Your output might resemble the following code:

       wlp_client_id: {{ randAlphaNum 32 | b64enc | quote }}
       wlp_client_secret: {{ randAlphaNum 32 | b64enc | quote }}
    
  4. Register a client with the IBM Cloud Private authentication service.

    cloudctl iam oauth-client-register -f registration.json
    

Onboard by using IAM

  1. Install kubectl. For more information, see Installing the Kubernetes CLI (kubectl).

  2. Obtain the OAUTH secret:

    OAUTH2_CLIENT_REGISTRATION_SECRET=$(kubectl -n kube-system get secret platform-oidc-credentials -o yaml | grep OAUTH2_CLIENT_REGISTRATION_SECRET | awk '{ print $2}' | base64 --decode)
    
  3. Construct the client registration payload.
    Following is a sample content from the registration.json file:

      {
      "token_endpoint_auth_method":"client_secret_basic",
      "client_id": "<WLP_CLIENT_ID>",
      "client_secret": "<WLP_CLIENT_SECRET>",
      "scope":"openid profile email",
      "grant_types":[
         "authorization_code",
         "client_credentials",
         "password",
         "implicit",
         "refresh_token",
         "urn:ietf:params:oauth:grant-type:jwt-bearer"
      ],
      "response_types":[
         "code",
         "token",
         "id_token token"
      ],
      "application_type":"web",
      "subject_type":"public",
      "post_logout_redirect_uris":[
         "https://<ICP_PROXY_IP>:<PORT_WHERE_SERVICE_RUNS>"   ],
      "preauthorized_scope":"openid profile email general",
      "introspect_tokens":true,
      "trusted_uri_prefixes":[
         "https://<ICP_ENDPOINT>:<port>", "https://<ICP_PROXY_IP>"    ],
      "redirect_uris":["https://<ICP_PROXY_IP>:<PORT_WHERE_SERVICE_RUNS>/auth/liberty/callback"]
      }
    
  4. Create the customized version of your regisration.json content by editing the sample content.
    The wlp_client_id and wlp_client_secret can be generated by the content service. Your output might resemble the following code:

       wlp_client_id: {{ randAlphaNum 32 | b64enc | quote }}
       wlp_client_secret: {{ randAlphaNum 32 | b64enc | quote }}
    
  5. Register a client with the IBM Cloud Private authentication service. Run the following API command from any node that has access to the master node:

    curl -i -k -X POST -u oauthadmin:$OAUTH2_CLIENT_REGISTRATION_SECRET -H "Content-Type: application/json" --data @platform-oidc-registration.json https://icp-ip:port/idauth/oidc/endpoint/OP/registration
    

Authentication enforcement by workloads

After you register the content service as a client of IBM Cloud Private authentication service, you can use the IBM Cloud Private OIDC authentication endpoints to enforce authentication. IBM Cloud Private supports two authentication protocols: OIDC and Security Assertion Markup Language (SAML). The OIDC-based authentication service is the default service in IBM Cloud Private. If required, you can be configure a SAML server to provide federated authentication.

OIDC and SAML are both used for single-sign on with IBM Cloud Private, but for different purposes.

IBM Cloud Private is an OIDC identity provider and provides authentication and authorization services to the IBM Cloud Private management console and APIs. It works along with one or more Lightweight Directory Access Protocol (LDAP) providers to authenticate the user ID and password with the LDAP service. It provides an access token for subsequent requests to IBM Cloud Private services. IBM Cloud Private is an identity provider through LDAP.

You can configure IBM Cloud Private as a SAML service provider to allow federated authentication with an external SAML 2.0 identity provider. When you log in to the management console, your browser is redirected to the third-party party login page and OIDC issues a bearer token to you.

The following endpoints can be used to enforce authentication for both the OIDC-based and SAML-based authentication services:

OIDC Endpoints for Authentication

IBM Cloud Private provides OIDC-based authentication through WebSphere Liberty server. The IAM authentication micro service manages the OIDC authentication. This authentication is backed by the Liberty-based OIDC server for providing local and LDAP directory-based authentication.

The following standard OIDC APIs are supported by IBM Cloud Private:

Similarly, https://icp-ip:port/oidc/endpoint/OP/token returns an encrypted token and can be used for all IBM Cloud Private APIs. https://icp-ip:port/idauth/oidc/endpoint/OP/token returns an unencrypted token and cannot be used for IBM Cloud Private APIs; it can be used by a content service for authentication or by a service that requires a default OIDC provider.

UI authentication - OAUTH Dance implementation

OAuth Dance is an authentication process that identifies users who use OAuth. It follows a two-step process:

  1. Call to the /authorize endpoint with client_id, scope, redirect_uri, and grant_type. The /authorize endpoint presents a login page where you can enter your user name and password. On successful authentication, a code is returned. Following are the default parameters:

    • scope: openid+email+profile
    • client_id: The unique ID that is used to recognize a service with
    • response_type: code
    • redirect_uri: https://ip:port/callback. The URL to which the user is redirect to after successfully authentication. In an OAuth dance, the call to the /authorize endpoint is with response_type value equal to the code.

    Following is an example of the authorize endpoint that calls the IBM Cloud Private management console login page:

    GET https://<Cluster Master Host>:<Cluster Master API Port>/idprovider/v1/auth/authorize?client_id=client_id&scope=openid&redirect_uri=redirect_uri&response_type=code&state=state
    
  2. After the user is authenticated, the OIDC server returns a code. The service that runs on the redirect_uri and listens on this URL, retrieves the code (https://ip:port/callback?code=xvcbdb) and calls the /token endpoint to retrieve the token. Following are the default parameters:

    • client_id: The service client ID
    • client_secret: The service client secret
    • scope: openid
    • redirect_uri: https://ip:port/callback
    • grant_type: authorization_code

The /authorize endpoint from the list of OIDC APIs can be used by the content service for its user interface based login. This API requires the client ID and secret to be passed to the IBM Cloud Private authentication service to make out where the user must be redirected to after a successful authentication. These URIs are the redirect_uris that are specified during the client registration process.

The redirect_uris is the callback that the Liberty server can call for completing the OAUTH Dance. This callback URL of the content service must take the authorization code and then send the /token request to get the valid access tokens. With these tokens set in the session, the content service can forward the request to the intended page on its service from successful authentication.

CLI authentication

IBM Cloud Private supports CLI-based authentication. If you are running sidecar applications and want to use IBM Cloud Private security features for authentication, you can use the following APIs by running the Curl commands:

Authenticate by using your user name and password:

curl -k -X POST -H "Content-Type: application/x-www-form-urlencoded;charset=UTF-8" \
-d "grant_type=password&client_id=<ID>&client_secret=<secret>&username=admin&password=admin&scope=openid" \
https://<Cluster Master Host>:<Cluster Master API Port>/idprovider/v1/auth/identitytoken --insecure

Where, <Cluster Master Host>:<Cluster Master API Port> is defined in Master endpoints.

Following is a sample output:

{
  "access_token": "38400d87f39a7c328a4605265eb601bebd9426e2ef6f1b51a449da6a9cb08e03543857ac4ffbd7d2c259867c89324563c5a89f026683aca9262858ae7ffb1e635242eabab3d579793e8f9da09070708dccf2a8d660f3be06550f02af681d2fa64562fb9dc3df1b19839a5d3933311f89348634fa6908fa7d2d50584ffd36f9dc298a3411d3f5abad5c7f45283428ecf0de249eac5534136c31317493f85363126bfe9a6f582403c34a3dab96e3e7bba83c263f1a4ff8d8609fca888852e097e3bc382b822576a53e55e6753c57f79d5703cf6b6bed4b015702ce3ce1636fd834944231fa77eb90079bca398be511f22fd58792a3766a100af10f274e6b9d75a2be2fe6ab18a3ce2ed0c8da7542e0b79f08e32a9ddced6a389572e6247230e1b62adf5fb0ee6549c06f99b85afc7cccd7a51012dea5df40fc27a934be37e9465ddb46a4f43ec542faecb4e6dd062189392b802b8a0ad8c38a00a14f7b9625bcdab251b87cd478c0e5d3c79f8887797da767f209f5fb2b3d44c8b051f49c2ed680a14cd15388b545ca573540184bb27be28378dbe0ecbe2d71c0ac3d7365fce5f1948ead1576f444f70c87d7ba89352b0d2b795a11ccc5ad06441c4143a3e78f80316c72110ba7062159f249719c664818befd6514b1526498729fe624852128495a5fa9c57ba8c9386a1040e0bb8013e93a751722de6e85966994cefce4c43066",
  "token_type": "Bearer",
  "expires_in": 43199,
  "scope": "openid",
  "refresh_token": "ryJlHRTJu0ZWgpDm9Ci11YenaPUk2ehZ51p1gAmL2w5VAThuff",
  "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdF9oYXNoIjoiNjZrYjBqMTY1NDBuN3ZhZXczem4iLCJyZWFsbU5hbWUiOiJjdXN0b21SZWFsbSIsInVuaXF1ZVNlY3VyaXR5TmFtZSI6ImFkbWluIiwiaXNzIjoiaHR0cHM6Ly9teWNsdXN0ZXIuaWNwOjk0NDMvb2lkYy9lbmRwb2ludC9PUCIsImF1ZCI6IjZhNTVlMWEzZmY1Mjc5NjY2YTBiNmI4NzcxYTViMzEwIiwiZXhwIjoxNTI5MzQzOTM4LCJpYXQiOjE1MjkzMTUxMzgsInN1YiI6ImFkbWluIiwidGVhbVJvbGVNYXBwaW5ncyI6W119.OHZTG7I5SjTk3uHIJsk7zzg5ueQM5fEU9nC11jSvpRw-tm1T-OBqjKHPQ_g-uhmFuuym3hvQcEB-wRQi4NMB_d580eeXHYYl_NiawunkHIl7AISQQetc7HS4U7ZXx3Mc2EmvqyVyo0zSYowGfT6D_X36O_E6Riz-_rrGvc1nrzOdGa8IjJIi_GncSs5IFNUQxtRA9ZwdtIbQcRrSs9B3hPH8sJqUnaZnOjAkctJA8zQY0eV3IAZ4lFc01_hT5DrOdtAiSAQBoakttxbY8iqEaNHAc07wUiN6J4rcgtJE2ZwOZth1D_39KyD5nbRbNO8HJh6hYFcBplFGwp9FDZb27A"
}

This API returns an access_token, id_token, and a refresh_token. The access_token is used for authorization of IBM Cloud Private security components that include team, user, user group, service ID, service, API key, and other components. The id_token is used for authorization of Kubernetes components that include pods, daemonsets, services, and other components. The refresh_token can be used to retrieve fresh tokens in case the tokens are expired.

Retrieve a fresh token

curl -H "Content-Type: application/x-www-form-urlencoded;charset=UTF-8" \
-d "grant_type=refresh_token&client_id=<ID>&client_secret=<secret>&scope=openid&refresh_token=ryJlHRTJu0ZWgpDm9Ci11YenaPUk2ehZ51p1gAmL2w5VAThuff" \
https://<Cluster Master Host>:<Cluster Master API Port>/idprovider/v1/auth/token --insecure

Following is a sample output:

{
  "access_token": "77f3ea9695e50d147a3081990c331f8ce9baa0b6d02ac4e970c886eabccd7aa7e7f12e1897ceacbdf6bdaf0881ed5a725f214209eb20b9415c2fcf4ad1afb90412a247aeab6ab0e026e08013b8f2b773b5bdb2d8d3c1247e9e7ebeaa8c9c9c66c1e85caf78105e35e934a28f21619bef2ff17cebe75792da86b4a65c19973713559569e92ae6aa86ddb8ee48991c6ced9caf41ae6c3b88f67fcaacf8c2c6af82018b5f55a4e35c1b9026438b690a606de0314bdced35eab21642b4b6c33c5241db457f2564840b9d32c255d0bfa9e4fda176416f7481c205ee98912790a11134597ce7245264669568fd69153a8e2f240df9edb4df3b219e213c3cfb0366713802a9a525fe85c9ec2a8c54ba61b5d845054ff23eb466c990c15dcb025ef320f36bb21ec0d0a412bcdecafba57da6b239891e22c139a7d4057f84fd741215ed5567c3f4b824d9bbfe92d56b77fe1712d35cea60e12f5207b727e3cc658db1b8b5002780049a5faefd8ccc2ccee9100472dfff58978ee3e7303547dc4ea03025275e58ec4e3da8e6ae91939bfb092f1ce78fe2d91124c179f55bda4027957093090c4f47037771e9cacf227867063c909e9aee3bf87140426052821116c6484037822a41f05a0fa565276b5ff1a8a654d3d5d119f6a665469a7591e4ec197d6a90bd586b8b95e227b9869b8654c23c10f78fc6a3fcbbe6d543638f379736193643",
  "token_type": "Bearer",
  "expires_in": 43199,
  "scope": "openid",
  "refresh_token": "5QM3H8fmGjxhPRyYlQ77s4Z5APOHVk5276ItT8q41e2xKNMxF6"
}

Validate tokens

At any point in time, if you want to validate the tokens that you received by using the previous APIs, you can use either user information or introspect call. See the following APIs:

Get user information
export ACCESS_TOKEN=<Your access token>
curl -k -X POST --header "Authorization: Bearer $ACCESS_TOKEN" \
https://<Cluster Master Host>:<Cluster Master API Port>/idprovider/v1/auth/userInfo

Following is a sample output:

{
  "sub":"admin",
  "iss":"https://mycluster.icp:9443/oidc/endpoint/OP"
}
Call introspect endpoint
export TOKEN=<your token>
export CLIENT_ID=<client_id>
export CLIENT_SECRET=<client_secret>

Get the basic authorization header by using the following commands:

BASIC_AUTH_HEADER=`echo -n "$CLIENT_ID:$CLIENT_SECRET" | base64 -w 0`
curl -H "Authorization: Basic $BASIC_AUTH_HEADER" -d "token=$TOKEN" https://<Cluster Master Host>:<Cluster Master API Port>/idprovider/v1/auth/introspect

Revoke a token

If you want to revoke a particular token instead of waiting for its expiry, you can use the following API:

export TOKEN=<Your access token here>
export CLIENT_ID=<client_id here>
export CLIENT_SECRET=<client_secret here>

Get the Basic authorization header by using the following commands:

BASIC_AUTH_HEADER=`echo -n "$CLIENT_ID:$CLIENT_SECRET" | base64 -w 0`
curl -k -X POST -H "Authorization: Basic $BASIC_AUTH_HEADER" -d "token_type_hint=access_token&token=$TOKEN" \
https://<Cluster Master Host>:<Cluster Master API Port>/idprovider/v1/auth/revoke

Following is a sample output:

{}