最近導入事例をよく聞くFalcoから、Slack経由でアラート通知してみました。
Falcoとは
特定のルールに基づきコンテナ、VM、クラウドサービス等のセキュリティリスクに繋がり得るイベントをリアルタイムで検知する、OSSのセキュリティソフトウェアです。
sysdigカーネルモジュールや eBPF(Extended Berkeley Packet Filter)を利用してシステムコールをトレーシングし、プロセスを監視します。
詳細はsysdigさんのブログと公式ドキュメントを参照してください。
事前準備
以下の環境で検証しました。
MacBook M3 Pro
OpenShift Local v2.49.0
Falco 4.21.3
Slack Incoming Webhook URLの作成
Slackの公式ドキュメントを参考に、Webhook URLを追加しました。
Falcoのインストール
公式が提供するHelm Chartをインストールしました。
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update
helm install --replace falco --namespace falco --create-namespace falcosecurity/falco -f values-falco.yml
values-falco.yml
# -- Attach the Falco process to a tty inside the container. Needed to flush Falco logs as soon as they are emitted.
# Set it to "true" when you need the Falco logs to be immediately displayed.
tty: true
# Driver settings (scenario requirement)
driver:
# -- Set it to false if you want to deploy Falco without the drivers.
# Always set it to false when using Falco with plugins.
enabled: true
# -- kind tells Falco which driver to use. Available options: kmod (kernel driver), ebpf (eBPF probe), modern_ebpf (modern eBPF probe).
kind: auto
falco:
# [Stable] `priority`
#
# -- Any rule with a priority level more severe than or equal to the specified
# minimum level will be loaded and run by Falco. This allows you to filter and
# control the rules based on their severity, ensuring that only rules of a
# certain priority or higher are active and evaluated by Falco. Supported
# levels: "emergency", "alert", "critical", "error", "warning", "notice",
# "info", "debug"
priority: warning
########################
# Falco integrations #
########################
# -- For configuration values, see https://github.com/falcosecurity/charts/blob/master/charts/falcosidekick/values.yaml
falcosidekick:
# -- Enable falcosidekick deployment.
enabled: true
# -- Enable usage of full FQDN of falcosidekick service (useful when a Proxy is used).
fullfqdn: false
# -- Listen port. Default value: 2801
listenPort: "2801"
# -- Sidekick pod securityContext
podSecurityContext:
runAsUser: 1234
fsGroup: 1234
runAsNonRoot: true
# -- Sidekick container securityContext
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
config:
slack:
# -- Slack Webhook URL (ex: <https://hooks.slack.com/services/XXXX/YYYY/ZZZZ>), if not `empty`, Slack output is *enabled*
webhookurl: "https://hooks.slack.com/services/XXXX/YYYY/ZZZZ"
# -- Slack channel (optionnal)
channel: ""
# -- Slack Footer
footer: ""
# -- Slack icon (avatar)
icon: ""
# -- Slack username
username: ""
# -- `all` (default), `text` (only text is displayed in Slack), `fields` (only fields are displayed in Slack)
outputformat: "all"
# -- minimum priority of event to use this output, order is `emergency\|alert\|critical\|error\|warning\|notice\|informational\|debug or ""`
minimumpriority: ""
# -- a Go template to format Slack Text above Attachment, displayed in addition to the output from `slack.outputformat`. If empty, no Text is displayed before Attachment
messageformat: ""
values-falco.yml
は、GitHubのdocsと各Chartのvalues.yaml
を参考に設定しました。
- https://github.com/falcosecurity/charts/blob/master/charts/falco/values.yaml
- https://github.com/falcosecurity/charts/blob/master/charts/falcosidekick/values.yaml
- https://github.com/falcosecurity/falcosidekick/blob/master/docs/outputs/slack.md
手元の環境ではOpenShift Security Context Constraintsの制約により、Podが起動しませんでした。
Falco, Falco sidekickのサービスアカウントにprivileged
のsccを付与することでエラーを回避しました。
oc adm policy add-scc-to-user privileged -z falco -n falco
oc adm policy add-scc-to-user privileged -z falco-falcosidekick -n falco
Falco Rulesの設定
Falcoのデフォルトルールをそのまま利用します。
独自のポリシーを運用したい場合、カスタムルールを作成することができます。
Helm Chartの設定を変更しなければ、自動的にデフォルトルールが適用されます。
インストール時のオプションでfalco.priority
にwarning
を設定しているため、priority: warning
以上のルールが照合されます。
Slack通知の動作確認
適当にPodを起動して、SSHコマンドやcurlを実行してみます。
$ oc run --image alpine -it alpine -- sh
If you don't see a command prompt, try pressing enter.
/ # apk update
...
/ # apk add openssh curl -y
...
/ # ssh --help
ssh: unrecognized option: -
usage: ssh [-46AaCfGgKkMNnqsTtVvXxYy] [-B bind_interface] [-b bind_address]
[-c cipher_spec] [-D [bind_address:]port] [-E log_file]
[-e escape_char] [-F configfile] [-I pkcs11] [-i identity_file]
[-J destination] [-L address] [-l login_name] [-m mac_spec]
[-O ctl_cmd] [-o option] [-P tag] [-p port] [-R address]
[-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]]
destination [command [argument ...]]
ssh [-Q query_option]
/ # curl https://kubernetes.default.svc:443 -kv
* Host kubernetes.default.svc:443 was resolved.
* IPv6: (none)
* IPv4: 10.217.4.1
* Trying 10.217.4.1:443...
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Request CERT (13):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Certificate (11):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256 / x25519 / RSASSA-PSS
* ALPN: server accepted h2
* Server certificate:
* subject: CN=10.217.4.1
* start date: Mar 16 15:05:47 2025 GMT
* expire date: Mar 16 15:05:48 2026 GMT
* issuer: OU=openshift; CN=kube-apiserver-service-network-signer
* SSL certificate verify result: self-signed certificate in certificate chain (19), continuing anyway.
* Certificate level 0: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
* Certificate level 1: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
* Connected to kubernetes.default.svc (10.217.4.1) port 443
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://kubernetes.default.svc:443/
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: kubernetes.default.svc]
* [HTTP/2] [1] [:path: /]
* [HTTP/2] [1] [user-agent: curl/8.12.1]
* [HTTP/2] [1] [accept: */*]
> GET / HTTP/2
> Host: kubernetes.default.svc
> User-Agent: curl/8.12.1
> Accept: */*
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* Request completely sent off
* received GOAWAY, error=0, last_stream=1
< HTTP/2 403
< audit-id: cc7f6007-b2d6-4584-baa5-44d93b855eca
< cache-control: no-cache, private
< content-type: application/json
< strict-transport-security: max-age=31536000; includeSubDomains; preload
< x-content-type-options: nosniff
< x-kubernetes-pf-flowschema-uid: d62aafa0-00ea-4bf5-986e-cd35691a2eb3
< x-kubernetes-pf-prioritylevel-uid: 9afd7176-4c2d-479b-82d4-1488dc281e4e
< content-length: 217
< date: Sun, 04 May 2025 02:43:11 GMT
<
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "forbidden: User \"system:anonymous\" cannot get path \"/\"",
"reason": "Forbidden",
"details": {},
"code": 403
* shutting down connection #0
* TLSv1.3 (OUT), TLS alert, close notify (256):
}/ #
コマンドを実行してから約1分後、Slackに通知メッセージが届きました。
補足情報
以下、補足情報です。
eBPFとは
Linuxカーネルの機能を拡張するためのプログラムです。
eBPFプログラムをLinuxカーネルにロードすることで、システムコールをフックし任意のプログラムが実行されます。
eBPFには、以下のようなメリットがあります。
- eBPFプログラムはJIT コンパイルされるため、実行効率が高い
- OS内部でサンドボックス化されたプログラムが実行されるため、安全です
- OSコードの改変が不要なため、ポータビリティに優れます
詳細は公式ドキュメントを参照してください。
他の選択肢
tetragon
とTracee
というツールがありました。
Falcoと同様にePBFを使用した、振る舞い監視を実現するためのセキュリティソフトウェアです。
Falcoctl
Falcoルールやプラグインのバージョン管理を実現するためのコマンドラインツールです。
GitHub Packages等のアーティファクトストアに、OCI artifactsとして登録できるそうです。
まとめ
FalcoのHelm Chartをインストールすることで、コンテナ内プロセスの振る舞い監視が簡単に実現できました。
実運用では誤検知や大量アラートを抑えるチューニングが求められそうですね。
もし導入を検討されている場合は、こちらの記事も読んでみてください。