Amazon Web Services ブログ
CNCF Falco を使用して Amazon EKS のランタイムセキュリティを実装する
この記事は Implementing Runtime security in Amazon EKS using CNCF Falco (記事公開日: 2020 年 11 月 19 日) を翻訳したものです。
多くの組織は、アプリケーションをコンテナに移行する過程にあります。コンテナは、アプリケーションレベルの依存関係の管理、スピーディな起動、不変性のサポートを実現します。これにより、コストを削減し、速度を上げ、効率性を向上させることができます。コンテナのライフサイクルを安全に管理するためには、コンテナイメージのハードニングと、エンドツーエンドのセキュリティチェックが重要な要素となります。コンテナは、Amazon Elastic Kubernetes Service (Amazon EKS) などのコンテナオーケストレーターにデプロイされる前に、デフォルトでセキュリティを確保する必要があります。コンテナをハードニングする旅は、次のように始まります。
- Dockerfile を Lint (静的解析) します。
 - Lint した Dockerfile または Docker Compose ファイルでイメージをビルドします。
 - コンテナの静的イメージスキャンを行います。
 - 脆弱性を検証します。
 - 手動の承認プロセスを設けます。
 - オーケストレーターである Amazon ECS または Amazon EKS にデプロイします。
 - コンテナの動的イメージスキャンを有効にし、定期的にログを分析します。
 
まず、パイプラインの流れをよりよく理解するために、静的スキャンと動的スキャンとは何かについて説明します。
- 静的スキャンは、使用またはデプロイされる前のコンテナレイヤーのディープスキャンの一種です。コンテナは、公開されているバグや CVE データベースに対してスキャンされます。
 - 動的スキャンは、コンテナレイヤーの実行後またはデプロイ中に行うディープスキャンの一種です。この手法では、必要に応じてスキャンして結果を公開したり、コンテナの実行中に継続的にログを分析したりできます。動的スキャンツールに該当する製品は、CNCF Falco、Twistlock、Aqua など、市場に複数存在します。(訳注: Twistlock は現在は Prisma Cloud に統合され Palo Alto Networks 社によってサービス提供されています。)
 
このトピックについて詳しく知りたい方は、Container DevSecOps on Amazon ECS Fargate with AWS CodePipeline というブログ記事をご覧ください。今回のこの記事では、Amazon EKS 上で CNCF Falco を使ってランタイムセキュリティを構築、インストール、使用する方法を紹介します。
この記事では、以下の AWS サービスとオープンソースツールを使用します。
- Amazon Elastic Kubernetes Service (Amazon EKS)
 - Amazon CloudWatch
 - FireLens
 - AWS CloudFormation
 - AWS CLI
 - CNCF Falco
 - falcosecurity/falco
 
Amazon EKS クラスターをセットアップする
Amazon EKS クラスターをセットアップする前に、システムに以下のツールをセットアップしてください。オペレーティングシステムの種類に応じたセットアップ方法の詳細は、リンク先に記載されています。
cluster-config.yaml という Amazon EKS クラスターの設定ファイル (下記参照) を作成します。この設定ファイルは、Amazon EKS クラスターをデプロイするための設定ファイルとして使用します。Amazon EKS クラスターは既存の VPC または新規の VPC にデプロイすることができます。私は既存の VPC を使用して、パブリックとプライベートの両方のサブネットにマネージド型ノードグループを持つクラスターをセットアップしました。
eksctl.io のページでは、ClusterConfig の多くの例を確認できます。以下は、使用できる設定ファイルの 1 つです。このデモでは、既存のリソースを使ってクラスターを構築する方法を示しています。ClusterConfig のスキーマ要素を理解するには、eksctl のドキュメントをご覧ください。
cluster-config.yaml ファイル:
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
  name: eks-managed-cluster
  region: ap-south-1
vpc:
  id: "vpc-xxxxxxxxxx" # VPC ID を記載
  cidr: "xxxxxxxxxxxx" # VPC の CIDR を記載
  subnets:
    public:
      ap-south-1a:
        id: "subnet-xxxxxxxx" # サブネット ID を記載
        cidr: "xxxxxxxxxxxx"  # サブネットの CIDR を記載
      ap-south-1b:
        id: "subnet-xxxxxxxx" # サブネット ID を記載
        cidr: "xxxxxxxxxxxx"  # サブネットの CIDR を記載
