As the saying goes, the first impression is everything. For any new user leveraging OpenShift for the first time, whether they are able to succeed in taking advantage of what the platform has to offer quickly and easily may ultimately determine whether they will continue to use the services. They may be interested in deploying a container image, exploring the metrics and monitoring dashboards, or learning more about the capabilities of the platform. While OpenShift provides two primary methods of interaction, the Command Line Interface (CLI) tool, and the Web Console, most first time users will leverage the Web Console. When navigating to the web console for the first time, users are (in most cases) presented with a login page for which they will need to authenticate against one of the defined identity providers. These providers can range from GitHub, OIDC, LDAP, or a simple htpasswd based configuration. In addition to any of the defined identity providers, OpenShift also includes a special kubeadmin user that has cluster administrator rights and is treated as a root user of the platform. An example of the page presented to users when multiple identity providers is shown below.

While having access to the kubeadmin user is useful for platform administrators, it not only presents challenges to end users accessing the platform for the first time, but can also represent a security issue as it exposes the presence of an administrative user. OpenShift does provide the ability to remove the kubeadmin user; however, it is good to have an alternate option for escalating to an administrative user in the event that it becomes necessary (for example, when access via an identity provider is not available). Fortunately, OpenShift does provide capabilities to obscure the visibility of the kubeadmin user within the web console through the ability to customize the web console and specifically the login provider selection page. This functionality not only streamlines the end-user experience, but hardens the security posture of the platform.

Customizing the web console involves the following steps:

  1. Use the OpenShift CLI to generate a baseline template to start from.
  2. Add the template as a secret.
  3. Update the OAuth Custom Resource to specify the name of the secret containing the template created previously.

Three templates relating to the login process can be customized:

  1. Error page
  2. Login page
  3. Login provider selector page

The login provider page is where the customizations to obstruct visibility to the kubeadmin user can be implemented and will be the focus throughout this discussion.

Removing the Kubeadmin User From the Provider Selection Page

NOTE: If you have not added an identity provider to your OpenShift environment, follow the OpenShift documentation to define a provider, such as HTpasswd of your choosing.

To remove the kubeadmin user from being a selectable option from the OpenShift identity provider selection page, first, generate the template for the provider selection page by executing the following command to create a file called providers-default-template.html:

$ oc adm create-provider-selection-template > providers-default-template.html

The file generated is a golang template-based resource that is used to display all the registered identity providers as authentication options as well as the kubeadmin user if enabled. The goal here is to modify the content of the template so that it does not display the kubeadmin user as an available option, even though it is still available for use.

What you may have noticed by browsing the generated providers-default-template.html template file is that it is fairly generic. It does not contain any of the existing styling and UI elements that you would typically find by navigating to the OpenShift web console. This is ideal if you are interested in heavily customizing the user experience, such as adding your own organizational branding and styling scheme. However, in our case, we just want to customize provider display logic while still retaining the out-of-the box styling. This can be accomplished by combining the logic contained in the generated template with the content of the provider selection page in the running cluster.

Obtain the content of the provider selection page by executing the following command, which will save the contents to a file called providers-template.html:

$ curl -sLk https://console-openshift-console.apps.<base-domain>/auth/login > providers-template.html

The primary area of interest in the downloaded providers-template.html file is the content within the <main> tag, as the remainder is static content. The logic to populate the list of providers can be found in the source code of the oauth-server:

<main class="pf-c-login__main">
   <div class="pf-c-login__main-body">
   {{ if eq (len .Providers) 1}}
       <a class="pf-c-button pf-m-primary pf-m-block" href="{{ (index .Providers 0).URL }}">Log In</a>
   {{ else }}
       <h1 class="pf-c-title pf-m-3xl">Log in with&hellip;</h1>
       <ul>
       {{ range $provider := .Providers }}
           <li class="idp">
           <a href="{{$provider.URL}}" class="pf-c-button pf-m-secondary pf-m-block" title="Log in with {{$provider.Name}}">{{$provider.Name}}</a>
           </li>
       {{ end }}
       </ul>
   {{ end }}
   </div>
</main>

