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

# Kubernetes

> Connect a Kubernetes cluster to Oleria to discover its service accounts, users, groups, roles, and the bindings that grant access, and manage role membership.

Connect Kubernetes to Oleria to see who can do what in a cluster: which service accounts, users, and groups hold which roles, where each grant applies, who is a cluster administrator, and which service accounts carry long-lived tokens. Oleria reads this from the cluster's API server, through its role-based access control (RBAC) objects.

One Oleria connection maps one cluster. Connect additional clusters as separate instances.

## What Oleria discovers

Once connected, Oleria continuously discovers and maps the following from the cluster:

* **Service accounts** - every service account in every namespace, as non-human identities, with its namespace, creation time, roles, and whether it is a cluster administrator. Service accounts the control plane manages are marked as system identities: those in the control-plane namespaces (`kube-system`, `kube-public`, `kube-node-lease`) and each namespace's `default` service account.
* **Users and groups** - Kubernetes doesn't store users or groups. Oleria shows the users and groups that RoleBindings and ClusterRoleBindings name, including the control plane's own identities such as `system:kube-scheduler`, and the three built-in groups every service account belongs to (`system:serviceaccounts`, `system:serviceaccounts:<namespace>`, and `system:authenticated`), with each service account as a member.
* **Roles** - every Role and ClusterRole, with a summary of its rules. Default Kubernetes roles are marked as standard. ClusterRoles that aggregate other ClusterRoles (such as `admin` and `edit`) are shown as including them.
* **Role membership** - which service accounts, users, and groups hold each role, and the scope of the grant: cluster-wide, or the namespaces where a RoleBinding applies.
* **Impersonation** - which accounts can act as other named users or service accounts (the `impersonate` verb), including rights granted to the built-in groups above, which apply to every service account in them. A right to impersonate any identity is flagged on the account.
* **Credentials** - service account token Secrets (the long-lived tokens Kubernetes creates for a service account), with their creation time, last use, and whether the control plane has marked them invalid. Tokens in the control-plane namespaces are marked as system identities. Oleria reads only the Secrets' metadata and never their values.
* **Cluster administrators** - accounts bound to an unrestricted ClusterRole such as `cluster-admin` through a ClusterRoleBinding, directly or, for service accounts, through one of the built-in groups above. A binding to `system:authenticated` makes every service account a cluster administrator.

Namespaces, workloads (pods, deployments, nodes), config maps, and other Secrets aren't synced.

## Prerequisites

* A cluster whose API server is reachable over **HTTPS from the internet** at a public address. API servers that are only reachable on a private network or VPN, or whose address resolves to a private IP, can't be connected.
* Kubernetes **1.28 or later** (the connection check uses the SelfSubjectReview API).
* Permission to create a ServiceAccount, a ClusterRole, and a ClusterRoleBinding in the cluster (for example, the `cluster-admin` role).
* If the API server presents a certificate from a private certificate authority, the cluster's **CA certificate** (PEM).

> [!NOTE]
>
> Use a dedicated service account for this integration rather than a person's credentials. Oleria never removes the connection's own service account from a role, and refuses to disable it.

## Create the service account and its permissions

**1. Create the read role**

Save the following as `oleria-reader.yaml` and apply it with `kubectl apply -f oleria-reader.yaml`:

```yaml theme={null}
apiVersion: v1
kind: ServiceAccount
metadata:
  name: oleria-reader
  namespace: oleria-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: oleria-reader
rules:
  - apiGroups: [""]
    resources: ["serviceaccounts", "secrets"]
    verbs: ["list"]
  - apiGroups: [""]
    resources: ["namespaces"]
    resourceNames: ["kube-system"]
    verbs: ["get"]
  - apiGroups: ["rbac.authorization.k8s.io"]
    resources: ["roles", "rolebindings", "clusterroles", "clusterrolebindings"]
    verbs: ["list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: oleria-reader
subjects:
  - kind: ServiceAccount
    name: oleria-reader
    namespace: oleria-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: oleria-reader
```

