실습환경 배포
실습 환경 소개 : k8s(1.33.4), cilium(1.18.1) - 기본 배포 가상 머신 : k8s-ctr, k8s-w1, k8s-w2
mkdir cilium-lab && cd cilium-lab
curl -O https://raw.githubusercontent.com/gasida/vagrant-lab/refs/heads/main/cilium-study/8w/Vagrantfile
vagrant up
vagrant ssh k8s-ctr
# 프로메테우스 접속
http://192.168.10.100:30001
# 그라파나 접속
http://192.168.10.100:30002
# 허블 UI 접속
http://192.168.10.100:30003
Cilium Security
Cilium 제공 보안 : Identity-Based(Layer3), Port Level(Layer4), Application protocol Level(Layer7) - Docs

- 보안 정책은 세션 기반 프로토콜에 대해 상태 저장 정책 적용되어, 응답 패킷은 자동으로 허용됨 - Docs
- 보안 정책은 수신 or 송신 시 적용됨
- 기본 보안 정책! - Docs
- 정책이 로드되지 않은 경우, 정책 적용이 명시적으로 활성화되지 않은 한 모든 통신을 허용하는 것이 기본 동작입니다.
- 첫 번째 정책 규칙이 로드되는 즉시 정책 적용이 자동으로 활성화되며, 모든 통신은 허용 목록에 추가되어야 하며, 그렇지 않으면 관련 패킷이 삭제됩니다.
- 마찬가지로, 엔드포인트에 L4 정책이 적용되지 않으면 모든 포트와의 통신이 허용됩니다.
- 엔드포인트에 하나 이상의 L4 정책을 연결하면 명시적으로 허용하지 않는 한 포트에 대한 모든 연결이 차단됩니다.
envoy Proxy

1. 투명한 암호화 : IPSec or WireGuard 로 Cilium 관리하는 트래픽의 투명한 암호화 지원
- IPSec : Limit(BPF 호스트 라우팅에서는 미동작, IPsec 터널당 단일 CPU 코어로 제한) - Docs
- WireGuard : 터널 모드는 두 번 캡슐화됨 - Docs , Youtube

2. Identity : 모든 엔드포인트에 ID가 할당. ID는 Labels 과 클러스터 내에 유일한 ID로 구성.
- 엔드포인트에는 Security Relevant Labels에 일치하는 ID가 할당.
- 엔드포인트들이 동일한 Security Relevant Labels 사용 시 동일한 ID를 공유.
kubectl get ciliumendpoints.cilium.io -n kube-system
NAME SECURITY IDENTITY ENDPOINT STATE IPV4 IPV6
coredns-674b8bbfcf-7v8gz 14735 ready 172.20.0.138
coredns-674b8bbfcf-sbftb 14735 ready 172.20.0.128
hubble-relay-fdd49b976-fps92 15715 ready 172.20.0.32
hubble-ui-655f947f96-cmncv 12634 ready 172.20.0.8
metrics-server-5dd7b49d79-nx56l 8836 ready 172.20.0.49
kubectl get ciliumidentities.cilium.io
NAME NAMESPACE AGE
12634 kube-system 9m31s
14215 cilium-monitoring 9m31s
14735 kube-system 9m31s
15715 kube-system 9m31s
42930 local-path-storage 9m31s
58553 cilium-monitoring 9m31s
8836 kube-system 9m31s
What is an Identity?
- 엔드포인트의 ID는 엔드포인트 에서 파생된 포드 또는 컨테이너와 연관된 레이블을 기반으로 결정됩니다.
- 파드 또는 컨테이너가 시작되면 Cilium은 컨테이너 런타임에서 수신한 이벤트를 기반으로 네트워크에서 포드 또는 컨테이너를 나타내는 엔드포인트 를 생성합니다 .
- 다음 단계로 Cilium은 생성된 엔드포인트 의 ID를 확인합니다 . 포드 또는 컨테이너의 레이블이 변경될 때마다 ID가 재확인되고 필요에 따라 자동으로 수정됩니다.
kubectl get ciliumidentities.cilium.io 14735 -o yaml | yq
{
"apiVersion": "cilium.io/v2",
"kind": "CiliumIdentity",
"metadata": {
"creationTimestamp": "2025-08-31T00:47:09Z",
"generation": 1,
"labels": {
"io.kubernetes.pod.namespace": "kube-system"
},
"name": "14735",
"resourceVersion": "808",
"uid": "ff72e5ce-02fe-4c3c-892d-cc1fcf9fdbce"
},
"security-labels": {
"k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name": "kube-system",
"k8s:io.cilium.k8s.policy.cluster": "default",
"k8s:io.cilium.k8s.policy.serviceaccount": "coredns",
"k8s:io.kubernetes.pod.namespace": "kube-system",
"k8s:k8s-app": "kube-dns"
}
}
kubectl exec -it -n kube-system ds/cilium -- cilium identity list
...
14735 k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=kube-system
k8s:io.cilium.k8s.policy.cluster=default
k8s:io.cilium.k8s.policy.serviceaccount=coredns
k8s:io.kubernetes.pod.namespace=kube-system
k8s:k8s-app=kube-dns
...
kubectl get pod -n kube-system -l k8s-app=kube-dns --show-labels
NAME READY STATUS RESTARTS AGE LABELS
coredns-674b8bbfcf-7v8gz 1/1 Running 0 14m k8s-app=kube-dns,pod-template-hash=674b8bbfcf
coredns-674b8bbfcf-sbftb 1/1 Running 0 14m k8s-app=kube-dns,pod-template-hash=674b8bbfcf

