> ## Documentation Index
> Fetch the complete documentation index at: https://docs.danubeai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Kubernetes

> Let agents see why pods crash, read logs and events, describe workloads and follow rollouts on EKS, GKE, AKS and self-hosted clusters

The Kubernetes connector talks to the cluster's API server over HTTPS. It works with Amazon EKS, Google GKE, Azure AKS, k3s, kind, OpenShift and any self-hosted cluster. There is no agent to install in the cluster: Danube signs in as an identity you create and can do exactly what that identity's RBAC allows.

## Tools

| Tool                  | What it returns                                                                                                                                                                                                                                                                                                              |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Test Connection**   | Server version, the identity Danube is signed in as, what it can read, and warnings when it can change deployments, delete pods, exec into pods or read Secrets. Errors say whether authentication, RBAC, the network or TLS failed                                                                                          |
| **List Namespaces**   | Namespaces with status, age and labels                                                                                                                                                                                                                                                                                       |
| **List Pods**         | Status, ready containers (`1/2`), restarts, age and node for each pod. A pod that is not ready carries `not_ready_reasons` from its container statuses: `CrashLoopBackOff`, `ImagePullBackOff`, `OOMKilled`, the exit code and the last termination. Filter by namespace, label selector, field selector or `only_not_ready` |
| **List Deployments**  | Desired, ready, updated and available replicas, images, strategy and conditions                                                                                                                                                                                                                                              |
| **List Services**     | Type, cluster IP, external address, ports and selector                                                                                                                                                                                                                                                                       |
| **Describe Resource** | One pod, deployment, service, statefulset, daemonset, replicaset, job, cronjob, configmap, node or ingress, without `managedFields`, plus its recent events. Secrets are refused                                                                                                                                             |
| **Get Pod Logs**      | The last lines of a container's log (default 200, max 5,000), optionally only the last `since_seconds`, from the previous crashed container, with timestamps. Capped at 512 KB, with obvious secrets masked and `error_line_numbers` pointing at ERROR, FATAL and exception lines                                            |
| **Get Events**        | Events newest first, optionally only warnings or only one object                                                                                                                                                                                                                                                             |
| **Rollout Status**    | Whether a deployment's rollout is `complete`, `progressing` or `stalled`, with the reason, observed generation, replica counts, conditions and the health of its pods                                                                                                                                                        |
| **Restart Rollout**   | Rolling restart of a deployment, like `kubectl rollout restart`. Needs a `read_write` connection and a confirmation on every call                                                                                                                                                                                            |
| **Scale Deployment**  | Sets a deployment's replicas (0 to 100) through the scale subresource. Needs a `read_write` connection and a confirmation on every call                                                                                                                                                                                      |

## Safety

* **Read-only at the source.** Connect with the read-only service account below. Its role has `get`, `list` and `watch` only, so the API server itself refuses a write (`permission_denied`, with the verb and resource the cluster refused).
* **Writes are separate tools.** Restart Rollout and Scale Deployment only run on a connection stored with mode `read_write`; on a `read_only` connection they are refused before anything is sent. Every call returns a `confirm_token` first that the agent must show you and send back. They also need an identity allowed to `patch` deployments.
* **Secrets are never read.** No tool requests a Secret, Describe Resource refuses `kind: secret` before any request, and the read-only role below has no access to Secrets at all. Environment variables that come from a `secretKeyRef` show only the Secret and key names; a literal `value` whose name looks like a credential (`DB_PASSWORD`, `API_TOKEN`) is masked. Test Connection warns when the identity could read Secrets.
* **TLS is always verified.** `insecure-skip-tls-verify` is not supported: store the cluster's CA certificate instead. A plain `http://` server is refused.
* **Limits on every call.** A 15 s timeout (up to 55 s with `timeout_seconds`), at most 500 items (up to 5,000 with `max_rows`) and 1 MB per result; logs stop at 512 KB. A cut result has `truncated: true`.
* **No secrets in results.** Tokens, keys and the kubeconfig are removed from every error message, and pod logs are scrubbed of bearer tokens, AWS access keys, JWTs and `token=` / `api_key=` values.
* **Every call is audited** with who called, which tool, the duration and the outcome.

