Skip to content
35 changes: 8 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,37 +16,17 @@ This repository contains two main components:
- [Listener](./docs/listener.md): watches a cluster and stores its openAPI spec in a directory.
- [Gateway](./docs/gateway.md): exposes the openAPI spec as a GraphQL endpoints.

## MultiCluster Support
## Operation Modes

The system supports three modes of operation:
The system supports two modes of operation:

1. **Single Cluster** (`ENABLE_KCP=false`, `MULTICLUSTER=false`): Gateway connects to the same cluster as the listener
2. **KCP Mode** (`ENABLE_KCP=true`): Designed for KCP-based multi-cluster scenarios
3. **MultiCluster Mode** (`ENABLE_KCP=false`, `MULTICLUSTER=true`): Gateway connects to multiple external clusters via ClusterAccess resources
1. **KCP Mode** (`ENABLE_KCP=true`): Designed for KCP-based multi-cluster scenarios
- See [Virtual Workspaces](./docs/virtual-workspaces.md) for advanced KCP configuration
2. **ClusterAccess Mode** (`ENABLE_KCP=false`): Designed for support of multiple standard clusters.

### MultiCluster with ClusterAccess
## ClusterAccess

In MultiCluster mode, the system uses ClusterAccess resources to store kubeconfig data and connection information. The listener processes these resources and embeds connection metadata into schema files, which the gateway then uses to establish cluster-specific connections.

For complete setup instructions, see:
- [ClusterAccess documentation](./docs/clusteraccess.md) - Manual setup
- [MultiCluster Kubeconfig Flow](./docs/multicluster-kubeconfig-flow.md) - Detailed flow explanation

### Quick Setup Scripts

```bash
# Create ClusterAccess with secure token authentication
./scripts/create-clusteraccess.sh --target-kubeconfig ~/.kube/prod-config

# Test end-to-end integration
./scripts/test-clusteraccess-integration.sh
```

### Gateway Requirements

- **Single Cluster Mode**: Requires KUBECONFIG to connect to the local cluster
- **KCP Mode**: Requires KUBECONFIG to connect to KCP management cluster
- **MultiCluster Mode**: Does NOT require KUBECONFIG - gets all connection info from schema files
For detailed information, see [Clusteraccess](./docs/clusteraccess.md) section.

## Authorization

Expand All @@ -71,3 +51,4 @@ If you find any bug that may be a security problem, please follow our instructio
## Licensing

