All resources
// Resources

Kubernetes RBAC and NetworkPolicy Review

Published July 21, 2026

Kubernetes RBAC governs requests to Kubernetes API. NetworkPolicy selects Pod traffic, but works only when installed CNI enforces it. Review them together: compromised workload with broad API token and open egress crosses boundaries differently from workload with minimal Role and constrained traffic. Neither control proves application authorization or node hardening.

Start with identities and bindings

Export ServiceAccounts, Roles, ClusterRoles, RoleBindings, ClusterRoleBindings, namespace labels, and active workload manifests. Kubernetes guidance advises least privilege, avoiding wildcard permissions, and minimizing privileged token distribution. Identify every cluster-admin, wildcard verb, wildcard resource, impersonate, secret read, pod exec, and binding to broad groups.

BoundaryCompleted artifactEvidence testOwnerPass / fail
Service accountworkload-to-SA mapdefault SA not granted privilegeworkload ownereach workload has intended identity
Namespace accessRole and RoleBinding exportkubectl auth can-i denies unnecessary verbnamespace ownerleast privilege evidenced
Cluster accessClusterRoleBinding registerscope justified; no broad accidental subjectcluster ownerbinding reviewed
Ingressdefault-deny policy plus allowed flowsunapproved Pod path blockednetwork ownerintended caller only
Egressdefault-deny policy plus DNS/service rulesunexpected destination blockednetwork ownerrequired flow works

Use Role and RoleBinding for namespace work. A ClusterRole can be bound through RoleBinding only within target namespace; ClusterRoleBinding grants its permissions cluster-wide. Do not bind application service account to cluster-admin to solve a deployment error. Replace it with exact API groups, resources, verbs, and names where resource names are stable.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata: { name: report-reader, namespace: payments }
rules:
  - apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["get"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata: { name: report-reader, namespace: payments }
subjects:
  - kind: ServiceAccount
    name: reports
    namespace: payments
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: report-reader

Record command, identity, namespace, expected result, actual result, and timestamp for authorization tests. Example fail: service account can list Secrets although workload has no need. Remediation means revised manifest, applied object export, denied retest, and owner—not “RBAC tightened.”

Default deny needs working dependencies

A NetworkPolicy selecting pods and declaring policyTypes: [Ingress, Egress] with no allow rules defaults selected pods to deny ingress and egress. First verify CNI supports NetworkPolicy; Kubernetes API acceptance alone is not evidence of enforcement. Inventory namespace, Pod labels, DNS resolver, dependencies, external endpoints, ports, and protocols before rollout.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: { name: default-deny, namespace: payments }
spec:
  podSelector: {}
  policyTypes: [Ingress, Egress]

Add narrow policies for known service callers and DNS. Test from matching and nonmatching pods, then preserve test output. NetworkPolicy combines applicable policies; it is not ordered firewall rules. Default-deny ingress without required frontend policy breaks callers. Default-deny egress without DNS allowance may break discovery. Do not use broad 0.0.0.0/0 as routine escape hatch; record why external access is needed and narrow it when provider and architecture allow.

Rollout and evidence

Apply policy first in a representative non-critical namespace when architecture allows. Capture before/after connection tests for API caller, worker, metrics, DNS, and intended external dependency. A failed dependency is evidence to refine an explicit allow rule, not reason to remove all egress controls. Record selected Pods, labels, namespace, CNI version, test command, observed result, and reviewer. Repeat after label, service, or CNI changes because selection can change without policy YAML changing.

Use short-lived projected service-account tokens where workload needs Kubernetes API access and disable token automount for workloads that do not. Confirm workloads reference intended service account rather than implicit default. Review controller-created Pods and Jobs too; they may inherit a privileged default unexpectedly. API audit logs can corroborate permission use, but absence of event is not proof that permission is unnecessary without considering collection scope.

Exceptions and deliverable

Exception requires affected namespace/workload, exact excessive permission or allowed flow, reason, compensating control, owner, approver, expiry, remediation, and retest date. Expired exception is fail. Deliver identity map, binding review, network-flow matrix, manifests, CNI enforcement evidence, pass/fail register, exceptions, and remediation tracker. Infrastructure testing can validate agreed cluster scope.

Worked case: namespace service account

Deploy test workload under named service account and request only listed API objects in its namespace. Expected output permits declared read action and denies secret read, cluster-scoped write, and same action in adjacent namespace. Capture API audit result and effective RoleBinding, then delete binding and verify access disappears. For NetworkPolicy, test allowed application path and denied cross-namespace path from real labeled pods; policy review must name DNS or egress dependencies instead of assuming deny behavior covers them.

Test label drift, default service account use, pod recreation, and emergency binding expiry. Closure record contains manifests, rendered policy, test pod identity, command outputs, audit references, and reviewer. Exceptions name namespace, verbs, resources, traffic peer, expiry, and independent removal check. Do not close from YAML reading alone; behavior under admission and runtime identity is evidence.

Operational handoff: platform owner inventories cluster add-ons needing egress and namespace labels. Application owner verifies service-account name in deployed pod, not manifest assumption. Rerun deny tests after chart or admission-controller change. Attach result to release record.

Final cluster check exercises deployed service account, namespace labels, and real pod network path rather than manifest intent alone. Expected result: required operations and traffic work while prohibited verbs and peers fail. Edge case: controller-created pods receive unexpected account or labels; inspect them after reconciliation. Close only when runtime audit and policy evidence identify same revision.

Sources

Have a system that needs testing?