Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion contrib/production/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ This directory contains assets and configuration files for production deployment

These assets are referenced by the production deployment documentation in `docs/content/setup/production/`.

Each deployment type (dekker, vespucci, comer) has its own subdirectory with complete configuration files and deployment manifests.
Each deployment type (dekker, vespucci, comer, zheng) has its own subdirectory with complete configuration files and deployment manifests.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we can scrap or shorten listing the types, if we add more it will get very long.

Suggested change
Each deployment type (dekker, vespucci, comer, zheng) has its own subdirectory with complete configuration files and deployment manifests.
Each deployment type (dekker, vespucci, ...) has its own subdirectory with complete configuration files and deployment manifests.


## Deployment Types

- **kcp-dekker**: Self-signed certificates, simple single-cluster deployment
- **kcp-vespucci**: External certificates with Let's Encrypt, public shard access
- **kcp-comer**: CDN integration with dual front-proxy configuration
- **kcp-zheng**: Distributed multi-cluster deployment with high availability

See the corresponding documentation in `docs/content/setup/production/` for detailed deployment instructions.
15 changes: 15 additions & 0 deletions contrib/production/kcp-mcp/certificate.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: mcp-tls
namespace: kcp-mcp
spec:
secretName: mcp-tls
duration: 2160h # 90 days
renewBefore: 360h # 15 days
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
group: cert-manager.io
dnsNames:
- mcp.vespucci.example.com
132 changes: 132 additions & 0 deletions contrib/production/kcp-mcp/values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Kubernetes MCP Server Helm Values for KCP
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
# Kubernetes MCP Server Helm Values for KCP
# Kubernetes MCP Server Helm Values for kcp

# This configuration deploys the MCP server to work with kcp control planes
# using OIDC bearer token authentication (same provider as kcp front-proxy)

# Replica count for the deployment
replicaCount: 1

# Container image configuration
image:
registry: ghcr.io
repository: mjudeikis/kubernetes-mcp-server
version: latest
pullPolicy: Always

# Service configuration - expose HTTPS on port 443, forward to container port 8443
service:
type: LoadBalancer
port: 8443
targetPort: 8443
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: nlb
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing

# Ingress disabled - using TLS termination at the application level
ingress:
enabled: false

# Service account configuration
serviceAccount:
create: true
annotations: {}
name: ""

# RBAC configuration - disable default RBAC as we use kcp's RBAC
rbac:
create: false

# Pod security context
podSecurityContext:
seccompProfile:
type: RuntimeDefault

# Container security context
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
runAsNonRoot: true

# Resource limits and requests
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi

# Extra volumes for mounting base kubeconfig and TLS certs
# The kubeconfig provides cluster endpoint/TLS only (no auth credentials)
# Authentication is handled via OIDC bearer tokens
# Note: config is handled by the chart via config.existingConfigMap
extraVolumes:
- name: kubeconfig
secret:
secretName: kcp-mcp-kubeconfig
- name: tls-certs
secret:
secretName: mcp-tls

# Extra volume mounts
# Mount to different paths to avoid conflicts with chart's default mounts
extraVolumeMounts:
- name: kubeconfig
mountPath: /etc/kcp-mcp/kube
readOnly: true
- name: tls-certs
mountPath: /etc/kcp-mcp/tls
readOnly: true

# Configuration file path
configFilePath: /etc/kcp-mcp/config/config.toml

# MCP Server configuration - this becomes TOML via the chart's toToml function
config:
port: "8443"
cluster_provider_strategy: "kcp"
kubeconfig: "/etc/kcp-mcp/kube/kubeconfig"
require_oauth: true
authorization_url: "https://auth.keycloak.example.com/realms/kcp"
oauth_audience: "kcp"
tls_cert: "/etc/kcp-mcp/tls/tls.crt"
tls_key: "/etc/kcp-mcp/tls/tls.key"
toolsets:
- "kcp"
- "core"
disabled_tools:
- "pods_list"
- "pods_list_in_namespace"
- "pods_get"
- "pods_delete"
- "pods_top"
- "pods_exec"
- "pods_log"
- "pods_run"
- "nodes_log"
- "nodes_stats_summary"
- "nodes_top"

# Liveness and readiness probes - use HTTPS scheme on port 8443
livenessProbe:
httpGet:
path: /healthz
port: 8443
scheme: HTTPS

readinessProbe:
httpGet:
path: /healthz
port: 8443
scheme: HTTPS

# Node selector, tolerations, and affinity
nodeSelector: {}
tolerations: []
affinity: {}

# Pod annotations and labels
podAnnotations: {}
podLabels: {}
93 changes: 93 additions & 0 deletions contrib/production/oidc-keycloak/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Keycloak OIDC Provider for kcp

This directory contains example Kubernetes manifests for deploying Keycloak as an OIDC provider for kcp.

## Prerequisites