# 기동 중인 파드에 label 추가 후 cilium id(보안 lable)에 반영 될지? : 반영되는가? 얼마나 시간이 걸리는가? ID가 변경되지는 않는가?
kubectl label pods -n kube-system -l k8s-app=kube-dns study=8w
kubectl exec -it -n kube-system ds/cilium -- cilium identity list
...
# (위 내용 확인 후 아래 진행) coredns deployment 에 spec.template.metadata.labels에 아래 추가 시 반영 확인
kubectl edit deploy -n kube-system coredns
...
template:
metadata:
labels:
app: testing
k8s-app: kube-dns
...
kubectl exec -it -n kube-system ds/cilium -- cilium identity list
...
- Cilium은 pod update 이벤트를 watch하므로, labels 변경 시 endpoint가 waiting-for-identity 상태로 전환되어 새로운 identity를 할당받습니다.
- 이로 인해 security labels와 관련된 네트워크 정책도 자동으로 재적용됩니다.
- pod(simple-pod)를 처음 생성하면 초기 security identity가 할당됩니다.
- 이후 kubectl label pod/simple-pod run=not-simple-pod --overwrite로 labels를 변경하면, kubectl get ciliumendpoints 명령에서 identity가 새 값(예: 52364)으로 업데이트된 것을 확인할 수 있습니다. 이는 policy enforcement에 즉시 반영됩니다.
- 다만, 대규모 클러스터에서 자주 labels를 변경하면 identity 할당이 빈번해져 성능 저하가 발생할 수 있으므로, identity-relevant labels를 제한하는 것이 권장됩니다
3.Special Identities
- Cilium에서 관리하는 모든 엔드포인트에는 ID가 할당됩니다.
- Cilium에서 관리하지 않는 네트워크 엔드포인트와의 통신을 허용하기 위해 이러한 엔드포인트를 나타내는 특수 ID가 존재합니다.
- 특별히 예약된 ID에는 reserved 문자열 접두사가 붙습니다.
kubectl exec -it -n kube-system ds/cilium -- cilium identity list
ID LABELS
1 reserved:host
reserved:kube-apiserver
2 reserved:world
3 reserved:unmanaged
4 reserved:health
5 reserved:init
6 reserved:remote-node
7 reserved:kube-apiserver
reserved:remote-node
8 reserved:ingress
9 reserved:world-ipv4
10 reserved:world-ipv6
8836 k8s:app.kubernetes.io/instance=metrics-server
k8s:app.kubernetes.io/name=metrics-server
k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=kube-system
k8s:io.cilium.k8s.policy.cluster=default
k8s:io.cilium.k8s.policy.serviceaccount=metrics-server
...
| Identity | Numeric ID | Description |
|---|---|---|
reserved:unknown |
0 | 아이덴티티를 도출할 수 없음. |
reserved:host |
1 | 로컬 호스트. 로컬 호스트 IP에서 발생하거나 그 대상으로 지정된 모든 트래픽. |
reserved:world |
2 | 클러스터 외부의 모든 네트워크 엔드포인트. |
reserved:unmanaged |
3 | Cilium이 관리하지 않는 엔드포인트(예: Cilium 설치 이전에 실행된 Kubernetes Pod). |
reserved:health |
4 | Cilium 에이전트가 생성하는 헬스 체크 트래픽. |
reserved:init |
5 | 아이덴티티가 아직 확정되지 않은 엔드포인트에 부여되는 초기 아이덴티티(부트스트랩 단계). 엔드포인트 생성 시 레이블을 알 수 없을 때만 할당됨(예: Docker 플러그인). |
reserved:remote-node |
6 | 원격 클러스터 호스트들의 집합. 로컬 노드를 제외한 다른 클러스터의 호스트 IP로부터/향하는 트래픽. |
reserved:kube-apiserver |
7 | kube-apiserver 백엔드를 제공하는 원격 노드(들). |
reserved:ingress |
8 | Ingress 프록시에서 나오는 연결의 소스 주소로 사용되는 IP에 부여됨. |

- ID는 전체 클러스터에서 유효합니다.
- 즉, 여러 클러스터 노드에서 여러 개의 포드 또는 컨테이너가 시작되더라도 ID 관련 레이블을 공유하는 경우 모든 포드 또는 컨테이너가 단일 ID를 확인하고 공유합니다.
- 이를 위해서는 클러스터 노드 간의 조정이 필요합니다.
- 엔드포인트 ID를 확인하는 작업은 분산 키-값 저장소를 통해 수행됩니다.
- 분산 키-값 저장소는 다음 값이 이전에 확인되지 않은 경우 새로운 고유 식별자를 생성하는 형태의 원자적 연산을 수행할 수 있도록 합니다.
- 이를 통해 각 클러스터 노드는 ID 관련 레이블 하위 집합을 생성한 다음 키-값 저장소를 쿼리하여 ID를 도출할 수 있습니다.
- 레이블 집합이 이전에 쿼리되었는지 여부에 따라 새 ID가 생성되거나 초기 쿼리의 ID가 반환됩니다.\\
NetworkPolicy : 3가지 형식 제공

- Pod의 유입 또는 유출 시 L3 및 L4 정책을 지원하는 표준 NetworkPolicy 리소스입니다.
- 3~7 계층에서 수신 및 송신 모두에 대한 정책 지정을 지원하는 CRD 으로 제공되는 확장된 CiliumNetworkPolicy 형식입니다.
Layer 3 예시
- 엔드포인트 기반: 두 엔드포인트가 Cilium에 의해 관리되고 레이블이 할당되는 경우
- IP 주소가 정책에 인코딩되지 않고 정책이 주소 지정과 완전히 분리된다는 것입니다.
# Simple Ingress 허용
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "l3-rule"
spec:
endpointSelector:
matchLabels:
role: backend
ingress:
- fromEndpoints:
- matchLabels:
role: frontend
- 서비스 기반: 레이블과 CIDR의 중간 형태로, 오케스트레이션 시스템의 서비스 개념을 활용합니다.
- 쿠버네티스의 서비스 엔드포인트 개념이 좋은 예입니다. 이 엔드포인트는 서비스의 모든 백엔드 IP 주소를 포함하도록 자동으로 유지됩니다. 이를 통해 Cilium에서 대상 엔드포인트를 제어하지 않더라도 정책에 IP 주소를 하드코딩하지 않아도 됩니다.
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "service-rule"
spec:
endpointSelector:
matchLabels:
id: app2
egress:
- toServices:
# Services may be referenced by namespace + name
- k8sService:
serviceName: myservice
namespace: default
# Services may be referenced by namespace + label selector
- k8sServiceSelector:
selector:
matchLabels:
env: staging
namespace: another-namespace
- 엔티티 기반 : 엔티티는 IP 주소를 알지 못해도 분류할 수 있는 원격 피어를 설명하는 데 사용됩니다. 여기에는 엔드포인트를 제공하는 로컬 호스트에 대한 연결이나 클러스터 외부에 대한 모든 연결이 포함됩니다.
# 레이블이 있는 모든 엔드포인트가 env=devkube-apiserver에 액세스하도록 허용
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "dev-to-kube-apiserver"
spec:
endpointSelector:
matchLabels:
env: dev
egress:
- toEntities:
- kube-apiserver
- 노드 기반 : 엔티티의 확장입니다
. 선택적으로 노드는 고유한 ID를 가질 수 있으며, 이를 사용하여 특정 노드의 접근만 허용하거나 차단할 수 있습니다.
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "to-prod-from-control-plane-nodes"
spec:
endpointSelector:
matchLabels:
env: prod
ingress:
- fromNodes:
- matchLabels:
node-role.kubernetes.io/control-plane: ""
- IP/CIDR 기반 : 원격 피어가 엔드포인트가 아닌 경우 외부 서비스와의 관계를 설명하는 데 사용됩니다. 이를 위해서는 IP 주소 또는 서브넷을 정책에 직접 지정해야 합니다.
- 이 구성은 안정적인 IP 또는 서브넷 할당이 필요하므로 최후의 수단으로 사용해야 합니다.
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "cidr-rule"
spec:
endpointSelector:
matchLabels:
app: myService
egress:
- toCIDR:
- 20.1.1.1/32
- toCIDRSet:
- cidr: 10.0.0.0/8
except:
- 10.96.0.0/12
- DNS 기반 : DNS 조회를 통해 IP로 변환된 DNS 이름을 사용하여 원격의 비클러스터 피어를 선택합니다. 위 IP/CIDR 기반 규칙의 모든 제한 사항을 공유합니다. DNS 정보는 프록시를 통해 DNS 트래픽을 라우팅하여 수집합니다. DNS TTL은 준수됩니다.
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "to-fqdn"
spec:
endpointSelector:
matchLabels:
app: test-app
egress:
- toEndpoints:
- matchLabels:
"k8s:io.kubernetes.pod.namespace": kube-system
"k8s:k8s-app": kube-dns
toPorts:
- ports:
- port: "53"
protocol: ANY
rules:
dns:
- matchPattern: "*"
- toFQDNs:
- matchName: "my-remote-service.com"
LAB 1 실습: DNS 기반 보안 정책
- CIDR 또는 IP 기반 정책은 외부 서비스와 연결된 IP가 자주 변경될 수 있으므로 관리가 어렵고 번거롭습니다.
- Cilium의 DNS 기반 정책은 DNS-IP 매핑 추적과 같은 복잡한 측면을 관리하는 동시에 액세스 제어를 쉽게 지정할 수 있는 메커니즘을 제공합니다.
- 이 가이드에서는 다음 사항에 대해 알아봅니다.
- DNS 기반 정책을 사용하여 클러스터 외부 서비스에 대한 이탈 액세스 제어
- 패턴(또는 와일드카드)을 사용하여 DNS 도메인 하위 집합을 허용 목록에 추가
- 외부 서비스 접근 제한을 위한 DNS, 포트 및 L7 규칙 결합
# hubble ui 에 pod name 표기를 위해 app labels 추가 >> 빼고 배포해보고 차이점을 확인해보자.
cat << EOF > dns-sw-app.yaml
apiVersion: v1
kind: Pod
metadata:
name: mediabot
labels:
org: empire
class: mediabot
app: mediabot
spec:
containers:
- name: mediabot
image: quay.io/cilium/json-mock:v1.3.8@sha256:5aad04835eda9025fe4561ad31be77fd55309af8158ca8663a72f6abb78c2603
EOF
kubectl apply -f dns-sw-app.yaml
kubectl wait pod/mediabot --for=condition=Ready
# 확인
kubectl exec -it -n kube-system ds/cilium -- cilium identity list
kubectl get pods
NAME READY STATUS RESTARTS AGE
mediabot 1/1 Running 0 41s
# 외부 통신 확인 : hubble ui 에서 확인
kubectl exec mediabot -- curl -I -s https://api.github.com | head -1
kubectl exec mediabot -- curl -I -s --max-time 5 https://support.github.com | head -1