Copyright 2025 SAP SE or an SAP affiliate company and platform-mesh contributors. Please see our [LICENSE](LICENSE) for copyright and license information. Detailed information including third-party components and their licensing/copyright information is available [via the REUSE tool](https://api.reuse.software/info/github.com/platform-mesh/kubernetes-graphql-gateway).

16 changes: 8 additions & 8 deletions docs/authorization.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
All requests must contain an `Authorization` header with a valid Bearer token by default:
```shell
{
"Authorization": $YOUR_TOKEN
"Authorization": "Bearer $YOUR_TOKEN"
}
```
You can disable authorization by setting the following environment variable:
Expand All @@ -14,21 +14,21 @@ This is useful for local development and testing purposes.

## Introspection authentication

By default, introspection requests (i.e. the requests that are made to fetch the GraphQL schema) are **not** protected by authorization.
By default, introspection requests (i.e., the requests that are made to fetch the GraphQL schema) are **not** protected by authorization.

You can protect those requests by setting the following environment variable:
```shell
export INTROSPECTION_AUTHENTICATION=true
export GATEWAY_INTROSPECTION_AUTHENTICATION=true
```

### Error fetching schema
### Error fetching schema in documentation explorer

When GraphiQL page is loaded, it makes a request to fetch the GraphQL schema and there is no way to add the `Authorization` header to that request.
When the GraphiQL page is loaded, it makes a request to fetch the GraphQL schema, and there is no way to add the `Authorization` header to that request.

We have this [issue](https://github.com/openmfp/kubernetes-graphql-gateway/issues/217) open to fix this.
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Check GitHub issue link target.

Link points to openmfp/kubernetes-graphql-gateway#217. Confirm the org/repo is correct (this repo appears under platform-mesh).


🏁 Script executed:

#!/bin/bash
gh issue view 217 -R openmfp/kubernetes-graphql-gateway || echo "Issue not found under openmfp"

Length of output: 523


Update issue link and wording

  • In docs/authorization.md (line 28), change the URL to point to platform-mesh/kubernetes-graphql-gateway#217 and adjust the text since the issue is closed (e.g., replace “open to fix this” with “see issue” or past tense).
🤖 Prompt for AI Agents
In docs/authorization.md around line 28, the issue link and wording reference
the wrong repo and use present-tense phrasing for a closed issue; update the URL
to https://github.com/platform-mesh/kubernetes-graphql-gateway/issues/217 (or
the repo’s correct issue path) and change the text from “open to fix this” to
past-tense or neutral phrasing such as “see issue” or “see issue #217” so the
sentence correctly points to platform-mesh/kubernetes-graphql-gateway#217 and
reflects the issue state.


But for now, you can use the following workaround:
1. Open the GraphiQL page in your browser.
2. Add the `Authorization` header in the `Headers` section of the GraphiQL user interface like so:
3. Press `Re-fetch GraphQL schema` button in the left sidebar(third button from the top).
4. Now the GraphQL schema should be fetched, and you can use the GraphiQL interface as usual.
2. Add the `Authorization` header in the `Headers` section of the GraphiQL user interface.
3. Press the `Re-fetch GraphQL schema` button in the left sidebar (third button from the top).
4. The GraphQL schema should now be fetched, and you can use the GraphiQL interface as usual.
184 changes: 184 additions & 0 deletions docs/clusteraccess-setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
# ClusterAccess Resource Setup

To enable the gateway to access external Kubernetes clusters, you need to create ClusterAccess resources. This section provides both an automated script and manual step-by-step instructions.

## Quick Setup (Recommended)

For development purposes, use the provided script to automatically create ClusterAccess resources:

**Example:**
```bash
./hack/create-clusteraccess.sh --target-kubeconfig ~/.kube/platform-mesh-config --management-kubeconfig ~/.kube/platform-mesh-config
```

The script will:
- Extract cluster name, server URL, and CA certificate from the target kubeconfig
- Create a ServiceAccount with cluster-admin access in the target cluster
- Generate a long-lived token for the ServiceAccount
- Create the admin kubeconfig and CA secrets in the management cluster
- Create the ClusterAccess resource with kubeconfig-based authentication
- Output a copy-paste ready bearer token for direct API access

## Manual Setup

## Prerequisites

- Access to the target cluster (the cluster you want to expose via GraphQL)
- Access to the management cluster (the cluster where the gateway runs)
- ClusterAccess CRDs installed in the management cluster
- Target cluster kubeconfig file

## Step 1: Create ServiceAccount with Admin Access in Target Cluster

```bash
# Switch to target cluster
export KUBECONFIG=/path/to/target-cluster-kubeconfig

# Create ServiceAccount with cluster-admin access
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
name: kubernetes-graphql-gateway-admin
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kubernetes-graphql-gateway-admin-cluster-admin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: kubernetes-graphql-gateway-admin
namespace: default
---
apiVersion: v1
kind: Secret
metadata:
name: kubernetes-graphql-gateway-admin-token
namespace: default
annotations:
kubernetes.io/service-account.name: kubernetes-graphql-gateway-admin
type: kubernetes.io/service-account-token
EOF
```

## Step 2: Extract CA Certificate from Target Cluster

```bash
# Extract CA certificate from kubeconfig
kubectl config view --raw --minify -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' | base64 -d
```

Copy the output (should start with `-----BEGIN CERTIFICATE-----` and end with `-----END CERTIFICATE-----`).

## Step 3: Get Target Cluster Server URL

```bash
# Get the server URL
kubectl config view --raw --minify -o jsonpath='{.clusters[0].cluster.server}'
```

Copy the server URL (e.g., `https://127.0.0.1:58308`).

## Step 4: Switch Back to Management Cluster

```bash
# Switch to the cluster where you'll create ClusterAccess
export KUBECONFIG=/path/to/management-cluster-kubeconfig

# Install ClusterAccess CRD if not already installed
kubectl apply -f config/crd/
```

## Step 5: Create Secrets and ClusterAccess in Management Cluster

Create a file called `my-cluster-access.yaml`:

```yaml
# Secret containing CA certificate for target-cluster
apiVersion: v1
kind: Secret
metadata:
name: my-target-cluster-ca
namespace: default
type: Opaque
stringData:
ca.crt: |
PASTE_CA_CERTIFICATE_FROM_STEP_2_HERE

---
# Secret containing admin kubeconfig for target-cluster
apiVersion: v1
kind: Secret
metadata:
name: my-target-cluster-admin-kubeconfig
namespace: default
type: Opaque
data:
kubeconfig: BASE64_ENCODED_TARGET_KUBECONFIG_HERE

---
# ClusterAccess resource for target-cluster
apiVersion: gateway.platform-mesh.io/v1alpha1
kind: ClusterAccess
metadata:
name: my-target-cluster
spec:
path: my-target-cluster # This becomes the filename in bin/definitions/
host: PASTE_SERVER_URL_FROM_STEP_3_HERE
ca:
secretRef:
name: my-target-cluster-ca
namespace: default
key: ca.crt
auth:
kubeconfigSecretRef:
name: my-target-cluster-admin-kubeconfig
namespace: default
```

To encode the kubeconfig:
```bash
cat /path/to/target-cluster-kubeconfig | base64
```

## Step 6: Apply the Configuration

```bash
kubectl apply -f my-cluster-access.yaml
```

## Step 7: Verify Resources

```bash
# Check if ClusterAccess was created
kubectl get clusteraccess

# Check if secrets were created
kubectl get secret my-target-cluster-admin-kubeconfig my-target-cluster-ca
```

## Step 8: Test with Listener

```bash
export ENABLE_KCP=false
export GATEWAY_SHOULD_IMPERSONATE=false
export LOCAL_DEVELOPMENT=false
export KUBECONFIG=/path/to/management-cluster-kubeconfig
task listener
```

## Key Points

- **ServiceAccount**: Created in the target cluster with cluster-admin access for full permissions
- **Kubeconfig**: Stored as a secret in the management cluster for authentication
- **CA Certificate**: Essential for TLS verification - without it you'll get certificate errors
- **Server URL**: Must match exactly from the target cluster's kubeconfig
- **Path**: Becomes the schema filename (e.g., `my-target-cluster`) in `bin/definitions/`
- **Secrets**: Keep them in the same namespace as the ClusterAccess resource

The listener will detect the ClusterAccess resource and generate schema files with metadata that the gateway can use to access the target cluster.
Loading
Loading