Skip to content

Conversation

@fitzthum
Copy link
Member

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 AdminRoles struct does not allow unknown fields when deserializing. The admin id is case insensitive. Etc

I created some unit tests. No integration tests yet due to merge conflicts with the previous admin PR.

@fitzthum fitzthum requested a review from a team as a code owner December 16, 2025 17:59
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())
Copy link
Member

Choose a reason for hiding this comment

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

What about

  1. 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)
  2. the input to the the id/subject or claims parsed from the input JWT of header's bearer.
  3. 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)

Copy link
Member Author

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.

Copy link
Member

@Xynnn007 Xynnn007 Dec 20, 2025

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:

  1. 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:

  1. 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.

  2. 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.

  1. 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:

  1. Higher implementation complexity in the initial iteration.

  2. 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?

Copy link
Member Author

@fitzthum fitzthum Dec 22, 2025

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.

Copy link
Member Author

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.

Copy link
Member

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

Copy link
Member Author

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?

Copy link
Member

Choose a reason for hiding this comment

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

Yes. Almost the PR

Copy link
Member Author

@fitzthum fitzthum Jan 7, 2026

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())
Copy link
Member

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)]
Copy link
Member

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?

Copy link
Member Author

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.

@fitzthum
Copy link
Member Author

fitzthum commented Jan 7, 2026

@mythi @mkulke ptal. this is not a very big PR

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.

2 participants