The logic in this golang template is as follows: If a single identity provider is defined in the cluster, a button with the words “Log In” will be displayed. Otherwise, the list of providers will be iterated upon and display a button with the name of the provider for the user to select. The logic for displaying a button if a single identity provider is defined is a carryover from when this was a configurable option in OpenShift 3. This option is no longer configurable in OpenShift 4, and as a result, the user is instead automatically sent to the login page for the identity provider. Since that logic is no longer necessary, we can safely remove the logic moving forward, which leaves us with the following:

<main class="pf-c-login__main">
   <div class="pf-c-login__main-body">
       <h1 class="pf-c-title pf-m-3xl">Log in with&hellip;</h1>
       <ul>
       {{ range $provider := .Providers }}
           <li class="idp">
           <a href="{{$provider.URL}}" class="pf-c-button pf-m-secondary pf-m-block" title="Log in with {{$provider.Name}}">{{$provider.Name}}</a>
           </li>
       {{ end }}
       </ul>
   </div>
</main>

 

Now, we can focus on the iteration of the providers starting on line 5. To avoid displaying the button for the kubeadmin user, a conditional check can be performed to assess whether the name of the current provider in the loop is named “kube:admin,” the name of the kubeadmin identity provider. The template with this logic included is displayed below:

<main class="pf-c-login__main">
   <div class="pf-c-login__main-body">
       <h1 class="pf-c-title pf-m-3xl">Log in with&hellip;</h1>
       <ul>
       {{ range $provider := .Providers }}
           {{ if ne $provider.Name "kube:admin" }}
               <li class="idp">
               <a href="{{$provider.URL}}" class="pf-c-button pf-m-secondary pf-m-block" title="Log in with {{$provider.Name}}">{{$provider.Name}}</a>
               </li>
           {{ end }}
       {{ end }}
       </ul>
   </div>
</main>

With the necessary logic in place, replace the contents of the <main> tag in the downloaded providers-template.html file with the content above. An example can be found here.

 

Next, create a secret in the openshift-config project containing the new providers selection template:

$ oc create secret generic providers-template --from-file=providers.html=providers-template.html -n openshift-config

Next, update the content of the OAuth custom resource to specify the template to use for the provider selection page:

$ oc patch oauth.config.openshift.io cluster --type='json' -p='{"spec":{"templates":{"providerSelection":{"name":"providers-template"}}}}' --type=merge

Once the OAuth custom resource has been updated, the authentication operator will deploy a new set of OAuth server pods. When the deployment is complete, navigate to the OpenShift web console to confirm that the kubeadmin user is no longer available as an option to login on the selector page.

 

The option to hide identity providers is not limited to just the kubeadmin user; any registered identity provider can be added to the conditional check as shown below. For example, if there was a desire to have the identity provider named “secret_identity_provider” not be available as a selectable option in addition to the kubeadmin user, the following template could be used:

<main class="pf-c-login__main">
   <div class="pf-c-login__main-body">
       <h1 class="pf-c-title pf-m-3xl">Log in with&hellip;</h1>
       <ul>
       {{ range $provider := .Providers }}
           {{ if or (ne $provider.Name "kube:admin") (ne $provider.Name "secret_identity_provider")  }}
               <li class="idp">
               <a href="{{$provider.URL}}" class="pf-c-button pf-m-secondary pf-m-block" title="Log in with {{$provider.Name}}">{{$provider.Name}}</a>
               </li>
           {{ end }}
       {{ end }}
       </ul>
   </div>
</main>

Accessing the Kubeadmin User

While we were successful in removing the kubeadmin from being displayed in the list of available identity providers, there still may be a need for authenticating against it to perform administrative functions. Fortunately, it can still be accessed by modifying one of the path parameters in the login flow.

To regain access to the login page for the kubeadmin user, navigate to the OpenShift web console where you will be presented with the list of available identity providers that will omit the kubeadmin user. Select one of the available providers, which will present you with the page to provide credentials. Copy the current URL that is generated by the oauth server and replace the name of the selected identity provider path with “kube:admin,” the name of the kubeadmin identity provider. The updated URL to access the login page for the kubeadmin user will appear similar to the following:

