|
| 1 | +# Keycloak OIDC Setup for Kubernetes MCP Server |
| 2 | + |
| 3 | +This guide shows you how to set up a local development environment with Keycloak for OIDC authentication testing. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +The local development environment includes: |
| 8 | +- **Kind cluster** with OIDC-enabled API server |
| 9 | +- **Keycloak** (deployed in the cluster) for OIDC provider |
| 10 | +- **Kubernetes MCP Server** configured for OAuth/OIDC authentication |
| 11 | + |
| 12 | +## Quick Start |
| 13 | + |
| 14 | +Set up the complete environment with one command: |
| 15 | + |
| 16 | +```bash |
| 17 | +make local-env-setup |
| 18 | +``` |
| 19 | + |
| 20 | +This will: |
| 21 | +1. Install required tools (kind) to `./_output/bin/` |
| 22 | +2. Create a Kind cluster with OIDC configuration |
| 23 | +3. Deploy Keycloak in the cluster |
| 24 | +4. Configure Keycloak realm and clients |
| 25 | +5. Build the MCP server binary |
| 26 | +6. Generate a configuration file at `_output/config.toml` |
| 27 | + |
| 28 | +## Running the MCP Server |
| 29 | + |
| 30 | +After setup completes, run the server: |
| 31 | + |
| 32 | +```bash |
| 33 | +# Start the server |
| 34 | +./kubernetes-mcp-server --port 8008 --config _output/config.toml |
| 35 | +``` |
| 36 | + |
| 37 | +Or use the MCP Inspector for testing: |
| 38 | + |
| 39 | +```bash |
| 40 | +npx @modelcontextprotocol/inspector@latest $(pwd)/kubernetes-mcp-server --config _output/config.toml |
| 41 | +``` |
| 42 | + |
| 43 | +## Quick Walkthrough |
| 44 | + |
| 45 | +### 1. Start MCP Inspector and Connect |
| 46 | + |
| 47 | +After running the inspector, in the `Authentication`'s **OAuth 2.0 Flow** set the `Client ID` to be `mcp-client` and the `Scope` to `mcp-server`, afterwards click the "Connect" button. |
| 48 | + |
| 49 | +<a href="images/keycloak-mcp-inspector-connect.png"> |
| 50 | + <img src="images/keycloak-mcp-inspector-connect.png" alt="MCP Inspector Connect Button" width="600" /> |
| 51 | +</a> |
| 52 | + |
| 53 | +### 2. Login to Keycloak |
| 54 | + |
| 55 | +You'll be redirected to Keycloak. Enter the test credentials: |
| 56 | +- Username: `mcp` |
| 57 | +- Password: `mcp` |
| 58 | + |
| 59 | +<a href="images/keycloak-login-page.png"> |
| 60 | + <img src="images/keycloak-login-page.png" alt="Keycloak Login Page" width="600" /> |
| 61 | +</a> |
| 62 | + |
| 63 | +### 3. Use MCP Tools |
| 64 | + |
| 65 | +After authentication, you can use the **Tools** from the Kubernetes-MCP-Server from the MCP Inspector, like below where we run the `pods_list` tool, to list all pods in the current cluster from all namespaces. |
| 66 | + |
| 67 | +<a href="images/keycloak-mcp-inspector-results.png"> |
| 68 | + <img src="images/keycloak-mcp-inspector-results.png" alt="MCP Inspector Tool Results" width="600" /> |
| 69 | +</a> |
| 70 | + |
| 71 | +## Architecture |
| 72 | + |
| 73 | +### Keycloak Deployment |
| 74 | +- Runs as a StatefulSet in the `keycloak` namespace |
| 75 | +- Exposed via Ingress with TLS at `https://keycloak.127-0-0-1.sslip.io:8443` |
| 76 | +- Uses cert-manager for TLS certificates |
| 77 | +- Accessible from both host and cluster pods |
| 78 | + |
| 79 | +### Kind Cluster with OIDC |
| 80 | +- Kubernetes API server configured with OIDC authentication |
| 81 | +- Points to Keycloak's `openshift` realm as the OIDC issuer |
| 82 | +- Validates bearer tokens against Keycloak's JWKS endpoint |
| 83 | +- API server trusts the cert-manager CA certificate |
| 84 | + |
| 85 | +### Authentication Flow |
| 86 | + |
| 87 | +``` |
| 88 | +User Browser |
| 89 | + | |
| 90 | + | 1. OAuth login (https://keycloak.127-0-0-1.sslip.io:8443) |
| 91 | + v |
| 92 | +Keycloak |
| 93 | + | |
| 94 | + | 2. ID Token (aud: mcp-server) |
| 95 | + v |
| 96 | +MCP Server |
| 97 | + | |
| 98 | + | 3. Token Exchange (aud: openshift) |
| 99 | + v |
| 100 | +Keycloak |
| 101 | + | |
| 102 | + | 4. Exchanged Access Token |
| 103 | + v |
| 104 | +MCP Server |
| 105 | + | |
| 106 | + | 5. Bearer Token in API request |
| 107 | + v |
| 108 | +Kubernetes API Server |
| 109 | + | |
| 110 | + | 6. Validate token via OIDC |
| 111 | + v |
| 112 | +Keycloak JWKS |
| 113 | + | |
| 114 | + | 7. Token valid, execute tool |
| 115 | + v |
| 116 | +MCP Server → User |
| 117 | +``` |
| 118 | + |
| 119 | +## Keycloak Configuration |
| 120 | + |
| 121 | +The setup automatically configures: |
| 122 | + |
| 123 | +### Realm: `openshift` |
| 124 | +- Token lifespan: 30 minutes |
| 125 | +- Session idle timeout: 30 minutes |
| 126 | + |
| 127 | +### Clients |
| 128 | + |
| 129 | +1. **mcp-client** (public) |
| 130 | + - Public client for browser-based OAuth login |
| 131 | + - PKCE required for security |
| 132 | + - Valid redirect URIs: `*` |
| 133 | + |
| 134 | +2. **mcp-server** (confidential) |
| 135 | + - Confidential client with client secret |
| 136 | + - Standard token exchange enabled |
| 137 | + - Can exchange tokens with `aud: openshift` |
| 138 | + - Default scopes: `openid`, `groups`, `mcp-server` |
| 139 | + - Optional scopes: `mcp:openshift` |
| 140 | + |
| 141 | +3. **openshift** (confidential) |
| 142 | + - Target client for token exchange |
| 143 | + - Accepts exchanged tokens from `mcp-server` |
| 144 | + - Used by Kubernetes API server for OIDC validation |
| 145 | + |
| 146 | +### Client Scopes |
| 147 | +- **mcp-server**: Default scope with audience mapper |
| 148 | +- **mcp:openshift**: Optional scope for token exchange with audience mapper |
| 149 | +- **groups**: Group membership mapper (included in tokens) |
| 150 | + |
| 151 | +### Default User |
| 152 | +- **Username**: `mcp` |
| 153 | +- **Password**: `mcp` |
| 154 | + |
| 155 | +- **RBAC**: `cluster-admin` (full cluster access) |
| 156 | + |
| 157 | +## MCP Server Configuration |
| 158 | + |
| 159 | +The generated `_output/config.toml` includes: |
| 160 | + |
| 161 | +```toml |
| 162 | +require_oauth = true |
| 163 | +oauth_audience = "mcp-server" |
| 164 | +oauth_scopes = ["openid", "mcp-server"] |
| 165 | +validate_token = false # Validation done by K8s API server |
| 166 | +authorization_url = "https://keycloak.127-0-0-1.sslip.io:8443/realms/openshift" |
| 167 | + |
| 168 | +sts_client_id = "mcp-server" |
| 169 | +sts_client_secret = "..." # Auto-generated |
| 170 | +sts_audience = "openshift" # Triggers token exchange |
| 171 | +sts_scopes = ["mcp:openshift"] |
| 172 | + |
| 173 | +certificate_authority = "_output/cert-manager-ca/ca.crt" # For HTTPS validation |
| 174 | +``` |
| 175 | + |
| 176 | +## Useful Commands |
| 177 | + |
| 178 | +### Check Keycloak Status |
| 179 | + |
| 180 | +```bash |
| 181 | +make keycloak-status |
| 182 | +``` |
| 183 | + |
| 184 | +Shows: |
| 185 | +- Keycloak pod status |
| 186 | +- Service endpoints |
| 187 | +- Access URL |
| 188 | +- Admin credentials |
| 189 | + |
| 190 | +### View Keycloak Logs |
| 191 | + |
| 192 | +```bash |
| 193 | +make keycloak-logs |
| 194 | +``` |
| 195 | + |
| 196 | +### Access Keycloak Admin Console |
| 197 | + |
| 198 | +Open your browser to: |
| 199 | +``` |
| 200 | +https://keycloak.127-0-0-1.sslip.io:8443 |
| 201 | +``` |
| 202 | + |
| 203 | +**Admin credentials:** |
| 204 | +- Username: `admin` |
| 205 | +- Password: `admin` |
| 206 | + |
| 207 | +Navigate to the `openshift` realm to view/modify the configuration. |
| 208 | + |
| 209 | +## Teardown |
| 210 | + |
| 211 | +Remove the local environment: |
| 212 | + |
| 213 | +```bash |
| 214 | +make local-env-teardown |
| 215 | +``` |
| 216 | + |
| 217 | +This deletes the Kind cluster (Keycloak is removed with it). |
0 commit comments