1. DNS Egress 정책 적용 ( 모든 엑세스 허용 )
# DNS Egress 정책 적용 1 : mediabot포드가 api.github.com에만 액세스하도록 허용
#
cat << EOF | kubectl apply -f -
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "fqdn"
spec:
endpointSelector:
matchLabels:
org: empire
class: mediabot
egress:
- toFQDNs:
- matchName: "api.github.com"
- toEndpoints:
- matchLabels:
"k8s:io.kubernetes.pod.namespace": kube-system
"k8s:k8s-app": kube-dns
toPorts:
- ports:
- port: "53"
protocol: ANY
rules:
dns:
- matchPattern: "*"
EOF
# 확인
kubectl get cnp
NAME AGE VALID
fqdn 4s True
kubectl exec -it -n kube-system ds/cilium -- cilium policy selectors
SELECTOR LABELS USERS IDENTITIES
&LabelSelector{MatchLabels:map[string]string{any.class: mediabot,any.org: empire,k8s.io.kubernetes.pod.namespace: default,},MatchExpressions:[]LabelSelectorRequirement{},} default/fqdn 1 5190
cilium config view | grep -i dns
dnsproxy-enable-transparent-mode true
dnsproxy-socket-linger-timeout 10
hubble-metrics dns drop tcp flow port-distribution icmp httpV2:exemplars=true;labelsContext=source_ip,source_namespace,source_workload,destination_ip,destination_namespace,destination_workload,traffic_direction
tofqdns-dns-reject-response-code refused
tofqdns-enable-dns-compression true
tofqdns-endpoint-max-ip-per-hostname 1000
tofqdns-idle-connection-grace-period 0s
tofqdns-max-deferred-connection-deletes 10000
tofqdns-preallocate-identities true
tofqdns-proxy-response-max-delay 100ms
# 외부 통신 확인 : hubble ui 에서 확인
kubectl exec mediabot -- curl -I -s https://api.github.com | head -1
kubectl exec mediabot -- curl -I -s --max-time 5 https://support.github.com | head -1

# cilium-agent 내에 go 로 구현된 lightweight proxy 가 DNS 쿼리/응답 감시와 캐싱 처리 : 기본 30초?
cilium hubble port-forward&
hubble observe --pod mediabot
Aug 31 03:59:53.209: default/mediabot:47883 (ID:5190) <- kube-system/coredns-674b8bbfcf-p6pbn:53 (ID:1363) dns-response proxy FORWARDED (DNS Answer "20.200.245.245" TTL: 30 (Proxy api.github.com. A))
...
Aug 31 03:59:53.212: default/mediabot:38212 (ID:5190) -> api.github.com:443 (ID:16777217) policy-verdict:L3-Only EGRESS ALLOWED (TCP Flags: SYN)
...
# (옵션) coredns 로그로 직접 확인해보기
k9s -> configmap (coredns) : log 추가
## 로깅 활성화
kubectl logs -n kube-system -l k8s-app=kube-dns -f
[INFO] 127.0.0.1:53356 - 20123 "HINFO IN 3756500092085339415.5275850396387885577. udp 57 false 512" NXDOMAIN qr,rd,ra 132 0.012008709s
[INFO] 172.20.1.2:45250 - 42740 "AAAA IN api.github.com.default.svc.cluster.local. udp 58 false 512" NXDOMAIN qr,aa,rd 151 0.001007s
[INFO] 172.20.1.2:45250 - 29173 "A IN api.github.com.default.svc.cluster.local. udp 58 false 512" NXDOMAIN qr,aa,rd 151 0.000149666s
[INFO] 172.20.1.2:52234 - 62454 "A IN api.github.com. udp 32 false 512" NOERROR qr,rd,ra 62 0.01456375s
[INFO] 172.20.1.2:52234 - 25330 "AAAA IN api.github.com. udp 32 false 512" NOERROR qr,rd,ra 129 0.014530834s
## 호출
kubectl exec mediabot -- curl -I -s https://api.github.com | head -1
kubectl exec mediabot -- curl -I -s https://api.github.com | head -1
hubble observe --pod mediabot
## cilium 파드 이름
export CILIUMPOD0=$(kubectl get -l k8s-app=cilium pods -n kube-system --field-selector spec.nodeName=k8s-ctr -o jsonpath='{.items[0].metadata.name}')
export CILIUMPOD1=$(kubectl get -l k8s-app=cilium pods -n kube-system --field-selector spec.nodeName=k8s-w1 -o jsonpath='{.items[0].metadata.name}')
export CILIUMPOD2=$(kubectl get -l k8s-app=cilium pods -n kube-system --field-selector spec.nodeName=k8s-w2 -o jsonpath='{.items[0].metadata.name}')
echo $CILIUMPOD0 $CILIUMPOD1 $CILIUMPOD2
## 단축키(alias) 지정
alias c0="kubectl exec -it $CILIUMPOD0 -n kube-system -c cilium-agent -- cilium"
alias c1="kubectl exec -it $CILIUMPOD1 -n kube-system -c cilium-agent -- cilium"
alias c2="kubectl exec -it $CILIUMPOD2 -n kube-system -c cilium-agent -- cilium"
##
c0 fqdn cache list
c1 fqdn cache list
c2 fqdn cache list
c2 fqdn cache list
Endpoint Source FQDN TTL ExpirationTime IPs
777 connection api.github.com. 0 2025-09-04T05:21:46.643Z 20.200.245.245
c0 fqdn names
c1 fqdn names
c2 fqdn names
{
"DNSPollNames": null,
"FQDNPolicySelectors": [
{
"regexString": "^api[.]github[.]com[.]$",
"selectorString": "MatchName: api.github.com, MatchPattern: "
}
]
}
2. DNS Egress 정책 적용 : 모든 GitHub 하위 도메인(예: 패턴)에 액세스.
# fqdn 캐시 초기화 및 정책 삭제
kubectl delete cnp fqdn
c1 fqdn cache clean -f
c2 fqdn cache clean -f
# dns-pattern.yaml 내용
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "fqdn"
spec:
endpointSelector:
matchLabels:
org: empire
class: mediabot
egress:
- toFQDNs:
- matchName: "*.github.com"
- toEndpoints:
- matchLabels:
"k8s:io.kubernetes.pod.namespace": kube-system
"k8s:k8s-app": kube-dns
toPorts:
- ports:
- port: "53"
protocol: ANY
rules:
dns:
- matchPattern: "*"
kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/1.18.1/examples/kubernetes-dns/dns-pattern.yaml
c1 fqdn names
c2 fqdn names
c1 fqdn cache list
c2 fqdn cache list
{
"DNSPollNames": null,
"FQDNPolicySelectors": [
{
"regexString": "^[-a-zA-Z0-9_]*[.]github[.]com[.]$",
"selectorString": "MatchName: , MatchPattern: *.github.com"
}
]
}
{
"DNSPollNames": null,
"FQDNPolicySelectors": []
}
Endpoint Source FQDN TTL ExpirationTime IPs
Endpoint Source FQDN TTL ExpirationTime IPs
# 확인
kubectl get cnp
NAME AGE VALID
fqdn 4s True
# 외부 통신 확인 : hubble ui 에서 확인 >> github.com 은 공식 문서 설명대로라면 안되야됨..
## It is important to note and test that this doesn’t allow access to github.com because the *.
## in the pattern requires one subdomain to be present in the DNS name
kubectl exec mediabot -- curl -I -s https://support.github.com | head -1
kubectl exec mediabot -- curl -I -s https://gist.github.com | head -1
kubectl exec mediabot -- curl -I -s --max-time 5 https://github.com | head -1
kubectl exec mediabot -- curl -I -s --max-time 5 https://cilium.io| head -1


