CI/CD Kubernetes platform Gitorion. Single Sign-On (SSO) to all platform services using Keycloak

Hi all! In the previous article, we looked in detail at the implementation of continuous CD delivery in the Gitorion platform based on Jenkins. In this article, we will take a closer look at the intricacies of implementing the Single Sign-On (SSO) single sign-on system into all services of the Gitorion platform using Keycloak.

Justification for the need for implementation

The Gitorion platform consists of services that implement CI/CD, monitoring and database management:

  • Gitea/Forgejo – lightweight code hosting and version control system based on Git;

  • Jenkins – continuous CD delivery;

  • Grafana – monitoring and visualization of Prometheus metrics;

  • phpMyAdmin – MySQL database management;

  • pgAdmin – PostgreSQL database management.

In total, a basic set of 5 services, each of which has its own authentication system and user database. With a small number of project participants, you can create user logins in each of the five services separately. With a large number of users, the task will become impossible. A unified authentication system and user database is required. We decided to implement Single Sign-On (SSO) using Keycloak.

How Keycloak works

Most modern applications are equipped with Keycloak clients (adapters) that allow you to connect to a Keycloak server. On the application login page there is a button “Connect using Keycloak”. The user clicks on this button, the adapter connects to Keycloak and redirects the user to the Keycloak authentication window. The user enters his username and password. Keycloak checks the user's login and password and redirects the already authenticated user back to the personal account of the service from which the user came.

Realm

Adapters of different services (in our case, all five services of the Gitorion platform) are combined into one area (Realm). By logging into the Web interface of any of the services connected to the Realm area, the user receives a token from Keycloak, which is recorded in the browser Cookie. In the Web interfaces of all other services whose adapters are connected to the same area, the user uses a token, without having to re-enter the login and password. This is how the mechanism of seamless authentication and single sign-on SSO is implemented.

Log in to the Keycloak Administration Console.

Keycloak main window

Keycloak main window

In the region selector at the top left, click the “Create realm” button.

List of areas in Keycloak

List of areas in Keycloak

At a minimum, it is enough to set only the name of the area “Realm name” and click the Create button.

Create a Realm in Keycloak

Create a Realm in Keycloak

Connecting the client (adapter) of the application to Keycloak

4 out of 5 services are equipped with adapters out of the box – Gitea/Forgejo, Jenkins, Grafana and pgAdmin. Below we will look at connecting the Gitea/Forgejo adapter to Keycloak as an example. Adapters for other services are well documented and connected in the same way. phpMyAdmin does not have a Keycloak adapter under the hood. We will consider connecting applications that do not have a Keycloak adapter or are not protected by an authentication window at all below.

Select the area created above, go to the Clients menu and click the “Create client” button.

Create a Gitea/Forgeo client in Keycloak

Create a Gitea/Forgeo client in Keycloak

Set “Client ID” – this is the unique identifier of the client (adapter). Click Next.

Gitea/Forgejo client (adapter) parameters

Gitea/Forgejo client (adapter) parameters

In the next window, enable “Client authentication” and click Next.

Enable authentication in the Keycloak client (adapter) settings

Enable authentication in the Keycloak client (adapter) settings

In “Root URL” specify the application URL to which the user will be redirected if Keycloak authentication is successful. Click the Save button.

Set the application URL to redirect back from Keycloak

Set the application URL to redirect back from Keycloak

After the client has been created, go to the Credentials tab and copy the “Client Secret”, which will be required below when setting up Gitea/Forgejo. With this key, the Gitea/Forgejo client will confirm its authenticity when connecting to Keycloak.

Gitea/Forgejo client (adapter) access key to Keycloak

Gitea/Forgejo client (adapter) access key to Keycloak

Let's move on to setting up Gitea/Forgejo. Log in to Gitea/Forgejo as a user with administrative rights and go to the control panel.

Administrator menu in Gitea/Forgejo

Administrator menu in Gitea/Forgejo

Go to the “Identity & Access” Authentication submenu and click the “Add New Source” button.

Add a new authentication source to Gitea/Forgejo

Add a new authentication source to Gitea/Forgejo

In the “Client ID (key)” field, enter the value that you entered above when setting up the client in Keycloak in the “Client ID” field. In the “Client Key” field, set the value to “Client Secret”, copied above from the Credentials tab of the client settings in Keycloak. In the “Icon URL” field, specify the icon that will be displayed on the Gitea/Forgejo authentication window opposite the “Log in with keycloak” button.

Keycloak Authentication Source Options in Gitea/Forgejo

Keycloak Authentication Source Options in Gitea/Forgejo

“Open ID Connect URL for login automation” go to the “Realm Settings” settings menu by copying the “Open ID Endpoint Configuration” link into Keycloak.

Link to Endpoint Keycloak parameters

