|
| 1 | +// Module included in the following assemblies: |
| 2 | +// |
| 3 | +// *mcp_gateway_config/mcp-gateway-authentication.adoc |
| 4 | + |
| 5 | +:_mod-docs-content-type: PROCEDURE |
| 6 | +[id="proc-configure-mcp-gateway-authentication_{context}"] |
| 7 | += Configuring {mcpg} authentication with an AuthPolicy |
| 8 | + |
| 9 | +[role="_abstract"] |
| 10 | +Configure authentication for your {mcpg} by using a Kuadrant `AuthPolicy` custom resource (CR) and an identity provider such as {keycloak}. |
| 11 | + |
| 12 | +[NOTE] |
| 13 | +==== |
| 14 | +The {mcpg} supports any Istio or Gateway API compatible authentication mechanism. Use the best solution for your {ocp} clusters. |
| 15 | +==== |
| 16 | + |
| 17 | +.Prerequisites |
| 18 | + |
| 19 | +* You installed {mcpg}. |
| 20 | +* You installed {prodname}. |
| 21 | +* You configured a `Gateway` object. |
| 22 | +* You installed and have ready an identity provider supporting OAuth 2.0 or 2.1, for example, {keycloak}. |
| 23 | +
|
| 24 | +.Procedure |
| 25 | + |
| 26 | +. Add a listener to the `Gateway` object for your identity provider by using the following command as an example: |
| 27 | ++ |
| 28 | +[source,json,subs="+quotes"] |
| 29 | +---- |
| 30 | +$ oc patch gateway _<mcp_gateway>_ -n _<gateway_system>_ --type json -p '[ |
| 31 | + { |
| 32 | + "op": "add", |
| 33 | + "path": "/spec/listeners/-", |
| 34 | + "value": { |
| 35 | + "name": "keycloak", |
| 36 | + "hostname": "keycloak.example.com", |
| 37 | + "port": 8002, |
| 38 | + "protocol": "HTTP", |
| 39 | + "allowedRoutes": { |
| 40 | + "namespaces": { |
| 41 | + "from": "Selector", |
| 42 | + "selector": { |
| 43 | + "matchLabels": { |
| 44 | + "kubernetes.io/metadata.name": "keycloak" |
| 45 | + } |
| 46 | + } |
| 47 | + } |
| 48 | + } |
| 49 | + } |
| 50 | + } |
| 51 | +]' |
| 52 | +---- |
| 53 | ++ |
| 54 | +* Replace `_<mcp_gateway>_` with the name of your MCP gateway. |
| 55 | +* Replace `_<gateway_system>_` with the namespace of your `Gateway` object. |
| 56 | +* Replace the {keycloak} `_<name>_`, `_<hostname>_`, and `_<kubernetes.io/metadata.name>_` with your identity provider information. |
| 57 | +
|
| 58 | +. Configure the {mcpg} broker component to respond with OAuth discovery information by setting the following environment variables: |
| 59 | ++ |
| 60 | +[source,terminal,subs="+quotes"] |
| 61 | +---- |
| 62 | +$ oc set env deployment/_<mcp_gateway>_ \ |
| 63 | + OAUTH_RESOURCE_NAME="MCP Server" \ |
| 64 | + OAUTH_RESOURCE="http://mcp.example.com:8001/mcp" \ |
| 65 | + OAUTH_AUTHORIZATION_SERVERS="http://keycloak.example.com:8002/realms/mcp" \ |
| 66 | + OAUTH_BEARER_METHODS_SUPPORTED="header" \ |
| 67 | + OAUTH_SCOPES_SUPPORTED="basic,groups,roles,profile" \ |
| 68 | + -n _<mcp_system>_ |
| 69 | +---- |
| 70 | ++ |
| 71 | +* Replace `_<mcp_gateway>_` with the name of your MCP gateway. |
| 72 | +* Replace `_<mcp_system>_` with the namespace of your MCP gateway. |
| 73 | +* `OAUTH_RESOURCE_NAME`: Human-readable name for the MCP server. |
| 74 | +* `OAUTH_RESOURCE`: Canonical URI of the MCP server that is used for token audience validation. |
| 75 | +* `OAUTH_AUTHORIZATION_SERVERS`: Authorization server URL for client discovery. |
| 76 | +* `OAUTH_BEARER_METHODS_SUPPORTED`: Supported bearer token methods. Valid values are usually `header`, `body`, or `query`. |
| 77 | +* `OAUTH_SCOPES_SUPPORTED`: The OAuth scopes this MCP server supports. |
| 78 | +
|
| 79 | +. Create an AuthPolicy CR that validates JWT tokens: |
| 80 | ++ |
| 81 | +.Example AuthPolicy CR |
| 82 | +[source,yaml,subs="+quotes"] |
| 83 | +---- |
| 84 | +apiVersion: kuadrant.io/v1 |
| 85 | +kind: AuthPolicy |
| 86 | +metadata: |
| 87 | + name: _<mcp_jwt_auth_policy>_ |
| 88 | + namespace: _<gateway_system>_ |
| 89 | +spec: |
| 90 | + targetRef: |
| 91 | + group: gateway.networking.k8s.io |
| 92 | + kind: Gateway |
| 93 | + name: _<mcp_gateway>_ |
| 94 | + sectionName: _<mcp>_ |
| 95 | + defaults: |
| 96 | + when: |
| 97 | + - predicate: "!request.path.contains('/.well-known')" |
| 98 | + rules: |
| 99 | + authentication: |
| 100 | + 'keycloak': |
| 101 | + jwt: |
| 102 | + issuerUrl: http://keycloak.example.com:8002/realms/mcp |
| 103 | + response: |
| 104 | + unauthenticated: |
| 105 | + code: 401 |
| 106 | + headers: |
| 107 | + 'WWW-Authenticate': |
| 108 | + value: Bearer resource_metadata=http://mcp.example.com:8001/.well-known/oauth-protected-resource/mcp |
| 109 | + body: |
| 110 | + value: | |
| 111 | + { |
| 112 | + "error": "Unauthorized", |
| 113 | + "message": "Authentication required." |
| 114 | + } |
| 115 | +---- |
| 116 | ++ |
| 117 | +* The `metadata.name:` parameter value is the name of the `AuthPolicy` CR. Replace `_<mcp_jwt_auth_policy>_` as needed. |
| 118 | +* The `metadata.namespace:` parameter value is the gateway namespace. Replace `_<gateway_system>_` with the namespace where you created your `Gateway` object to apply the `AuthPolicy` CR to the namespace. |
| 119 | +* The `spec.targetRef.name:` parameter value is the name of your MCP gateway. Replace `_<mcp_gateway>_` as needed. |
| 120 | +* The `spec.targetRef.sectionName:` parameter value is the target gateway listener. In this example, `mcp` is used. |
| 121 | +* The `spec.defaults.when` parameter value in this example allows unauthenticated access to `/.well-known` endpoints. |
| 122 | +* The `spec.defaults.rules.authentication:` parameter defines which tokens to validate and how. In this case, JWT validation validates tokens against Keycloak's OIDC issuer. |
| 123 | +* The `spec.defaults.rules.response.unauthenticated.headers.'WWW-Authenticate':` parameter points clients to OAuth discovery metadata. Replace the `resource_metadata=` information as required. |
| 124 | +* The `spec.defaults.rules.response.unauthenticated.body.value:` parameter is set with a standard response. This configuration returns a `401` error in an OAuth error format. |
| 125 | +
|
| 126 | +. Apply the AuthPolicy CR by running the following command: |
| 127 | ++ |
| 128 | +[source,terminal,subs="+quotes"] |
| 129 | +---- |
| 130 | +$ oc apply -f _<mcp_jwt_authpolicy.yaml>_ |
| 131 | +---- |
| 132 | ++ |
| 133 | +Replace `_<mcp_jwt_authpolicy.yaml>_` with the name of your CR. |
| 134 | + |
| 135 | +.Verification |
| 136 | + |
| 137 | +. Test that the broker now serves OAuth discovery information by checking the protected resource metadata endpoint with the following command: |
| 138 | ++ |
| 139 | +[source,terminal,subs="+quotes"] |
| 140 | +---- |
| 141 | +$ curl http://_<mcp.example.com:8001/.well_known/oauth_protected_resource>_ |
| 142 | +---- |
| 143 | ++ |
| 144 | +* Replace the URL with your protected resource information. |
| 145 | ++ |
| 146 | +.Example output |
| 147 | +[source,text] |
| 148 | +---- |
| 149 | +{ |
| 150 | + "resource_name": "MCP Server", |
| 151 | + "resource": "http://example.com:8001/mcp", |
| 152 | + "authorization_servers": [ |
| 153 | + "http://keycloak.example.com:8002/realms/mcp" |
| 154 | + ], |
| 155 | + "bearer_methods_supported": [ |
| 156 | + "header" |
| 157 | + ], |
| 158 | + "scopes_supported": [ |
| 159 | + "basic", |
| 160 | + "groups", |
| 161 | + "roles", |
| 162 | + "profile" |
| 163 | + ] |
| 164 | +} |
| 165 | +---- |
| 166 | +
|
| 167 | +. Test that protected endpoints now require authentication by running the following command: |
| 168 | ++ |
| 169 | +[source,terminal,subs="+quotes"] |
| 170 | +---- |
| 171 | +$ curl -v http://_<mcp.example.com:8001/mcp>_ \ |
| 172 | + -H "Content-Type: application/json" \ |
| 173 | + -d '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}' |
| 174 | +---- |
| 175 | ++ |
| 176 | +Replace `_<mcp.example.com:8001/mcp>_` with your endpoint. |
| 177 | ++ |
| 178 | +.Example output |
| 179 | +[source,text] |
| 180 | +---- |
| 181 | +{ |
| 182 | + "error": "Unauthorized", |
| 183 | + "message": "Authentication required." |
| 184 | +} |
| 185 | +---- |
| 186 | ++ |
| 187 | +A `401` error with `WWW-Authenticate` header is expected. |
| 188 | + |
| 189 | +.Next steps |
| 190 | + |
| 191 | +* Control which users can access specific tools by configuring authorization policies. |
| 192 | +* Connect authenticated external MCP services. |
0 commit comments