Kubernetes Networking & Security
NetworkPolicies, RBAC, Pod Security Standards, Secrets management, এবং যে default-deny posture ক্লাস্টারকে hardened রাখে।
গল্পে বুঝি
ফাতিমা আল-ফিহরি একটা বিশাল দেয়ালঘেরা ক্যাম্পাসের ব্যবস্থাপক। ভেতরে অনেকগুলো বিল্ডিং — গবেষণাগার, লাইব্রেরি, হিসাবরক্ষণ। এক বিভাগ যখন অন্য বিভাগের কারো কাছে পৌঁছাতে চায়, তখন কে কোন ঘরে বসে সেটা মুখস্থ করতে হয় না — একটা অভ্যন্তরীণ ফোন ডিরেক্টরি আছে, শুধু বিভাগের নাম বললেই কল কানেক্ট হয়ে যায়। লোকজন ডেস্ক বদলালেও, নতুন কেউ যোগ দিলেও, নামটা এক থাকে বলে যোগাযোগ কখনো ভাঙে না। আর বাইরে থেকে যে অতিথিরা আসে, তারা সবাই ঢোকে একটাই মূল ফটক দিয়ে — সেখানে বসা রিসেপশনিস্ট আল-খোয়ারিজমি প্রত্যেক অতিথিকে জিজ্ঞেস করেন কোন বিল্ডিং খুঁজছেন, নাম শুনে তবেই সঠিক দিকে পাঠান।
কিন্তু ভেতরে ঢুকলেই সব দরজা খোলা নয়। দেয়ালে সাঁটা নিয়ম বলে দেয় কোন বিল্ডিং কোন বিল্ডিংয়ে লোক পাঠাতে পারবে — হিসাবরক্ষণ থেকে লাইব্রেরিতে যাওয়া যায়, কিন্তু গবেষণাগারে ঢোকা বারণ। আর প্রত্যেকের গলায় ঝোলানো একটা রঙিন ব্যাজ, যা ঠিক করে দেয় সে কোন কোন ঘরে ঢুকতে পারবে আর সেখানে কী করতে পারবে — ইবনে সিনার নীল ব্যাজে শুধু আর্কাইভ পড়ার অনুমতি, ফাইল বদলানোর নয়।
এই গল্পটাই আসলে Kubernetes-এর নেটওয়ার্কিং আর সিকিউরিটি। অভ্যন্তরীণ ফোন ডিরেক্টরি — যেখানে নাম দিয়ে ডাকলেই পৌঁছে যায়, ডেস্ক বদলালেও নয় — হলো Service আর তার স্থায়ী internal DNS নাম। মূল ফটকের রিসেপশনিস্ট যিনি অতিথির চাওয়া নাম শুনে সঠিক বিল্ডিংয়ে পাঠান, তিনি Ingress (host/path দেখে বাইরের traffic কে ভেতরের Service-এ রুট করা)। দেয়ালে সাঁটা “কে কার কাছে যেতে পারবে” নিয়ম হলো NetworkPolicy (pod-to-pod traffic নিয়ন্ত্রণ), আর রঙিন ব্যাজ যা প্রতিটা ভূমিকাকে শুধু নির্দিষ্ট ঘর ও কাজের অনুমতি দেয় সেটা RBAC (কে কোন resource-এ কী করতে পারবে)। বাস্তবে ঠিক এভাবেই একটা hardened ক্লাস্টার চলে — Service নাম দিয়ে খুঁজে পাওয়া যায়, Ingress বাইরের request রুট করে, NetworkPolicy default-deny posture বজায় রাখে, আর RBAC least-privilege নিশ্চিত করে।
বাস্তব জীবনের উদাহরণ
একটা সিকিউর অফিস বিল্ডিং: প্রতিটা কর্মীর একটা ব্যাজ আছে (RBAC — কে কী করতে পারবে সেটা নিয়ন্ত্রণ করে), ফ্লোরগুলোর access zone আছে (NetworkPolicies — কোন pod কোন pod-এর সাথে কথা বলতে পারবে সেটা নিয়ন্ত্রণ করে), সংবেদনশীল ফাইল নির্দিষ্ট ক্যাবিনেটে তালাবদ্ধ (Secrets management), এবং বিল্ডিংয়ে এমন সিকিউরিটি পলিসি আছে যা সবার জন্য প্রযোজ্য (Pod Security Standards — কেউ মেটাল ডিটেক্টর এড়িয়ে যেতে পারে না)।
NetworkPolicies
default-এ, ক্লাস্টারের সব pod অন্য সব pod-এর সাথে যোগাযোগ করতে পারে। NetworkPolicy এটা সীমিত করে।
একটা namespace-এর জন্য default-deny:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {} # applies to all pods
policyTypes:
- Ingress
- Egress এখন production-এর কোনো pod কোনো traffic গ্রহণ বা পাঠাতে পারবে না। যা দরকার তা allow করতে policy যোগ করুন।
নির্দিষ্ট ingress allow করা:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-order-service-ingress
namespace: production
spec:
podSelector:
matchLabels:
app: order-service
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: api-gateway # only from the gateway
- namespaceSelector:
matchLabels:
name: monitoring # and from the monitoring namespace (Prometheus scrape)
ports:
- protocol: TCP
port: 3000 নির্দিষ্ট service-এ egress allow করা:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: order-service-egress
namespace: production
spec:
podSelector:
matchLabels:
app: order-service
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- protocol: TCP
port: 5432
- to:
- podSelector:
matchLabels:
app: redis
ports:
- protocol: TCP
port: 6379
- to: # allow DNS
- namespaceSelector: {}
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53 NetworkPolicy CNI plugin দিয়ে enforce হয় (একা Flannel এগুলো সাপোর্ট করে না — Calico বা Cilium ব্যবহার করুন)।
# Install Cilium as CNI (supports NetworkPolicies and more)
helm repo add cilium https://helm.cilium.io/
helm install cilium cilium/cilium \
--namespace kube-system \
--set kubeProxyReplacement=strict RBAC
Kubernetes RBAC নিয়ন্ত্রণ করে কে কোন resource-এ কী করতে পারবে।
তিনটা object:
- Role/ClusterRole — permission সংজ্ঞায়িত করে (কোন resource-এ কোন verb)
- ServiceAccount — একটা pod-এর identity
- RoleBinding/ClusterRoleBinding — একটা Role-কে একটা ServiceAccount-এর (বা user-এর) সাথে bind করে
# ServiceAccount for order-service
apiVersion: v1
kind: ServiceAccount
metadata:
name: order-service
namespace: production # Role: what order-service is allowed to do
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: order-service-role
namespace: production
rules:
- apiGroups: ['']
resources: ['secrets']
verbs: ['get'] # can only read secrets, not list/create/delete
resourceNames: ['order-service-secrets'] # only this specific secret
- apiGroups: ['']
resources: ['configmaps']
verbs: ['get', 'list', 'watch'] # Bind the role to the service account
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: order-service-rolebinding
namespace: production
subjects:
- kind: ServiceAccount
name: order-service
namespace: production
roleRef:
kind: Role
name: order-service-role
apiGroup: rbac.authorization.k8s.io # Tell the Deployment to use this ServiceAccount
spec:
template:
spec:
serviceAccountName: order-service Principle of least privilege: প্রতিটা service account শুধু সেই permission পায় যা তার আসলেই দরকার।
মানুষের জন্য (kubectl access):
# Grant a developer read-only access to production
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: developer-readonly
subjects:
- kind: User
name: 'layla@example.com'
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: view # built-in: read-only for most resources
apiGroup: rbac.authorization.k8s.io # Check what a service account can do
kubectl auth can-i get secrets --as=system:serviceaccount:production:order-service -n production
# Check your own permissions
kubectl auth can-i --list -n production Pod Security Standards
Kubernetes-এ তিনটা built-in security profile আছে:
- Privileged — unrestricted (workload-এর জন্য ব্যবহার করবেন না)
- Baseline — পরিচিত privilege escalation ঠেকায়
- Restricted — hardened, security best practice অনুসরণ করে
namespace level-এ apply করুন:
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/audit: restricted restricted-এর ক্ষেত্রে, pod-কে অবশ্যই:
- non-root হিসেবে চলতে হবে
securityContext.runAsNonRoot: trueব্যবহার করতে হবেallowPrivilegeEscalation: falseসেট করতে হবেALLcapability drop করতে হবেseccompProfile.type: RuntimeDefaultবাLocalhostব্যবহার করতে হবে
spec:
containers:
- name: order-service
securityContext:
runAsNonRoot: true
runAsUser: 1001
runAsGroup: 1001
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ['ALL']
seccompProfile:
type: RuntimeDefault
volumeMounts:
- name: tmp
mountPath: /tmp # writable tmp since root is read-only
volumes:
- name: tmp
emptyDir: {} Secrets Management
Kubernetes Secret base64-encoded, encrypted নয়। Secret-এ RBAC access আছে এমন যে কেউ সেগুলো পড়তে পারে। এভাবে harden করুন:
Encryption at rest:
# Enable in kube-apiserver config
--encryption-provider-config=/etc/kubernetes/encryption-config.yaml # encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: <base64-encoded-32-byte-key>
- identity: {} External Secrets Operator (preferred):
AWS Secrets Manager, HashiCorp Vault, বা GCP Secret Manager থেকে secret sync করে Kubernetes Secret-এ নিয়ে আসে।
# ExternalSecret — pulls from AWS Secrets Manager
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: order-service-secrets
namespace: production
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secretsmanager
kind: ClusterSecretStore
target:
name: order-service-secrets # creates/updates this K8s Secret
data:
- secretKey: database_url
remoteRef:
key: production/order-service
property: database_url
- secretKey: jwt_secret
remoteRef:
key: production/order-service
property: jwt_secret secret-টা থাকে AWS Secrets Manager-এ; Kubernetes-এ একটা কপি থাকে যা sync-এ রাখা হয়। AWS-এ rotation করলে সেটা অটোমেটিক pod পর্যন্ত propagate হয়।
Sealed Secrets (git-safe):
secret-কে cluster-specific key দিয়ে encrypt করুন যাতে সেগুলো git-এ commit করা যায়:
# Install Sealed Secrets controller
helm install sealed-secrets sealed-secrets/sealed-secrets -n kube-system
# Encrypt a secret
kubectl create secret generic order-service-secrets \
--from-literal=database_url='postgres://...' \
--dry-run=client -o yaml | \
kubeseal --format yaml > sealed-secret.yaml
# Commit sealed-secret.yaml to git — safe to store
git add sealed-secret.yaml
git commit -m "add order-service sealed secrets" controller ক্লাস্টারের উপর decrypt করে; encrypted রূপটা ক্লাস্টারের বাইরে কোনো কাজেরই নয়।
mTLS with Cilium or Istio
zero-trust networking-এর জন্য — প্রতিটা service-to-service কল mutually authenticated আর encrypted:
Cilium (simpler):
# Enable mTLS for the namespace
apiVersion: cilium.io/v2alpha1
kind: CiliumNetworkPolicy
metadata:
name: mtls-policy
namespace: production
spec:
endpointSelector: {}
ingress:
- fromEndpoints:
- matchLabels:
io.cilium.k8s.policy.serviceaccount: order-service
toPorts:
- ports:
- port: '3000'
rules:
l7proto: http Istio (comprehensive):
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: production
spec:
mtls:
mode: STRICT # all traffic must use mTLS STRICT mode-এ mTLS থাকলে, কোনো unencrypted বা unauthenticated traffic গ্রহণ করা হয় না। Service-রা Istio-র CA দিয়ে ম্যানেজ করা সার্টিফিকেটের মাধ্যমে নিজেদের identity প্রমাণ করে। কোনো application code পরিবর্তন লাগে না — Envoy sidecar-ই সেটা সামলায়।