# EKS サービスロールを記載
# iam:
#   serviceRoleARN: "arn:aws:iam::11111:role/eks-base-service-role"
# 以下はセルフマネージド型ノードグループの設定例
# nodeGroups:
#   - name: ng-1
#     instanceType: m5.large
#     desiredCapacity: 3
#     iam:
#       instanceProfileARN: "arn:aws:iam::11111:instance-profile/eks-nodes-base-role"
#       instanceRoleARN: "arn:aws:iam::1111:role/eks-nodes-base-role"
#     privateNetworking: true
#     securityGroups:
#       withShared: true
#       withLocal: true
#       attachIDs: ['sg-xxxxxx', 'sg-xxxxxx']
#     ssh:
#       publicKeyName: 'my-instance-public-key'
#     tags:
#       'environment:basedomain': 'example.org'
# 以下は EKS マネージド型ノードグループの設定例
managedNodeGroups:
- name: eks-managed-ng-1 # ノードグループの名前を記載
  minSize: 1             # Auto Scaling グループの設定
  maxSize: 2             # Auto Scaling グループの設定
  instanceType: t2.small # ワーカーノードのインスタンスタイプ
  desiredCapacity: 1     # Auto Scaling グループの設定
  volumeSize: 20         # ワーカーノードのボリュームサイズ
  ssh:
    allow: true
    # パブリックキーを提供することでインスタンスにログイン可能
    publicKeyPath: ~/.ssh/id_rsa.pub
    # sourceSecurityGroupIds: ["sg-xxxxxxxxxxx"] # オプション
    labels: {role: worker}
    tags:
      nodegroup-role: worker
  iam:
    withAddonPolicies:
    externalDNS: true
      certManager: true
# IAM ロールをアタッチする場合は ARN を記載
#   iam:
#     instanceRoleARN: "arn:aws:iam::1111:role/eks-nodes-base-role" 
       以下のコマンドを実行して、Amazon EKS クラスターを作成します。
eksctl create cluster -f cluster-config.yaml 
       以下のように、AWS CloudFormation によって作成されたクラスターを見つけることができます。

AWS マネジメントコンソールの Amazon EKS のページにアクセスして、以下のようにクラスターの作成状況を確認することができます。

Amazon EKS クラスターでサンプルデプロイメントをセットアップする
サンプルアプリケーション用に deployment.yaml という新しい設定ファイルを作成します。ここでは、サンプルの Nginx ウェブサイトの Pod を、クラスター設定ファイル cluster-config.yaml で指定したパブリックサブネット上に作成します。
以下のサンプル deployment.yaml ファイルを確認してください。
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx2
  labels:
    app: nginx2
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx2
  template:
    metadata:
      labels:
        app: nginx2
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: beta.kubernetes.io/arch
                operator: In
                values:
                - amd64
                - arm64
      containers:
      - name: nginx
        image: nginx:1.19.2
        ports:
        - containerPort: 80 
       それでは、以下のように Nginx をデプロイしましょう。
kubectl apply -f deployment.yaml 
       kubectl コマンドを使用して Deployment のステータスを確認することができます。
kubectl get deployments --all-namespaces 
       次のような出力が表示されます。