3. DNS Egress 정책 적용 : DNS, Port 조합 적용
# dns-port.yaml 내용
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "fqdn"
spec:
endpointSelector:
matchLabels:
org: empire
class: mediabot
egress:
- toFQDNs:
- matchPattern: "*.github.com"
toPorts:
- ports:
- port: "443"
protocol: TCP
- toEndpoints:
- matchLabels:
"k8s:io.kubernetes.pod.namespace": kube-system
"k8s:k8s-app": kube-dns
toPorts:
- ports:
- port: "53"
protocol: ANY
rules:
dns:
- matchPattern: "*"
kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/1.18.1/examples/kubernetes-dns/dns-port.yaml
c1 fqdn names
c2 fqdn names
c1 fqdn cache list
c2 fqdn cache list
c1 fqdn cache clean -f
c2 fqdn cache clean -f
# 외부 통신 확인 : hubble ui 에서 확인
kubectl exec mediabot -- curl -I -s https://support.github.com | head -1
kubectl exec mediabot -- curl -I -s --max-time 5 http://support.github.com | head -1
80은 드랍되고
443은 포워딩 됨

[ Lab2] WireGuard 설정 및 실습
- Each node automatically creates its own encryption key-pair and distributes its public key via the io.cilium.network.wg-pub-key annotation in the Kubernetes CiliumNode custom resource object.
- Each node’s public key is then used by other nodes to decrypt and encrypt traffic from and to Cilium-managed endpoints running on that node.
- 한 노드 내에서 파드(엔드포인트)간 통신 시에는 암호화 되지 않습니다.
- The WireGuard tunnel endpoint is exposed on UDP port 51871 on each node.
- Limitations : L7 policy enforcement and visibility , eBPF-based host routing

1. WireGuard 설정 및 실습: 터널 모드는 두번 캡슐화됨
- WireGuard 터널 엔드포인트는 51871 각 노드의 UDP 포트에 노출.
# [커널 구성 옵션] CONFIG_WIREGUARD=m on Linux 5.6 and newe
uname -ar
grep -E 'CONFIG_WIREGUARD=m' /boot/config-$(uname -r)
# 설정 전 기본 정보 확인
ip -c addr
ip -c route
ip rule show
# 설정
helm upgrade cilium cilium/cilium --version 1.18.1 --namespace kube-system --reuse-values \
--set encryption.enabled=true --set encryption.type=wireguard
kubectl -n kube-system rollout restart ds/cilium
# 확인
cilium config view | grep -i wireguard
kubectl exec -it -n kube-system ds/cilium -- cilium encrypt status
Encryption: Wireguard
Interface: cilium_wg0
Public key: o4ISkG+hN88144j0FCwTEo0NtfvLnID3/q48eJ1pfVQ=
Number of peers: 2
kubectl exec -it -n kube-system ds/cilium -- cilium status | grep Encryption
Encryption: Wireguard [NodeEncryption: Disabled, cilium_wg0 (Pubkey: o4ISkG+hN88144j0FCwTEo0NtfvLnID3/q48eJ1pfVQ=, Port: 51871, Peers: 2)]
kubectl exec -it -n kube-system ds/cilium -- cilium debuginfo --output json
kubectl exec -it -n kube-system ds/cilium -- cilium debuginfo --output json | jq .encryption
ip -d -c addr show cilium_wg0
ip rule show
# wg 정보 확인
wg -h
wg show
interface: cilium_wg0
public key: UywNVxgvRBwecznbmGk/vHcD1gTXtmCi9kEQEZd5lxc=
private key: (hidden)
listening port: 51871
fwmark: 0xe00
peer: jm4w0DGrufZ5yINKr327f6aG4AAgqI+yy19cCtpCGnA=
endpoint: 192.168.10.102:51871
allowed ips: 192.168.10.102/32, 172.20.2.0/24, 172.20.2.197/32, 172.20.2.82/32, 172.20.2.219/32, 172.20.2.2/32
latest handshake: 2 minutes, 31 seconds ago
transfer: 556 B received, 468 B sent
peer: o4ISkG+hN88144j0FCwTEo0NtfvLnID3/q48eJ1pfVQ=
endpoint: 192.168.10.101:51871
allowed ips: 172.20.1.60/32, 192.168.10.101/32, 172.20.1.97/32, 172.20.1.0/24, 172.20.1.118/32
wg show all public-key
wg show all private-key
wg show all preshared-keys
wg show all endpoints
wg show all transfer
# 퍼블릭 키 확인
kubectl get cn -o yaml | grep annotations -A1

- Cilium이 WG 인터페이스를 생성했고 피어가 연결됨 (cilium_wg0)
- 포트 51871,
- fwmark: 0xe00
- Number of peers: 2 → 이 노드 기준 동료 노드가 2개(=클러스터 최소 3노드) 라는 뜻입니다.
- latest handshake가 최근이고 transfer 카운터가 증가 → 터널로 실제 트래픽이 흐르고 있어요.

1. Pod CIDR 간 암호화(기본)만 활성
cilium status에 Encryption: Wireguard [NodeEncryption: Disabled, ...] → 현재는 Pod↔Pod(노드 간 Pod CIDR) 트래픽만 암호화, 호스트 네트워크 트래픽은 암호화되지 않음을 의미합니다.
- 노드 레벨(예: kubelet/노드포트/호스트↔호스트)까지 암호화하려면 Helm 값에 --set encryption.nodeEncryption=true(버전에 따라 --set encryption.nodeEncryption=true 또는 동등 옵션)도 추가해야 합니다. 재배포 후 상태가 NodeEncryption: Enabled로 바뀌어야 해요.

kubectl exec -it curl-pod -- curl webpod
kubectl exec -it curl-pod -- curl webpod
# tcpdump
tcpdump -i cilium_wg0 -n
(⎈|HomeLab:N/A) root@k8s-ctr:~# tcpdump -i cilium_wg0 -n
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on cilium_wg0, link-type RAW (Raw IP), snapshot length 262144 bytes
09:45:37.803823 IP 172.20.0.84.50120 > 172.20.2.108.80: Flags [S], seq 665635368, win 64860, options [mss 1380,sackOK,TS val 940871706 ecr 0,nop,wscale 7], length 0
09:45:37.808464 IP 172.20.2.108.80 > 172.20.0.84.50120: Flags [S.], seq 308098457, ack 665635369, win 64296, options [mss 1380,sackOK,TS val 3073665892 ecr 940871706,nop,wscale 7], length 0
09:45:37.808568 IP 172.20.0.84.50120 > 172.20.2.108.80: Flags [.], ack 1, win 507, options [nop,nop,TS val 940871710 ecr 3073665892], length 0
09:45:37.808643 IP 172.20.0.84.50120 > 172.20.2.108.80: Flags [P.], seq 1:71, ack 1, win 507, options [nop,nop,TS val 940871711 ecr 3073665892], length 70: HTTP: GET / HTTP/1.1
09:45:37.810758 IP 172.20.2.108.80 > 172.20.0.84.50120: Flags [.], ack 71, win 502, options [nop,nop,TS val 3073665895 ecr 940871711], length 0
09:45:37.812206 IP 172.20.2.108.80 > 172.20.0.84.50120: Flags [P.], seq 1:322, ack 71, win 502, options [nop,nop,TS val 3073665896 ecr 940871711], length 321: HTTP: HTTP/1.1 200 OK
09:45:37.812245 IP 172.20.0.84.50120 > 172.20.2.108.80: Flags [.], ack 322, win 505, options [nop,nop,TS val 940871714 ecr 3073665896], length 0
09:45:37.812526 IP 172.20.0.84.50120 > 172.20.2.108.80: Flags [F.], seq 71, ack 322, win 505, options [nop,nop,TS val 940871714 ecr 3073665896], length 0
09:45:37.817186 IP 172.20.2.108.80 > 172.20.0.84.50120: Flags [F.], seq 322, ack 72, win 502, options [nop,nop,TS val 3073665900 ecr 940871714], length 0
09:45:37.817257 IP 172.20.0.84.50120 > 172.20.2.108.80: Flags [.], ack 323, win 505, options [nop,nop,TS val 940871719 ecr 3073665900], length 0
tcpdump -eni any udp port 51871
tcpdump -eni any udp port 51871 -w /tmp/wg.pcap
# vagrant scp k8s-ctr:/tmp/wg.pcap . > wireshark 로 확인
# query the flow API and look for flows
hubble observe --pod curl-pod
- 원복
#
helm upgrade cilium cilium/cilium --version 1.18.1 --namespace kube-system --reuse-values \
--set encryption.enabled=false
kubectl -n kube-system rollout restart ds/cilium
# 확인
cilium config view | grep -i wireguard
kubectl exec -it -n kube-system ds/cilium -- cilium encrypt status
kubectl exec -it -n kube-system ds/cilium -- cilium status | grep Encryption
2. Cilium TLS interception 설정( SDS 모드)

- 소개
- 이 문서는 네트워크 보안 팀이 Cilium을 사용하여 TLS 암호화 연결을 투명하게 검사하는 방법을 소개합니다.
- 이 TLS 인식 검사는 클라이언트가 HTTPS를 통해 API 서비스에 액세스하는 경우처럼 클라이언트 간 통신이 TLS로 보호되는 연결에서도 Cilium API 인식 가시성 및 정책을 작동시킬 수 있도록 합니다.
- 이 기능은 기존 하드웨어 방화벽과 유사하지만, Kubernetes 워커 노드에서 전적으로 소프트웨어로 구현되며 정책 기반으로 작동하므로 선택된 네트워크 연결만 검사할 수 있습니다.
- 네트워크 보안 모니터링을 위한 "친근한 차단"의 경우, Cilium은 TLS 검사 기능을 갖춘 기존 방화벽과 유사한 모델을 사용합니다.
- 네트워크 보안 팀은 외부 대상에 대한 대체 인증서를 생성하는 데 사용할 수 있는 자체 "내부 인증 기관"을 생성합니다.
- 이 모델에서는 각 클라이언트 워크로드가 이 새 인증서를 신뢰해야 하며, 그렇지 않으면 클라이언트의 TLS 라이브러리가 연결을 유효하지 않은 것으로 간주하여 거부합니다.
- 이 모델에서 네트워크 방화벽은 내부 CA에서 서명한 인증서를 사용하여 대상 서비스처럼 작동하고 TLS 연결을 종료합니다.
- 이를 통해 방화벽은 애플리케이션 계층 데이터를 검사하고 수정한 후 실제 대상 서비스에 대한 다른 TLS 연결을 시작할 수 있습니다.
- TLS의 CA 모델은 암호화 키와 인증서를 기반으로 합니다. 위 모델을 구현하려면 네 가지 주요 단계가 필요
- CA 개인 키와 CA 인증서를 생성하여 내부 인증 기관을 만듭니다.
- TLS 검사가 필요한 모든 대상(예: 아래 예의 httpbin.org)에 대해 대상 DNS 이름과 일치하는 일반 이름을 사용하여 개인 키와 인증서 서명 요청을 생성합니다.
- CA 개인 키를 사용하여 서명된 인증서를 만듭니다.
- TLS 검사를 실시하는 모든 클라이언트에 CA 인증서가 설치되어 해당 CA가 서명한 모든 인증서를 신뢰할 수 있는지 확인하세요.
- Cilium은 클라이언트와의 초기 TLS 연결을 종료하고 대상에 대한 새로운 TLS 연결을 생성하므로, 대상 서비스에 대한 새로운 TLS 연결을 검증할 때 Cilium이 신뢰해야 하는 CA 집합에 Cilium에 대한 정보를 알려야 합니다.

- TLS 검사 작동 방식
- 모든 TLS 검사는 수락될 인증서를 사용하여 원래 연결을 종료한 다음, 필요한 경우 클라이언트 인증서를 사용하여 새로운 TLS 연결을 시작하는 데 의존합니다.
- 이러한 이유로 네트워크 정책에서는 terminatingTLS및 선택적으로 originatingTLS스탠자를 구성해야 합니다.
- 네트워크 정책에 이러한 세부 정보가 포함되어 있으면 Cilium은 TLS 연결을 Envoy로 리디렉션하고 TLS 핸드셰이크를 완료하고 구성된 네트워크 정책을 전달하는 연결을 허용합니다.
- 이를 구성하는 데 가장 중요한 부분 중 하나는 인증서를 Envoy에 전달하는 방법입니다.
- 현재 버전에서 Cilium에는 NPDS(원래 버전)와 SDS(새롭고 향상된 버전)의 두 가지 옵션이 있습니다.
- 네트워크 정책 검색 서비스(NPDS)
- 이 버전에서는 인증서와 키가 Cilium 소유의 네트워크 정책 검색 서비스의 전용 필드에 Base64 인코딩된 텍스트로 인라인으로 전송됩니다.
- 이 방법은 간단하게 구축할 수 있다는 장점이 있지만 큰 단점도 있습니다.
- TLS 가로채기를 수행하는 각 네트워크 정책 규칙은 Envoy의 NPDS 구성에 각 비밀의 사본을 인라인으로 보관합니다. 따라서 (대규모 설치 환경에서 흔히 발생하는 것처럼) 동일한 비밀을 여러 번 재사용하는 경우(예: 여러 SAN에 대해 만료되는 인증서를 하나 생성했지만 해당 인증서를 사용하는 규칙이 여러 개 있거나 구성에 유효한 루트 인증서 번들을 포함하는 경우 originatingTLS) 인증서의 여러 사본이 Envoy의 메모리에 저장됩니다. 이러한 메모리 사용량은 대규모 설치 환경에서는 상당히 증가할 수 있습니다.
- 비밀 발견 서비스(SDS)
- 위의 두 가지 이유 때문에 Envoy는 Cilium 1.17부터 네트워크 정책 비밀에 대한 SDS를 지원합니다.
- 이 구성에서 Cilium은 구성된 시크릿 네임스페이스에서 관련 시크릿을 읽고, 핵심 Envoy SDS API를 사용하여 Envoy에 노출합니다. 이러한 시크릿은 Envoy로 전송된 NPDS 구성에서 참조되며, Base64로 인코딩된 텍스트로 직접 포함되는 대신 이름을 기준으로 네트워크 정책 필터를 구성합니다.
- 즉, Envoy는 Ingress 또는 Gateway API 구성에 대한 비밀을 찾는 것과 같은 방식으로 NPDS에 대한 SDS 비밀을 찾습니다.
- 이 방법을 사용하면 Envoy가 비밀의 저장을 중복 제거할 수 있습니다. 비밀은 본질적으로 값으로 전달되는 것이 아니라 참조로 전달되기 때문입니다.
- 이러한 NPDS 방식에 비해 우수한 점 때문에 Cilium 1.17부터는 새로운 Cilium 설치에 SDS가 기본값으로 적용됩니다.
#
kubectl get all,secret,cm -n cilium-secrets
NAME DATA AGE
configmap/kube-root-ca.crt 1 7h31m
#
cat << EOF > tls-config.yaml
tls:
readSecretsOnlyFromSecretsNamespace: true
secretsNamespace:
name: cilium-secrets # This setting is optional, as it is the default
secretSync:
enabled: true
EOF
helm upgrade cilium cilium/cilium --version 1.18.1 --namespace kube-system --reuse-values \
-f tls-config.yaml
kubectl -n kube-system rollout restart deploy/cilium-operator
kubectl -n kube-system rollout restart ds/cilium
# 확인
cilium config view | grep -i secret
enable-ingress-secrets-sync true
enable-policy-secrets-sync true
ingress-secrets-namespace cilium-secrets
policy-secrets-namespace cilium-secrets
policy-secrets-only-from-secrets-namespace true
- 운영 기본값이 바뀜 (1.17+)
새 클러스터의 권장/기본은 SDS 방식입니다. 시크릿은 원래 네임스페이스에 두고, Cilium Operator가 이를 cilium-secrets(기본)로 복사→Envoy에 SDS로 공급→정책(NPDS)에서는 이름으로 참조합니다. 메모리 중복이 줄고(시크릿을 값이 아닌 참조로 전달), 보안·운영성이 좋아집니다. docs.cilium.io - 레거시/호환 모드 두 가지
- (비권장) 에이전트가 클러스터 전역 시크릿 읽기 권한을 가져 원위치에서 직접 읽고 NPDS 인라인으로 전송. 보안 범위가 크게 넓어집니다. docs.cilium.io
- (업그레이드 클러스터 기본) cilium-secrets에 직접 시크릿을 넣고 사용(SDS 미사용). 업그레이드 호환을 위한 기본입니다. docs.cilium.io
- Helm 키의 의미(요점)
- tls.secretsNamespace.name 기본값 cilium-secrets : TLS 인터셉션 시크릿을 둘 전용 네임스페이스. Ingress/Gateway/BGP의 유사 설정과 기본값을 공유하지만 다르게도 설정 가능.
- tls.readSecretsOnlyFromSecretsNamespace 기본 true(신규 설치 기준): 에이전트는 cilium-secrets에서만 읽음. false로 두면 에이전트가 클러스터 전 시크릿 GET/LIST/WATCH 권한이 필요해져 비권장. (과거 tls.secretsBackend의 대체: true=local, false=k8s).
- tls.secretSync.enabled 신규 클러스터 기본 true: 시크릿 동기화+SDS 활성화. 이 값을 false로 두면 SDS는 비활성화(인라인/직접 읽기 경로).
[Lab3] Cilium TLS Interception Demo 실습 - Docs
- TLS 가로채기를 시연하기 위해 DNS 인식 정책 예제에 사용한 것과 동일한 애플리케이션을 사용할 것입니다. 이 애플리케이션은 HTTPS를 사용하여 Star Wars API 서비스에 액세스합니다. 이는 일반적으로 Cilium과 같은 네트워크 계층 메커니즘이 통신의 HTTP 계층 세부 정보를 볼 수 없음을 의미합니다. 모든 애플리케이션 데이터는 네트워크로 전송되기 전에 TLS를 사용하여 암호화되기 때문입니다.
- 이 가이드에서는 다음 사항에 대해 알아봅니다.
- TLS 가로채기를 활성화하기 위해 내부 인증 기관(CA)과 해당 CA가 서명한 관련 인증서를 만듭니다.
- DNS 기반 정책 규칙을 사용하여 가로챌 트래픽을 선택하려면 Cilium 네트워크 정책을 사용합니다.
- cilium monitor를 사용하여 HTTP 요청의 세부 사항을 검사합니다
- (Hubble을 통해 이 가시성 데이터에 액세스하고 Cilium 네트워크 정책을 적용하여 HTTP 요청을 필터링/수정하는 것도 가능하지만 이 간단한 시작 가이드의 범위를 벗어납니다)
#
cat << EOF > dns-sw-app.yaml
apiVersion: v1
kind: Pod
metadata:
name: mediabot
labels:
org: empire
class: mediabot
app: mediabot
spec:
containers:
- name: mediabot
image: quay.io/cilium/json-mock:v1.3.8@sha256:5aad04835eda9025fe4561ad31be77fd55309af8158ca8663a72f6abb78c2603
EOF
kubectl apply -f dns-sw-app.yaml
kubectl wait pod/mediabot --for=condition=Ready
# 확인
kubectl get pods
kubectl exec mediabot -- curl -I -s https://api.github.com | head -1
kubectl exec mediabot -- curl -I -s --max-time 5 https://support.github.com | head -1

