-
Notifications
You must be signed in to change notification settings - Fork 140
Add Admin Roles #1111
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
base: main
Are you sure you want to change the base?
Add Admin Roles #1111
Conversation
| fn validate_admin_token(&self, _request: &HttpRequest) -> Result<String> { | ||
| warn!("Allow All admin backend is set. Anyone can access admin APIs"); | ||
| Ok(()) | ||
| Ok("Anonymous".to_string()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about
- have a separate policy file (no need to be rego, but if rego is good we can use rego) to define admin authZ things (What this PR is intending to do)
- the input to the the id/subject or claims parsed from the input JWT of header's bearer.
- The output is true/false.
We can by default give a allow all/deny all policy.
In this way we can have a simple authZ system that is code-policy-decoupled.
The policy can includes all the "role" names and its acceptable paths (e.g. in regex)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's too complicated. Users are already confused by the two policies we have. Let's only add another one if we absolutely have to. What is implemented here is basically a policy mechanism, but it's made as simple as possible. Let's not do anything more complex unless users explicitly ask for it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, what we are aiming for right now in the admin module is a simple authorization (AuthZ) mechanism, i.e., defining which APIs can be accessed.
The solution proposed in this PR enables a quick way to define roles and their accessible APIs, and it is ready for deployment. This approach is very useful for some internal or short-term projects where simplicity and fast iteration are the primary goals.
However, from a longer-term evolution perspective—especially if we expect more frequent policy changes or additional authorization scenarios - there are a few concerns worth discussing:
- Authorization rules are embedded in startup configuration
Currently, the rules are defined in the KBS configuration at startup time and are not independently versioned or reloadable. As a result, updating or modifying authorization rules requires restarting the entire KBS, which may become inconvenient as policies evolve.
2.Mixed abstraction between token verification and authorization decision
The current validate_admin_token abstraction mixes two different concerns:
- Token Verification / Identity Resolution (e.g., extracting credentials, verifying signatures, validating issuers), and
- Authorization Decision (allow / deny, or mapping to accessible APIs).
In retrospect, this separation was not clearly enforced in earlier designs (including my own previous review in https://github.com/confidential-containers/trustee/pull/1014/changes#diff-57ec221f4d45eb2d52007f10e72821894545bdea23a2ca94924f4a55fe39a44a), and this PR makes the boundary more visible. It may be beneficial to clarify this abstraction going forward.
From a directional and longer-term design point of view (not necessarily a requirement for this PR), one possible evolution could be:
-
Move client authentication toward token-based credentials
As a follow-up direction, the kbs-client could rely on tokens rather than private keys. For example, docker-compose or Kubernetes deployments could generate tokens at launch time and mount them at a well-defined path for the kbs-client to consume. This would be a change that we once talked about and can be considered independently of this PR. -
Conceptually split
admin::validate_admin_token(the module's than the plugin's) into two stages
- Token Verification / Identity Resolution: pluggable implementations that support bearer tokens, JWTs, or other credential formats, and return structured identity or claims.
- Authorization Decision: a separate step that evaluates whether the resolved identity is allowed to access a given API.
This separation could exist conceptually first, even if the initial implementation remains simple.
- Introduce a simple, standalone authorization policy
The authorization decision could be driven by a lightweight policy definition (e.g., file-based), instead of being embedded in startup configuration. KBS would still not perform identity issuance or user management; it would only verify externally issued credentials and apply a local authorization policy. More complex authentication or identity logic could remain out of band.
This direction certainly has drawbacks:
-
Higher implementation complexity in the initial iteration.
-
Increased learning cost for users, who would need to understand the policy model.
That said, this could be mitigated by providing a default policy (e.g., allow_all) for simple use cases.
Overall, the current PR provides a practical and usable solution, while the points above are intended as considerations for future evolution rather than blockers for the current implementation.
wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Runtime configuration of admin roles is out of scope. Maybe sometime we could add an API to update the roles (and store them in the kv backend), but this is complicated, and currently we don't even have an admin login interface.
For 2, I will just rename the upper function to be more generic. We already have a split between checking the token, which is handled by the admin backends, and allowing access to the endpoint. It isn't perfect since the allow-all backend could be specified and roles could block things on top of that, but I've updated the docs to explain the different.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Xynnn007 let's revisit this before the PR gets stale. i renamed a few things and updated the docs. I think it's best to use a simple approach for now. We have some internal people asking for this feature. I am hoping to get some feedback from them after we implement something and iterate if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about this? I will do some changes upon your current PR after getting it merged. including moving key pair to token and some other changes about code structure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, but what do you have in mind generally?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Almost the PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. I have some comments about that PR but we can save for when it is actually posted. It seems fine in general although it's much more complex.
When the admin backend validates a token, it should extract a role string and return it. The role will be used by the common admin code to grant access to specific endpoints. Since the ALlowAll endpoint does not have any roles, it will always return "Anonymous" as the role. Signed-off-by: Tobin Feldman-Fitzthum <[email protected]>
Introduce the admin role configuration at the admin level (rather than the admin backend level). This way, we don't need to duplicate the admin logic for each backend. An admin role matches a particular admin id to a regex. The regex controls which endpoints are allowed. In the future, we could make both fiels regular expressions to more flexibly match different admin ids. If no roles are specified, all admin will have access to all endpoints. This provides backwards compatibility. Signed-off-by: Tobin Feldman-Fitzthum <[email protected]>
Add unit tests for admin roles. Try creating the Admin struct with a few different configs, and validate some requests. I find putting a bunch of JSON into the rstest macro to be hard to read, so these tests just do everything in Rust. Signed-off-by: Tobin Feldman-Fitzthum <[email protected]>
Quick fixup of the integration test. An integration test using roles will follow in a future PR. Signed-off-by: Tobin Feldman-Fitzthum <[email protected]>
Update the KBS config doc to include the structure of the admin roles configuration and a description of how admin roles work. Signed-off-by: Tobin Feldman-Fitzthum <[email protected]>
| fn validate_admin_token(&self, _request: &HttpRequest) -> Result<String> { | ||
| warn!("Allow All admin backend is set. Anyone can access admin APIs"); | ||
| Ok(()) | ||
| Ok("Anonymous".to_string()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about this? I will do some changes upon your current PR after getting it merged. including moving key pair to token and some other changes about code structure
| pub id: String, | ||
| /// A regular expression selecting request paths this rule allows. | ||
| /// In other words, the paths that the above role can access. | ||
| #[serde(default)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That means by default no endpoints can be accessed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. That seems less error-prone.
This is a powerful feature, but it's relatively simple to implement.
First, make each admin backend return a role string. This allows us to implement the role logic not in each individual backend, but in the common admin code. This logic is fairly simple. We have a list of admin roles which specify an id and a regular expression. If no roles are specified, all admin will have access to all requests. This provides backwards compatibility.
Since this is a security-critical configuration, I did some defensive programming. For example, the
AdminRolesstruct does not allow unknown fields when deserializing. The admin id is case insensitive. EtcI created some unit tests. No integration tests yet due to merge conflicts with the previous admin PR.