Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restructure authentication policies. #1232

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open

Conversation

partim
Copy link
Member

@partim partim commented Sep 12, 2024

This PR restructures how authentication policies are used in Krill. It removes the use of Oso and its policy definition language and instead switches to simple, straightforward mappings between permissions, roles, and users.

The existing concept of roles is augmented to serve as the central configuration option for limiting a user’s access to certain action and resources. Roles are now user configurable via the new auth_roles configuration directive. For each role, a set of permissions has to be provided. Optionally, a list of resource handles (vulgo: CAs) can be given in which case access is limited to these resources.

The authentication providers now assign one of these roles to each logged in user.

The OpenID Connect provider now only determines claims for “id,” i.e., the user name, and the “role.” Since we replaced the previous use of JMES paths with custom functions with a more stringent model of matching and substitution, the configuration had to change in a non-compatible way, anyway, so we cleaned it up a bit and switched from a map to an array for the claims.

For the config file provider, this was already possible by adding a “role” attribute. This has now been changed into a “role” field of the user details. In order to make upgrading seamless, the “role” attribute is still accepted but a deprecation warning is logged. Since the auth_users configuration is not used for the OpenID Connect provider any more, the password_hash and salt fields of the user details are now mandatory.

Custom policies have been removed.

This currently is an unfinished draft PR.

@partim partim marked this pull request as draft September 12, 2024 11:50
@partim
Copy link
Member Author

partim commented Sep 12, 2024

At this point, I have removed the oso and jmespath crates and shifted all policy decisions into the new daemon::auth::policy module. However, the module is currently just a stub. Next we need to define the actual policy configuration and implement it.

@partim
Copy link
Member Author

partim commented Oct 30, 2024

The auth::policy module is gone again and has been split into private auth::roles and auth::permissions modules with their types re-exported at auth.

I have also implemented the new strategy outlined in #1229 with a tweak: the OpenID Connect provider now only resolves the ID and role name from the claims. The roles themselves are defined in the configuration and include both the permissions and possible limitations for the CAs access is allowed to. This means you can’t include the allowed CAs in the OpenID Connect claims any more but hopefully this is fine.

Still missing for this PR to leave draft state are documentation adjustments, both internally and in the manual.

@partim partim marked this pull request as ready for review November 6, 2024 15:59
@partim
Copy link
Member Author

partim commented Nov 6, 2024

Both implementation and documentation are done now. This now needs some testing, in particular the OpenID Connect parts, but it is ready for review now.

@partim partim linked an issue Nov 7, 2024 that may be closed by this pull request
@partim
Copy link
Member Author

partim commented Nov 13, 2024

Alright, I‘m calling this done. Now have at it ;)

# or readwrite depending on which GUID was matched. The GUIDs for your groups
# will be different than those used in this example, see your Krill log for the
# GUIDs to match on.
# [[auth_openidconnect.claims]]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the examples for Azure and the others are outdated now that you've split id_claims and role_claims.

# For array claim values, the first element is
# used.
#
# subst No This field describes a transformation of a
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might be nice to add (maybe as an example) that this may just be a literal rather than a substitution if used without match. I.e. the case "if you can log in, you're admin".

@@ -1022,7 +1021,7 @@ pub async fn metrics(req: Request) -> RoutingResult {

//------------ Publication ---------------------------------------------------

/// Handle RFC8181 queries and return the appropriate response.
/// MyHandle RFC8181 queries and return the appropriate response.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this was intentional :-)

}

Err(Self::internal_error(
format!("OpenID Connect: no value found for '{}' claim.", dest),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error message also bubbles up when a user that doesn't match any roles successfully logs in, which might be confusing.

// and don't result in an obvious timing difference between
// the two scenarios which could potentially
// be used to discover user names.
if encoded_hash != user_password_hash {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this was not changed recently, but I don't like the "succeed unless it fails" flow for authentication. I prefer an explicit "fail unless it succeeds" flow, as if authentication becomes more complex in the future, then making a small mistake where the checks are all bypassed becomes easier.

IdTokenAdditionalClaim,
UserInfoStandardClaim,
UserInfoAdditionalClaim,
fn default_id_claims() -> Vec<TransformationRule> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps make it more explicit in the config/manual that this is the default (and does not need to be manually configured)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Replace use of JMES paths.
3 participants