fbpx

ThreatMapperを使って実利用中コンテナの脆弱性を検出してみた

はじめに

Kubernetesがインフラの選択肢に入るようになってからそれなりに経ち、Kubernetesで利用するコンテナイメージの脆弱性スキャンをCI時に実施したりしているかと思います。

しかし、新たに脆弱性が発見されると安全と言われるバージョンが変わっていくので、CI過程でのスキャンだけだと長期利用するコンテナの脆弱性に気がつけない局面もあるかもしれません。

そんな課題を緩和するDeepfence社のOSS、ThreatMapperをご紹介します。

https://github.com/deepfence/ThreatMapper

(かなり多機能なので今回はコンテナスキャンに的を絞ります)

この記事は「これさえ入れておけば全部大丈夫!」といった事は意図しておらず、「セキュリティのスタートラインに立つ」であったり「コンテナの脆弱性スキャン何もやってなければこの辺りからやってみよう」といった意図になります。

本記事での準拠バージョン

本記事では下記を利用します。

HelmChart

  • deepfence-console-2.1.1
  • deepfence-router-2.1.0

主要コンテナイメージ

  • docker.io/deepfenceio/deepfence_server_ce:2.1.1
  • docker.io/deepfenceio/deepfence_router_ce:2.1.1

ThreatMapperをざっくり紹介

ThreatMapperは米国の企業、Deepfence社がApache-2.0 licenseで公開しているOSSでCloud-Native Application Protection Platform (以下CNAPP)の実装のひとつです。

1文で紹介するならば、「クラウド、オンプレ、ベアメタル、VM、コンテナ、コンテナイメージ、Kubernetesの脆弱性、コンプライアンス、シークレット、マルウェアのスキャン・可視化を行ってくれるOSS」になります。

CI中のスキャンやコンテナイメージのスキャンだけでなく、利用中のコンテナやベアメタル/VMサーバを定期的にスキャンする機能もあります。

発見された事項をPagerDuty、Slack、Teamsなどへ連携する設定もできます。

Kubernetesもしくはdocker-composeで動作します。

ホームページ: https://github.com/deepfence/ThreatMapper

GitHubリポジトリ: https://github.com/deepfence/ThreatMapper

公式ドキュメント: https://community.deepfence.io/threatmapper/docs/

https://github.com/deepfence/threatmapper

エンタープライズ版について

ThreatMapperには機能強化/追加を施し、サポートも付いたThreatStrykerという製品があります。

Deepfence社のホストするSaaS版の他、AWS Marketplaceからもご利用可能です。

詳細や機能の比較などはDeepfence社の公式ページを参照してください。

詳細: https://www.deepfence.io/threatstryker

機能比較: https://www.deepfence.io/compare

ThreatMapperで緩和する問題

  • 脆弱性の監視体制が整っていない
  • クラウドのコンプライアンスがちょっと心配
  • シークレットを平文で格納してしまっている
  • マルウェアスキャンを行っていない
  • SBOMが無くてOSS監査に手間取っている

といった問題を緩和することができます。

本記事では実利用中のコンテナに対し定期的に脆弱性スキャンを実行し、ある程度の脆弱性監視体制を整えるまでを実践してみます。

ThreatMapperの構成

基本的にはスキャン対象にエージェントを導入し、ThreatMapper Management Consoleに情報を連携する構成を取っています。

参考画像に表現されていませんが、クラウドのコンプライアンススキャンなどにはエージェントは利用されず、クラウドのAPIを利用するようです。

詳しくは公式のドキュメントを参照してください。https://community.deepfence.io/threatmapper/docs/architecture/

https://github.com/deepfence/threatmapper

ThreatMapper Management Consoleの構築

ここからは構築手順の紹介になります。

consoleの見た目や具体的にどのようなデータが取れるのか確認したいだけであれば公式のdemo環境にログインするのがオススメです。https://community.deepfence.io/threatmapper/docs/demo

システム要件

v2.1現在の要件は画像の通りになります。

最新情報は公式ドキュメントを参照してください。https://community.deepfence.io/threatmapper/docs/console/requirements

お試しにピッタリ、docker-composeでの構築

公式GitHubからdocker-compose.yamlを取得し、docker-composeコマンドより構築します。

wget https://github.com/deepfence/ThreatMapper/raw/release-2.1/deployment-scripts/docker-compose.yml
docker-compose up -d

常設にピッタリ、Helmを使ってKubernetes上に構築

前提

今回はThreatMapper Management Console用と監視対象用の2クラスタを手元のPCにkindを利用して構築、検証しました。

オンプレの場合はStorageClassを準備する必要があります。ThreatMapperの公式ドキュメントではOpenEBSを用いていたので、それに倣いOpenEBSを導入しました。

