OIDC step-up auth: Allow higher trust levels for admin area and groups / projects
Context / Background
Certain enterprise organizations have strict high security requirements. In such an environment, users in self-hosted GitLab setup need prove their identity with multiple auth methods (beyond MFA) to when accessing certain security-critical projects or groups, e.g. device-based, location-based authentication.
In most cases, these enterprise organizations have internal identity providers (IDPs) that have already implemented a variety of authentication methods and the OIDC auth standard. We can levergage the IDPs and OIDC to ensure that a GitLab users meets the security requirements. With GitLab's omniauth OIDC provider, it possible to integrate these IDPs as authentication providers.
With OIDC it is possible to define Authentication Context Classes (ACRs) in the IDP and bind these ACRs to certain auth methods and security levels. When a users is authenticated then the IDP ensures that the desired ACR (high or low) is met.
Problem / Motivation
Currently, it is possible to define a fixed ACR for the integrated IDP that is used to authenticate the user. For example, we can define a strong ACR and require all users to use the strongest auth method (highest security level) even if the projects of the user would require much weaker auth methods. Vice versa, if we define a weaker ACR it would not be enough for GitLab admin users because we would like to enfore a stronger authentication.
In order to strike the balance between strong security and usability, it would be good to implement step-up authentication. With step-up auth, users can access some resources with one set of credentials but will prompt them for more credentials when they request access to sensitive resources, e.g. accessing the admin area or specifc projects. This could be implemented by defining the desired ACRs in a dynamic way. But, this is not possible at the moment.
Proposal / Solution
We do not believe that step-up auth flow and it's logic should be implemented by GitLab. In other words, the user should not be asked for more credentials inside the GitLab application.
Instead, we propose to implement step-up authentication and dynamic ACRs in combination with the OIDC omniauth provider (already integrated in GitLab). In other words, the step-up auth flow is delegated completely to the OIDC-compatible identity providers (IDP). GitLab informs the IDP which ACR is necessary and the IDP ensures the user authenticates with the necessary ACR (security level).
For the integration of GitLab and the IDPs, we rely on the OIDC standard and the OIDC implementation from different identity providers (IDP), e.g. Keycloak, etc. According to the OIDC specification, authorization endpoint accepts two ways to request the desired acr
values:
- By adding the request param
acr_values
that provides a comma-separated list of desired auth context class (acr
values) that the IdP should try to fulfill, e.g.http://keycloak.local/realms/step-up-auth-gitlab-realm/protocol/openid-connect/auth?acr_values=gold&client-id=...
. - By specifying the desired
acr
values in the request paramclaims
(in a url-encoded way), e.g.http://keycloak.local/realms/step-up-auth-gitlab-realm/protocol/openid-connect/auth?claims="id_token":{"auth_time": {"essential": true},"acr": {"values": ["gold"] }}&client-id=...
.
Note: Depending on the IdP's implementation, either way should be accepted.
The IdP will assess if the user already contains the necessary acr and initiates a step-up auth flow if necessary. After completing the auth flow, the user is redirected back to GitLab's omniauth callback endpoint. Among others, this callback request also contains the acr
value that was reached by the user. The callback request is processed and the acr
value is stored in the user session. Similar to how the session is checked by GitLab, the acr
value of the user session can also be checked everytime the user accesses a GitLab page.
The following flowchart illustrates the proposed request flow.
flowchart LR
1[1. User requests a GitLab page
that requires step-up auth,
e.g. /admin]
2{2. GitLab checks if
session metadata includes the necessary ACR}
3[3. Check succeeded and
render the requested page]
4[4. Redirecting user
to authorization endpoint of IDP
with the necessary acr]
5[5. Wait for IDP to authenticate user and
return to omniauth callback endpoint]
6[6. Store the acr value in session metadata]
7[7. Redirect to originally requested page]
1 --> 2
2 -->|Yes,
necessary ACR exists
in session metadata| 3
2 -->|No,
necessary ACR does not exists
in session metadata| 4
4 --> 5
5 --> 6
6 --> 7
7 -.Request flow repeats.-> 1
Implementation plan
In the spirit of start small, we propose to start with the admin users / admin area and extend the step-up auth capability to "normal" users and projects and groups.
-
1. Step-up auth for admin area (and admin users): Require step-up (re-)auth when admin user accesses admin area -
Create new feature flag -
Store acr
value in session in callback controller -
Create model to encapsulate acr auth method, similar to CurrentUserMode
-
Check if current admin user session has necessary acr
value (consider with/without admin mode) -
Provide configuration to define the necessary acr
value for the admin area -
Rollout feature flag
-
-
2. Step-up auth for projects and groups: Require step-up (re-)auth when a user accesses a project / group -
TBD
-
-
**3. Step-up auth for personal access tokens (PAT): Initiate OAuth 2.0 Step Up Authentication Challenge Protocol for certain projects / groups -
TBD
-