Create the `oleria-system` namespace first if it doesn't exist: `kubectl create namespace oleria-system`.

**2. Know what each permission is for**

| Permission | Used for |
| :- | :- |
| `list serviceaccounts` | The service accounts, as non-human identities. |
| `list roles`, `list clusterroles` | The roles and what they allow. |
| `list rolebindings`, `list clusterrolebindings` | Who holds each role, the users and groups bindings name, and where each grant applies. |
| `get namespaces` (only `kube-system`) | The cluster's identity: the UID of the `kube-system` namespace keeps the integration stable if the API server address changes. Required. |
| `list secrets` | The service account token inventory. Optional. Oleria asks the API server for metadata only, so token values never leave the cluster. If you leave this out, Oleria syncs everything else and doesn't list tokens. |

**3. Optional - allow remediation**

To let Oleria change role membership and disable service accounts, also apply this role and bind it to the same service account:

```yaml theme={null}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: oleria-writer
rules:
  - apiGroups: [""]
    resources: ["serviceaccounts"]
    verbs: ["create", "delete"]
  - apiGroups: [""]
    resources: ["secrets"]
    verbs: ["delete"]
  - apiGroups: ["rbac.authorization.k8s.io"]
    resources: ["rolebindings", "clusterrolebindings"]
    verbs: ["create", "update", "delete"]
  - apiGroups: ["rbac.authorization.k8s.io"]
    resources: ["roles", "clusterroles"]
    verbs: ["bind"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: oleria-writer
subjects:
  - kind: ServiceAccount
    name: oleria-reader
    namespace: oleria-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: oleria-writer
```

> [!WARNING]
>
> As written, this role is equivalent to `cluster-admin`. The `bind` permission is how Kubernetes lets an account grant a role it doesn't hold itself, and together with creating ClusterRoleBindings it lets whoever holds the token grant any role, including `cluster-admin`, to any subject. Limit the `bind` rule with `resourceNames` to the roles Oleria should grant, for example:
>
> ```yaml theme={null}
> - apiGroups: ["rbac.authorization.k8s.io"]
>   resources: ["roles", "clusterroles"]
>   verbs: ["bind"]
>   resourceNames: ["view"]
> ```
>
> Don't add `edit`, `admin`, or any other role that can read Secrets or create pods. Bound in a namespace such as `kube-system`, those let the token act as that namespace's service accounts, several of which hold cluster-wide rights. Actions on most roles outside the list are refused. The API server still allows binding a role whose permissions the token already holds in full. If you don't need remediation, skip this step: the read role alone can't change the cluster.

**4. Create a token**

Create a token for the service account. Keep the lifetime short, especially if you bound the remediation role; the API server may also cap it. Create a new token and update the integration before it expires.

```bash theme={null}
kubectl create token oleria-reader --namespace oleria-system --duration=2160h
```

Copy the token. Kubernetes shows it only once.

**5. Find the API server address and CA certificate**

Run `kubectl config view --raw --minify`. Use the `server` value as the API server URL. If the cluster uses a private certificate authority, decode `certificate-authority-data` (`echo <value> | base64 -d`) to get the CA certificate. Managed clusters (EKS, GKE, AKS) show the endpoint and certificate authority in the provider's console.

## Connect Kubernetes to Oleria

**1. Open the integration**

Go to your Oleria workspace, select **Integrations** -> select **Kubernetes**.

**2. Complete the connection form**

| Field | Notes |
| :- | :- |
| API server URL | Required. The HTTPS address of the API server, for example `https://api.cluster.example.com:6443`. Oleria doesn't follow redirects, because each request carries the token. You can't change the URL after the integration is saved. |
| Bearer token | Required. The service account token you created. When you edit the integration later, leave it blank to keep the stored token. |
| CA certificate | Optional. The cluster's CA certificate in PEM format, when the API server uses a private certificate authority. When you provide it, Oleria trusts only this certificate authority for the connection. Leave it empty if the API server's certificate is issued by a public authority. Never paste a private key. |

**3. Authenticate**

Select **Authenticate** to validate and save the integration. Oleria checks that the token authenticates, that it can read the cluster's identity, and that it can list every RBAC object it syncs. If the token can't list a required resource, the form names the missing permission.

## Verify the integration

Confirm the Kubernetes instance appears on the **Connected** tab of your Oleria **Integrations** page with a status of **Healthy**. After the first sync completes, review the discovered service accounts, users, roles, and grants in your Oleria workspace.

## Remediation actions

If you granted the optional remediation role, Oleria can take these actions:

| Action | What it does | Revert |
| :- | :- | :- |
| Add user to role | Binds the user or service account to the role. For a ClusterRole, Oleria creates a ClusterRoleBinding (cluster-wide). For a Role, it creates a RoleBinding in the Role's namespace. Oleria names the binding `oleria-<id>` and labels it `app.kubernetes.io/managed-by: oleria`. It never edits your existing bindings. If the subject is already bound in that scope, nothing changes. | Supported - deletes the binding Oleria created. |
| Remove user from role | Removes the user or service account from every binding that gives it the role (for a ClusterRole, the ClusterRoleBindings and the RoleBindings in all namespaces). A binding that Oleria created and that is left empty is deleted. Your own bindings are kept, with the subject removed. | Supported - puts the subject back in each binding, recreating a deleted one. |
| Disable NHI (service account) | Deletes the service account, which invalidates every token issued for it, including its token Secrets. | Supported - recreates the service account with the same name, labels, annotations, and settings. The new service account has a new UID: tokens issued before aren't restored, and workloads get new tokens on their next refresh. |
| Disable NHI (token Secret) | Deletes the service account token Secret. | No - Kubernetes would issue a different token to a recreated Secret. |

Oleria confirms each change by reading it back. If a removal fails partway through, Oleria puts the subject back into the bindings it already changed. If putting it back also fails, the action says how many bindings may still be missing the subject, so you can check them in the cluster. If the API server doesn't answer clearly, the action reports that the outcome is unknown so you can check the cluster.

> [!NOTE]
>
> Oleria refuses to:
>
> * remove the integration's own service account from a role, or disable it or its tokens
> * disable service accounts and token Secrets in `kube-system`, `kube-public`, and `kube-node-lease`, or a namespace's `default` service account, which Kubernetes recreates immediately
> * change the default bindings Kubernetes restores itself (labeled `kubernetes.io/bootstrapping: rbac-defaults`)
> * add or remove groups: group membership comes from your cluster's authentication, not from Kubernetes

## Known limitations

* **Users and groups come from bindings.** Kubernetes has no user or group objects, so Oleria shows only the users and groups that a binding names. Their status, email (unless the name is an email address), last sign-in, and multi-factor authentication aren't available from the API. Connect your identity provider to Oleria to see everyone.
* **Group members aren't synced.** Kubernetes groups come from your cluster's authentication (for example an OIDC groups claim). Oleria shows which groups hold a role, and the three groups every service account belongs to (`system:serviceaccounts`, `system:serviceaccounts:<namespace>` and `system:authenticated`), but not who is in your other groups. A user who is an administrator only through a group isn't flagged as one.
* **No activity.** The API server writes audit events to a log file or sends them to a webhook; it doesn't expose them through the API. Oleria shows no activity or last use for service accounts.
* **Short-lived tokens aren't listed.** Tokens requested for pods and with `kubectl create token` are issued on demand and aren't stored. Only the long-lived token Secrets are inventoried, and only if you allow `list secrets`.
* **Private API endpoints can't be reached.** Oleria connects only to public addresses.
* **Only RBAC is read.** Access granted by a webhook authorizer or by node authorization isn't visible.
* **Namespaces and workloads aren't synced.** A namespace appears as the scope of a grant.

## Contact us

For questions about this integration, contact us at [support@oleria.com](mailto:support@oleria.com).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.