Skip to main content

Control Plane Mode

Deploy the Backend

To go with the default, you can deploy the manifests at:

kubectl apply -f /path/to/klutchio/bind/contrib/manifests/example-backend/control-plane-mode/example-backend.yaml

It's also possible to use both OIDC and control plane mode. To do that, just add the argument --control-plane-mode to the arguments of a backend configured for OIDC.

Configure Resources to share

Navigate to the klutch-bind deployment directory:

cd /path/to/klutchio/bind/deploy/resources

Edit kustomization.yaml and uncomment the services you need (e.g., PostgreSQL). Then apply the modified Kustomization:

kubectl apply --kustomize /path/to/klutchio/bind/deploy/resources

Prepare the App Cluster

In control-plane mode, the control plane requires cluster-admin access to the App cluster. Please create a kubeconfig that grants that access. As an example, we demonstrate how to set it up using a Service account token.

Create a Service Account

Create a ServiceAccount in the kube-system namespace of the App Cluster:

kubectl create serviceaccount klutch-control-plane -n kube-system

Bind the cluster-admin Role

Grant the ServiceAccount cluster-admin privileges:

kubectl create clusterrolebinding klutch-control-plane-admin \
--clusterrole=cluster-admin \
--serviceaccount=kube-system:klutch-control-plane

Create a Long-Lived Token

Since Kubernetes 1.24+, ServiceAccount tokens are no longer auto-generated as Secrets. Create one explicitly:

kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: klutch-control-plane-token
namespace: kube-system
annotations:
kubernetes.io/service-account.name: klutch-control-plane
type: kubernetes.io/service-account-token
EOF

Wait a moment, then retrieve the token:

TOKEN=$(kubectl get secret klutch-control-plane-token -n kube-system -o jsonpath='{.data.token}' | base64 -d)

Build the Kubeconfig

Gather the cluster's API server address and CA certificate, then assemble the kubeconfig:

CLUSTER_NAME="app-cluster"
SERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
CA=$(kubectl get secret klutch-control-plane-token -n kube-system -o jsonpath='{.data.ca\.crt}')
cat > klutch-app-cluster-kubeconfig.yaml <<EOF
apiVersion: v1
kind: Config
clusters:
- name: ${CLUSTER_NAME}
cluster:
server: ${SERVER}
certificate-authority-data: ${CA}
contexts:
- name: klutch-control-plane@${CLUSTER_NAME}
context:
cluster: ${CLUSTER_NAME}
user: klutch-control-plane
current-context: klutch-control-plane@${CLUSTER_NAME}
users:
- name: klutch-control-plane
user:
token: ${TOKEN}
EOF

Verify Access

Confirm the kubeconfig works:

kubectl --kubeconfig=klutch-app-cluster-kubeconfig.yaml get nodes

You should see the App Cluster's nodes listed. The resulting klutch-app-cluster-kubeconfig.yaml file can now be provided to the Control Plane.

Enable the binding on the control plane cluster

Apply the Kubeconfig as a Secret

Switch your kubectl context to the Control Plane cluster, then create a Secret from the kubeconfig file:

kubectl create secret generic app-cluster-kubeconfig \
--from-file=kubeconfig=klutch-app-cluster-kubeconfig.yaml \
-n default

This Secret is referenced by the AppClusterBinding resource via kubeconfigSecretRef.

Then, tell Klutch that the App cluster can be bound by applying the AppClusterBinding custom resource.

kubectl apply -f - <<EOF
apiVersion: klutch.anynines.com/v1alpha1
kind: AppClusterBinding
metadata:
name: aws-app-cluster
namespace: default
spec:
apiExports:
# APIs to be shared. APIServiceExportTemplates must exist on the control plane cluster
- group: anynines.com
resource: postgresqlinstances
konnector:
# Deploys the konnector to the control plane, simplest way to make the binding active
deploy: true
# optional
#overrides:
#image: <image override>
kubeconfigSecretRef:
key: kubeconfig
name: app-cluster-kubeconfig
namespace: default
EOF

Verify the binding is working

kubectl get appclusterbinding
NAME READY AGE
aws-app-cluster True 5d2h

Troubleshooting

Quick Checklist

  • The app cluster kubeconfig secret exists and uses a service account token (no exec plugins)
  • The konnector is deployed in the control plane cluster
kubectl get deployments.apps -n klutch-bind-default-aws-app-cluster
  • The konnector deployment args reference the correct secret name/namespace/key
kubectl describe deployments.apps -n klutch-bind-default-aws-app-cluster konnector-aws-app-cluster

Resources are not syncing

  • Check that the app cluster kubeconfig is valid and the API server is reachable
  • Verify that the service account in the app cluster kubeconfig has appropriate permissions
  • Check konnector logs for connection errors
kubectl logs -n klutch-bind-default-aws-app-cluster deployments/konnector-aws-app-cluster

APIServiceBindings not found

  • In default mode: APIServiceBindings must be created in the app cluster
  • In control plane mode: APIServiceBindings must be created in the control plane cluster, not the app cluster
  • Verify you're creating the APIServiceBinding in the correct cluster based on your deployment mode