Ingressリソースは細かくカスタマイズしたかったので、Helm Chartで構築せずに自前で用意する手順を取りました。

また、PostgreSQLだけ上手く稼動しない可能性があるので、その場合は別途bitnami/postgresql Helm Chartで自前構築するかマネージドサービスなどをご利用ください(本記事でも自前で構築しています)。

各種パラメータはThreatMapperの公式ドキュメントを参照してください。 https://community.deepfence.io/threatmapper/docs/console/managed-database 

参考までにbitnami/postgresqlチャートでの構築に利用したvalues.yamlを掲載しておきます。

global:
  postgresql:
    auth:
      postgresPassword: "===CHANGE TO YOUR postgres USER PASSWORD==="
      username: "deepfence"
      password: "===CHANGE TO YOUR deepfence USER PASSWORD==="
      database: "deepfence"

手順

  • Helm Chartを入手する

helm repo add deepfence https://deepfence-helm-charts.s3.amazonaws.com/threatmapper
helm repo update
  • valuesのテンプレートを入手する
helm show values deepfence/deepfence-console --version 2.1.1 > deepfence_console_values.yamlhelm show values deepfence/deepfence-router --version 2.1.0 > deepfence_router_values.yaml
  • valuesのテンプレートを編集し、環境に合わせた値を入れる
    • 長いので差分のみの記載とします。

deepfence_console_values.yaml

global:
  imageTag: 2.1.1
  storageClass: "openebs-hostpath" # AWSの場合はgp3, GCPの場合はstandard
kafka:
  config:
    # kafka-storage.sh random-uuidコマンドなどで生成する
    STORAGE_UUID: "===CHANGE TO YOUR UUID==="
postgres:
  create: false # このHelm ChartでPostgreSQLも構築する場合はtrue
  secretName: "secrets-postgres"
fileserver:
  secrets: # 各シークレットはランダム生成するなりしておく
    MINIO_ROOT_USER: "===CHANGE TO YOUR MINIO USER==="
    MINIO_ROOT_PASSWORD: "===CHANGE TO YOUR MINIO PASSWORD==="
neo4j:
  secrets:
    # set the below to change the default credentials
    # format should be username/password
    NEO4J_AUTH: "neo4j/===CHANGE TO YOUR NEO4J PASSWORD==="

deepfence_router_values.yaml

service:
  type: ClusterIP # LoadBalancer/NodePort/Ingress/ClusterIPから選択
  • 作成したvaluesを用いてThreatMapper Management Consoleを構築する
helm install -f deepfence_console_values.yaml deepfence-console deepfence/deepfence-console \
    --namespace deepfence-console \
    --create-namespace \
    --version 2.1.1

helm install -f deepfence_router_values.yaml deepfence-router deepfence/deepfence-router \
    --namespace deepfence-console \
    --create-namespace \
    --version 2.1.0
  • ThreatMapper Management ConsoleがPostgreSQLに接続するために利用するシークレットを作成しておく
apiVersion: v1
kind: Secret
type: Opaque
metadata:
  name: secrets-postgres
  namespace: deepfence-console
stringData:
  DEEPFENCE_POSTGRES_USER_DB_PORT: "5432"
  DEEPFENCE_POSTGRES_USER_DB_HOST: “===CHANGE TO YOUR POSTGRESQL HOST===”
  DEEPFENCE_POSTGRES_USER_DB_SSLMODE: disable
  DEEPFENCE_POSTGRES_USER_DB_USER: deepfence
  DEEPFENCE_POSTGRES_USER_DB_PASSWORD: "===CHANGE TO YOUR deepfence USER PASSWORD==="
  DEEPFENCE_POSTGRES_USER_DB_NAME: deepfence
  • ユーザ、監視対象のクラスタがThreatMapper Management Consoleに接続するためのIngressを作成する
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/backend-protocol: HTTPS
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    nginx.ingress.kubernetes.io/proxy-body-size: 200m
  name: deepfence-router-ingress
  namespace: deepfence-console
spec:
  ingressClassName: nginx
  rules:
    - host: “===CHANGE TO YOUR FQDN===”
      http:
        paths:
          - backend:
              service:
                name: deepfence-console-router
                port:
                  number: 443
            path: /
            pathType: Prefix
  tls:
    - hosts:
        - “===CHANGE TO YOUR FQDN===”
      secretName: router-tls
  • Helmで構築したpodが正常動作し、Ingressで指定したFQDNにwebブラウザから接続してログイン画面が表示されれば正常に構築が完了しています

使い方

スケジュール機能検証のためにKubernetesホストの時間をずらして検証しているので、一部深夜や未来の時間が表示されたりしていますが、気にしないでください。