Link to Endpoint Keycloak parameters

Click the “Add New Source” button in Gitea/Forgejo and a new authentication source will be created, bound to Keycloak. A “Login with keycloak” button will appear on the Gitea/Forgejo authentication page.

Keycloak login button on Gitea/Forgejo interface

Keycloak login button on Gitea/Forgejo interface

The user clicks on the “Login with keycloak” button and is redirected to the Keycloak authentication window.

Authentication window in Keycloak

Authentication window in Keycloak

The user enters the username and password, and if authentication is successful, Keycloak redirects the user to his personal account in Gitea/Forgejo.

User's personal account in Gitea/Forgejo

User's personal account in Gitea/Forgejo

And a user session will appear in Keycloak.

Active user session in Keycloak

Active user session in Keycloak

Database of logins and user groups

Keycloak can either independently store logins, passwords and other information about users in its own database, or act as a provider to external authentication sources, such as Microsoft Active Directory, LDAP, etc. In our case, an external authentication source was not required, and we created logins and user groups directly in Keycloak.

Login to your Keycloak admin console, select an area and go to the Groups menu. In our case, we divided all users into two groups:

  • admins – users with administrative rights in all services (for team leads);

  • devs – users with read-only rights (for developers).

User groups in Keycloak

User groups in Keycloak

Click the “Create group” button and enter a group name.

Create a user group in Keycloak

Create a user group in Keycloak

Click the Create button. Repeat the same steps and create the devs group.

Next, as an example, let's create a user owneruser and add it to the admins group. And also the user user1 and add him to the devs group. Go to the Users menu and click the “Add users” button.

Users in Keycloak

Users in Keycloak