- 이제 TLS를 이해하고 Cilium을 구성하여 TLS 가로채기를 사용했으므로 유틸리티를 사용하여 적절한 키와 인증서를 생성하는 구체적인 단계를 살펴보겠습니다.
- 다음 이미지는 생성되거나 복사되는 암호화 데이터가 포함된 다양한 파일과 시스템의 어떤 구성 요소가 해당 파일에 액세스해야 하는지 설명합니다.
- 로컬 시스템에 openssl이 이미 설치되어 있다면 사용할 수 있지만, 그렇지 않은 경우 간단한 단축키를 사용하여 cilium 포드 내에서 실행한 후 결과 명령을 실행할 수 있습니다.
- Kubernetes 시크릿을 생성하거나 포드에 복사할 때 cilium 포드에서 결과 파일을 복사하는 데 사용할 수 있습니다 .
내부 기관 CA 만들기
# 'myCA.key'라는 이름의 CA 개인 키를 생성합니다.
openssl genrsa -des3 -out myCA.key 2048
Enter PEM pass phrase: qwe123 # 아무 비밀번호나 입력하세요. 이후 단계에서 사용할 수 있도록 기억.
Verifying - Enter PEM pass phrase: qwe123
ls *.key
myCA.key
# 개인 키에서 CA 인증서를 생성
openssl req -x509 -new -nodes -key myCA.key -sha256 -days 1825 -out myCA.crt
Enter pass phrase for myCA.key: qwe123
Country Name (2 letter code) [AU]:KR
State or Province Name (full name) [Some-State]:Seoul
Locality Name (eg, city) []: Seoul
Organization Name (eg, company) [Internet Widgits Pty Ltd]: cloudneta
Organizational Unit Name (eg, section) []:study
Common Name (e.g. server FQDN or YOUR name) []:cloudneta.net
Email Address []:
ls *.crt
myCA.crt
openssl x509 -in myCA.crt -noout -text
Issuer: C = KR, ST = Seoul, L = Seoul, O = cloudneta, OU = study, CN = cloudneta.net
Validity
Not Before: Aug 31 08:31:07 2025 GMT
Not After : Aug 30 08:31:07 2030 GMT
Subject: C = KR, ST = Seoul, L = Seoul, O = cloudneta, OU = study, CN = cloudneta.net
...
X509v3 Basic Constraints: critical
CA:TRUE
지정된 DNS 이름에 대한 개인 키 및 인증서 서명 요청 생성
# 검사를 위해 가로채려는 대상 서비스의 DNS 이름과 일치하는 일반 이름을 사용하여 내부 개인 키와 인증서 서명을 생성합니다
## 이 예에서는 httpbin.org
# 먼저 개인 키를 만듭니다.
openssl genrsa -out internal-httpbin.key 2048
ls internal-httpbin.key
# 다음으로, 인증서 서명 요청을 생성하고, 메시지가 표시되면 일반 이름 필드에 대상 서비스의 DNS 이름을 지정합니다.
# 다른 모든 메시지에는 원하는 값을 입력할 수 있습니다.
# 특정 값이어야 하는 유일한 필드는 클라이언트에 제공될 정확한 DNS 대상을 보장하는 것입니다. Common Name: httpbin.org
# 이 예제 워크플로는 정책 YAML(아래)의 toFQDNs 규칙도 인증서의 DNS 이름과 일치하도록 업데이트되는 한 모든 DNS 이름에 적용됩니다.
openssl req -new -key internal-httpbin.key -out internal-httpbin.csr
Common Name (e.g. server FQDN or YOUR name) []:httpbin.org
ls internal-httpbin.csr
CA를 사용하여 DNS 이름에 대한 서명된 인증서 생성
# 내부 CA 개인 키를 사용하여 httpbin.org에 대한 서명된 인증서를 생성합니다 internal-httpbin.crt
openssl x509 -req -days 360 -in internal-httpbin.csr -CA myCA.crt -CAkey myCA.key -CAcreateserial -out internal-httpbin.crt -sha256
Certificate request self-signature ok
subject=C = KR, ST = Seoul, L = Seoul, O = cloudneta, OU = study, CN = httpbin.org
Enter pass phrase for myCA.key: qwe123
ls internal-httpbin.crt
openssl x509 -in internal-httpbin.crt -noout -text
...
Issuer: C = KR, ST = Seoul, L = Seoul, O = cloudneta, OU = study, CN = cloudneta.net
Validity
Not Before: Aug 31 08:36:33 2025 GMT
Not After : Aug 26 08:36:33 2026 GMT
Subject: C = KR, ST = Seoul, L = Seoul, O = cloudneta, OU = study, CN = httpbin.org
# 다음으로 대상 서비스에 대한 개인 키와 서명된 인증서를 모두 포함하는 Kubernetes 비밀을 생성합니다.
kubectl create secret tls httpbin-tls-data -n kube-system --cert=internal-httpbin.crt --key=internal-httpbin.key
kubectl get secret -n kube-system httpbin-tls-data
클라이언트 포드 내에서 신뢰할 수 있는 CA로 내부 CA 추가
- CA 인증서가 클라이언트 포드에 저장된 후에도 애플리케이션에서 사용하는 TLS 라이브러리가 CA 파일을 인식하는지 확인해야 합니다. 대부분의 Linux 애플리케이션은 Linux 배포판과 함께 제공되는 신뢰할 수 있는 CA 인증서 세트를 자동으로 사용합니다. 이 가이드에서는 Ubuntu 컨테이너를 클라이언트로 사용하므로 Ubuntu별 지침에 따라 업데이트합니다. 다른 Linux 배포판은 다른 메커니즘을 사용합니다. 또한, 개별 애플리케이션은 OS 인증서 저장소를 사용하는 대신 자체 인증서 저장소를 활용할 수 있습니다. Java 애플리케이션과 aws-cli가 대표적인 예입니다. 자세한 내용은 애플리케이션 또는 애플리케이션 런타임 설명서를 참조하십시오.
#
kubectl exec -it mediabot -- ls -l /usr/local/share/ca-certificates/
# Ubuntu의 경우 먼저 추가 CA 인증서를 클라이언트 Pod 파일 시스템에 복사합니다.
kubectl cp myCA.crt default/mediabot:/usr/local/share/ca-certificates/myCA.crt
kubectl exec -it mediabot -- ls -l /usr/local/share/ca-certificates/
# /etc/ssl/certs/ca-certificates.crt에 있는 신뢰할 수 있는 인증 기관의 글로벌 세트에 이 인증서를 추가하는 Ubuntu 전용 유틸리티 실행
kubectl exec -it mediabot -- ls -l /etc/ssl/certs/ca-certificates.crt # 사이즈, 생성/수정 날짜 확인
kubectl exec mediabot -- update-ca-certificates
kubectl exec -it mediabot -- ls -l /etc/ssl/certs/ca-certificates.crt # 사이즈, 생성/수정 날짜 확인
Cilium에 신뢰할 수 있는 CA 목록 제공
- 다음으로, Cilium이 보조 TLS 연결을 시작할 때 신뢰해야 하는 CA 세트를 제공합니다. 이 목록은 조직에서 신뢰하는 표준 글로벌 CA 세트와 일치해야 합니다. 논리적인 옵션 중 하나는 운영 체제에서 신뢰하는 표준 CA 세트입니다. 이는 TLS 검사 도입 이전에 사용되던 CA 세트이기 때문입니다.
- 간단하게 설명하기 위해 이 예에서 우리는 mediabot 포드의 Ubuntu 파일 시스템에서 이 목록을 복사할 것입니다. 하지만 이 신뢰할 수 있는 CA 목록은 특정 TLS 클라이언트나 서버에만 국한되지 않는다는 점을 이해하는 것이 중요합니다. 따라서 TLS 검사에 참여하는 TLS 클라이언트나 서버의 수에 관계없이 이 단계는 한 번만 수행하면 됩니다.
#
kubectl cp default/mediabot:/etc/ssl/certs/ca-certificates.crt ca-certificates.crt
# 이 인증서 번들을 사용하여 Kubernetes 비밀을 생성하여 Cilium이 인증서 번들을 읽고 이를 사용하여 나가는 TLS 연결을 검증할 수 있도록 합니다.
kubectl create secret generic tls-orig-data -n kube-system --from-file=ca.crt=./ca-certificates.crt
kubectl get secret -n kube-system tls-orig-data
Apply DNS and TLS-aware Egress Policy
- 지금까지 TLS 검사를 활성화하기 위한 키와 인증서를 생성했지만, Cilium에 어떤 트래픽을 가로채서 검사할지 알려주지 않았습니다. 이 작업은 다른 Cilium 네트워크 정책에 사용되는 것과 동일한 Cilium 네트워크 정책 구조를 사용하여 수행됩니다.
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "l7-visibility-tls"
spec:
description: L7 policy with TLS
endpointSelector:
matchLabels:
org: empire
class: mediabot
egress:
- toFQDNs:
- matchName: "httpbin.org"
toPorts:
- ports:
- port: "443"
protocol: "TCP"
terminatingTLS:
secret:
namespace: "kube-system"
name: "httpbin-tls-data"
originatingTLS:
secret:
namespace: "kube-system"
name: "tls-orig-data"
rules:
http:
- {}
- toPorts:
- ports:
- port: "53"
protocol: ANY
rules:
dns:
- matchPattern: "*"
- 즉 , 이 정책은 출구 접근 권한이 있는 endpointSelector라벨이 있는 포드에만 적용됩니다 .class: mediabot, org:empire
- 첫 번째 출구 섹션에서는 사양을 사용하여 TCP 포트 443 출구를 허용합니다 .toFQDNs: matchNamehttpbin.org
- httptoFQDNs 규칙 아래의 섹션은 이러한 연결이 모든 요청을 허용하는 정책에 따라 HTTP로 구문 분석되어야 함을 나타 냅니다 {}.
- 및 섹션은 TLS 가로채기를 사용하여 mediabot에서의 초기 TLS 연결을 종료하고 .에 대한 새로운 아웃바운드 TLS 연결을 시작해야 함을 나타 terminatingTLS냅니다 .originatingTLShttpbin.org
- 두 번째 출구 섹션은 mediabot포드가 kube-dns서비스에 접근할 수 있도록 합니다. Cilium이 지정된 패턴과 일치하는 DNS 조회를 검사하고 허용하도록 지시합니다. 이 경우 모든 DNS 쿼리를 검사하고 허용합니다.rules: dns
# 모니터링 : hubble cli 나 ui 에서 https 이니 L7 정보 확인 불가능
hubble observe --pod mediabot -f
#
kubectl get pods
kubectl exec -it mediabot -- curl -sL 'https://httpbin.org/anything'
kubectl exec -it mediabot -- curl -sL 'https://httpbin.org/headers' -v # 서버 인증서 확인
* Server certificate:
* subject: CN=httpbin.org
* start date: Jul 20 00:00:00 2025 GMT
* expire date: Aug 17 23:59:59 2026 GMT
* subjectAltName: host "httpbin.org" matched cert's "httpbin.org"
* issuer: C=US; O=Amazon; CN=Amazon RSA 2048 M03
* SSL certificate verify ok.
# 정책 적용
kubectl create -f https://raw.githubusercontent.com/cilium/cilium/1.18.1/examples/kubernetes-tls-inspection/l7-visibility-tls.yaml
kubectl get cnp
- Demonstrating TLS Inspection
- 우리가 푸시한 정책은 에서 mediabot로의 모든 HTTPS 요청을 허용 httpbin.org하지만 모든 데이터는 HTTP 계층에서 구문 분석한다는 점을 기억하세요. 즉, cilium monitor는 모든 HTTP 요청과 응답을 보고합니다.
- 이를 확인하려면 새 창을 열고 다음 명령을 실행하여 mediabot포드와 동일한 Kubernetes 워커 노드에서 실행 중인 cilium 포드의 이름(예: cilium-97s78)을 식별합니다.
# 모니터링 : hubble cli 나 ui 에서 https 이니 L7 정보 확인 불가능
hubble observe --pod mediabot -f
#
kubectl exec -it mediabot -- curl -sL 'https://httpbin.org/anything'
kubectl exec -it mediabot -- curl -sL 'https://httpbin.org/headers' -v # 서버 인증서 확인
* Server certificate:
* subject: C=KR; ST=Seoul; L=Seoul; O=cloudneta; OU=study; CN=httpbin.org
* start date: Aug 31 08:36:33 2025 GMT
* expire date: Aug 26 08:36:33 2026 GMT
* common name: httpbin.org (matched)
* issuer: C=KR; ST=Seoul; L=Seoul; O=cloudneta; OU=study; CN=cloudneta.net
* SSL certificate verify ok.

실습리소스 삭제
kubectl delete -f https://raw.githubusercontent.com/cilium/cilium/1.18.1/examples/kubernetes-dns/dns-sw-app.yaml
kubectl delete cnp l7-visibility-tls
kubectl delete secret -n kube-system tls-orig-data
kubectl delete secret -n kube-system httpbin-tls-data'컨테이너 > 쿠버네티스 네트워크' 카테고리의 다른 글
| [Cilium] (16) 실리움 네트워킹 _ k8s performance test (0) | 2025.08.29 |
|---|---|
| [Cilium] (15) 실리움 네트워킹 _ ServiceMesh (2) | 2025.08.19 |
| [Cilium] (14) 실리움 네트워킹 _ Service LB IPAM (BGP) (1) | 2025.08.12 |
| [Cilium] (13) 실리움 네트워킹 _ BGP Control Plane (8) | 2025.08.12 |
| [Cilium] (12) 실리움 네트워킹 _ Service LB-IPAM (4) | 2025.08.06 |