Skip to content

Conversation

cbbayburt
Copy link
Contributor

This RFC presents two architectural patterns for securely connecting the Uyuni MCP server to the Uyuni API. The core challenge is bridging an OAuth-based system with Uyuni's existing credential-based API. This document details two viable solutions: a "Service Account with Internal Authorization" pattern that requires no changes to Uyuni's codebase, and an "OAuth Token Exchange" pattern that offers tighter integration at the cost of modifying Uyuni. Both designs aim to enable secure, user-delegated actions from an LLM-based agent.

See the rendered version.

@jordimassaguerpla
Copy link

jordimassaguerpla commented Aug 1, 2025

Thanks @cbbayburt for putting this RFC together. It's really helpful to have a clear breakdown of the problem and the different options.

I've been thinking about Pattern 1 and have some concerns about the security of the mcp-service-account. Since it's a single, highly privileged user that all MCP server users would rely on, a compromise of that key would be a huge problem—it would grant full access to Uyuni. The RFC mentions this is a high-impact risk, and I completely agree.

Plus, if the MCP server is run locally, any user would have to know that super user key. If that key is ever compromised, we'd have to revoke it, which would cut off access for everyone.

I think there's a different way we could approach this that might be more secure and still fairly straightforward to implement. Instead of a single powerful API key, what if we used a unique API key for each user?

Here's the basic idea:

  1. The MCP server would securely store a mapping of each user's OAuth ID to their individual Uyuni API key.
  2. When a user delegates an action, the server would retrieve that user's specific key.
  3. The API call to Uyuni would then be made using the user's own key.

I see a few big wins with this approach:

  • Better Security: If a key is compromised, it only affects one user. We can just revoke that single key without impacting anyone else.

  • Easier Auditing: All actions would show up in Uyuni's native logs under the correct user, so we don't have to manage a separate audit log on the MCP server.

  • Built-in RBAC: We can continue to rely on Uyuni's existing RBAC system, so users would only be able to perform actions they're already authorized for.

  • Pragmatic Implementation: This seems easier than implementing the full OAuth token exchange in Pattern 2, as it doesn't require any changes to Uyuni's core codebase.

What do you think? Curious to hear your thoughts on this as a potential alternative.

@cbbayburt
Copy link
Contributor Author

cbbayburt commented Aug 6, 2025

@jordimassaguerpla thanks for the input.

I think there's a different way we could approach this that might be more secure and still fairly straightforward to implement. Instead of a single powerful API key, what if we used a unique API key for each user?

This sounds like a good compromise between the two patterns.

The only part that needs clarification is:

  1. The MCP server would securely store a mapping of each user's OAuth ID to their individual Uyuni API key.

How do we manage the API keys from multiple users? In this pattern, the complexity changes from the authorization logic to key lifecycle management:

  1. How does a new user submit their API key to the MCP server? A manual process where an admin adds/manages API keys for a new user won't be scalable, as API keys can be added and revoked at any time.
  2. What happens when a user's key is revoked in Uyuni or needs to be rotated? We need to make sure the API keys on the MCP server are up-to-date.

A straightforward solution for this could be implementing a simple UI for adding/managing API keys for users. When the user first logs in via OAuth, we can redirect them to this UI to add their API key and store it. Later, at any time, the user can navigate to this UI to manage their key.

Another issue is that we don't have a UI in Uyuni to generate API keys for users. This will need to be implemented in the UI as well.

Nevertheless, I'll add this idea to the RFC for further discussion/comparison.


1. **User Authentication (OAuth)**: The end-user authenticates with the MCP proxy ecosystem via a standard OAuth 2.0 flow. The LLM agent receives a JWT access token representing the user.

2. **MCP Server Authentication**:
Copy link
Member

Choose a reason for hiding this comment

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

This one looks more tricky, since uses one single account to rule them all

Copy link
Contributor

Choose a reason for hiding this comment

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

Would it be advisable to shorten as much as possible the duration of the sessions in this case? Or re-evaluate RBAC permissions in case they somehow changed while the session is still valid.

- A single, non-human **Service Account** (e.g., `mcp-service-account`) is created in Uyuni with a powerful role that includes the permissions necessary to execute any tool within the Uyuni MCP server.
- An API key is generated for this account and stored securely in the MCP server's environment. The MCP server uses this key to authenticate itself to the Uyuni API.

3. **Authorization Flow**:
Copy link
Member

Choose a reason for hiding this comment

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

This is moving the authorization check to the MCP server. It should be relatively safe since it's done by API call to extract the data, but it would still be duplicating the user validation.

3. **The MCP server performs a pre-flight authorization check.** It makes a read-only call to the Uyuni API (`access.list_permissions`) to verify that `alice` has the necessary permissions for the requested action on the target resource.
4. Only if the permission check passes, the MCP server executes the command using its own privileged Service Account API key.

4. **Auditing**: The MCP server **must** maintain its own immutable audit log that maps every executed command back to the originating user's identity from the JWT. This is critical, as Uyuni's native logs will only show the `mcp-service-account` as the actor.
Copy link
Member

Choose a reason for hiding this comment

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

The auditing will be part of MCP and not the MLM. So if we have users interacting directly with MLM and other users MCP, to have a complite picture of the auditing, we need to look at two systems?
I would prefer to keep it all centralized in the MLM server

2. **Custom Authentication Backend in Uyuni**:
- A new API endpoint is added to Uyuni that is capable of validating JWTs issued by the external Authorization Server.

3. **Authorization Flow (Token Exchange)**:
Copy link
Member

Choose a reason for hiding this comment

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