- Kubernetes cluster with kubectl access
- [cert-manager](https://cert-manager.io/) installed
- [CloudNativePG](https://cloudnative-pg.io/) operator installed
- [Keycloak Operator](https://www.keycloak.org/operator/installation) installed

## Files

| File | Description |
|------|-------------|
| `postgres-cluster.yaml` | CloudNativePG PostgreSQL cluster for Keycloak backend |
| `postgres-database.yaml` | Database resource for the PostgreSQL cluster |
| `keycloak-db-secret.yaml` | Secret for Keycloak to connect to PostgreSQL |
| `certificate-dns.yaml` | cert-manager Certificate for TLS |
| `keycloak.yaml` | Keycloak CRD deployment |
| `values.yaml.template` | Template showing all configuration options |

## Deployment

1. Create the namespace:
```sh
kubectl create namespace oidc
```

2. Deploy PostgreSQL:
```sh
kubectl apply -f postgres-cluster.yaml
kubectl apply -f postgres-database.yaml
```

3. Wait for PostgreSQL to be ready:
```sh
kubectl wait --for=condition=Ready cluster/keycloak-auth -n oidc --timeout=300s
```

4. Create the database secret for Keycloak:
```sh
kubectl apply -f keycloak-db-secret.yaml
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Instead of a fixed file a create secret command with --from-literal values instead?
Same in postgres-cluster. I think that's clearer and nicer for users going through the docs and we won't run into the possibility of some codescanning recognizing that as secrets.

```

5. Create the TLS certificate:
```sh
kubectl apply -f certificate-dns.yaml
```

6. Wait for the certificate to be issued:
```sh
kubectl wait --for=condition=Ready certificate/keycloak-tls-cert -n oidc --timeout=300s
```

7. Deploy Keycloak:
```sh
kubectl apply -f keycloak.yaml
```

8. Wait for Keycloak to be ready:
```sh
kubectl get keycloaks/keycloak -n oidc -w
```

## Post-Deployment Configuration

After Keycloak is running:

1. Get the initial admin credentials:
```sh
kubectl get secret keycloak-initial-admin -n oidc -o jsonpath='{.data.username}' | base64 -d
kubectl get secret keycloak-initial-admin -n oidc -o jsonpath='{.data.password}' | base64 -d
```

2. Access the admin console at your configured hostname (e.g., `https://auth.keycloak.example.com/admin`)

3. Create a realm for kcp (e.g., `kcp`)

4. Create a client for kcp with:
- Client ID: `kcp`
- Public client: Yes
- Valid redirect URIs: `http://localhost:8000`, `http://127.0.0.1:8000/`

## Security Notes

- Change all default passwords before production use
- Enable MFA for the admin account
- Review and restrict redirect URIs as needed

## Documentation

For more details, see the [Keycloak setup guide](../../../docs/content/setup/keycloak.md).
17 changes: 17 additions & 0 deletions contrib/production/oidc-keycloak/certificate-dns.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: keycloak-tls-cert
namespace: oidc
spec:
secretName: keycloak-tls
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
group: cert-manager.io
dnsNames:
- auth.keycloak.example.com
usages:
- digital signature
- key encipherment
10 changes: 10 additions & 0 deletions contrib/production/oidc-keycloak/keycloak-db-secret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
apiVersion: v1
data:
username: a2V5Y2xvYWs= # keycloak
password: cGFzc3dvcmQ= # password - CHANGE IN PRODUCTION
kind: Secret
metadata:
namespace: oidc
name: keycloak-db-secret
type: kubernetes.io/basic-auth
16 changes: 16 additions & 0 deletions contrib/production/oidc-keycloak/keycloak-service-lb.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
apiVersion: v1
kind: Service
metadata:
name: keycloak-lb
namespace: oidc
spec:
type: LoadBalancer
selector:
app: keycloak
app.kubernetes.io/instance: keycloak
ports:
- name: https
port: 443
targetPort: 8443
protocol: TCP
25 changes: 25 additions & 0 deletions contrib/production/oidc-keycloak/keycloak.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
apiVersion: k8s.keycloak.org/v2alpha1
kind: Keycloak
metadata:
name: keycloak
namespace: oidc
spec:
instances: 1
db:
vendor: postgres
host: keycloak-auth-rw.oidc.svc.cluster.local
usernameSecret:
name: keycloak-db-secret
key: username
passwordSecret:
name: keycloak-db-secret
key: password
http:
tlsSecret: keycloak-tls
hostname:
hostname: auth.keycloak.example.com
proxy:
headers: xforwarded
ingress:
enabled: false # Using LoadBalancer service instead
39 changes: 39 additions & 0 deletions contrib/production/oidc-keycloak/postgres-cluster.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: keycloak-auth
namespace: oidc
spec:
instances: 1
bootstrap:
initdb:
database: keycloak
owner: keycloak
secret:
name: keycloak-postgres
enableSuperuserAccess: true
superuserSecret:
name: keycloak-superuser
storage:
size: 10Gi
---
apiVersion: v1
data:
username: a2V5Y2xvYWs= # keycloak
password: cGFzc3dvcmQ= # password - CHANGE IN PRODUCTION
kind: Secret
metadata:
namespace: oidc
name: keycloak-postgres
type: kubernetes.io/basic-auth
---
apiVersion: v1
data:
username: cG9zdGdyZXM= # postgres
password: cGFzc3dvcmQ= # password - CHANGE IN PRODUCTION
kind: Secret
metadata:
namespace: oidc
name: keycloak-superuser
type: kubernetes.io/basic-auth
10 changes: 10 additions & 0 deletions contrib/production/oidc-keycloak/postgres-database.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: postgresql.cnpg.io/v1
kind: Database
metadata:
namespace: oidc
name: db-keycloak
spec:
name: keycloak
owner: keycloak
cluster:
name: keycloak-auth
2 changes: 1 addition & 1 deletion docs/content/setup/.pages
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ nav:
- quickstart.md
- helm.md
- kubectl-plugin.md
- integrations.md
- integrations
- production

Loading
Loading