Falco ランタイムセキュリティをセットアップする
ここでは、コンテナのセキュリティイベントのディープな分析とアラートのために、よく知られたランタイムセキュリティツールである CNCF Falco をインストールします。Falco は、FireLens や Amazon CloudWatch などの他の AWS サービスと連携して動作します。FireLens はログアグリゲータ製品であり、コンテナのログを収集して Amazon CloudWatch など Amazon エコシステム内の多くのサービスに送信し、さらなる分析とアラートの仕組みを提供する機能を持っています。FireLens は、Fluent Bit または Fluentd を使用しており、両方の製品のすべての機能と構成をサポートしています。また、AWS FireLens のログ出力を、外部のロギングや分析サービスに送ることも可能です。
Amazon CloudWatch は、Amazon が提供する詳細なモニタリング、アラート、分析サービスであり、ログを受信したサービスに関する多くのインサイトを提供します。私たちは、ログに関するカスタムダッシュボードメトリクス、アラート、インサイトを作成することができます。こちらの Amazon CloudWatch のドキュメントを確認してください。Falco では、このブログで説明しているように、FireLens と Amazon CloudWatch を特に以下のように使用しています。
- Falco は、Pod 内で実行されているコンテナを継続的にスキャンし、セキュリティ、デバッグ、または監査イベントを JSON 形式で STDOUT に送信します。
 - その後、FireLens は JSON のログファイルを収集し、Fluent Bit の設定ファイルに従ってログファイルを処理します。
 - Fluent Bit コンテナによるログ変換後、ログは最終的な送信先として Amazon CloudWatch に送信されます。
 
このブログでは、Falco をインストールする方法と、他の AWS サービスとの連携について詳しく説明しています。
Falco 統合のサンプルリポジトリをクローンする
このリポジトリを git clone します: https://github.com/sysdiglabs/falco-aws-firelens-integration
eks/fluent-bit というディレクトリを確認してください。aws と kubernetes という 2 つのディレクトリがあります。
aws – このディレクトリには iam_role_policy.json という IAM ポリシーがあります。このポリシーを EKS クラスターを作成またはデプロイしたとき、ワーカーノードに自動的にアタッチされるワーカーノード VM のロールにアタッチします。このポリシーは、ワーカーノード上で動作している Fluent Bit が、Falco のログを Amazon CloudWatch に送信/ストリームできるようにします。
Kubernetes – このディレクトリには、configmap.yaml、daemonset.yaml、service-account.yaml の 3 つのファイルがあります。これらのファイルは、Fluent Bit の設定のための ConfigMap、すべてのワーカーノードで実行される Fluent Bit の DaemonSet、そして最後に RBAC による認可のための ClusterRole と ServiceAccount を作成するために apply されます。これらのファイルはすべて一度に apply します。
この Falco ブログでは、標準的な Falco のインストール方法についても同様に説明しています。以下のように、IAM ポリシーをノードインスタンスにアタッチして、ログを Amazon CloudWatch にストリームする権限を与えます。(訳注: IRSA を使用して IAM ポリシーを Fluent Bit の Pod にアタッチすることも可能です。)
IAM パーミッションと Fluent Bit をセットアップする
aws iam create-policy --policy-name EKS-CloudWatchLogs --policy-document file://./fluent-bit/aws/iam_role_policy.json 
       これにより、Amazon CloudWatch にログを送信する権限を持つ EKS-CloudWatchLogs というポリシーが作成されます。
aws iam attach-role-policy --role-name <EKS-NODE-ROLE-NAME> --policy-arn `aws iam list-policies | jq -r '.[][] | select(.PolicyName == "EKS-CloudWatchLogs") | .Arn'` 
       補足: “EKS-NODE-ROLE-NAME” は、ワーカーノードにアタッチされているロールです。アタッチされているロールを見つけて下さい。例えば私の場合、EKS クラスターをセットアップした後、eksctl-eks-managed-cluster-nodegr-NodeInstanceRole-1T0251NJ7YV04 がノードにアタッチされたロールでした。
aws iam attach-role-policy --role-name eksctl-eks-managed-cluster-nodegr-NodeInstanceRole-1T0251NJ7YV04 --policy-arn `aws iam list-policies | jq -r '.[][] | select(.PolicyName == "EKS-CloudWatchLogs") | .Arn'` 
       最後に、kubernetes ディレクトリ全体を apply すると、リストされたすべての設定ファイル (configmap.yaml、daemonset.yaml、service-account.yaml) が apply されます。(訳注: configmap.yaml でログの送信先のリージョンが指定されていますので、必要に応じて修正して下さい。)
kubectl apply -f eks/fluent-bit/kubernetes/ 
       Falco の Helm リポジトリをセットアップする