Enter user details. Be sure to specify an email (Grafana uses the user's email instead of a login for authentication).

User Settings

User Settings

Click the “Join Groups” button, add the user to the admins group and click the Join button.

Add a user to a group

Add a user to a group

Click the Create button to create a user. Similarly, create the user user1 and add it to the devs group.

Authorization based on Roles

Authorization and delimitation of powers were required in Jenkins and Grafana. Team leads needed to be given full access so that they could create pipelines in Jenkins and dashboards in Grafana. And give developers read-only permissions so that they can monitor their pipelines and monitor the load on dashboards in Grafana.

Login to the Keycloak admin console, go to the “Realm roles” menu.

List of roles Roles area

List of roles Roles area

Click the “Create role” button. In the next window, specify a name for the role and click the Save button.

Parameters of the created role

Parameters of the created role

Go to the Groups menu, select the admins group and go to the “Role mapping” tab.

Group Roles Tab

Group Roles Tab

Click the “Assign role” button, select the admins role and click the Assign button.

Associate a role with a group

Associate a role with a group

Likewise, associate the devs group with the devs role. Now, in case of successful authorization, Keycloak, among other information about the user, will also transfer the user’s role to the service from which the user came to authenticate. And the service will be able to authorize the user and assign permissions in accordance with his role. Keycloak transmits information about the client to Scopes, a list of which can be viewed in the “Client scopes” menu.

List of Scopes Areas

List of Scopes Areas

Among other Scopes, there are roles by default.

Configure role-based permissions in Jenkins. Go to the “Manage and Assign Roles” section in the Jenkins settings and select the “Maname Roles” sub-item. In the window that appears, in the “Role to add” field, enter the name of the role admins and click the Add button. Add the devs role in the same way. In the access matrix, set the Administer checkbox for the admins role in the Full column, and for the devs role check the Read checkbox in the Full and Task columns.

Setting up roles in Jenkins

Setting up roles in Jenkins

Log in to Jenkins as owneruser from the admins group, and you will have access to the “+ Create Item” option for adding pipelines and the “Configure Jenkins” settings item.

User account with administrative rights in Jenkins

User account with administrative rights in Jenkins

Log in as user1, and the items for creating pipelines and Jenkins settings will disappear. It will only be possible to view information about pipelines.

User account with read-only rights in Jenkins

User account with read-only rights in Jenkins

For Grafana, you need to associate Keycloak roles with the built-in Grafana roles in the grafana.ini configuration file.

role_attribute_path: contains(realm_access.roles[], 'admins') && 'Admin' || contains(realm_access.roles[], 'editor') && 'Editor' || 'Viewer'

Associate the admins role from Keycloak with the Admin role from Grafana. All other roles are associated with the Viewer role in Grafana.

Login to Grafana via Keycloak as owneruser from the admins group and you will have full access to Grafana settings.

Personal user account with administrative rights in Grafana

Personal user account with administrative rights in Grafana

The user user1 from the devs group has read-only rights, and the Administration item is missing from the menu.

User account with read-only rights in Grafana

User account with read-only rights in Grafana

Application authentication without adapter

Some applications do not have a Keycloak adapter under the hood, and sometimes are not protected by an authentication window at all. You can close such applications with a login and password and configure authentication for them via Keycloak using the mod_auth_openidc module included in Apache2. In this case, the apache2 server interacts with Keycloak and implements authentication for the Location, where the application that requires authentication needs to be located. Such an application in our case turned out to be phpMyAdmin, which has its own authentication, but does not have a Keycloak client. The developers suggest implementing SSO yourself using this script.

In the config.inc.php configuration file for phpMyAdmin, switch the standard authentication using login and password to authentication using the signon.php script

$cfg['Servers'][$i]['auth_type']     = 'signon';
$cfg['Servers'][$i]['SignonSession'] = 'SignonSession';
$cfg['Servers'][$i]['SignonURL']     = 'examples/signon.php';

And configure Location for phpMyAdmin in apache2

LoadModule auth_openidc_module modules/mod_auth_openidc.so

ServerName gitrion.ru

<VirtualHost *:80>

    ServerName phpmyadmin
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html/
    DirectoryIndex examples/signon.php

    OIDCProviderMetadataURL https://auth.gitorion.ru/realms/gitrion/.well-known/openid-configuration
    OIDCRedirectURI /redirect_uri
    OIDCDefaultURL https://phpmyadmin.staging.gitorion.ru:443/
    OIDCCryptoPassphrase 0123456789
    OIDCClientID phpmyadmin
    OIDCClientSecret 2jb0IUaoAfYUxPpAuJSwtcF2EEMEMdOb

    OIDCRemoteUserClaim preferred_username

    OIDCXForwardedHeaders X-Forwarded-Host
    OIDCXForwardedHeaders X-Forwarded-Port
    OIDCXForwardedHeaders X-Forwarded-Proto

    <Location />
    FallbackResource index.php
    DirectoryIndex index.php
        AuthType openid-connect
        Require valid-user
    </Location>

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

</VirtualHost>

When going to the phpMyAdmin web interface, the user is redirected to the Keycloak authentication window. If authentication is successful, Keycloak will redirect the user to the phpMyAdmin personal account.

User's personal account in phpMyAdmin

User's personal account in phpMyAdmin

Browser Flow and restricting access within an area based on Roles

Adapters for the Gitea/Forgejo, Jenkins, Grafana Web interfaces and the phpMyAdmin and pgAdmin database Web interfaces for the development, staging and production circuits are located in the same area. A developer, having logged into any of the platform’s Web interfaces, will have access to the Web interfaces for database management in the development circuit, as well as in the staging and production circuits. Which is unacceptable! It was possible to block developer access to the Web interfaces of databases in the staging and production circuits by adding Roles-based access checks to the Browser Flow for phpMyAdmin and pgAdmin clients (adapters). Browser Flow specifies the order in which client access parameters are checked. By default, the presence of the token in Cookei is first checked. If the user has previously logged in and has a token, then the user is granted access to the service. If not, you are prompted to enter your username and password. We created a custom Browser Flow based on the default one, which, after checking the token in Cookie and login with password, also checks the user’s Role and denies access to users with the devs role to the Web interfaces of databases in the staging and production circuits.

Log into the Keycloak administrative console, select an area, go to the Configure menu, Authentication submenu, click the three-dot icon to the right of Flow called browser and click the Duplicate button.

List of Flows areas

List of Flows areas

Set a name for the custom Flow and click the Dupliacate button.

Duplicate browser Flow

Duplicate browser Flow

Go to Flow browser-custom and add a Sub-flow named RBAC to browser-custom forms.

Add Sub-flow RBAC access checks based on Roles

Add Sub-flow RBAC access checks based on Roles

In Sub-flow RBAC, add Condition user-role.

Add Condition user role

Add Condition user role

Click on the gear to the right of Condition user-role, set Alias ​​and associate it with the devs role.

Associate the Condition user role with the devs role

Associate the Condition user role with the devs role

Add Step Deny Access

Step Deny Access

Step Deny Access

Click the gear to the right of Step Deny Access, set the Alias ​​and the text of the message that will be displayed to the user from the devs group when trying to access databases in the staging and production circuits.

Error message

Error message

Connect a custom Flow browser-custom to the phpMyAdmin and pgAdmin clients (adapters) in the staging and production circuits. Go to the Advanced tab in the client settings, go to the very bottom and set browser-custom in the Browser Flow field.

Set a custom Browser Flow

Set a custom Browser Flow

When a user with the devs role tries to access the database Web interface in the staging or production loops, a warning will appear.

Access error message

Access error message

Conclusion

In this article, we highlighted our experience in implementing Single Sign-On (SSO) into all services of the Gitorion platform using Keycloak. We welcome feedback, comments and constructive criticism. Thank you.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *