Namespace access control

Configuring per-user authorized namespaces.

Introduction

In authentication strategies other than anonymous Kiali supports limiting the namespaces that are accessible on a per-user basis. The anonymous authentication strategy does not support this, although you can still limit privileges when using an OpenShift cluster. See the access control section in Anonymous strategy.

To authorize namespaces, the standard Roles resources (or ClusterRoles) and RoleBindings resources (or ClusterRoleBindings) are used.

Kiali can only restrict or grant read access to namespaces as a whole. So, keep in mind that while the RBAC capabilities of the cluster are used to give access, Kiali won’t offer the same privilege granularity that the cluster supports. For example, a user that does not have privileges to get Kubernetes Deployments via typical tools (e.g. kubectl) would still be able to get some details of Deployments through Kiali when listing Workloads or when viewing detail pages, or in the Graph.

Some features allow creating or changing resources in the cluster (for example, the Wizards). For these write operations which may be sensitive, the users will need to have the required privileges in the cluster to perform updates - i.e. the cluster RBAC takes effect.

Granting access to namespaces

Kiali uses two Kubernetes RBAC verbs to determine which namespaces a user can see:

  • GET – grants access to individual namespaces. A user who can GET a specific namespace (api/v1/namespaces/{name}) will see that namespace in Kiali. Use per-namespace RoleBindings to control this.
  • LIST – grants access to all namespaces at once. A user who can LIST namespaces (api/v1/namespaces) will, by default, see every namespace returned by the list. This is typically granted via a ClusterRoleBinding.

Whichever verb a user has, Kiali applies the result consistently to the data it serves itself: graphs, detail pages, metrics, dashboards, traces and validations use the same namespace access rules. Application, proxy and waypoint logs are fetched with the user’s own credentials, so Kubernetes additionally requires pods/log permission in the namespace containing the pod. Correlated ztunnel logs are fetched with Kiali’s service account; Kiali checks the user’s access to the application’s namespace before returning those logs.

In most setups, granting LIST is the simplest way to give a user access to all namespaces, while GET via RoleBindings provides fine-grained, per-namespace control.

You, probably, will want to have this small ClusterRole to help you in authorizing individual namespaces in Kiali:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: kiali-namespace-authorization
rules:
- apiGroups: [""]
  resources:
  - namespaces
  - pods/log
  verbs:
  - get

Once you have created this ClusterRole, you would authorize a namespace foobar to user john with the following RoleBinding:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: authorize-ns-foobar-to-john
  namespace: foobar
subjects:
- kind: User
  name: john
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: kiali-namespace-authorization # The name of the ClusterRole created previously
  apiGroup: rbac.authorization.k8s.io

If you want to authorize a user to access all namespaces in the cluster, the most efficient way to do it is by creating a ClusterRole with the list verb for namespaces and bind it to the user using a ClusterRoleBinding:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: kiali-all-namespaces-authorization
rules:
- apiGroups: [""]
  resources:
  - namespaces
  - pods/log
  verbs:
  - get
  - list
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: authorize-all-namespaces-to-john
subjects:
- kind: User
  name: john
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: kiali-all-namespaces-authorization
  apiGroup: rbac.authorization.k8s.io

Alternatively, you could also use the previously mentioned kiali-namespace-authorization rather than creating a new one with the list privilege, and it will work. However, Kiali will perform better if you grant the list privilege.

Multi-tenant environments and require_namespace_get

Kiali supports two modes for deciding which namespaces a user can see when they hold cluster-wide LIST permission:

  • Default mode trusts the LIST result: a user who can list namespaces sees everything the list returns, on every view.
  • Strict mode additionally requires per-namespace GET permission, and is enabled with the require_namespace_get feature flag:
spec:
  kiali_feature_flags:
    authz:
      require_namespace_get: true

In strict mode, Kiali verifies GET permission for each namespace individually, even if the user’s LIST call succeeds. Only namespaces where the user has GET permission are visible — LIST permission alone is never sufficient to see a namespace.

Granting write privileges to namespaces

Changing resources in the cluster can be a sensitive operation. Because of this, the logged in user will need to be given the needed privileges to perform any updates through Kiali. The following ClusterRole contains all read and write privileges that may be used in Kiali:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: kiali-write-privileges
rules:
- apiGroups: [""]
  resources:
  - namespaces
  - pods
  - replicationcontrollers
  - services
  verbs:
  - patch
- apiGroups: ["extensions", "apps"]
  resources:
  - daemonsets
  - deployments
  - replicasets
  - statefulsets
  verbs:
  - patch
- apiGroups: ["batch"]
  resources:
  - cronjobs
  - jobs
  verbs:
  - patch
- apiGroups:
  - networking.istio.io
  - security.istio.io
  - extensions.istio.io
  - telemetry.istio.io
  - gateway.networking.k8s.io
  resources: ["*"]
  verbs:
  - get
  - list
  - watch
  - create
  - delete
  - patch

Similarly to giving access to namespaces, you can either use a RoleBinding to give read and write privileges only to specific namespaces, or use a ClusterRoleBinding to give privileges to all namespaces.

Tracing

Kiali’s tracing views follow the same namespace permissions as the rest of Kiali. This is worth knowing because the tracing backends Kiali integrates with (Jaeger, Grafana Tempo) do not have their own access control — Kiali enforces the logged-in user’s namespace access before returning trace data to the user. A user must have access to a namespace to see its traces, spans and error-trace counts. To open a trace by its ID, the user must have access to at least one namespace the trace passes through; a trace that crosses several namespaces is visible to any user who can access one of them. Authorization is per trace, not per span: once a trace is accessible, all of its spans are shown, including the spans of services in namespaces the user cannot access.

In a multicluster setup, when the tracing telemetry identifies the cluster a trace belongs to, the user must have access to the namespace in that cluster — access to a same-named namespace in a different cluster does not authorize opening the trace. Traces whose telemetry does not identify a cluster are checked against the namespace name in any cluster. The cluster match uses Kiali’s cluster names, which must match the Istio cluster IDs — they do by default, but explicitly configured names that diverge make the mismatched clusters’ namespaces unmatchable, so traces whose recognizable namespaces are all attributed to those clusters are denied (see the multi-cluster configuration page).

A trace must carry namespace information in its telemetry for Kiali to show it: Kiali reads the istio.namespace, istio.source_namespace, istio.destination_namespace and k8s.namespace.name span attributes (and the node_id of sidecar spans). Traces whose spans carry none of these cannot be authorized for any user and are excluded from the tracing views. The service.namespace attribute is not read for authorization: it is a logical service grouping controlled by the application, not the Kubernetes namespace the span was produced in. Istio mesh telemetry carries the namespace attributes; spans emitted directly by applications through an OpenTelemetry collector may not — configure the collector’s k8sattributes processor to set k8s.namespace.name on those spans so their traces remain visible.