以下のように falcosecurity/falco の Helm チャートリポジトリをクローンし、Helm チャートリポジトリを追加します。
git clone https://github.com/falcosecurity/charts.git
helm repo add falcosecurity https://falcosecurity.github.io/charts 
       Helm リポジトリを更新する
falco/rules ディレクトリに移動し、デフォルトのルール設定ファイルを確認してください。これらはすぐに適用できます。デフォルトのルールセットの yaml ファイルには、それぞれに指定されているルールの詳細な説明がありますので、目を通してください。カスタムルールを追加することも可能です。
- application_rules.yaml
 - falco_rules.local.yaml
 - falco_rules.yaml
 - k8s_audit_rules.yaml
 
Falco の動作は、設定パラメータによって制御することができます。設定パラメータは、チャートのインストール時に引数として指定するか、そのためのファイル、たとえば values.yaml (任意の名前を付けることができます) を作成して指定します。このページを確認し、Falco の監査レベル、ログレベル、ファイル出力などの実行時の動作を制御するすべての設定パラメータについて理解して下さい。
values.yaml のサンプルが以下にありますので、参考にしてください。
https://github.com/falcosecurity/charts/blob/master/falco/values.yaml
それでは、Helm チャートをインストールしましょう。
helm install falco -f values.yaml falcosecurity/falco 
       次のような出力が表示されます。
デプロイが完了すると、Falco は Kubernetes クラスターの Pod をスキャンしてセキュリティや疑わしいイベントの動作を確認し、ログイベントを FireLens に送信します。FireLens は指定された設定に従って JSON ログを変換し、最終的にログを CloudWatch に送信します。
最終的には、以下の Pod がデプロイされているはずです。
kubectl get pods --all-namespaces 
       次のような出力が表示されます。
コンソールで CloudWatch にアクセスし、ロググループとログストリームを探してください。

シミュレーションとテスト
Falco は、Pod 上の疑わしいアクティビティをキャッチします。 テスト用のデプロイメント (ここでは NGINX アプリケーション Pod) の中に入り、特定のコマンドをシミュレートして Falco が実装するデフォルトのルールをトリガーすることで、これをテストできます。
例 1: falco_rules.yaml のルールをシミュレートする: いずれかの NGINX Pod に入り、以下のステートメントを実行すると、“write below etc” および “Read sensitive file untrusted” というルールがトリガーされます。
上述のコマンド (kubectl get pods) を使用して、EKS クラスター上で稼働しているすべての Pod をリストアップし、NGINX Pod の 1 つに入り、以下のような疑わしい動作をシミュレートすることができます。たとえば、NGINX Pod の 1 つである nginx2-7844999d9c-wdpz8 に入り、作成したルールセットに基づいて Falco がキャッチするいくつかのアクションをシミュレートできます。
Falco は、クラスターインスタンス全体のすべての Pod に対する疑わしいアクティビティをすべてキャッチすることができます。
kubectl exec -it 'nginx2-7844999d9c-wdpz8' /bin/bash 
       以下のようにアクティビティを生成します。
touch /etc/2
cat /etc/shadow > /dev/null 2>&1 
       このテストシミュレーションでは、Falco は以下のように CloudWatch 上にアラートを生成します。


例 2: いずれかの NGINX Pod に入り、以下のステートメントを実行します。これにより “Mkdir binary dirs” というルールがトリガーされます。
kubectl exec -it 'nginx2-7844999d9c-wdpz8' /bin/bash 
       以下のようにアクティビティを生成します。
cd /bin
mkdir hello 
       このテストシミュレーションでは、Falco は以下のように CloudWatch 上にアラートを生成します。

