Connect Kubernetes
Create a namespace reader, produce its kubeconfig and verify a real cluster read.
How-to · Updated 2026-10-26 · Describes release 0.1.164
Before you start
Use Bash with kubectl configured for the intended cluster. Check your current context before running the setup. Your cluster administrator must be allowed to create a service account, role bindings and a node-read ClusterRole. The AIOps or private-agent machine must reach the Kubernetes API endpoint in the generated kubeconfig.
Choose Kubernetes (kubectl + kubeconfig) for this guide. The separate Kubernetes MCP connector requires an already-running MCP server; pasting a Kubernetes API URL into that MCP field will not work.
1. Create read access for one namespace
Copy this entire command. It asks for the existing application namespace, grants its service account the built-in view role there, and adds only node get/list for the connection check. It creates aiops-readonly.kubeconfig in your current directory and refuses to overwrite it.
bash <<'BASH'
set -euo pipefail
umask 077
kubectl config current-context
read -r -p 'Existing application namespace to read: ' AIOPS_NAMESPACE </dev/tty
: "${AIOPS_NAMESPACE:?A namespace is required}"
kubectl get namespace "$AIOPS_NAMESPACE"
AIOPS_OUTPUT="$PWD/aiops-readonly.kubeconfig"
test ! -e "$AIOPS_OUTPUT" || { printf 'aiops-readonly.kubeconfig already exists; use a fresh directory.\n' >&2; exit 1; }
kubectl -n "$AIOPS_NAMESPACE" create serviceaccount aiops-reader --dry-run=client -o yaml | kubectl apply -f -
kubectl -n "$AIOPS_NAMESPACE" create rolebinding aiops-reader-view --clusterrole=view --serviceaccount="$AIOPS_NAMESPACE:aiops-reader" --dry-run=client -o yaml | kubectl apply -f -
kubectl create clusterrole aiops-reader-nodes --verb=get,list --resource=nodes --dry-run=client -o yaml | kubectl apply -f -
kubectl create clusterrolebinding "aiops-reader-nodes-$AIOPS_NAMESPACE" --clusterrole=aiops-reader-nodes --serviceaccount="$AIOPS_NAMESPACE:aiops-reader" --dry-run=client -o yaml | kubectl apply -f -
AIOPS_TEMP=$(mktemp -d)
trap 'rm -rf "$AIOPS_TEMP"' EXIT
AIOPS_SERVER=$(kubectl config view --raw --minify -o jsonpath='{.clusters[0].cluster.server}')
kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' | base64 --decode > "$AIOPS_TEMP/ca.crt"
test -s "$AIOPS_TEMP/ca.crt" || { printf 'This context has no embedded CA. Ask your cluster administrator for its trusted CA.\n' >&2; exit 1; }
AIOPS_TOKEN=$(kubectl -n "$AIOPS_NAMESPACE" create token aiops-reader --duration=1h)
kubectl --kubeconfig="$AIOPS_OUTPUT" config set-cluster estate --server="$AIOPS_SERVER" --certificate-authority="$AIOPS_TEMP/ca.crt" --embed-certs=true
kubectl --kubeconfig="$AIOPS_OUTPUT" config set-credentials aiops-reader --token="$AIOPS_TOKEN"
kubectl --kubeconfig="$AIOPS_OUTPUT" config set-context estate --cluster=estate --user=aiops-reader --namespace="$AIOPS_NAMESPACE"
kubectl --kubeconfig="$AIOPS_OUTPUT" config use-context estate
kubectl --kubeconfig="$AIOPS_OUTPUT" get nodes -o name
kubectl --kubeconfig="$AIOPS_OUTPUT" get pods
printf 'Ready: %s\nThe requested token lifetime is one hour; the API server may choose a different duration.\n' "$AIOPS_OUTPUT"
BASH
Expected result: node names and the namespace's pods, or “No resources found” for an empty namespace. A forbidden or connection error must be fixed before the next step. This grants no Secrets read, pod exec or workload writes. The built-in view role can be extended by your cluster's aggregated roles, so review its effective permissions. Kubernetes RBAC · Bound token duration.
This is a short-lived first-use credential. For ongoing monitoring, arrange token renewal with the cluster administrator. A copied token is not automatically renewed by the connection. The connection refuses a kubeconfig whose user runs a credential plugin (exec, such as aws eks get-token or kubelogin, or the older auth-provider) or that names a file on the platform host (tokenFile, client-certificate, client-key, certificate-authority as a path), when you save it and again before every use: the platform runs no such plugin and reads no such file. Use a static token or a service-account token with the certificate data embedded, as the command above does (--embed-certs=true).
2. Connect and verify
Open Data sources (in the product: /portal/datasources) → Connect datasource → Kubernetes (kubectl + kubeconfig). Choose Investigate only and paste the generated file into kubeconfig YAML. Add the namespace and service names in the connection notes. The estate inventory reads the namespace this kubeconfig's context names; if you bind the reader in more namespaces, list them all in Namespaces.
Select Connect and verify. Expected result: the real get nodes request succeeds. Namespace-only view without the node-read grant fails this verification. If the endpoint is private, install a private agent inside that network first; do not replace a private API address with an unrelated public address.
3. Discover the application
Scan the verified connection in Estate x-ray (in the product: /portal/xray). Review namespace coverage and any denied reads, then use the inventory and dependencies you trust. Missing namespaces are expected when you deliberately granted only one namespace.
4. Send an alert and review the evidence
Send a validation alert with the service you connected, then open its incident and ask which pods and events support the finding. For real Kubernetes alerts, use your Prometheus Alertmanager or other supported sender.
For a deployment restart, add an Approved changes only (separate credential) connection with narrowly scoped Kubernetes permissions, then enable Allow use for approved plans. Name the namespace in its kubeconfig context: that namespace is the scope a restart may target, and a context without one confirms none. A shared credential is also supported if you choose that use explicitly. The incident or Change prepares the exact deployment and namespace for review; there is no allowed-action setup form. Keeping separate service accounts also enforces the investigation read boundary in Kubernetes RBAC.
Compliance on Kubernetes: a cluster contributes change capture — the kube-apiserver audit webhook, or EKS audit logs read through the AWS connection — to the change ledger. The platform checks EST-01 to EST-06 read cloud accounts, not clusters. An audit webhook batch must stay under 16 MiB per POST, and under 1 MiB while an ingress-nginx in front of the platform keeps its default proxy-body-size (the audit webhook).
Change capture on EKS: turn on the cluster's audit control-plane log type (EKS → the cluster → Observability → Control plane logging), then set k8s_audit: true on the AWS read connection of that account. The harvest reads /aws/eks/<cluster>/cluster with CloudWatch Logs Insights; CloudTrail never sees a kubectl. People's writes are recorded, and the writes of CI/CD service accounts in the namespaces listed in k8s_ci_namespaces — see CI/CD service accounts.