Kubernetes 클러스터 보안 설정 테스트.
RBAC.
NetworkPolicy.
Pod Security Standards.
RBAC 예제.
apiVersion: v1
kind: Namespace
metadata:
name: app-ns
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-deployer
namespace: app-ns
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: app-deployer-role
namespace: app-ns
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: app-deployer-binding
namespace: app-ns
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: app-deployer-role
subjects:
- kind: ServiceAccount
name: app-deployer
namespace: app-ns
적용.
kubectl apply -f rbac-example.yaml
확인.
kubectl get rolebindings -n app-ns
kubectl describe rolebinding app-deployer-binding -n app-ns
권한 테스트.
kubectl auth can-i get pods \
--as=system:serviceaccount:app-ns:app-deployer \
-n app-ns
kubectl auth can-i create pods \
--as=system:serviceaccount:app-ns:app-deployer \
-n app-ns
Secret 접근은 막힘.
kubectl auth can-i get secrets \
--as=system:serviceaccount:app-ns:app-deployer \
-n app-ns
Pod에서 ServiceAccount 사용.
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-deployer-pod
namespace: app-ns
spec:
replicas: 1
selector:
matchLabels:
app: app-deployer
template:
metadata:
labels:
app: app-deployer
spec:
serviceAccountName: app-deployer
containers:
- name: app
image: nginx:alpine
volumeMounts:
- name: token
mountPath: /var/run/secrets/kubernetes.io/serviceaccount
readOnly: true
volumes:
- name: token
projected:
sources:
- serviceAccountToken:
audience: https://kubernetes.default.svc.cluster.local
expirationSeconds: 3600
path: token
NetworkPolicy 예제.
기본 차단 후 필요한 통신만 허용.
frontend -> api
api -> database
Namespace.
apiVersion: v1
kind: Namespace
metadata:
name: multi-tier
기본 deny.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
namespace: multi-tier
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Frontend -> API 허용.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: frontend-to-api
namespace: multi-tier
spec:
podSelector:
matchLabels:
tier: api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
tier: frontend
ports:
- protocol: TCP
port: 8000
API -> Database 허용.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-to-database
namespace: multi-tier
spec:
podSelector:
matchLabels:
tier: database
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
tier: api
ports:
- protocol: TCP
port: 5432
Frontend 80 허용.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: frontend-ingress
namespace: multi-tier
spec:
podSelector:
matchLabels:
tier: frontend
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector: {}
ports:
- protocol: TCP
port: 80
DNS egress 허용.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns-egress
namespace: multi-tier
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
name: kube-system
ports:
- protocol: UDP
port: 53
- to:
- namespaceSelector: {}
ports:
- protocol: TCP
port: 443
적용.
kubectl apply -f network-policy-example.yaml
확인.
kubectl get networkpolicies -n multi-tier
테스트.
kubectl exec -it <frontend-pod> -n multi-tier -- sh
curl http://api-service:8000
nc -zv database-service 5432
frontend에서 database는 실패해야 함.
api pod에서는 database 접근 성공해야 함.
Pod Security Standards.
Namespace에 restricted 적용.
apiVersion: v1
kind: Namespace
metadata:
name: secure-app
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
보안 Pod.
apiVersion: v1
kind: Pod
metadata:
name: secure-app
namespace: secure-app
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: python:3.11-slim
ports:
- containerPort: 8000
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
volumeMounts:
- name: tmp
mountPath: /tmp
- name: app-data
mountPath: /app/data
volumes:
- name: tmp
emptyDir: {}
- name: app-data
emptyDir: {}
보안 Deployment.
apiVersion: apps/v1
kind: Deployment
metadata:
name: secure-deployment
namespace: secure-app
spec:
replicas: 2
selector:
matchLabels:
app: secure-app
template:
metadata:
labels:
app: secure-app
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
containers:
- name: app
image: nginx:1.25-alpine
ports:
- containerPort: 8080
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "128Mi"
cpu: "200m"
volumeMounts:
- name: cache
mountPath: /var/cache/nginx
- name: run
mountPath: /var/run
- name: tmp
mountPath: /tmp
volumes:
- name: cache
emptyDir: {}
- name: run
emptyDir: {}
- name: tmp
emptyDir: {}
PDB.
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: secure-app-pdb
namespace: secure-app
spec:
minAvailable: 1
selector:
matchLabels:
app: secure-app
적용.
kubectl apply -f pod-security-example.yaml
확인.
kubectl get namespace secure-app --show-labels
kubectl get pod secure-app -n secure-app -o yaml | grep -A 10 securityContext
non-root 확인.
kubectl exec -it secure-app -n secure-app -- id
read-only root filesystem 확인.
kubectl exec -it <pod-name> -n secure-app -- touch /test.txt
Capability 확인.
kubectl exec -it <pod-name> -n secure-app -- grep Cap /proc/1/status
팀별 RBAC 예시.
apiVersion: v1
kind: ServiceAccount
metadata:
name: team-a
namespace: team-a-ns
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: deployer
namespace: team-a-ns
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "create", "update", "patch"]
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "list"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: team-b
namespace: team-b-ns
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: viewer
namespace: team-b-ns
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list"]
체크리스트.
RBAC 활성화.
NetworkPolicy 적용.
Pod Security Standards 적용.
non-root 실행.
readOnlyRootFilesystem 설정.
allowPrivilegeEscalation false.
capabilities drop ALL.
resource limits 설정.