カスタムルールを作成する
サンプルのカスタムルールで YAML ファイルを作成するか、既存のデフォルトルールセットにルールを追加できます。このデモでは、custom_alerts.yaml という新しいカスタムルールセットファイルを作成し、希望するルール条件を入れてみます。この例では、whoami や who といった単純なコマンドに対するアラートを作成します。これらのコマンドが NGINX コンテナ内で実行されると、Falco がアラートを出します。
サンプルの custom_alerts.yaml ファイル:
customRules:
  rules-nginx.yaml: |
    - macro: nginx_consider_syscalls
      condition: (evt.num < 0)
    - macro: app_nginx
      condition: container and container.image contains "nginx"
    # Any outbound traffic raises a WARNING
    - rule: The program "whoami" is run in a container
      desc: An event will trigger every time you run "whoami" in a container
      condition: evt.type = execve and evt.dir=< and container.id != host and proc.name = whoami
      output: "whoami command run in container (user=%user.name %container.info parent=%proc.pname cmdline=%proc.cmdline)"
      priority: NOTICE
      warn_evttypes: False
    - rule: The program "find" is run in a container
      desc: An event will trigger every time you run "find" in a container
      condition: evt.type = execve and evt.dir=< and container.id != host and proc.name = find
      output: "find command run in container (user=%user.name %container.info parent=%proc.pname cmdline=%proc.cmdline)"
      priority: NOTICE
      warn_evttypes: False 
       それでは、セキュリティアラートを追加する新しい設定ファイルで Helm リリースをアップグレードしましょう。
helm upgrade falco -f custom_alerts.yaml falcosecurity/falco 
       以下のような出力が表示されます。
次に、いずれかの NGINX Pod に接続し、次のステートメントを実行します。これによりカスタムルールがトリガーされます。
kubectl exec -it 'nginx2-7844999d9c-wdpz8' /bin/bash 
       そして、以下のようにアクティビティを生成します。
whoami
find 
       このテストシミュレーションでは、Falco は以下のように CloudWatch 上にアラートを生成します。


同様に、アプリケーションやシステムの要件に応じて、いくつでもカスタムルールを作成することができます。カスタムルールの作成に関する詳しい説明はこちらをご確認ください。
カスタム Amazon CloudWatch Logs Insights を作成する
AWS コンソールの Amazon CloudWatch Logs Insights にアクセスし、必要に応じてカスタムインサイトやダッシュボードを作成します。このデモでは、falco という名前のカスタムダッシュボードを作成し、これまでにシミュレーションしたルールに基づいて 2 つのインサイトを追加します。
ルール “Mkdir binary dirs” と “Read sensitive file untrusted” に対する 2 つのインサイトを作成します。これらは過去 3 時間のログを取得して、ログ内のすべてのメッセージを “Mkdir binary dirs” とマッチし、ダッシュボードを作成します。


最終的に、ダッシュボード Falcoは、サンプルとして以下のスクリーンショットのようになるはずです。

カスタム Amazon CloudWatch アラームを作成する
E メールアラートを送信するための適切なアクセス許可を使用して、Amazon SNS トピックと E メールのサブスクリプションを作成します。
AWS コンソールの Amazon CloudWatch にアクセスし、以下のようにアラームを作成します。

LogGroupName の設定で Amazon CloudWatch ロググループ名を選択し、Statistic に適切な値を選択します。このデモでは、 Statistic を Sum とし、アラートの閾値を 1 としました。これにより、Falco が Amazon CloudWatch に少なくとも 1 つのログイベントを送信すると、Amazon CloudWatch アラームが E メールでアラートを出します。この設定では、5 分間のログイベント数が閾値を超えると、すべてログイベントが 1 つのアラートとしてアラートされます。


全体として、アラームは次のスクリーンショットのようになります。

CloudWatch アラームは、以下のように、設定された E メールアドレスに応じてアラートを送信します。

まとめ
この記事では、サンプルの NGINX アプリケーションが動作する Amazon EKS クラスターをセットアップし、CNCF Falco と Amazon CloudWatch によるランタイムコンテナのセキュリティ分析をカスタムダッシュボードとアラームを使用して構成する方法を示しました。CNCF Falco は、標準的なアラートだけでなく、任意のカスタムログをストリームするように構成できます。新しい機能を提案したり、EKS チームによる最新のロードマップを確認したい場合は、Amazon EKS セキュリティの最新のアップデートや EKS セキュリティベストプラクティスの GitHub ページを確認してください。
翻訳はプロフェッショナルサービスの杉田が担当しました。原文はこちらです。