## Create a read-only identity

Apply this once with an admin kubeconfig. It creates a `danube` namespace, a `danube-readonly` service account bound to a read-only ClusterRole, and a long-lived token for it.

```yaml danube-readonly.yaml theme={null}
apiVersion: v1
kind: Namespace
metadata:
  name: danube
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: danube-readonly
  namespace: danube
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: danube-readonly
rules:
  - apiGroups: [""]
    resources: ["pods", "pods/log", "services", "endpoints", "events", "namespaces", "nodes",
                "configmaps", "persistentvolumeclaims", "replicationcontrollers"]
    verbs: ["get", "list", "watch"]
  - apiGroups: ["apps"]
    resources: ["deployments", "deployments/scale", "replicasets", "statefulsets", "daemonsets"]
    verbs: ["get", "list", "watch"]
  - apiGroups: ["batch"]
    resources: ["jobs", "cronjobs"]
    verbs: ["get", "list", "watch"]
  - apiGroups: ["networking.k8s.io"]
    resources: ["ingresses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: ["events.k8s.io"]
    resources: ["events"]
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: danube-readonly
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: danube-readonly
subjects:
  - kind: ServiceAccount
    name: danube-readonly
    namespace: danube
---
apiVersion: v1
kind: Secret
metadata:
  name: danube-readonly-token
  namespace: danube
  annotations:
    kubernetes.io/service-account.name: danube-readonly
type: kubernetes.io/service-account-token
```

```bash theme={null}
kubectl apply -f danube-readonly.yaml

# The token, the CA certificate and the API server URL for the connection form
kubectl -n danube get secret danube-readonly-token -o jsonpath='{.data.token}' | base64 -d
kubectl -n danube get secret danube-readonly-token -o jsonpath='{.data.ca\.crt}' | base64 -d
kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}'
```

The ClusterRole deliberately leaves out `secrets`. To limit Danube to some namespaces, bind the same ClusterRole with a `RoleBinding` in each namespace instead of the `ClusterRoleBinding` (List Namespaces and nodes then need their own small ClusterRole, or leave them out).

A short-lived token works too: `kubectl -n danube create token danube-readonly --duration=24h`. Store it again when it expires.

To let agents restart and scale deployments, create a second service account with this extra rule, and store it on a separate connection with mode `read_write`:

```yaml theme={null}
  - apiGroups: ["apps"]
    resources: ["deployments", "deployments/scale"]
    verbs: ["patch"]
```

## Connect

Open **Kubernetes** in the dashboard's tool catalog and click **Connect**, or let the agent call `store_credential`. Fill in one of:

* **API server URL**, **Service account token** and **CA certificate** (the three values printed above). This is the recommended form.
* **Kubeconfig**: a kubeconfig with inline credentials. Danube uses its `current-context`, or the context named in **Context**. Run `kubectl config view --raw --minify --flatten` to inline certificate files. Tokens and client certificates (`client-certificate-data` / `client-key-data`) work; `exec` and `auth-provider` plugins (`gke-gcloud-auth-plugin`, `kubelogin`, `aws eks get-token`) cannot run inside Danube and are refused with a message saying so.
* **EKS**: see below.

Set **Default namespace** to the namespace agents should look at when a prompt names none. Mode stays **Read only** unless you want the two write tools to work.

