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.
-
**0. Implement a POC for step-up auth for admin area and for group => Draft: OIDC Step-up auth: Enhanced reauth for a... (!160899) -
1. Step-up auth for admin area (and admin users): Require step-up (re-)auth when admin user accesses admin area -
Hide step-up auth feature behind a feature flag => Step-up auth: Add omniauth step-up auth for adm... (!171643) -
Store step-up auth state in session in callback controller => Step-up auth: Add omniauth step-up auth for adm... (!171643) -
Create model to encapsulate acr auth method, similar to CurrentUserMode
=> Step-up auth: Add omniauth step-up auth for adm... (!171643) -
Check if current admin user session has necessary acr
value (consider with/without admin mode) -
Add feature tests for more advanced scenarios => Draft: Step-up auth: Add feature tests for step... (!176095) and Draft: Step-up auth: Add feature tests for diff... (!175986) -
Provide configuration to define the necessary acr
value for the admin area -
Integrate step-up auth state in session -
Implement deletion of step-up auth session object related to the admin mode when leaving the admin mode -
Implement the requested state for admin mode -
Evaluate if it is necessary to move the session to redis namespaced approach just like it is done for amdin mode -
Show info text regarding step-up auth state in active sessions view => Draft: Step-up auth: Show step-up auth for admi... (!175441) -
Implement evaluation of step-up auth conditions for array value (array values are to be evaluated in a sorted way) -
Implemnent experiation date for the step-up auth state and process; GitLab needs to ask for re-authentication with step-up after a default time or after the experiation time returned by the IdP -
Implement step-up auth states as suggested here -
Implement new structure for step-up auth session as suggessted here -
Implement an UI page in admin area to see the current configuration for step-up authentication -
Include the documentation url for step-up whenever possible to provide a click link to the users -
Refine / Finalize documentation for oidc step-up authentication -
Ensure that admin user (admin mode) is still allowed to do everythign even though group requires step-up authentication -
Ensure to allow step-up auth settings only for oauth oidc providers and not for others (?) -
Use prepare provider route to stub the oauth provider setting for openid_connect -
Rollout feature flag
-
-
2. Step-up auth for projects and groups: Require step-up (re-)auth when a user accesses a project / group -
Add model attribute for required provider for group => !176295 -
Enforce step-up auth protection for group => !176295 -
Evaluate if parent (ancestor) group is step-up auth protected -
Implement the UI in the group setting page to enable step-up auth for the given group -
Refine / Finalize documentation for oidc regarding group scope -
Consider parent groups and root namespaces when evaluating if the step-up authentication is required -
Ensure that admin user (admin mode) is still allowed to do everythign even though group requires step-up authentication -
Refine / Finalize documentation for oidc step-up authentication
-
-
3. Step-up auth for personal access tokens (PAT): Initiate OAuth 2.0 Step Up Authentication Challenge Protocol for certain projects / groups -
TBD
-