|
| 1 | + |
| 2 | +// Module included in the following assemblies: |
| 3 | +// |
| 4 | +// *mcp_gateway_config/mcp-gateway-authorization.adoc |
| 5 | + |
| 6 | +:_mod-docs-content-type: PROCEDURE |
| 7 | +[id="proc-mcp-gateway-authorization_{context}"] |
| 8 | += Configuring {mcpg} authorization with an AuthPolicy |
| 9 | + |
| 10 | +[role="_abstract"] |
| 11 | +The following example demonstrates using a Kuadrant `AuthPolicy` custom resource (CR) with Common Expression Language (CEL) to implement role-based access control. You can use this procedure as a general pattern for applying the authorization specific to your use case. The {mcpg} supports Istio or Gateway API compatible authorization mechanisms. |
| 12 | + |
| 13 | +.Prerequisites |
| 14 | + |
| 15 | +* You installed {mcpg}. |
| 16 | +* You installed {prodname}. |
| 17 | +* You configured a `Gateway` object. |
| 18 | +* You completed authentication procedures. |
| 19 | +* You configured your identity provider to include `group` and `role` claims in JSON Web Tokens (JWT). |
| 20 | +
|
| 21 | +.Procedure |
| 22 | + |
| 23 | +. Ensure that your identity provider includes the required `group` and `role` claims in the issued JWTs. In the following example, {keycloak} is used: |
| 24 | ++ |
| 25 | +.Example issued OAuth token claims: |
| 26 | +[source,json] |
| 27 | +---- |
| 28 | +{ |
| 29 | + "resource_access": { |
| 30 | + "mcp-ns/arithmetic-mcp-server": { |
| 31 | + "roles": ["add", "sum", "multiply", "divide"] |
| 32 | + }, |
| 33 | + "mcp-ns/geometry-mcp-server": { |
| 34 | + "roles": ["area", "distance", "volume"] |
| 35 | + } |
| 36 | + } |
| 37 | +} |
| 38 | +---- |
| 39 | ++ |
| 40 | +* The `"mcp-ns/arithmetic-mcp-server"` specification must match the namespaced name of the `MCPServerRegistration` CR. |
| 41 | +* The `"roles": ["add", "sum", "multiply", "divide"]` parameter and values specify the roles representing the allowed tools. |
| 42 | +
|
| 43 | +. Configure tool-level authorization by creating an `AuthPolicy` CR that enforces tool-level access control, as shown in the following example: |
| 44 | ++ |
| 45 | +.Example tool-level access control AuthPolicy |
| 46 | +[source,yaml,subs="+quotes"] |
| 47 | +---- |
| 48 | +apiVersion: kuadrant.io/v1 |
| 49 | +kind: AuthPolicy |
| 50 | +metadata: |
| 51 | + name: _<mcp_tool_auth_policy>_ |
| 52 | + namespace: _<gateway_system>_ |
| 53 | +spec: |
| 54 | + targetRef: |
| 55 | + group: gateway.networking.k8s.io |
| 56 | + kind: Gateway |
| 57 | + name: _<mcp_gateway>_ |
| 58 | + sectionName: _<mcps>_ |
| 59 | + rules: |
| 60 | + authentication: |
| 61 | + 'sso-server': |
| 62 | + jwt: |
| 63 | + issuerUrl: http://keycloak.example.com:8002/realms/mcp |
| 64 | + authorization: |
| 65 | + 'tool-access-check': |
| 66 | + patternMatching: |
| 67 | + patterns: |
| 68 | + - predicate: | |
| 69 | + request.headers['x-mcp-toolname'] in (has(auth.identity.resource_access) && auth.identity.resource_access.exists(p, p == request.headers['x-mcp-servername']) ? auth.identity.resource_access[request.headers['x-mcp-servername']].roles : []) |
| 70 | + response: |
| 71 | + unauthenticated: |
| 72 | + headers: |
| 73 | + 'WWW-Authenticate': |
| 74 | + value: Bearer resource_metadata=http://mcp.example.com:8001/.well-known/oauth-protected-resource/mcp |
| 75 | + body: |
| 76 | + value: | |
| 77 | + { |
| 78 | + "error": "Unauthorized", |
| 79 | + "message": "MCP Tool Access denied: Authentication required." |
| 80 | + } |
| 81 | + unauthorized: |
| 82 | + body: |
| 83 | + value: | |
| 84 | + { |
| 85 | + "error": "Forbidden", |
| 86 | + "message": "MCP Tool Access denied: Insufficient permissions for this tool." |
| 87 | + } |
| 88 | +---- |
| 89 | ++ |
| 90 | +* Replace `metadata.name:` with the name of the `AuthPolicy`. |
| 91 | +* Replace `metadata.namespace:` with the namespace where the `AuthPolicy` CR is applied. |
| 92 | +* Replace `spec.targetRef.name:` with the name of the `Gateway` CR. |
| 93 | +* The `spec.targetRef.sectionName:` value targets the MCP server listener. |
| 94 | +* Authentication: Validates the JWT token using the configured issuer URL |
| 95 | +* Authorization Logic: CEL expression checks if user's roles allow access to the requested tool |
| 96 | +* CEL Breakdown: |
| 97 | +** `request.headers['x-mcp-toolname']`: The name of the requested MCP tool, stripped from prefix. |
| 98 | +** `request.headers['x-mcp-servername']`: The namespaced name of the MCP server matching the `MCPServerRegistration` CR. |
| 99 | +** `auth.identity.resource_access`: The JWT claim containing all roles representing each allowed tool the user can access, grouped by MCP server. |
| 100 | +* Response handling: Custom `401` and `403` responses for unauthenticated and unauthorized access attempts. |
| 101 | +
|
| 102 | +. Apply the AuthPolicy CR by running the following command: |
| 103 | ++ |
| 104 | +[source,terminal,subs="+quotes"] |
| 105 | +---- |
| 106 | +$ oc apply -f _<mcp_tool_auth_policy.yaml>_ |
| 107 | +---- |
| 108 | +* Replace `_<mcp_tool_auth_policy.yaml>_` with the name of the `AuthPolicy` YAML filename. |
| 109 | +
|
| 110 | +.Verification |
| 111 | + |
| 112 | +. Monitor authorization decisions by checking the `AuthPolicy` CR `status` with the following command: |
| 113 | ++ |
| 114 | +[source,terminal] |
| 115 | +---- |
| 116 | +$ oc get authpolicy -A |
| 117 | +---- |
| 118 | ++ |
| 119 | +.Example output |
| 120 | +[source,text] |
| 121 | +---- |
| 122 | +NAMESPACE NAME STATUS |
| 123 | +gateway-system mcp-tool-auth-policy Enforced |
| 124 | +---- |
| 125 | + |
| 126 | +. Check the authorization logs by running the following command: |
| 127 | ++ |
| 128 | +[source,terminal] |
| 129 | +---- |
| 130 | +$ oc logs -n mcp-system -l app.kubernetes.io/name=mcp-gateway |
| 131 | +---- |
0 commit comments