so, basically it enhances the login endpoint to also allow login with JWT tokens instead of just username/password. Then the session token should be sent


---

### Pattern 2: OAuth Token Exchange
Copy link
Member

Choose a reason for hiding this comment

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

I would upvote for this one. The most straightforward approach, and follows all the best standards.

Copy link
Contributor

Choose a reason for hiding this comment

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

Could this be done with some sort of auth proxy? So user sessions would be managed between Uyuni server and the auth proxy.


**Architecture:**

1. **Prerequisite: Implement Native API Key Management in Uyuni**:
Copy link
Member

Choose a reason for hiding this comment

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

This would not be much different from OAuth. The benefit of OAuth is that it is standard and doesn't need revoked. When the tokes is end of live, it cannot be used anymore. Or I'm getting it wrong?


2. **User Authentication (OAuth)**: Same as other patterns. The end-user authenticates via OAuth, and the LLM agent receives a JWT access token.

3. **Per-User API Key Storage**:
Copy link
Member

Choose a reason for hiding this comment

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

If we also need the OAuth token on this approach why over-engineering and ask for another key?

- **Implementation Complexity**: The authorization logic must be carefully implemented and maintained within the MCP server.

**Of Pattern 2 (Token Exchange):**
- **Extra Development Effort**: Requires significant changes to the core Uyuni product to support JWT validation and session exchange.
Copy link
Member

Choose a reason for hiding this comment

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

We just need to have JWT authentication on the login endpoint. Then existing session toke could be used.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also token lifecycle management, as already pointed out.

**Of Pattern 2 (Token Exchange):**
- **Extra Development Effort**: Requires significant changes to the core Uyuni product to support JWT validation and session exchange.
- **Increased Coupling**: Tightly couples Uyuni's authentication mechanism with the external Authorization Server.
- **Complex Setup**: The initial configuration of the trust relationship between Uyuni and the Authorization Server is more complex.
Copy link
Member

Choose a reason for hiding this comment

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

These last 2 items also applies to pattern 3

@jordimassaguerpla
Copy link

@jordimassaguerpla thanks for the input.

I think there's a different way we could approach this that might be more secure and still fairly straightforward to implement. Instead of a single powerful API key, what if we used a unique API key for each user?

This sounds like a good compromise between the two patterns.

The only part that needs clarification is:

  1. The MCP server would securely store a mapping of each user's OAuth ID to their individual Uyuni API key.

How do we manage the API keys from multiple users? In this pattern, the complexity changes from the authorization logic to key lifecycle management:

  1. How does a new user submit their API key to the MCP server? A manual process where an admin adds/manages API keys for a new user won't be scalable, as API keys can be added and revoked at any time.
  2. What happens when a user's key is revoked in Uyuni or needs to be rotated? We need to make sure the API keys on the MCP server are up-to-date.

A straightforward solution for this could be implementing a simple UI for adding/managing API keys for users. When the user first logs in via OAuth, we can redirect them to this UI to add their API key and store it. Later, at any time, the user can navigate to this UI to manage their key.

Another issue is that we don't have a UI in Uyuni to generate API keys for users. This will need to be implemented in the UI as well.

What about we use mcp elicitation?

@cbbayburt
Copy link
Contributor Author

@rjmateus, thanks for the input.

I guess it's obvious that Pattern 2 is the way to go for a standard enterprise setup. I think this will be the only approved solution from SUSE AI as well. And, considering there's also work needed to support API keys in Uyuni, there's not even much development overhead compared to other patterns.

@cbbayburt
Copy link
Contributor Author

@rjmateus @jordimassaguerpla I think I'll just remove alternative patterns to make the RFC simpler before sharing it to a wider audience.

@rjmateus
Copy link
Member

rjmateus commented Aug 7, 2025

@cbbayburt I think you can move the other option to the end in a section Alternatives.
The option 2 is basically add support for OAuth2 on the API methods. MLM manager already have integration for OAuth2 on the UI, maybe we can even re-use the same endpoint and the grab the authentication coookie and re-use it for the json over HTTP calls, since it uses the same authentication mechanism

1. **User Authentication (OAuth)**: The end-user authenticates with the MCP proxy ecosystem via a standard OAuth 2.0 flow. The LLM agent receives a JWT access token representing the user.

2. **MCP Server Authentication**:
- A single, non-human **Service Account** (e.g., `mcp-service-account`) is created in Uyuni with a powerful role that includes the permissions necessary to execute any tool within the Uyuni MCP server.
Copy link
Contributor

Choose a reason for hiding this comment

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

So would it exist a custom Uyuni role for the service that would be read-only access except for whatever is needed to run the available tools, correct?


1. **User Authentication (OAuth)**: The end-user authenticates with the MCP proxy ecosystem via a standard OAuth 2.0 flow. The LLM agent receives a JWT access token representing the user.

2. **MCP Server Authentication**:
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it be advisable to shorten as much as possible the duration of the sessions in this case? Or re-evaluate RBAC permissions in case they somehow changed while the session is still valid.


---

### Pattern 2: OAuth Token Exchange
Copy link
Contributor

Choose a reason for hiding this comment

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

Could this be done with some sort of auth proxy? So user sessions would be managed between Uyuni server and the auth proxy.

- **Implementation Complexity**: The authorization logic must be carefully implemented and maintained within the MCP server.

**Of Pattern 2 (Token Exchange):**
- **Extra Development Effort**: Requires significant changes to the core Uyuni product to support JWT validation and session exchange.
Copy link
Contributor

Choose a reason for hiding this comment

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

Also token lifecycle management, as already pointed out.

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.

4 participants