<Tabs>
  <Tab title="Public API endpoint">
    EKS, GKE and AKS clusters with a public endpoint connect directly. Restrict the endpoint to Danube's egress addresses: EKS `publicAccessCidrs`, GKE authorized networks, AKS authorized IP ranges. See [Connect your production database safely](/connectors/production-database#allowlist-danubes-addresses) for the addresses.
  </Tab>

  <Tab title="Private cluster, SSH bastion">
    Fill in the **SSH bastion** fields: the bastion's public host, user, private key and host key fingerprint. Set **API server URL** to the private endpoint as the bastion sees it, for example `https://10.0.12.4:6443` or the private EKS endpoint. Danube keeps the original host name for TLS, so the certificate is still verified against it. The bastion's host key is checked against the stored fingerprint and never trusted on first use.
  </Tab>

  <Tab title="Private cluster, data-plane agent">
    Run the [data-plane agent](/organizations/data-plane) inside the network (it can run in the cluster itself) and store the token as a reference, for example `env://K8S_TOKEN`, or the kubeconfig as `env://KUBECONFIG_TEXT`. The call runs on the agent, which resolves the reference locally. Nothing inbound is opened, and the token never reaches Danube. Add the API server's host to the agent's `DANUBE_ALLOWED_DESTINATIONS`.
  </Tab>
</Tabs>

Run **Test Connection** after saving. It tells you which of these failed: the credential (`auth_required`), RBAC (`permission_denied`), the network (`connection_error`, `destination_blocked`) or TLS (`tls_error`), and what the identity can do.

### Amazon EKS

Either store a service account token as above (it works on every EKS cluster), or sign in with IAM: fill in **EKS cluster name**, **AWS region**, **AWS access key ID**, **AWS secret access key** and, for temporary credentials, **AWS session token**. Danube mints the same token `aws eks get-token` does for every call: a presigned STS `GetCallerIdentity` URL, valid 60 seconds. No IAM permission is needed to mint it.

Also store **API server URL** and **CA certificate** (`aws eks describe-cluster --name prod --query 'cluster.[endpoint,certificateAuthority.data]'`). If you leave them empty, Danube reads them with `eks:DescribeCluster`, which the IAM identity then needs.

Map the IAM identity to the read-only group in the cluster. First bind the ClusterRole above to a group:

```bash theme={null}
kubectl create clusterrolebinding danube-readonly-group \
  --clusterrole=danube-readonly --group=danube-readonly
```

Then, with **access entries** (recommended):

```bash theme={null}
aws eks create-access-entry --cluster-name prod \
  --principal-arn arn:aws:iam::123456789012:role/danube-readonly \
  --kubernetes-groups danube-readonly
```

Or, on a cluster that still uses the `aws-auth` ConfigMap, add under `mapRoles`:

```yaml theme={null}
- rolearn: arn:aws:iam::123456789012:role/danube-readonly
  username: danube-readonly
  groups:
    - danube-readonly
```

Do not map the identity to `system:masters` or associate `AmazonEKSClusterAdminPolicy`; Test Connection warns when it can write.

### Google GKE

GKE kubeconfigs use the `gke-gcloud-auth-plugin` exec plugin, which cannot run inside Danube. Use the service account token instead: apply the YAML above, then store the cluster endpoint (`gcloud container clusters describe prod --format='value(endpoint)'`, as `https://<endpoint>`), the token and the CA (`--format='value(masterAuth.clusterCaCertificate)'`, base64 is accepted). For a private cluster, use the bastion or the data-plane agent.

### Azure AKS

Clusters with Microsoft Entra ID integration use `kubelogin`, an exec plugin. Use the service account token instead, with the API server URL from `az aks show -g rg -n prod --query fqdn` and the CA from the token Secret. For a private cluster, use the bastion or the data-plane agent (for example on a VM in the cluster's virtual network).

## Example prompts

* "Why is `payments-worker` crash looping?"
* "Tail the logs of the checkout pods since 10 minutes ago."
* "Which pods in `production` are not ready, and why?"
* "Show me the warning events in the `payments` namespace from the last hour."
* "Is the `api` rollout finished? If it is stuck, what is blocking it?"
* "Restart the `checkout` deployment and tell me when the new pods are ready." (read\_write connection)
