Managing a Kubernetes cluster? Then you know security is not optional. But between RBAC, Network Policy, and Pod Security Standards, it's easy to get lost or misconfigure everything. We at Meteora Web work on real clusters for clients, and we've seen mistakes that cost unauthorized access and traffic leaks. This guide shows how to set up these three components without holes.
Why RBAC is the first step in Kubernetes security?
RBAC (Role-Based Access Control) decides who can do what in the cluster. Without RBAC, anyone with cluster access can read secrets, delete namespaces, run arbitrary pods. We always start here: minimum identities and granular permissions. The golden rule: no user, service, or pod should have more permissions than necessary to function.
Role vs ClusterRole
A Role grants permissions within a single namespace. A ClusterRole grants cluster-wide permissions (all namespaces or non-namespaced resources).
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]RoleBinding and ClusterRoleBinding
A RoleBinding binds a Role to a subject (user, group, service account) in a namespace. A ClusterRoleBinding binds a ClusterRole cluster-wide.
Sponsored Protocol
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: production
subjects:
- kind: ServiceAccount
name: my-app
namespace: production
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.ioCommon mistake: using a ClusterRoleBinding for namespace-scoped access. This exposes every namespace to potential abuse.
How to write a Network Policy that actually blocks traffic?
By default, Kubernetes allows all traffic between pods and to the outside. A Network Policy limits it. Without at least one policy, traffic is fully open. One misconfigured policy can isolate an entire application.
Basic structure
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-allow-frontend
namespace: production
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
egress:
- to:
- podSelector:
matchLabels:
app: database
ports:
- protocol: TCP
port: 5432This policy only allows pods with label app: frontend to talk to app: api on port 8080, and only app: api to talk to app: database on port 5432. Everything else is blocked.
Sponsored Protocol
External access rules
To allow external traffic (e.g., from a load balancer), use ipBlock or namespaceSelector. But don't forget egress for DNS (port 53) – otherwise pods can't resolve names. We always add a policy for UDP 53 to the cluster DNS.
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53Operational checklist for Network Policy:
- Always specify
policyTypes(Ingress/Egress) - Don't forget DNS (UDP 53)
- Use
podSelectorwith clear, consistent labels - Test with
kubectl run --rm -it busybox -- shto verify connectivity
What are the essential Pod Security Standards rules?
Pod Security Standards (PSS) replaced the old PodSecurityPolicy. They define three levels: Privileged, Baseline, and Restricted. We recommend starting with Baseline as a minimum, and moving to Restricted for non-privileged workloads.
Sponsored Protocol
Applying PSS with Pod Security Admission
Kubernetes 1.23+ has the Pod Security Admission controller built in. Apply it at namespace level with labels:
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restrictedThe enforce mode blocks non-compliant pods, audit logs violations, warn shows warnings to the user.
Typical mistakes
- Using
privilegedfor all pods, defeating security. - Overlooking container
securityContext(e.g.,runAsUser: 0). - Forgetting to update the admission controller after a cluster upgrade.
How to test and verify that policies work?
Writing YAML is only half the job. We test with:
kubectl auth can-ifor RBAC:kubectl auth can-i list pods --as=system:serviceaccount:production:my-app- Busybox test pods for network connectivity:
kubectl run test --image=busybox --rm -it -- shthenwget ... - Tools like
kube-benchandkube-hunterfor automated audits.
Practical tip: keep all security manifests in a Git repo and use a CI/CD pipeline (e.g., GitHub Actions) to validate every change with kubectl apply --dry-run=server and conftest for policy as code.
Sponsored Protocol
What to do now
- Check current permissions: run
kubectl describe clusterrolebindingand identify over-permissioned accounts. - Apply a default deny Network Policy: create a policy that blocks all ingress and egress in every namespace, then add permissive rules.
- Set Pod Security Standards on every namespace: start with
warningandaudit, then move toenforcein production. - Automate tests: add a periodic job that runs
kube-benchand sends reports. - Read the official docs: RBAC Good Practices and Pod Security Standards.
This guide is part of our Pillar on Cloud Security and DevSecOps. We covered only RBAC, Network Policy, and Pod Security; the pillar has everything from pipelines to IAM. Happy configuring — and if you want a cluster audit, we know where to look.