はじめに
最近コンテナをプロジェクトで使う機会も増えてきましたが、コンテナのセキュリティ対策で悩むことも多いのではないでしょうか。
FalcoがAWS Fargateに対応しているようなので、今回はFalcoでAWS Fargateのコンテナランタイムの保護ができるか検証してみます。
構成
コンテナ定義
Falco
以下はFalcoコンテナのDockerfileです。
FROM scratch COPY --from=ollypom/pdig:latest /pdig /vendor/falco/bin/pdig COPY --from=falcosecurity/falco:0.32.2-slim /usr/bin/falco /vendor/falco/bin/falco COPY --from=falcosecurity/kilt-utilities:latest /kilt/ /vendor/falco/bin/ COPY --from=falcosecurity/falco:0.32.2-slim /etc/falco/ /vendor/falco/etc/falco/ VOLUME ["/vendor/falco"] CMD ["/vendor/falco/bin/waitforever"]
上記定義は、以下を参考にしました。
https://github.com/aws-samples/aws-fargate-falco-examples/tree/main/containerimages/mountedbinaries
PHP
以下はPHPコンテナのDockerfileです。
FROM php:8-fpm COPY falco_conf/ /data/
「falco_conf」ディレクトリには、falco.yaml
、falco_rules.local.yaml
を格納します。
アップデートや、PHPの設定などは割愛します。
AWS構成
タスク定義
今回の構成は、以下のようなタスク定義で実行しました。 全体ではなく、一部抜粋となります。
Falcoはサイドカーでも動作するようですが、AWS Fargateではまだサポートしていないようです。
サンプルにあるmountedbinaries
、embeddedbinaries
の2パターンで動作するようですが、アプリケーションコンテナを汚したくなかったのでmountedbinaries
を今回は選択しました。
{ "name": "binaries", "image": "<ECRのFalcoコンテナURI>", "cpu": 0, "essential": true }, { "name": "php", "image": "<ECRのPHPコンテナURI>", "cpu": 0, "portMappings": [], "essential": true, "entryPoint": [ "/vendor/falco/bin/launcher", "/vendor/falco/bin/pdig", "sh", "-c", "php-fpm", "--" ], "command": [ "/vendor/falco/bin/falco", "--userspace", "-c", "/data/falco.yaml" ], "environment": [ { "name": "__CW_LOG_GROUP", "value": "/aws/ecs/service/falco_alerts" } ], "volumesFrom": [ { "sourceContainer": "binaries", "readOnly": true } ], "linuxParameters": { "capabilities": { "add": [ "SYS_PTRACE" ] } }, "dependsOn": [ { "containerName": "binaries", "condition": "START" } ], "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-group": "/aws/ecs/service/mountedbinaries", "awslogs-region": "ap-northeast-1", "awslogs-stream-prefix": "falco-app" } } }
entryPoint
でfalco
からphp-fpm
を起動したり、linuxParameters
でSYS_PTRACE
を許可しているのがポイントですね。
この辺りの構成は、PrismaCloudとほぼ同じです。
使い勝手
検知
Falcoの検知ルールは、以下ファイルに定義します。
/vendor/falco/etc/falco/falco_rules.yaml
:デフォルトルール/data/falco_rules.local.yaml
:カスタムルール
定義の例は以下のとおりです。
デフォルトルールの例や、GitHubのドキュメントを確認しながらカスタムルールを作っていく感じですね。
- rule: write_binary_dir desc: an attempt to write to any file below a set of binary directories condition: open_write and not proc.name in (package_mgmt_binaries) and bin_dir output: "File below a known binary directory opened for writing (user=%user.name command=%proc.cmdline file=%fd.name)" priority: WARNING - macro: outbound_corp condition: > (((evt.type = connect and evt.dir=<) or (evt.type in (sendto,sendmsg) and evt.dir=< and fd.l4proto != tcp and fd.connected=false and fd.name_changed=true)) and (fd.typechar = 4 or fd.typechar = 6) and (fd.ip != "0.0.0.0" and fd.net != "127.0.0.0/8") and (evt.rawres >= 0 or evt.res = EINPROGRESS)) - rule: outbound connection desc: Container attempted to connect to the outer world condition: outbound_corp output: "Outbound network traffic connection (srcip=%fd.cip dstip=%fd.sip dstport=%fd.sport proto=%fd.l4proto procname=%proc.name)" priority: WARNING
アラート
CloudWatchLogs
始めに、ログをCloudWatchLogsに送信してみます。
Falcoデフォルト値が標準出力に出力されるように設定しているので、ECSタスク定義の設定でCloudWatchLogsに送信されるように設定します。
アラートは、以下のような形式でCloudWatchLogsに出力されました。
エラーの内容は、/etc
配下のファイルへの書き込み検知です。
結果としては出力されたのですが、アラートがなかなかCloudWatchLogsに送信されない事象が発生しました。
原因はログはバッファされるようで、いくつかアラートが溜まらないとCloudWatchLogsに送信されないようです。
Fluentd等のログルーターを介して送信するのがよさそうです。
https://falco.org/docs/outputs/channels/
If the logs are inspected by tailing container logs (e.g. kubectl logs -f in Kubernetes) it might look like events can take a long time to appear, sometimes longer than 15 minutes. This is not an issue with Falco but is simply a side effect of the system output buffering.
Slack
FalcoはSlackにも送ることができるようなのでやってみます。
falco.yaml
を以下のように修正します。
#program_output: # enabled: true # keep_alive: true # program: "/vendor/falco/bin/logshipper" json_output: true program_output: enabled: true program: "jq '{text: .output}' | curl -d @- -X POST <Slack WebHookURL>"
- program_outputは1つしか認識しないようなので無効化します。
- jpコマンドを使うので、コンテナにjpパッケージが必要です。
アラートを起こすと以下のような形式で通知が来ました。Slackの方はすぐにアラートが来ます。
Slackに通知できることが分かりましたが、program_output
が1つしか設定できないのでSlackに送るとCloudWatchLogsに送信できなくなってしまいます。
program_output
でCloudWatchLogsへ送信し、内容を検知してChatBot等でSlackに送るのがよさそうですね。
まとめ
確かにAWS Fargateで動作し、定義したルールに沿って攻撃を検知できることは確認できました。
最近、AWS Fargateにアップデートがありコンテナランタイムセキュリティツールのプロセス監視が容易になったと話題になりましたので、今後のFalcoのアップデートに期待したいです。
参考
falcosecurity/falco
aws-samples/aws-fargate-falco-examples
falco-rules