https://oauth-openshift.apps.<base-domain>/login/kube:admin?then=%2Foauth%2Fauthorize%3Fclient_id%3Dconsole%26idp%3Dkubeadmin%26redirect_uri%3Dhttps%253A%252F%252Fconsole-openshift-console.apps.<base-domain>%252Fauth%252Fcallback%26response_type%3Dcode%26scope%3Duser%253Afull

 

Navigate to the location of the newly constructed URL and confirm that you are able to login successfully using the credentials for the kubeadmin user.

Customizing the Identity Provider Name

Another enhancement that can be made to the provider-selection page of the OpenShift Web Console is specifying a more user-friendly name of the identity provider. By default, the name of the provider registered in the OAuth server is displayed. This name may not be applicable to end users, as it could relate to a technical implementation instead of a more common name that users would be accustomed to, such as ldap_ad, as the provider name referring to the use of the LDAP identity provider connecting to a Microsoft Active Directory backend. Instead of this more technical name, the display name given to users could be “Enterprise Login”. As with each of the prior sections, this type of enhancement to specify more user-friendly names can be made in the provider-selection template.

As demonstrated with our examples previously, a single end user facing identity provider is registered to the cluster called my_htpasswd_provider and makes use of the scenario as described in the “Configuring an HTPasswd Identity Provider” section of the OpenShift documentation. Instead of displaying “my_htpassword_provider”, let’s change the title to display “HTPasswd Login”.

To implement this change, conditional logic can be added to the golang template while iterating over the provider. If the name of the provider matches one of the providers we are looking to customize, use the custom name. Otherwise, use the default name of the provider. This change can be implemented using the following content of the <main> tag:

<main class="pf-c-login__main">
   <div class="pf-c-login__main-body">
     <h1 class="pf-c-title pf-m-3xl">Log in with&hellip;</h1>
     <ul>
       {{/* Iterate over Identity Providers */}}
       {{ range $provider := .Providers }}


        {{/* Set the name of the provider  */}}
       {{ $providerName := $provider.Name }}


        {{/* Set a custom display name for a known provider  */}}
       {{ if eq $providerName "my_htpasswd_provider" }}
       {{ $providerName = "HTPasswd Login" }}
       {{ end }}


        {{/* Show providers that are not kube:admin  */}}
       {{ if ne $provider.Name "kube:admin" }}
       <li class="idp">
         <a href="{{$provider.URL}}" class="pf-c-button pf-m-secondary pf-m-block"
           title="Log in with {{$providerName}}">{{$providerName}}</a>
       </li>
       {{ end }}
       {{ end }}
     </ul>
   </div>
 </main>

Additional golang template logic is being applied in this example. Let’s walk through the changes. A variable to hold the name of the provider is defined on line 9 and defaults to the name of the provider in the cluster. Line 12 performs a conditional check to assess whether the name of the current provider is “my_htpasswd_provider”, and if so, sets the name of the provider to the custom name (HTPasswd Login). This name is then used in the button on line 19. If there was a desire to implement custom names for multiple identity providers, they could be defined through the use of additional conditional statements starting on line 14.

With an understanding of the changes needed to be made to allow for a custom name for an identity provider, make a copy of the providers-template.html file called providers-custom-httpd-name-template.html and replace the content of the <main> tag with the snippet from above.

Replace the existing template by first deleting the existing secret and creating a new secret containing the updated template:

$ oc delete secrets -n openshift-config providers-template
$ oc create secret generic providers-template --from-file=providers.html=providers-custom-httpd-name-template.html -n openshift-config

As soon as the new secret containing the updated template is created, the authentication operator will deploy a new set of OAuth server pods. Navigate to the OpenShift web console once again to confirm the custom name is now displayed on the provider selection page:

 

Wrapping It Up

These enhancements, albeit small in the context of what OpenShift as a platform can bring, enable a more personalized user experience that allows the end user to quickly be able to accomplish their goals with as little barrier to entry as possible.

Examples of each of the preceding scenarios above can be found in this repository.

Do you have an idea of how to further enhance the login experience? Submit them as an enhancement share with the greater community.


About the author

Andrew Block is a Distinguished Architect at Red Hat, specializing in cloud technologies, enterprise integration and automation.

Read full bio