ブログ

Falcoを利用したGKE セキュリティ, Pub/Sub および、 Cloud Functions

Falcoを利用したGKE セキュリティ, Pub/Sub および、 Cloud Functions

本文の内容は、2019年5月14日にSysdigのMateo Burilloが投稿したブログ(https://sysdig.com/blog/gke-security-using-falco/)を元に日本語に翻訳・再構成した内容となっております。

このブログでは、GKEセキュリティスタックを構築し、異常検知とコンテナランタイムセキュリティ脅威を防ぐ方法について説明して行きます。 FalcoランタイムセキュリティエンジンをGoogle Cloud FunctionsおよびPub/Subと統合します。

このGKEセキュリティスタックは、2つの異なるデプロイメントで構成されています:

  • Kubernetes Falcoエージェント:Kubernetesノードから直接ランタイムセキュリティイベントを収集します。異常な動作を検出するには、クラスタにFalcoをインストールする必要があります。
  • サーバーレス/クラウドプレイブック:Google Cloud Functionsセットとして、トリガーされたときにセキュリティプレイブックを実行(疑わしいポッドの強制終了または隔離など)します。

これらは、Google Pub/Subを使用して通信します。

完全なGKEセキュリティスタックを説明する前に、これから使用する構成要素について詳しく学んでいきましょう!

GKE security向けのFalcoの紹介

Falcoは、KubernetesなどのCloud Nativeプラットフォーム用のコンテナセキュリティ用のオープンソースプロジェクトです。 もともとSysdigで開発されましたが、現在は、CNCF傘下の独立したプロジェクトです。

SysdigのオープンソースLinuxカーネル計測を利用して、Falcoはシステムの振る舞いについての深い洞察を得ます。 その後、ルールエンジンは、アプリケーション、コンテナ、基盤となるホスト、およびコンテナプラットフォーム自体における異常なアクティビティおよびランタイムセキュリティの脅威を検出できます。

Falcoエンジンは、YAMLファイルを使用して記述された一連のデフォルトおよびユーザー定義のセキュリティルールを動的にロードします。 以下は、コンテナを対象としたFalcoランタイムセキュリティルールのトークン例です。

- rule: Terminal shell in container
  desc: A shell was used as the entrypoint/exec point into a container with an attached terminal.
  condition: >
    spawned_process and container
    and shell_procs and proc.tty != 0
    and container_entrypoint
  output: >
    A shell was spawned in a container with an attached terminal (user=%user.name %container.info
    shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline terminal=%proc.tty)
  priority: NOTICE
  tags: [container, shell]

上記の規則は、実行中のコンテナにターミナルシェルをアタッチしようとする試みを検出して通知します。 これは、通常起こりえない事象です。(少なくとも本番環境、ユーザー向けインフラストラクチャでは起こりえません)。 本ブログではFalcoルールの形式や機能を完全に説明することはできませんので、ここではデフォルトのセキュリティルールセットを使用します。必要に応じて、独自のコンテナセキュリティルールを作成およびカスタマイズする事も可能です。

また、Falcoはカーネル計装データソースを利用しているだけでなく、Kubernetes Audit Logなどの他のランタイムソースからのセキュリティ関連のイベントを利用する事もできます。以下は、予期しないKubernetes ClusterRoleの改竄を検出するように設計されたFalcoルールの例です。

- rule: System ClusterRole Modified/Deleted
  desc: Detect any attempt to modify/delete a ClusterRole/Role starting with system
  condition: kevt and (role or clusterrole) and (kmodify or kdelete) and (ka.target.name startswith "system:") and ka.target.name!="system:coredns"
  output: System ClusterRole/Role modified or deleted (user=%ka.user.name role=%ka.target.name ns=%ka.target.namespace action=%ka.verb)
  priority: WARNING
  source: k8s_audit
  tags: [k8s]

GKE セキュリティスタック: Falco, Pub/Sub と Cloud Functions

Falcoを拡張するために、スタックの一部として、Google Cloud FunctionsとGoogle Cloud Pub / Subの2つのGoogle Cloudテクノロジを統合します。

Google Cloud Functionsは、開発者がサーバーやランタイム環境を管理することなくCloudイベントに応答する単一目的のスタンドアロン機能を作成するための軽量コンピューティングソリューションです。 このサーバーレスアプローチを使用して、セキュリティプレイブック、つまりFalcoエンジンからのイベントデータとコンテナメタデータに基づく自動修復アクションを実装していきます。

一連のプロデューサとコンシューマ間の非同期通信には、効率的で信頼性の高いメッセージングミドルウェアが必要です。 これらのソリューションは一般的にPublish/Subscribeメッセージング(PubSub)として知られています。 Google Cloud Pub/Subを使用することで、2つの主要な構成要素の通信に関連するすべての複雑さを抽象化できます。

下記のダイアグラムが全体像となります。

以下アルファベット順:

A - GKE cluster と Kubernetes nodes

監視および保護を行う対象のKubernetesクラスタです。 GKEセキュリティワークフローの開始(セキュリティの脅威を検出)、終了する(修復アクションを実行する)箇所となります。

B - DaemonSetを用いてFalcoをデプロイメント

FalcoはKubernetes DaemonSetとしてデプロイされます。つまり、各KubernetesノードでFalco podが実行されます。 このpodは2つのコンテナー「C」と「D」で構成されています。

C - Falco クラウドネイティブランタイムセキュリティエンジン

上記で説明しましたFalcoセキュリティエンジンはコンテナ内で実行されます。ホストとコンテナーのアクティビティを監視し、トリガーされたセキュリティイベントをコンテナー「D」に転送し続けます。

Falcoによって生成されたセキュリティイベントメッセージを見て行きましょう:

{ 
   "output":"17:10:29.724747835: Notice A shell was spawned in a container with an attached terminal (user=root nginx1 (id=06b29170462e) shell=bash parent=<NA> cmdline=bash  terminal=34816)",
   "priority":"Notice",
   "rule":"Terminal shell in container",
   "time":"2019-03-28T17:10:29.724747835Z",
   "output_fields":{ 
      "container.id":"06b29170462e",
      "container.name":"nginx",
      "evt.time":1553793029724747835,
      "proc.cmdline":"bash ",
      "proc.name":"bash",
      "proc.pname":null,
      "proc.tty":34816,
      "user.name":"root"
   }
}

必要な情報は、全て揃っています:

  • トリガーされたセキュリティルール
  • 影響のあるコンテナー(および、そのID)
  • イベントタイムスタンプ
  • 侵害されているユーザ、プロセスID

コネクターサイドカーコンテナー"D"へイベントが渡されます。

D - Falco Pub/Subサイドカーコネクター

このコンテナは、セキュリティイベントのJSONペイロードをGoogle Cloud Pub / Subキューに送信する前に受信して処理します。

E - Google Cloud Pub/Subメッセージブローカー message

このミドルウェアは、Falcoイベント・エミッター(B)とサーバーレス機能コンシューマー(F)の間の接続を管理します。

このメディエーションで、2つのパーツを別々に交換することができます。相手側がまだメッセージを送受信する準備ができていない場合はイベントを使用します。また、必要に応じて、将来様々なイベントコンシューマを異なる目的で接続する事も出来ます。

F - Google Cloud Functionして実装されたセキュリティプレイブック

Google Cloud Functionsを使用すると、インフラストラクチャのサポートやメンテナンスを気にする事無しにセキュリティ機能を実装することができます。

様々な、セキュリティプレイブックを実装する事が可能です:

  • 問題のあるポッドをKilllする
  • セキュリティインシデントに対して高度なフォレンジックを行うためにSysdigキャプチャを生成する
  • ネットワークからpodを隔離する
  • Slack通知を転送する
  • セキュリティイベントがトリガーされたノードを隔離する
  • 等々、、

これらの機能はPubSubトピックをサブスクライブします。運用上のワークフローは以下のように要約できます:

  • PubSubサブスクリプションフックは、パイプで待機している新しいセキュリティイベントが発生する毎に関数へ通知します。
  • 個々の関数はすべてイベントを解析し、イベントタイプとコンテナのメタデータに応じてレスポンスを起動するかどうかを決定します。
  • この機能が起動されると、Kubernetes API(H)に通知し、あらかじめ設定された修復アクションを実行します。

G - Kubernetes API server

GKEは、Google Cloud機能要求を承認して受け入れるKubernetes APIエンドポイントを提供しています。 アクションはクラスタ内で実行され(つまり、問題のあるポッドは効果的に削除されます)、サイクルを完了します。

H - Google Cloud セキュリティコマンドセンター

Falcoセキュリティエンジンは、セキュリティイベントとアラートをGoogle Cloud セキュリティコマンドセンター用に変換し、転送することができます。 このシンプルなな統合だけで、GCSCCはFalcoランタイムエンジンのSIEMとしても機能します。

FalcoでGKEにセキュリティを実装する

もうセオリーは置いておいて、GKEにセキュリティスタックを実装していきましょう!

下記が必要となります:

  • Google Kubernetesエンジンを使用して作成されたKubernetesクラスタ
  • Googleクラウドアカウントに接続するように初期化および設定されたgcloud cliツール
  • GKE Kubernetesクラスタに接続できるように設定されたkubectl cliツール
  • Google Pub / Subトピックをすばやく作成するために開発したオートメーションを使用している場合は、利用可能なテラフォーム
  • Kubernetes Response Engineリポジトリのクローン

GKE上に必要なインフラストラクチャーを作成する

Sysdigはオートメーション化に着目しています。 Pub / Subトピックを作成することは大したことではありませんが、このタスクを自動化するためにTerraformマニフェストを作成しました。

まず始めにリポジトリーをクローンします:

$ git clone https://github.com/falcosecurity/kubernetes-response-engine.git

次のステップは、デプロイメントディレクトリにアクセスし、google-cloudディレクトリを選択して、Pub / Subトピックをデプロイするためにmakeと入力するだけです。

$ cd kubernetes-response-engine/deployment/google-cloud
$ make

もちろん、Google Cloudプロジェクトの必須設定を指定する必要があり、環境変数の使用を推奨しています。direnvのようなもので参照のために値を保持することもできます。 Google Cloud Consoleツールを使用する事も可能です。

GKE上にFalcoをインストールする

上述のように、このソフトウェアスタックは2つの主要なビルディングブロックで構成されています。 クラスタ内にソフトウェアFalco DaemonSetのインストールを行なっていきます。

FALCOをGKEにデプロイする方法はいくつかありますが、今回はGoogleマーケットプレイスを使用して行います。 マーケットプレイスにアクセスしてFalco Kubernetesアプリケーションを選択したら、FalcoをGKEクラスターにデプロイするように構成します。

以下のフィールドへの設定が必要です:

  • FalcoのPub / Sub outputを有効にする:FalcoがPub / Subにアラートを送信できるようにするには有効にする必要があります。
  • Falcoがアラートを送信しようとしているPub / Subトピック:FalcoをGoogle Cloud Functionsに接続するPubSubトピックの名前。たとえば、falco-pubsubのように任意の名前を使用できます。機能を同じトピックに関連付ける必要があります。
  • Pub / Subトピックがデプロイされているプロジェクト:KubernetesクラスターをホストしているGoogle Cloudプロジェクト。GoogleCloud WebコンソールからプロジェクトIDを確認できます。
  • FalcoからPub / SubトピックへのAertの発行に使用されるサービスアカウントの資格情報:いくつかのGoogleクラウドサービスで認証するためには、IDを提供する必要があります。この場合、Pub / Subトピックにメッセージを送信するための認証が必要です。 Google Cloudのドキュメントで、サービスアカウントキーの作成方法と管理方法に関する詳細情報を入手できます。 JSONファイルを入手したら、それをフィールドにコピーすることも、必要に応じてbase64でエンコードしてそのコンテンツをフィールドにコピーすることもできます。

Falcoをデプロイした数分程度後に、ポッドが稼働している事を確認できます(ノードごとに1つ)

$ kubectl get pods
NAME                   READY   STATUS    RESTARTS   AGE
sysdig-falco-1-mwv2j   2/2     Running   1          2m
sysdig-falco-1-t2prc   2/2     Running   1          2m
sysdig-falco-1-zldz2   2/2     Running   1          2m

ご覧のとおり、ポッドごとに2つのコンテナーがあります(READY列)。 クラスタ内のパートは準備完了です。次は、サーバレスエンティティをデプロイしていきましょう!

Google Cloud機能としてのGKE用セキュリティプレイブックのデプロイする

kubernetes-response-engineリポジトリをすでにクローンしている場合は、ディレクトリをplaybooksディレクトリに変更します。

$ cd kubernetes-response-engine/playbooks

このリポジトリでは利用可能なさまざまなサーバーレス機能の一覧を確認できます。

$ ls functions/
capture.py  delete.py  demisto.py  isolate.py  phantom.py  slack.py  taint.py

GKEセキュリティスタックの動作を確認するためにこれらの関数の1つをデプロイしてみます。 利用可能な機能の完全なリストとその目的および入力パラメータをここで確認できます。

デプロイをする機能はdeleteです。 これを処理するシェルスクリプトを提供しています。コマンドを1つ入力するだけで完了です。

$ ./deploy_playbook_gke -p delete -t falco-alerts -s falco.notice.terminal_shell_in_container -k <cluster_name> -z <gcloud_zone> -n <gcloud_project>
  • cluster_name:セキュリティ保護しようとしているKubernetesのクラスタ名。
  • gcloud_zone:リソースを管理するGoogle Cloudのデフォルトゾーン。Kubernetesクラスタがデプロイされているゾーンと同じゾーンを使用できます。
  • gcloud_project:KubernetesクラスタをホストしているGoogle Cloudプロジェクトです。GoogleクラウドWebコンソールからプロジェクトIDを確認できます。

これらのフィールドはすべてGoogle Cloud Console上で確認する事もできます。

スクリプトを実行すると、以下のようになります。

Fetching cluster endpoint and auth data.
kubeconfig entry generated for sysdig-work.
Deploying function (may take a while - up to 2 minutes)...done.
availableMemoryMb: 256
entryPoint: handler
environmentVariables:
  KUBECONFIG: kubeconfig
  KUBERNETES_LOAD_KUBE_CONFIG: '1'
  SUBSCRIBED_ALERTS: falco.notice.terminal_shell_in_container
eventTrigger:
  eventType: google.pubsub.topic.publish
  failurePolicy: {}
  resource: projects/<gcloud_project>/topics/falco-alerts
  service: pubsub.googleapis.com
labels:
  deployment-tool: cli-gcloud
name: projects/<gcloud_project>/locations/us-central1/functions/delete
runtime: python37
serviceAccountEmail: <gcloud_project>@appspot.gserviceaccount.com
sourceUploadUrl: [...]                                                                                                                                       
status: ACTIVE
timeout: 60s
updateTime: '2019-04-10T15:17:24Z'
versionId: '1'

これで完了です!Googleコンソールでも確認できます。

GKEセキュリティブックでアクション!

これらの機能をテストするために、ランダムに餌食にするポッドを作成することができます。

$ kubectl run --generator=run-pod/v1 nginx-falco --image=nginx       
pod/nginx-falco created


$ kubectl get pods
NAME                   READY   STATUS    RESTARTS   AGE
nginx-falco            1/1     Running   0          5s

次に、このコンテナー内に対話式シェルを生み出すセキュリティーインシデントをシミュレートします。

$ kubectl exec -it nginx-falco bash                          
root@nginx-falco:/# command terminated with exit code 137

ご覧のとおり、bashプロセスとポッド自体は終了しました。

Falcoエンジンによって生成されたログを確認しましょう。

$ kubectl logs -l role=security -c falco | grep "nginx-falco"
{"output":"16:16:47.908565738: Notice A shell was spawned in a container with an attached terminal (user=root k8s.pod=nginx-falco container=0042056722bb shell=bash parent=<NA> cmdline=bash  terminal=34816)","priority":"Notice","rule":"Terminal shell in container","time":"2019-04-01T16:16:47.908565738Z", "output_fields": {"container.id":"0042056722bb","evt.time":1554135407908565738,"k8s.pod.name":"nginx-falco","proc.cmdline":"bash ","proc.name":"bash","proc.pname":null,"proc.tty":34816,"user.name":"root"}}

あなたの関数名(delete)をクリックして、関数実行に関連するログをチェックしましょう:

デプロイしたGKEセキュリティパイプラインは機能し、オペレーション全体のすべてのログを確認できます!

GKE ハッカーの皆さん、ようこそFalcoへ :)

この記事の内容を広範囲に発散させないために、デフォルトのFalcoルールセットと単純な「terminal shell in container」の例を使用しました。 しかし、Falcoエンジンでできることは他にもたくさんあります。

  • 特定のCVEが公開された後にすぐに対応して、インフラストラクチャを即座に保護できます。
  • Kubernetes監査ログを解析してクラスタレベルでの異常な操作を検出可能です。これは、Kubernetesユーザーまたはソフトウェアエンティティに関連するサービスアカウントによって実行されます。
  • Falcoレポジトリで利用可能なプレイブックライブラリと機能を拡張する独自のセキュリティプレイブックを作成し、それらをサーバーレス機能としてデプロイできます。

このGKEセキュリティスタックに何らかの変更を加えた、またはそれを使用していてフィードバックを共有したい場合は、是非、我々にあなたの経験についてお聞かせください!

ご質問・お問い合わせはこちら

top