쿠버네티스 클러스터의 리소스를 실시간으로 감시하기 위해서는 단순히 LGTM 스택과 같은 모니터링 도구 외에도 런타임 보안에 대한 대비가 필요하다는 생각이 들었습니다. 그러던 중, 시스템 콜 기반의 보안 이벤트 감지 기능을 제공하는 오픈소스 도구인 Falco를 알게 되었습니다.

이 글에서는 Falco를 쿠버네티스에 도입하면서 겪은 트러블슈팅, Falcosidekick을 활용한 Web UI 구성까지의 과정을 정리해보려고 합니다.
🔗 공식 홈페이지 바로가기
🔗 공식 GitHub 바로가기
공식 문서에서 Falco의 쿠버네티스 설치 과정을 자세히 확인할 수 있습니다.
Falco는 쿠버네티스, 컨테이너, 호스트, 클라우드 환경에서 발생하는 런타임 보안 위협을 탐지하는 오픈소스 런타임 보안 도구입니다. CNCF(Cloud Native Computing Foundation)에서 관리하며, 클러스터 내부의 비정상적인 활동을 실시간으로 감지하고 알림을 제공합니다.
Falco 동작 방식
Falco는 시스템에서 발생하는 다양한 이벤트(리눅스 시스템 콜, 쿠버네티스 Audit 로그, CloudTrail 이벤트 등)를 수집하고, 이를 사전에 정의된 보안 규칙과 비교해 이상 행동을 탐지합니다.
1) 시스템 콜 기반 감시
Falco의 핵심 기능은 리눅스 커널 수준에서 발생하는 시스템 콜을 실시간으로 감시하는 것입니다. 이 과정을 통해, 컨테이너 내부에서 발생하는 민감한 작업이나 의심스러운 활동을 빠르게 감지할 수 있습니다.
2) eBPF 및 커널 모듈 지원
Falco는 시스템 콜을 수집하기 위해 두 가지 방식 중 하나를 사용합니다.
eBPF
고속의 샌드박스 실행 환경을 활용하여, 커널 수준에서 안전하고 효율적으로 이벤트를 수집합니다.
Kernel Module
eBPF를 사용할 수 없는 환경에서는 전통적인 커널 모듈 방식을 통해 시스템 콜을 감시합니다
주요 감시 항목
Falco는 이러한 이벤트를 Notice, Warning, Critical 등의 우선순위로 분류하고, 로그 출력 또는 외부 시스템(Slack, Webhook, Email 등)으로 실시간 전송할 수 있습니다. Falcosidekick과 함께 사용하면 다양한 연동과 시각화도 가능합니다.

# Helm repo 추가
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update
# 기본 설치
helm install --replace falco --namespace falco --create-namespace --set tty=true falcosecurity/falco
문제
Falco를 설치한 후, 파드가 정상적으로 실행되지 않고 CrashLoopBackOff 상태를 반복했습니다.
kubectl get pods -n falco
NAME READY STATUS RESTARTS AGE
falco-4j7nt 0/2 CrashLoopBackOff 7 16m
falco-sptbr 0/2 CrashLoopBackOff 8 18m
파드 로그를 확인해보면 다음과 같은 오류 메시지가 출력되었습니다.
Error: could not initialize inotify handler
원인
Falco는 내부적으로 inotify를 사용하여 파일 시스템 이벤트를 감시합니다. 이 오류는 노드의 inotify 리소스 한도가 낮아 Falco가 핸들러를 초기화하지 못하면서 발생하였습니다.
💡 inotify는 리눅스 커널에서 파일 시스템 이벤트를 감지하는 서브시스템입니다.
해결 방법: inotify 리소스 한도 증가
각 클러스터 노드에서 다음 명령어를 실행하여 inotify 설정 값을 늘려주었습니다.
# 임시 적용
sudo sysctl fs.inotify.max_user_instances=512
sudo sysctl fs.inotify.max_user_watches=524288
# 영구 적용
echo 'fs.inotify.max_user_instances=512' | sudo tee -a /etc/sysctl.conf
echo 'fs.inotify.max_user_watches=524288' | sudo tee -a /etc/sysctl.conf
Falco는 기본적으로 CLI로만 로그를 출력하기 때문에, 이벤트를 확인하기엔 불편함이 있었습니다. 그래서 시각화 도구인 Falcosidekick과 Web UI를 함께 도입했습니다.

