07. Kubernetes 보μ
07. Kubernetes 보μ¶
νμ΅ λͺ©ν¶
- Kubernetes 보μ μν€ν μ² μ΄ν΄
- RBACμ ν΅ν μ κ·Ό μ μ΄ κ΅¬ν
- NetworkPolicyλ‘ λ€νΈμν¬ κ²©λ¦¬
- Secrets λ° λ―Όκ° μ 보 κ΄λ¦¬
- Pod 보μ μ μ± μ μ©
λͺ©μ°¨¶
- Kubernetes 보μ κ°μ
- RBAC (μν κΈ°λ° μ κ·Ό μ μ΄)
- ServiceAccount
- NetworkPolicy
- Secrets κ΄λ¦¬
- Pod 보μ
- μ°μ΅ λ¬Έμ
1. Kubernetes 보μ κ°μ¶
1.1 4C 보μ λͺ¨λΈ¶
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Cloud (ν΄λΌμ°λ) β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Cluster (ν΄λ¬μ€ν°) β β
β β βββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β Container (컨ν
μ΄λ) β β β
β β β βββββββββββββββββββββββββββββββββββββββ β β β
β β β β Code (μ½λ) β β β β
β β β β - μ·¨μ½μ μ€μΊλ β β β β
β β β β - μμ‘΄μ± κ΄λ¦¬ β β β β
β β β β - 보μ μ½λ© β β β β
β β β βββββββββββββββββββββββββββββββββββββββ β β β
β β β - μ΄λ―Έμ§ 보μ β β β
β β β - λ°νμ 보μ β β β
β β β - 리μμ€ μ ν β β β
β β βββββββββββββββββββββββββββββββββββββββββββββββ β β
β β - RBAC, NetworkPolicy β β
β β - Secrets κ΄λ¦¬ β β
β β - Pod 보μ β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β - λ€νΈμν¬ λ³΄μ β
β - IAM, λ°©νλ²½ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
1.2 μΈμ¦κ³Ό μΈκ°¶
βββββββββββββββ ββββββββββββββββ βββββββββββββββ
β User ββββββΆβ API μλ² ββββββΆβ 리μμ€ β
β (kubectl) β β β β (Pods) β
βββββββββββββββ ββββββββββββββββ βββββββββββββββ
β
ββββββββββββββΌβββββββββββββ
βΌ βΌ βΌ
ββββββββββββ ββββββββββββ ββββββββββββ
β μΈμ¦ β β μΈκ° β β Admissionβ
β(AuthN) β β(AuthZ) β β Control β
ββββββββββββ€ ββββββββββββ€ ββββββββββββ€
ββ’ μΈμ¦μ β ββ’ RBAC β ββ’ κ²μ¦ β
ββ’ ν ν° β ββ’ ABAC β ββ’ λ³ν β
ββ’ OIDC β ββ’ Webhook β ββ’ μ μ±
β
ββββββββββββ ββββββββββββ ββββββββββββ
1.3 보μ κ΅¬μ± μμ¶
# νμ¬ ν΄λ¬μ€ν° 보μ μν νμΈ
# API μλ² μ€μ νμΈ
kubectl describe pod kube-apiserver-<master-node> -n kube-system
# μΈμ¦ λͺ¨λ νμΈ
kubectl api-versions | grep rbac
# rbac.authorization.k8s.io/v1
# ν΄λ¬μ€ν° κΆν νμΈ
kubectl auth can-i --list
2. RBAC (μν κΈ°λ° μ κ·Ό μ μ΄)¶
2.1 RBAC ν΅μ¬ κ°λ ¶
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β RBAC κ΅¬μ± μμ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββββ βββββββββββββββββ β
β β Role β β ClusterRole β β
β β (λ€μμ€νμ΄μ€)β β (ν΄λ¬μ€ν°) β β
β βββββββββ¬ββββββββ βββββββββ¬ββββββββ β
β β β β
β β λ°μΈλ© β λ°μΈλ© β
β βΌ βΌ β
β βββββββββββββββββ βββββββββββββββββ β
β β RoleBinding β βClusterRole β β
β β β β Binding β β
β βββββββββ¬ββββββββ βββββββββ¬ββββββββ β
β β β β
β ββββββββββββββββ¬ββββββββββββββββββββ β
β βΌ β
β βββββββββββββββββ β
β β Subjects β β
β β β’ User β β
β β β’ Group β β
β β β’ ServiceAcc β β
β βββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2.2 Role μ μ¶
# role-pod-reader.yaml
# νΉμ λ€μμ€νμ΄μ€μμ Pod μ½κΈ° κΆν
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: development
name: pod-reader
rules:
- apiGroups: [""] # "" = core API group
resources: ["pods"]
verbs: ["get", "watch", "list"]
---
# role-deployment-manager.yaml
# Deployment κ΄λ¦¬ κΆν
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: development
name: deployment-manager
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
---
# role-secret-reader.yaml
# νΉμ Secretλ§ μ½κΈ° (resourceNames μ¬μ©)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: specific-secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["app-config", "db-credentials"] # νΉμ 리μμ€λ§
verbs: ["get"]
2.3 ClusterRole μ μ¶
# clusterrole-node-reader.yaml
# ν΄λ¬μ€ν° μ 체μμ λ
Έλ μ 보 μ½κΈ°
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: node-reader
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "watch", "list"]
---
# clusterrole-pv-manager.yaml
# PersistentVolume κ΄λ¦¬ (ν΄λ¬μ€ν° λ²μ 리μμ€)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: pv-manager
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch"]
---
# clusterrole-namespace-admin.yaml
# λͺ¨λ λ€μμ€νμ΄μ€μμ κ΄λ¦¬μ μν
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: namespace-admin
rules:
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["*"]
verbs: ["*"]
---
# μ§κ³λ ClusterRole (Aggregation)
# clusterrole-monitoring.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: monitoring
labels:
rbac.example.com/aggregate-to-monitoring: "true"
aggregationRule:
clusterRoleSelectors:
- matchLabels:
rbac.example.com/aggregate-to-monitoring: "true"
rules: [] # κ·μΉμ μλμΌλ‘ μ§κ³λ¨
2.4 RoleBinding & ClusterRoleBinding¶
# rolebinding-pod-reader.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: development
subjects:
- kind: User
name: jane
apiGroup: rbac.authorization.k8s.io
- kind: Group
name: developers
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
---
# rolebinding-sa.yaml
# ServiceAccountμ μν λ°μΈλ©
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: app-deployment-binding
namespace: development
subjects:
- kind: ServiceAccount
name: app-deployer
namespace: development
roleRef:
kind: Role
name: deployment-manager
apiGroup: rbac.authorization.k8s.io
---
# clusterrolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: node-reader-binding
subjects:
- kind: Group
name: ops-team
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: node-reader
apiGroup: rbac.authorization.k8s.io
---
# ClusterRoleμ νΉμ λ€μμ€νμ΄μ€μ λ°μΈλ©
# (ClusterRole μ¬μ¬μ©)
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: admin-binding
namespace: staging
subjects:
- kind: User
name: admin-user
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole # ClusterRoleμ΄μ§λ§
name: admin # RoleBindingμΌλ‘ λ²μ μ ν
apiGroup: rbac.authorization.k8s.io
2.5 RBAC ν μ€νΈ λ° λλ²κΉ ¶
# κΆν νμΈ
kubectl auth can-i create pods --namespace development
# yes
kubectl auth can-i delete pods --namespace production --as jane
# no
kubectl auth can-i '*' '*' --all-namespaces --as system:serviceaccount:default:admin
# yes
# νΉμ μ¬μ©μμ λͺ¨λ κΆν νμΈ
kubectl auth can-i --list --as jane --namespace development
# RBAC 리μμ€ μ‘°ν
kubectl get roles -n development
kubectl get rolebindings -n development
kubectl get clusterroles
kubectl get clusterrolebindings
# μμΈ μ 보
kubectl describe role pod-reader -n development
kubectl describe rolebinding read-pods -n development
3. ServiceAccount¶
3.1 ServiceAccount κΈ°λ³Έ¶
# serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-service-account
namespace: production
annotations:
description: "Application service account for production"
# Kubernetes 1.24+μμλ ν ν°μ΄ μλ μμ±λμ§ μμ
---
# ν ν° μμ± (Kubernetes 1.24+)
apiVersion: v1
kind: Secret
metadata:
name: app-sa-token
namespace: production
annotations:
kubernetes.io/service-account.name: app-service-account
type: kubernetes.io/service-account-token
3.2 Podμμ ServiceAccount μ¬μ©¶
# pod-with-sa.yaml
apiVersion: v1
kind: Pod
metadata:
name: app-pod
namespace: production
spec:
serviceAccountName: app-service-account
automountServiceAccountToken: true # ν ν° μλ λ§μ΄νΈ
containers:
- name: app
image: myapp:latest
# ν ν°μ /var/run/secrets/kubernetes.io/serviceaccount/μ λ§μ΄νΈλ¨
---
# ν ν° λ§μ΄νΈ λΉνμ±ν (보μ κ°ν)
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
serviceAccountName: restricted-sa
automountServiceAccountToken: false # ν ν° λΉλ§μ΄νΈ
containers:
- name: app
image: myapp:latest
3.3 ServiceAccountλ₯Ό μν RBAC¶
# CI/CD νμ΄νλΌμΈμ© ServiceAccount μμ
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: cicd-deployer
namespace: cicd
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cicd-deployer-role
rules:
# Deployment κ΄λ¦¬
- apiGroups: ["apps"]
resources: ["deployments", "replicasets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
# Service κ΄λ¦¬
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
# ConfigMap, Secret μ½κΈ°
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get", "list", "watch"]
# Pod μν νμΈ
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cicd-deployer-binding
subjects:
- kind: ServiceAccount
name: cicd-deployer
namespace: cicd
roleRef:
kind: ClusterRole
name: cicd-deployer-role
apiGroup: rbac.authorization.k8s.io
3.4 ServiceAccount ν ν° μ¬μ©¶
# ServiceAccount ν ν° κ°μ Έμ€κΈ°
TOKEN=$(kubectl create token app-service-account -n production)
# λλ Secretμμ κ°μ Έμ€κΈ°
TOKEN=$(kubectl get secret app-sa-token -n production -o jsonpath='{.data.token}' | base64 -d)
# ν ν°μΌλ‘ API νΈμΆ
curl -k -H "Authorization: Bearer $TOKEN" \
https://kubernetes.default.svc/api/v1/namespaces/production/pods
# kubeconfig μμ±
kubectl config set-credentials sa-user --token=$TOKEN
kubectl config set-context sa-context --cluster=my-cluster --user=sa-user
4. NetworkPolicy¶
4.1 NetworkPolicy κ°μ¶
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β NetworkPolicy λμ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β NetworkPolicy μμ: β
β βββββββ βββββββ βββββββ β
β βPod AββββββΆβPod BββββββΆβPod Cβ λͺ¨λ νΈλν½ νμ© β
β βββββββ βββββββ βββββββ β
β β
β NetworkPolicy μ μ©: β
β βββββββ βββββββ βββββββ β
β βPod AββββββΆβPod Bβ β βPod Cβ μ μ±
μ λ°λΌ μ ν β
β βββββββ βββββββ βββββββ β
β β
β β οΈ μ£Όμ: CNI νλ¬κ·ΈμΈμ΄ NetworkPolicyλ₯Ό μ§μν΄μΌ ν¨ β
β (Calico, Cilium, Weave Net λ±) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
4.2 κΈ°λ³Έ NetworkPolicy¶
# deny-all-ingress.yaml
# κΈ°λ³Έμ μΌλ‘ λͺ¨λ μΈλ°μ΄λ νΈλν½ κ±°λΆ
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-ingress
namespace: production
spec:
podSelector: {} # λͺ¨λ Podμ μ μ©
policyTypes:
- Ingress
# ingress κ·μΉ μμ = λͺ¨λ μΈλ°μ΄λ κ±°λΆ
---
# deny-all-egress.yaml
# λͺ¨λ μμλ°μ΄λ νΈλν½ κ±°λΆ
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-egress
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
# egress κ·μΉ μμ = λͺ¨λ μμλ°μ΄λ κ±°λΆ
---
# default-deny-all.yaml
# λͺ¨λ νΈλν½ κ±°λΆ (κ°μ₯ μ νμ )
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
4.3 νμ© μ μ± ¶
# allow-frontend-to-backend.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
---
# allow-backend-to-database.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-backend-to-database
namespace: production
spec:
podSelector:
matchLabels:
app: database
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: backend
ports:
- protocol: TCP
port: 5432
---
# λ€λ₯Έ λ€μμ€νμ΄μ€μμμ μ κ·Ό νμ©
# allow-from-monitoring.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-monitoring
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: monitoring
podSelector:
matchLabels:
app: prometheus
ports:
- protocol: TCP
port: 9090
4.4 λ³΅ν© μ μ± ¶
# comprehensive-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-server-policy
namespace: production
spec:
podSelector:
matchLabels:
app: api-server
policyTypes:
- Ingress
- Egress
ingress:
# 1. κ°μ λ€μμ€νμ΄μ€μ frontendμμ νμ©
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 443
# 2. Ingress Controllerμμ νμ©
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
ports:
- protocol: TCP
port: 443
# 3. νΉμ IP λμμμ νμ©
- from:
- ipBlock:
cidr: 10.0.0.0/8
except:
- 10.0.1.0/24 # μ΄ λμμ μ μΈ
ports:
- protocol: TCP
port: 443
egress:
# 1. λ°μ΄ν°λ² μ΄μ€λ‘ μμλ°μ΄λ
- to:
- podSelector:
matchLabels:
app: database
ports:
- protocol: TCP
port: 5432
# 2. μΊμ μλ²λ‘ μμλ°μ΄λ
- to:
- podSelector:
matchLabels:
app: redis
ports:
- protocol: TCP
port: 6379
# 3. DNS νμ© (νμ!)
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
4.5 NetworkPolicy λλ²κΉ ¶
# NetworkPolicy μ‘°ν
kubectl get networkpolicy -n production
kubectl describe networkpolicy api-server-policy -n production
# Pod λ μ΄λΈ νμΈ
kubectl get pods -n production --show-labels
# μ°κ²° ν
μ€νΈ
kubectl run test-pod --rm -it --image=busybox -n production -- /bin/sh
# Pod λ΄λΆμμ
wget -qO- --timeout=2 http://backend-service:8080
nc -zv database-service 5432
# CNI νλ¬κ·ΈμΈ νμΈ
kubectl get pods -n kube-system | grep -E "calico|cilium|weave"
5. Secrets κ΄λ¦¬¶
5.1 Secret μ ν¶
# 1. Opaque (μΌλ° λ°μ΄ν°)
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
namespace: production
type: Opaque
data:
# base64 μΈμ½λ© νμ
username: YWRtaW4= # admin
password: cGFzc3dvcmQxMjM= # password123
stringData:
# stringDataλ μΈμ½λ© λΆνμ
api-key: my-secret-api-key
---
# 2. kubernetes.io/dockerconfigjson (컨ν
μ΄λ λ μ§μ€νΈλ¦¬)
apiVersion: v1
kind: Secret
metadata:
name: docker-registry-secret
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: eyJhdXRocyI6eyJodHRwczovL2luZGV4LmRvY2tlci5pby92MS8iOnsidXNlcm5hbWUiOiJ1c2VyIiwicGFzc3dvcmQiOiJwYXNzIiwiYXV0aCI6ImRYTmxjanB3WVhOeiJ9fX0=
---
# 3. kubernetes.io/tls (TLS μΈμ¦μ)
apiVersion: v1
kind: Secret
metadata:
name: tls-secret
type: kubernetes.io/tls
data:
tls.crt: LS0tLS1CRUdJTi...
tls.key: LS0tLS1CRUdJTi...
---
# 4. kubernetes.io/basic-auth
apiVersion: v1
kind: Secret
metadata:
name: basic-auth
type: kubernetes.io/basic-auth
stringData:
username: admin
password: t0p-Secret
5.2 Secret μμ± λͺ λ Ήμ΄¶
# Opaque Secret (literal)
kubectl create secret generic db-credentials \
--from-literal=username=admin \
--from-literal=password=secret123 \
-n production
# νμΌμμ μμ±
kubectl create secret generic ssh-key \
--from-file=ssh-privatekey=~/.ssh/id_rsa \
--from-file=ssh-publickey=~/.ssh/id_rsa.pub
# Docker λ μ§μ€νΈλ¦¬ μν¬λ¦Ώ
kubectl create secret docker-registry regcred \
--docker-server=ghcr.io \
--docker-username=myuser \
--docker-password=mytoken \
--docker-email=user@example.com
# TLS μν¬λ¦Ώ
kubectl create secret tls app-tls \
--cert=path/to/cert.pem \
--key=path/to/key.pem
5.3 Secret μ¬μ©¶
# νκ²½ λ³μλ‘ μ¬μ©
apiVersion: v1
kind: Pod
metadata:
name: app-with-secrets
spec:
containers:
- name: app
image: myapp:latest
env:
# νΉμ ν€λ§ μ¬μ©
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-credentials
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
# μ 체 Secretμ νκ²½λ³μλ‘
envFrom:
- secretRef:
name: app-secrets
---
# λ³Όλ₯¨μΌλ‘ λ§μ΄νΈ
apiVersion: v1
kind: Pod
metadata:
name: app-with-secret-volume
spec:
containers:
- name: app
image: myapp:latest
volumeMounts:
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
- name: tls-volume
mountPath: /etc/tls
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: app-secrets
# νΉμ ν€λ§ λ§μ΄νΈ
items:
- key: api-key
path: api-key.txt
mode: 0400 # νμΌ κΆν
- name: tls-volume
secret:
secretName: tls-secret
---
# μ΄λ―Έμ§ Pull Secret
apiVersion: v1
kind: Pod
metadata:
name: private-image-pod
spec:
containers:
- name: app
image: ghcr.io/myorg/private-app:latest
imagePullSecrets:
- name: regcred
5.4 Secret 보μ κ°ν¶
# Secret μνΈν μ€μ (kube-apiserver)
# /etc/kubernetes/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: {} # ν΄λ°± (μνΈν μ λ¨)
---
# RBACμΌλ‘ Secret μ κ·Ό μ ν
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: secret-reader
namespace: production
rules:
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["app-secrets"] # νΉμ Secretλ§
verbs: ["get"]
5.5 μΈλΆ Secret κ΄λ¦¬ λꡬ¶
# External Secrets Operator μμ
# AWS Secrets Managerμμ κ°μ Έμ€κΈ°
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: aws-secret
namespace: production
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secretsmanager
kind: SecretStore
target:
name: db-credentials # μμ±λ K8s Secret μ΄λ¦
data:
- secretKey: username
remoteRef:
key: production/db-credentials
property: username
- secretKey: password
remoteRef:
key: production/db-credentials
property: password
---
# Sealed Secrets (GitOpsμ©)
# kubesealλ‘ μνΈν
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: mysecret
namespace: production
spec:
encryptedData:
password: AgBy8hCi...μνΈνλλ°μ΄ν°...
6. Pod 보μ¶
6.1 Pod Security Standards¶
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Pod Security Standards (PSS) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Privileged (κΆν) β
β βββ μ ν μμ β
β βββ μμ€ν
Podμ© β
β β
β Baseline (κΈ°μ€) β
β βββ μλ €μ§ κΆν μμΉ λ°©μ§ β
β βββ hostNetwork, hostPID κΈμ§ β
β βββ λλΆλΆμ μν¬λ‘λμ μ ν© β
β β
β Restricted (μ ν) β
β βββ κ°λ ₯ν 보μ μ μ±
β
β βββ λΉroot μ€ν νμ β
β βββ μ½κΈ° μ μ© λ£¨νΈ νμΌμμ€ν
β
β βββ 보μ λ―Όκ° μν¬λ‘λμ© β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
6.2 Pod Security Admission¶
# λ€μμ€νμ΄μ€μ 보μ λ 벨 μ μ©
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
# enforce: μλ° μ κ±°λΆ
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
# audit: κ°μ¬ λ‘κ·Έμ κΈ°λ‘
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/audit-version: latest
# warn: κ²½κ³ λ©μμ§ νμ
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/warn-version: latest
---
# baseline λ 벨 λ€μμ€νμ΄μ€
apiVersion: v1
kind: Namespace
metadata:
name: staging
labels:
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/warn: restricted
6.3 보μ 컨ν μ€νΈ¶
# secure-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
# Pod λ 벨 보μ 컨ν
μ€νΈ
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: myapp:latest
# 컨ν
μ΄λ λ 벨 보μ 컨ν
μ€νΈ
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
# νμν capabilityλ§ μΆκ°
# add:
# - NET_BIND_SERVICE
# 리μμ€ μ ν
resources:
limits:
cpu: "500m"
memory: "128Mi"
requests:
cpu: "250m"
memory: "64Mi"
# μμ λ³Όλ₯¨ (μ½κΈ° μ μ© λ£¨νΈμμ μ°κΈ° νμ μ)
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /app/cache
volumes:
- name: tmp
emptyDir: {}
- name: cache
emptyDir:
sizeLimit: 100Mi
6.4 κ³ κΈ λ³΄μ μ€μ ¶
# highly-secure-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: secure-app
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: secure-app
template:
metadata:
labels:
app: secure-app
spec:
# ServiceAccount ν ν° λΉλ§μ΄νΈ
automountServiceAccountToken: false
# Pod 보μ 컨ν
μ€νΈ
securityContext:
runAsNonRoot: true
runAsUser: 65534 # nobody
runAsGroup: 65534
fsGroup: 65534
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: myapp:latest
imagePullPolicy: Always
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
# ν¬νΈ
ports:
- containerPort: 8080
protocol: TCP
# 리μμ€ μ ν
resources:
limits:
cpu: "1"
memory: "512Mi"
requests:
cpu: "100m"
memory: "128Mi"
# ν¬μ€ 체ν¬
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
volumeMounts:
- name: tmp
mountPath: /tmp
- name: config
mountPath: /etc/app
readOnly: true
volumes:
- name: tmp
emptyDir:
medium: Memory
sizeLimit: 64Mi
- name: config
configMap:
name: app-config
# νΈμ€νΈ λ€νΈμν¬/PID μ¬μ© κΈμ§
hostNetwork: false
hostPID: false
hostIPC: false
# DNS μ μ±
dnsPolicy: ClusterFirst
6.5 보μ μ€μΊλ¶
# μ΄λ―Έμ§ μ·¨μ½μ μ€μΊλ (Trivy)
trivy image myapp:latest
# ν΄λ¬μ€ν° 보μ μ€μΊ (kubescape)
kubescape scan framework nsa --exclude-namespaces kube-system
# Pod 보μ κ²μ¬ (kube-bench)
kubectl apply -f https://raw.githubusercontent.com/aquasecurity/kube-bench/main/job.yaml
kubectl logs job/kube-bench
# OPA/Gatekeeper μ μ±
νμΈ
kubectl get constrainttemplates
kubectl get constraints
7. μ°μ΅ λ¬Έμ ¶
μ°μ΅ 1: κ°λ°ν RBAC ꡬ챶
# μꡬμ¬ν:
# - development λ€μμ€νμ΄μ€μμ κ°λ°μλ Pod, Deployment, Service κ΄λ¦¬ κ°λ₯
# - production λ€μμ€νμ΄μ€μμλ Pod μ‘°νλ§ κ°λ₯
# - Secret μ κ·Ό λΆκ°
# Role λ° RoleBinding μμ±
μ°μ΅ 2: λ§μ΄ν¬λ‘μλΉμ€ NetworkPolicy¶
# μꡬμ¬ν:
# - frontend -> api-gateway -> backend -> database μμλ‘λ§ ν΅μ
# - monitoring λ€μμ€νμ΄μ€μμ λͺ¨λ Podμ /metrics μ κ·Ό νμ©
# - μΈλΆμμ frontendλ§ μ κ·Ό κ°λ₯
# NetworkPolicy μμ±
μ°μ΅ 3: μμ ν μ ν리μΌμ΄μ λ°°ν¬¶
# μꡬμ¬ν:
# - λΉroot μ¬μ©μλ‘ μ€ν
# - μ½κΈ° μ μ© λ£¨νΈ νμΌμμ€ν
# - λͺ¨λ capability μ κ±°
# - 리μμ€ μ ν μ€μ
# - Secretμ νκ²½λ³μμ λ³Όλ₯¨μΌλ‘ λ§μ΄νΈ
# Deployment μμ±
μ°μ΅ 4: 보μ κ°μ¬¶
# λ€μ νλͺ© μ κ²:
# 1. ν΄λ¬μ€ν°μμ privileged Pod μ°ΎκΈ°
# 2. default ServiceAccount μ¬μ©νλ Pod μ°ΎκΈ°
# 3. Secretμ΄ νκ²½λ³μλ‘ λ
ΈμΆλ Pod μ°ΎκΈ°
# 4. NetworkPolicyκ° μλ λ€μμ€νμ΄μ€ μ°ΎκΈ°
# λͺ
λ Ήμ΄ μμ±
λ€μ λ¨κ³¶
- 08_Kubernetes_μ¬ν - Ingress, StatefulSet, PV/PVC
- 09_Helm_ν¨ν€μ§κ΄λ¦¬ - Helm μ°¨νΈ κ΄λ¦¬
- 10_CI_CD_νμ΄νλΌμΈ - μλν λ°°ν¬
μ°Έκ³ μλ£¶
β μ΄μ : Docker Compose | λ€μ: Kubernetes μ¬ν β | λͺ©μ°¨