현재 많은 기업이 Kubernetes를 사용하고 있지만, 보안 체계까지 제대로 갖추고 있는 경우는 드물다. DevOps나 플랫폼 엔지니어 입장에서는 CI/CD, 오토스케일링, 운영 효율화 같은 과제를 해결하기에도 벅차기 때문에, 보안은 늘 뒷전으로 밀리는 영역이 되기 쉽다.
Kubernetes는 유연하고 확장성이 뛰어난 만큼, 그 안에서 발생할 수 있는 보안 위협도 다양하고 복잡하다.
특히, 컨테이너 내부에서 어떤 명령어가 실행되고 어떤 파일이 접근되었는지를 실시간으로 추적하기 어렵다는 점은, 공격자에게는 큰 기회가 된다.
Falco는 이러한 보안 침해 징후를 미리 감지하고 대응할 수 있도록 도와준다.
Falco란?
Falco는 CNCF(Cloud Native Computing Foundation)에서 관리하는 Graduated(최상위 등급)의 오픈소스 런타임 보안 도구이다. Linux 시스템의 시스템 호출(syscall)을 eBPF나 커널 모듈을 통해 실시간으로 감시해, 예상치 못한 프로세스 실행, 파일 접근, 네트워크 연결 등을 감지하여 알림을 준다. 또한 Kubernetes 환경은 물론, 일반적인 Linux 서버나 VM에서도 사용 가능하여 단순한 클라우드 보안 도구가 아닌, 범용적인 런타임 보안 탐지 도구로 활용할 수 있다.
예를 들면, Kubernetes 환경에서 누군가가 컨테이너 안에서 bash를 실행하거나, 민감 정보가 있는 /etc/shadow 파일에 접근하거나, 역쉘을 만들어 네트워크로 데이터를 빼내려는 시도를 했을 때 이를 실시간으로 탐지해 준다.
Falco Rule 구조
Falco는 내부적으로 정의한 Rule(규칙)에 따라 동작하는데, 이 Rule이 어떤 행동이 "정상인지" 또는 "의심스러운지"를 판단하는 기준이 된다.
Falco Rule은 다음과 같이 필수 필드들로 구성된다.
- rule: 해당 규칙의 이름으로 대시보드나 로그에 표시될 때 이 이름이 사용된다
- desc: 해당 룰이 무엇을 탐지하는지에 대한 설명
- condition: 어떤 상황에서 경고를 발생시킬지 정의
- output: 탐지 시 표시할 메시지 포맷
- priority: 경고 수준 (CRITICAL, WARNING, NOTICE 등)
- tags: 필터링 및 분류용 태그
- enabled(선택): 해당 룰의 활성화 여부를 지정. true 또는 false로 설정하며, 생략 시 기본값은 true이다
그 외 필드는 여기를 참고한다.
Falco 이벤트 탐지 동작
사용자가 cat 명령어로 컨테이너 내부의 /etc/shadow 파일을 읽으면 어떻게 Falco가 이를 탐지하는지 알아보자.
아래는 Falco가 이 과정을 어떻게 감지하고 분석하는지를 단계별로 설명한 것이다.
1. 사용자가 cat /etc/shadow 명령을 컨테이너 내부에서 실행한다.
2. Linux 커널에서 openat("/etc/shadow") syscall이 발생한다.
3. Falco Driver(eBPF Probe 또는 kernel module)가 커널에서 해당 syscall 이벤트를 캡처한다.
4. Falco 엔진이 다음과 같은 과정을 거친다.
- libscap 라이브러리를 통해 syscall raw 이벤트를 수신한다.
- libsinsp 라이브러리를 통해 받은 이벤트를 파싱 및 해석한다.
5. 이벤트가 Rule 조건과 일치하면, 해당 Rule에 정의된 Alert(경고) 메시지를 생성한다.
6. 생성된 경고 이벤트는 외부 시스템으로 전달한다.
이번 글에서는 Kubernetes 클러스터에 Falco를 설치해 보고, 실제 보안 위협을 일으켜 Falco가 어떤 Rule에 따라 어떤 행동을 탐지하고, 어떤 메시지를 남기는지 실습을 통해 확인해 보겠다.
구성 환경
- Amazon EKS: 1.30
- Helm CLI: 3.17.2
설치 버전
- Falco
- APP : 0.40.0
- CHART: 4.21.3
전제 조건
- Amazon EKS 클러스터
- Kubectl, Helm CLI 도구
1. Falco 설치
Falco는 Helm Chart를 통해 간단하게 설치할 수 있다.
먼저, Helm Chart 저장소를 추가 후 설치한다.
$ helm repo add falcosecurity https://falcosecurity.github.io/charts
$ helm repo update
$ helm install falco falcosecurity/falco --namespace falco --create-namespace
Falco 설치가 완료되면, 아래 명령어로 falco 네임스페이스 내에 실행 중인 Pod를 확인할 수 있다.
Falco는 기본적으로 DaemonSet 형태로 배포되므로, 각 노드마다 하나씩 Falco Pod가 배포되어 있어야 하며, 각 Pod가 노드의 시스템 호출을 감시한다.
$ kubectl get po -n falco
NAME READY STATUS RESTARTS AGE
falco-cj9dr 2/2 Running 0 72m
falco-cvv2z 2/2 Running 0 73m
falco-czjxt 2/2 Running 0 73m
2. Falco 대시보드 활성화 및 접근 (Falcosidekick)
Falco는 자체적으로 Web UI를 포함하고 있진 않지만, Falcosidekick를 활성화하여 Web UI를 볼 수 있다.
Falcosidekick은 Falco가 감지한 이벤트를 Webhook, Slack, Elasticsearch, Loki, Web UI 등 외부 시스템으로 전달해 주는 Event Forwarder이다.
Falco Helm 설치 시 values.yaml 또는 --set 옵션을 통해 Falcosidekick과 Web UI를 함께 활성화한다. 기본 로그인 계정은 "admin/admin"이다.
- values.yaml
# values.yaml
tty: true
falcosidekick:
enabled: true
webui:
enabled: true
user: "admin:admin"
위처럼 values.yaml 파일을 작성했으면 Helm 명령어로 업데이트한다.
% helm upgrade --install falco falcosecurity/falco \
--namespace falco \
-f values.yaml
만약 helm --set 옵션을 사용해서 업데이트한다면 아래와 같이 입력한다.
- --set
helm upgrade --install falco falcosecurity/falco \
--namespace falco \
--set falcosidekick.enabled=true \
--set falcosidekick.webui.enabled=true \
--set falcosidekick.webui.user="admin:admin"
설치가 완료되면, falco 네임스페이스 내에 실행 중인 Pod를 확인한다.
$ kubectl get po -n falco
# ... 중략
falco-falcosidekick-78578c494-xxxxx 1/1 Running
falco-falcosidekick-78578c494-xxxxx 1/1 Running
falco-falcosidekick-ui-846cd7fcf5-xxxxx 1/1 Running
falco-falcosidekick-ui-846cd7fcf5-xxxxx 1/1 Running
falco-falcosidekick-ui-redis-0 1/1 Running
- falcosidekick : Falco가 탐지한 이벤트를 외부 시스템으로 전달
- falcosidekick-ui : Falco 이벤트를 확인할 수 있는 Web UI
- falcosidekick-ui-redis : Falco 이벤트 캐시 역할
UI에 접근하기 위해 로컬 port-forward를 사용한다.
$ kubectl port-forward svc/falcosidekick-ui -n falco 2802:2802
브라우저에서 다음 주소로 접속한다. 접속 정보는 Helm Chart에서 설정한 정보인데 아무것도 설정하지 않았으면 기본 "admin/admin" 이다.
- http://{IP Address}:2802
접속이 되면 아래와 같이 대시보드를 확인할 수 있다.
3. Default Rules 실습 및 분석
Falco가 정상적으로 설치되었다면 이제 실제 Rule이 어떻게 동작하는지 테스트해 볼 수 있다.
Kubernetes 환경에 Falco를 설치하면 컨테이너 내부에서 이상 행위가 감지되면 경고 이벤트를 발생시킬 수 있도록 기본 Rule이 설정되어 있다. 현재 약 25개의 Rule이 기본으로 활성화되어 있는데, 이 중 몇 가지 대표적인 Rule을 실습을 통해 확인해 보자.
3-1. 컨테이너 내부에서 쉘 실행 탐지 (Terminal shell in container)
해당 rule은 kubectl exec -it 명령어처럼 터미널(TTY)이 연결된 쉘이 실행되는 상황을 탐지한다.
간단한 테스트를 위해 Nginx Pod를 배포하고 해당 컨테이너에 bash로 진입해 보겠다.
$ cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
EOF
$ kubectl exec -it deployments/nginx-deployment -- /bin/bash
Falco 대시보드 Rule에서 한 가지 이상 행위가 탐지된 걸 확인할 수 있다.
EVENTS 탭을 눌러 확인해 보면 다음과 같이 해당 이벤트에 대한 자세한 정보를 확인할 수 있다.
이러한 탐지가 어떻게 가능한지 확인하기 위해 Terminal shell in container의 rule 설정을 직접 확인해 보자.
방금 탐지된 이벤트는 다음과 같은 조건을 모두 만족할 때 동작한다.
# Falco Default Rule
- rule: Terminal shell in container
# ... 중략
condition: >
spawned_process
and container
and shell_procs
and proc.tty != 0
and container_entrypoint
and not user_expected_terminal_shell_in_container_conditions
# ... 중략
- spawned_process : 새로운 프로세스가 생성되었는지 확인
- container : 컨테이너 환경에서 발생한 이벤트인지 확인
- shell_procs : 프로세스가 쉘인지 확인 (bash, sh 등)
- proc.tty != 0 : 터미널을 연결한 상태로 실행 (kubectl exec -it)
- container_entrypoint : 컨테이너 런타임이 직접 실행한 것인지 확인 (runc, containerd-shim, docker-runc 등)
- user_expected_terminal_shell_in_container_conditions : 사용자 정의 예외 조건에 해당하지 않을 경우
- 사용자 정의 예외 조건은 기본적으로 false로 설정되어 있으며, 룰의 조건식에서는 not false가 되어 항상 true가 된다. 즉, 아무 동작도 하지 않는 '껍데기 조건' 역할을 하여 초기 rule에 영향을 주지 않는다. 예외 조건을 추가하고 싶은 경우 이 영역에 조건을 정의하여 예외 처리할 수 있다.
이게 무슨 말이냐면 예를 들어, 특정 네임스페이스의 접근을 탐지 대상에서 제외하고 싶다면 해당 네임스페이스 조건을 여기에 추가하여 룰이 무시되도록 설정할 수 있다. 어떻게 하는지는 아래 "예외 조건 추가" 실습에서 다루겠다.
- 사용자 정의 예외 조건은 기본적으로 false로 설정되어 있으며, 룰의 조건식에서는 not false가 되어 항상 true가 된다. 즉, 아무 동작도 하지 않는 '껍데기 조건' 역할을 하여 초기 rule에 영향을 주지 않는다. 예외 조건을 추가하고 싶은 경우 이 영역에 조건을 정의하여 예외 처리할 수 있다.
위 6가지 조건을 종합해 보자면 'kubectl exec -it {pod_name} -- /bin/bash' 명령어로 Pod에 접속하면 경고 이벤트가 발생하는 규칙이다.
3-2. 민감 파일 접근 탐지 (Read sensitive file untrusted)
해당 rule은 /etc/shadow, id_rsa 등과 같은 민감 파일에 대한 접근을 감지한다.
단순히 파일을 읽는 행위만으로는 탐지되지는 않고, Falco 규칙에서 정의한 신뢰되지 않은 프로세스(not proc.name)에 의해 접근되어야 이벤트가 발생한다.
간단한 테스트를 위해, 앞에서 배포한 Nginx 컨테이너에 bash로 진입한 후 python 명령어를 통해 /etc/shadow 파일을 읽어보자.
$ kubectl exec -it deployments/nginx-deployment -- /bin/bash
$ apt update
$ apt install -y python3
$ python3 -c "open('/etc/shadow').read()"
EVENTS 탭을 눌러 확인해 보면 위에서 실행한 명령어(command)를 통해 /etc/shadow 파일을 읽은 행위가 탐지되어 이벤트에 보이는 것을 확인할 수 있다.
4. 불필요한 규칙 비활성화
Falco 설치 시 적용되는 기본 Rule은 대부분의 일반적인 보안 위협을 탐지할 수 있도록 구성되어 있다. 하지만 그중 일부 Rule은 너무 자주 발생하거나 현재 시스템에는 불필요한 알림일 수 있다.
지금도 이벤트를 보면 Contact K8S API Server From Container Rule의 이벤트가 지속적으로 발생하는 것을 확인할 수 있다.
Contact K8S API Server From Container Rule은 컨테이너 내부에서 Kubernetes API 서버에 연결하는 행위를 탐지한다.
실제로는 많은 컨테이너가 Service Discovery, ConfigMap, Secret 조회 등을 위해 API 서버와 통신하기 때문에 이는 불필요한 이벤트로 볼 수 있다.
이런 경우에는 해당 Rule을 비활성화하거나, 예외 조건을 추가하는 방식으로 비활성화할 수 있다.
4-1. 기본 규칙 비활성화
다음과 같이 Helm values.yaml 파일에 추가하여 Rule을 비활성화한다.
# ... 생략
customRules:
disable-contacts-k8s.yaml: |-
- rule: Contact K8S API Server From Container
override:
enabled: replace
enabled: false
추가한 내용을 반영한다.
$ helm upgrade --install falco falcosecurity/falco \
--namespace falco -f values.yaml
Falco 대시보드를 확인해 보면 더 이상 이벤트가 발생하지 않는 것을 확인할 수 있다.
4-2. 예외 조건 추가
앞서 확인한 기본 Rule 중 하나인 Terminal shell in container는 kubectl exec을 통해 컨테이너에 bash로 접근할 경우 이벤트를 발생시킨다.
하지만 특정 네임스페이스에서는 이러한 접근이 허용되도록 탐지 대상에서 제외하고 싶은 경우가 있을 수 있다. 이럴 때는 예외 조건macro을 추가하여 특정 조건을 탐지 대상에서 제외할 수 있다.
예를 들어, default나 kube-system 네임스페이스에 대한 접근은 감지되지 않도록 설정하려면 values.yaml의 customRules 항목에 다음과 같이 설정한다.
customRules:
# ... 생략
allow-terminal-shell.yaml: |-
- macro: user_expected_terminal_shell_in_container_conditions
condition: (k8s.ns.name in (default, kube-system))
위 설정은 Terminal shell in container Rule의 예외 조건인 user_expected_terminal_shell_in_container_conditions 매크로를 오버라이드 하여, 지정된 네임스페이스(default, kube-system)에서는 탐지되지 않도록 설정한 것이다.
설정 후 다음 명령어로 Helm 값을 반영한다.
$ helm upgrade --install falco falcosecurity/falco \
--namespace falco -f values.yaml
이제 실제로 예외 처리가 적용되었는지 테스트해 보자.
defualt 네임스페이스에 있는 nginx pod와 falco 네임스페이스에 있는 falco pod에 접근해 보자.
$ kubectl exec -it deployments/nginx-deployment -- /bin/bash
$ kubectl exec -it -n falco daemonset/falco -- /bin/bash
Falco 대시보드의 EVENTS 탭을 확인해 보면, default 네임스페이스의 접근은 이벤트로 기록되지 않고, falco 네임스페이스의 접근만 탐지된 것을 확인할 수 있다.
5. 사용자 정의 규칙 추가
기본 제공되는 Falco Rule 외에도 필요에 따라 탐지 항목을 직접 정의하여 추가할 수 있다.
이번에는 네트워크 디버깅이나 포트 스캐닝 도구로 자주 사용되는 Netcat(nc)을 실행할 때 이를 감지하는 사용자 정의 Rule을 추가해 보려 한다.
하지만 여기서 한 가지 주의할 점이 있다.
Falco는 여러 Rule 간에 조건이 겹칠 경우 먼저 충족되는 Rule만 탐지 이벤트로 출력한다.
예를 들어, nc 명령어를 실행하면 Falco는 기본 Rule인 Drop and execute new binary in container Rule을 먼저 탐지한다.
해당 Rule은 컨테이너 이미지에 포함되지 않은 실행 파일이 실행될 때 발생한다. 앞서 실습을 위해 배포한 Nginx Pod는 기본적으로 nc 바이너리를 포함하지 않기 때문에, 실습을 위해 nc 패키지를 설치하여 nc 명령을 실행하게 되면 기본 Rule이 먼저 작동하여 사용자 정의로 추가한 Rule은 이벤트로 표시되지 않는다.
따라서 이런 상황에서는 우선 적용되는 기본 Rule에 예외 조건을 추가하여 nc 명령 탐지를 생략하도록 설정해야 추가한 사용자 정의 Rule이 정상적으로 탐지 이벤트를 발생시킬 수 있다.
nc 명령어를 사용하는 경우 Drop and execute new binary in container Rule에 탐지되지 않도록 values.yaml의 customRules 섹션에 다음과 같이 macro를 추가하여 예외 처리한다.
customRules:
# ... 중략
detect-nc-port-scan.yaml: |-
- macro: known_drop_and_execute_activities
condition: (proc.name = nc)
이제 Netcat 포트 스캔 시도를 탐지하는 사용자 정의 Rule을 추가한다.
아래는 nc -zv 등 포트 스캔 명령을 사용하는 경우 이벤트가 발생하도록 구성한 예시이다.
customRules:
# ... 중략
detect-nc-port-scan.yaml: |-
- macro: known_drop_and_execute_activities
condition: (proc.name = nc)
# Rule 추가
- rule: Netcat port scan attempt
desc: Detect use of netcat for port scanning inside a Kubernetes container
condition: >
spawned_process
and container
and proc.name = nc
and (proc.args contains "-z" or proc.args contains "-v" or proc.args = "")
and proc_name_exists
output: >
ALERT: Netcat port scan detected (command=%proc.cmdline user=%user.name pod=%k8s.pod.name ns=%k8s.ns.name image=%container.image.repository)
priority: WARNING
tags: [custom, container, network-scan, netcat, k8s]
enabled: true
앞서 배포한 nginx pod로 접근하여 nc 명령을 설치하고 실행해 보자.
$ kubectl exec -it deployments/nginx-deployment -- /bin/bash
$ apt install -y netcat-openbsd
총 3회 nc 명령을 실행하고 Falco 대시보드의 EVENTS 탭을 확인한다.
$ nc
usage: nc [-46CDdFhklNnrStUuvZz] [-I length] [-i interval] [-M ttl]
[-m minttl] [-O length] [-P proxy_username] [-p source_port]
[-q seconds] [-s sourceaddr] [-T keyword] [-V rtable] [-W recvlimit]
[-w timeout] [-X proxy_protocol] [-x proxy_address[:port]]
[destination] [port]
$ nc -v 10.10.1.74 80
Connection to 10.10.1.74 80 port [tcp/*] succeeded!
$ nc -vz 10.10.1.74 80
Connection to 10.10.1.74 80 port [tcp/*] succeeded!
사용자 정의 Rule에 설정한 대로 이벤트가 감지된 것을 확인할 수 있다.
마무리
지금까지 Falco를 Kubernetes 클러스터에 설치하고, 기본 Rule의 동작 방식과 사용자 정의 Rule을 추가하는 방법, 그리고 예외 조건을 설정해 탐지를 세밀하게 조정하는 과정까지 살펴보았다.
Falco는 실제 운영 환경에서 발생할 수 있는 보안 위협을 실시간으로 감지하고 대응할 수 있도록 도와주는 강력한 보안 도구이다.
특히, Kubernetes와 같은 동적인 환경에서는 이러한 실시간 모니터링은 보안 강화의 첫걸음이 될 수 있다.
기본 Rule을 이해하고, 환경에 맞는 탐지 항목을 구성하며, 불필요한 오탐지를 줄이는 세팅을 적절하게 적용한다면 Kubernetes 클러스터를 더욱 안전하게 지킬 수 있을 것이다.
'Orchestration > Kubernetes' 카테고리의 다른 글
컨테이너 이미지 최적화 - 실무를 위한 전략과 팁 (0) | 2025.04.24 |
---|---|
[Kubernetes] 환경에서 External Secrets Operator(ESO)로 안전하게 Secrets 관리하기 (0) | 2025.03.26 |
[Amazon EKS] 환경에서 Pod IP 부족 문제 해결하기 (0) | 2024.07.11 |
[K8sGPT] 사용하여 Kubernetes 문제 해결하기 (0) | 2024.07.03 |
[Amazon EKS] AutoScaling 속도 비교(Cluster Autoscaler vs Kerpenter) (0) | 2023.10.22 |
댓글