ユーザセットアップ

  • webブラウザからThreatMapper Management Consoleに接続する
    • docker-composeで構築した場合は構築マシンのIPアドレス、もしくはFQDNにwebブラウザから接続する。
    • Kubernetesで構築した場合はIngressで指定したFQDNにwebブラウザから接続する。
  • 画面下部のRegister nowから一人目のユーザを登録する

誰でもログイン画面から登録できるかに思えましたが、二人目以降はログイン画面から登録できない仕様のようなので二人目以降は一人目のユーザが招待してください。

監視対象のセットアップ(エージェントの導入)

例としてKubernetesクラスタを監視対象としてセットアップします。

基本的にはログイン後の画面の通りに進めるだけです。

  • 監視対象の種類を選択する
    • ここではKubernetes Clustersを選択
  • ThreatMapper Management Console上に表示するクラスタ名(実際のクラスタ名とは無関係でもOK)やContainer Runtimeに何を使っているか指定する
  • 画面下部にエージェントの導入用コマンドが出力されているので、こちらをコピーして監視対象のクラスタに対して実行する
  • 画面下部のGO TO CONNECTORSを押下し、クラスタが接続されたことを確認する
    • セットアップにある程度時間がかかるので、PODが稼働したらページを更新してみてください。

このままクラスタ全体にスキャンを実施することも可能ですが、ここでは一旦main dashboardに移動します。

監視対象を増やしたい場合はURLを編集して/onboard/に接続するかSettingsのConnection instructionsにアクセスして同様の手順で進めてください

コンテナの脆弱性スキャン

試しにデプロイした古いnginxコンテナに対してスキャンを実施してみます。

コンテナの脆弱性スキャンはTopologyメニューから実施することができます。

コンテナの詳細画面の右上のACTIONSボタンからStart Vulnerability Scanから実施できます。

基本的にはパッケージマネージャのデータを利用してOSパッケージ、各種言語パッケージのSBOMを作成し、脆弱性データベースと突き合わせるようです。

OSのパッケージの他、Java、Javascript、Rust、GoLang、Ruby、Python、PHP、Dotnetが対応している模様です。

注意点ですが、スキャン対象はパッケージマネージャを利用して導入したものに限られそうです。

今回の例ですと、bitnami/nginxイメージではnginxの導入をパッケージマネージャではなくバイナリのコピーで行っているようなので、スキャン結果には引っかかりません。

スキャン結果はVulnerabilitiesメニューから見ることができます。

余談ですがVIEW/DOWNLOAD SBOM機能を利用するとSBOMをダウンロードすることができます。

OSSライセンス監査などにお役立てください。

スケジュール機能

各種スキャンをスケジュールに合わせて実行する機能もあります。

脆弱性スキャンについては週一回、日曜の深夜0時0分@UTC(日本時間日曜日の午前9時0分)に行うルールがあります(デフォルトは無効)。

こちらを有効化すると定期的にコンテナの脆弱性をスキャンすることができます。

手動などでこれまでにスキャンした事がある対象もスキャンされ、新たにCVE IDが割り振られた脆弱性も発見することができます。

画像では一旦手動でスキャンしたものを日曜の深夜0時0分@UTC(日本時間日曜日の午前9時0分)にスキャンが走った状態を示しています。

任意のスケジュールを設定したい場合にはREST APIをご利用ください。

通知機能

Integrationsメニューから通知やSIEM、LLM等との連携機能が設定可能です。

今回はSlack連携のみ紹介します。

Slackと連携するにはSlackワークスペースにIncoming Webhookアプリをインストール、設定し、得られるWebhook URLをThreatMapperに引き渡します。

この際に何を通知するかや、どのチャンネルに通知するか、通知対象をフィルタするかを設定できます。

意外と簡単にSlack側のレート制限に引っかかるので、適切にフィルタを設定するなり必ずThreatMapper側で確認するなど、利用のルールを定めると良いでしょう。

具体的にSlackにはこのようなフォーマットで通知が届きます。

その他紹介が漏れた機能

ここで詳しくは紹介しませんが、他にどのような機能があるか箇条書きで軽く載せておきます。

  • シークレットのスキャン
  • マルウェアのスキャン
  • 各種クラウド等に対するコンプライアンスのスキャン
    • CIS、PCI-DSS、HIPAA等のベンチマークと照合する機能
  • コンテナレジストリのスキャン
  • CI/CDパイプラインでのスキャン
  • その他連携機能
  • etc…

最後に

CIのタイミング以後でも定期的に稼働中コンテナのスキャンを行い、新たに報告された脆弱性に長期利用中のコンテナでも気がつける環境の構築にThreatMapperが役立つかと思います。

他にも様々な機能があるので、皆様ぜひお試しください。

また機会があれば他の機能についてもご紹介しようかと思います。

Author

色々やらせてもらっている系エンジニア。
Arch Linuxユーザー。

菅野 洋信の記事一覧

新規CTA