Helm 설치
helm upgrade --install falco falcosecurity/falco \
--namespace falco \
--set tty=true \
--set falcosidekick.enabled=true \
--set falcosidekick.webui.enabled=true \
--set falcosidekick.webui.user="admin:admin"
외부 접근을 위한 NodePort 설정
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
name: falcosidekick-ui-nodeport
namespace: falco
spec:
type: NodePort
ports:
- port: 2802
targetPort: 2802
nodePort: 30802
protocol: TCP
selector:
app.kubernetes.io/name: falcosidekick
app.kubernetes.io/component: ui
EOF
Falcosidekick Web UI에 접속은 가능했지만, 어떠한 이벤트도 표시되지 않는 문제가 발생했습니다.
문제 1: Falco와 Falcosidekick 간 연결 실패
먼저 Falco의 로그를 확인했을 때, 이벤트가 JSON 형태로 출력되지 않았습니다.
# Falco 로그 확인
kubectl logs -n falco -l app.kubernetes.io/name=falco --tail=20
# 이벤트가 JSON으로 출력되지 않음
해결 방법: HTTP 출력 활성화
helm upgrade falco falcosecurity/falco \
--namespace falco \
--set falcosidekick.enabled=true \
--set falcosidekick.fullfqdn=falcosidekick.falco.svc.cluster.local \
--set falco.httpOutput.enabled=true \
--set falco.httpOutput.url=http://falcosidekick.falco.svc.cluster.local:2801
문제 2: Falcosidekick 인스턴스 혼재
설치를 여러 번 반복하면서, 서로 다른 이름의 Falcosidekick 인스턴스가 동시에 존재하는 상황이 발생했습니다.
kubectl get pods -n falco | grep falcosidekick
falcosidekick-5f766c58d9-lqqkc 1/1 Running 0 22m
falco-falcosidekick-797dfcd975-bmbzt 1/1 Running 0 19m
기존 UI는 falcosidekick 인스턴스를 바라보고 있었고, falco는 falco-falcosidekick 인스턴스로 이벤트를 전송하고 있었습니다.
🎯 Falco와 UI가 서로 다른 인스턴스와 연결되어 있었던 것이 문제였습니다. 따라서 모든 리소스를 정리하고, Helm 릴리스를 하나로 통합하여 재설치를 선택하였습니다.
문제 3: 네임스페이스 삭제 불가
문제를 해결하기 위해 기존 falco 네임스페이스를 삭제했지만, 다음과 같이 지속적으로 Terminating 상태가 발생했습니다.
kubectl delete namespace falco --force --grace-period=0
# Terminating 상태로 계속 남음
쿠버네티스는 네임스페이스를 삭제할 때, 그 안에 존재하는 모든 리소스를 먼저 정리한 후 삭제를 완료합니다. 하지만 Falco 설치 중 생성된 일부 리소스가 metrics.k8s.io/v1beta1 API를 참조하고 있었고, 해당 API가 제대로 동작하지 않으면서 쿠버네티스가 리소스 상태를 확인하지 못했습니다.
결과적으로 리소스 정리가 정상적으로 이루어지지 않았고, 이로 인해 네임스페이스 삭제도 완료되지 못하고 멈춰버린 상황이 발생했습니다.
해결 방법
문제를 빠르게 해결하기 위해, 새로운 네임스페이스를 생성하여 Falco를 재설치하는 방법을 선택했습니다.
kubectl create namespace falco-security
# 1. 새로운 네임스페이스에 설치
kubectl create namespace falco-security
# 2. 올바른 설정으로 설치
helm upgrade --install falco falcosecurity/falco \
--namespace falco-security \
--set tty=true \
--set falcosidekick.enabled=true \
--set falcosidekick.webui.enabled=true \
--set falcosidekick.webui.user="admin:admin"
# 3. NodePort 생성
kubectl apply -f falcosidekick-ui-nodeport.yaml
최종 확인
# 파드 상태 확인
kubectl get pods -n falco-security
NAME READY STATUS RESTARTS AGE
falco-4bh8p 2/2 Running 0 3m43s
falco-falcosidekick-788cf94f5b-q6xsc 1/1 Running 0 3m44s
falco-falcosidekick-ui-5f585c96bb-7xwzn 1/1 Running 0 3m44s
falco-falcosidekick-ui-redis-0 1/1 Running 0 3m45s
# 실시간 이벤트 확인
kubectl logs -n falco-security -l app.kubernetes.io/name=falco -f
{"hostname":"host-10-10-17-253","output":"17:45:26.612832346: Notice Unexpected connection to K8s API Server from container"...}
🥳 성공


아직 직접 커스텀 규칙을 만들어보진 않았지만, 앞으로는 Falco 룰을 활용해 더욱 효율적인 보안 정책을 구성해보고 싶습니다 :)
# 불필요한 규칙 비활성화 (values.yaml)
customRules:
disable-k8s-api.yaml: |-
- rule: Contact K8S API Server From Container
override:
enabled: replace
enabled: false