コンテナセキュリティのベストプラクティス

By 清水 孝郎 - OCTOBER 12, 2021

SHARE:

Container security feature image

本文の内容は、2021年10月12日に Álvaro Iradierが投稿したブログ(https://sysdig.com/blog/container-security-best-practices/)を元に日本語に翻訳・再構成した内容となっております。 コンテナセキュリティのベストプラクティスにこだわることは、検証済みソフトウェアの提供を成功させるだけでなく、深刻なセキュリティ侵害とその結果を防ぐためにも重要です。 2020年のCNFC調査によると、92%の企業が本番環境でコンテナを使用しており、2016年から300%増加しています。このように、KubernetesやOpenshiftなどのコンテナ技術はあらゆる場所に存在しています。 しかし、コンテナは安全で隔離されたものではないのでしょうか?まあ、そんなところです。 例えば、コンテナ内部の悪用可能な脆弱性が、露出したメタデータや誤った認証情報の設定と組み合わさると、クラウドのインフラ全体を危険にさらすことになります。クラウドラテラルムーブメントの記事で説明したように、ハッカーは、この一連の脆弱性と誤った設定を利用して、お客様のクラウドアカウントでクリプトマイニングアプリケーションを実行することができます。 コンテナは、自己完結型アプリケーションの配布メカニズムとして設計されており、分離された環境でプロセスを実行できるようになっています。 分離の目的で、カーネルカーネルネームスペースを使用する軽量メカニズムを採用し、完全なオペレーティングシステム、CPUとハードウェアの仮想化など、VM内のいくつかの追加レイヤーの要件を排除しています。 このような追加の抽象化レイヤーがないことや、カーネル、オペレーティングシステム、コンテナランタイムとの緊密な結合により、コンテナの内部から外部へ、またはその逆にジャンプするためのエクスプロイトが利用しやすくなります。 Container security feature imageコンテナセキュリティの機能イメージ コンテナセキュリティのベストプラクティスには、配信されるアプリケーションやコンテナイメージ自体だけでなく、コンテナのビルド、配布、特別な実行に使用されるコンポーネントスタック全体も含まれます。 これには以下が含まれます:

  • ホストまたはVM
  • コンテナのランタイム
  • クラスター技術
  • クラウドプロバイダーの構成
  • などがあります。
セキュリティは、開発、配布、実行、検知、脅威への対応など、それぞれの段階で適用することができます。 Diagram security container それでは、一般的な考え方を、DevOpsのワークフローに適用できる18の具体的なコンテナセキュリティのベストプラクティスに分解しながら、興味深い詳細を見ていきましょう。

複雑なスタック

コンテナの成功は、2つの便利な機能によって支えられています。
  • コンテナは、従来のVMイメージよりもはるかに軽量でありながら、すべてのライブラリと依存関係を含む自己完結型の実行イメージとして、ソフトウェアを配布・実行するための非常に便利な方法です。
  • カーネルネームスペースを使用して、マウント、PID、ネットワーク、IPCなどを含む独自の “jail “内でプロセスを実行することで、優れたレベルのセキュリティと分離を提供し、カーネルcgroupsを介してCPU使用量とメモリをリソース制限します。メモリ保護やパーミッションの適用などは、標準的なカーネルセキュリティメカニズムを介して行われます。
VM vs ContainerVMとコンテナの比較 ほとんどの場合、コンテナのセキュリティモデルで十分かもしれませんが、例えば、AWSはサーバーレスソリューションに追加のセキュリティを加えています。これは、Firecrackerというマイクロ仮想マシンの中でコンテナを実行することで実現しています。このマイクロ仮想マシンは、顧客間での侵入を防ぐために、もう一つのレベルの仮想化を追加します。 これはコンテナが安全ではないということなのでしょうか? それは諸刃の剣だと言えます。 コンテナの中で動作するアプリケーションは、マシンの中で直接動作するアプリケーションと変わらず、他の多くのアプリケーションとファイルシステムやプロセスを共有しています。ある意味では、悪用可能な脆弱性を含む可能性のあるアプリケーションに過ぎません。 コンテナ内で実行すると、これを防ぐことはできませんが、アプリケーションのエクスプロイトからホストシステムにジャンプしたり、他のアプリケーションからデータにアクセスしたりすることが非常に困難になります。 一方で、コンテナは、別のカーネル機能、コンテナランタイム、そして通常はクラスターやオーケストレータに依存しており、これらも悪用される可能性があります。 そのため、スタック全体を考慮する必要があり、コンテナのライフサイクルのさまざまな段階でコンテナセキュリティのベストプラクティスを適用することができます。この2つの次元を以下の図に反映させ、各ブロックで適用できるプラクティスに焦点を当ててみましょう:
Prevent Protect Detect Respond
Code (1) Code Scanning(2) Dependencies
CI/CD (1) Code Scanning(2) Dependencies (3) Image Scanning
Registry (3) Image Scanning(4) Signing (10) Verify signature(12) Vuln. Mgmt.
Cloud (5) Configuration(6) IaC Scanning (9) Security Groups(9) Network rules (13) Event and logs(14) Resource monitoring (15) Isolate, investigate, forensics.(16) Fix configuration
Host (5) Configuration(7) Host Scanning (5) Configuration(12) Vuln. Mgmt. (9) Harden security (13) Events and logs(14) Resource monitoring(13) Syscall audit (15) Isolate, investigate, forensics.(16) Fix Configuration (17) Patch vulnerabilities
Kernel (7) Host Scanning (12) Vuln. Mgmt. (13) Syscall audit (17) Patch vulnerabilities
Container Runtime (8) Admission Controller(5) Configuration (5) Configuration(9) Network policies (12) Vulnerabilities Management (10) Verify signature (3) Image Scanning(13) Events and logs (16) Fix configuration(17) Patch vulnerabilities
Live container (11) User Privileges Network Storage(12) Vulnerabilities Management (13) Logs(14) Resource monitoring (13) Syscall audit (17) Update base image Update OS packages Update dependencies Fix application
サーバーレスのコンピュートエンジンであるECS FargateやGoogle Cloud Runなどのように、これらのピースの一部が我々の手に負えない場合もあるので、責任共有モデルで対応しています。
  • プロバイダーは、ベースとなるピースの動作とセキュリティの維持に責任を持ちます。
  • そして、あなたは上位レイヤーに集中することができます。
Shared Responsibility Model責任共有モデル

予防:シフトレフトセキュリティにおける8つのステップ

Shift Left Securityシフトレフトセキュリティ コンテナ内のアプリケーションが実行される前に、脅威の発生を防ぐためのさまざまな技術を適用できる場所がいくつかあります。 予防とセキュリティの早期適用が重要であり、コンテナイメージの開発と配布時にいくつかのグッドプラクティスを適用すれば、最小限の労力で多くのトラブル、時間、コストを削減することができます。

1. CI/CDプロセスにコードスキャンを組み込む

セキュリティスキャンとは、ソフトウェア、構成、インフラを分析し、潜在的な問題や既知の脆弱性を検出するプロセスです。スキャンは、さまざまな段階で行うことができます。
  • コード
  • 依存関係
  • コードとしてのインフラ
  • コンテナイメージ
  • ホスト
  • クラウド構成
  • …などなど
最初のステージであるコードに注目してみましょう。アプリケーションの提供を行う前に、あるいはアプリケーションをビルドする前に、コードをスキャンしてバグや悪用される可能性のあるコード(新しい脆弱性)を検出することができます。 アプリケーションコードについては、さまざまな言語に対応した脆弱性スキャナを提供するsonarqubeや、goのコードを分析し、ルールやリンターなどに基づいて問題を検出するgosecなど、さまざまなSAST(Static Application Security Testing)ツールがあります。 これらを開発者のマシンで実行することもできますが、コードスキャンツールをCI/CDプロセスに統合することで、最低限のコード品質を確保することができます。例えば、いくつかのチェックが失敗した場合、プルリクエストをデフォルトでブロックすることができます。 gosecをGithub Actionで実行する:
name: "Security Scan"
on:
  push:
jobs:
  tests:
    runs-on: ubuntu-latest
    env:
      GO111MODULE: on
    steps:
      - name: Checkout Source
        uses: actions/checkout@v2
      - name: Run Gosec Security Scanner
        uses: securego/gosec@master
        with:
          args: ./...
そして、それに対応する出力: Github Actions Output

2. 依存性スキャンによる外部脆弱性の低減

サードパーティ製のライブラリやフレームワークを使用しないのは、非常にミニマムでトイなアプリケーションだけです。しかし、外部の依存関係にあるコードを再利用することは、これらの依存関係にあるバグや脆弱性をアプリケーションの一部として含むことになります。依存関係のスキャンは、あらゆるアプリケーションのビルドプロセスにおいて、ベストプラクティスとして含めるべきです。 npmmaven、goなどのパッケージ管理ツールは、脆弱性データベースとアプリケーションの依存関係を照合し、有用な警告を提供することができます。 例えば、Mavenでdependency-checkプラグインを有効にするには、pom.xmlにプラグインを追加するだけです:
<project>
    ...
    <build>
        ...
        <plugins>
            ...
            <plugin>
              <groupId>org.owasp</groupId>
              <artifactId>dependency-check-maven</artifactId>
              <version>6.2.2</version>
              <executions>
                  <execution>
                      <goals>
                          <goal>check</goal>
                      </goals>
                  </execution>
              </executions>
            </plugin>
            ...
        </plugins>
        ...
    </build>
    ...
</project>
そして、mavenが実行されるたびに、脆弱性レポートが生成されます: Dependencies check 依存関係にあるものを、修正を加えた新しいバージョンに更新することで、依存関係による脆弱性の導入を回避します。 Dependences tree依存関係のツリー 場合によっては、修正プログラムが利用できなかったり、バージョンを上げるには、破壊的な変更のために多くのリファクタリングが必要になったりするため、これができないこともあります。依存関係のスキャンによって明らかになった脆弱性を分析して、その影響度や悪用可能性を評価し、その脆弱性が悪用されるのを防ぐために、コード内のチェックや保護メカニズムなどの追加措置を導入します。 なお、依存関係を後からスキャンすることも可能ですが、アプリケーションがビルドされると、メタデータの情報が得られないものもあるため、依存関係のスキャンの精度は低くなります。また、GoやRustのように静的にリンクされたアプリケーションでは不可能な場合もあります。

3. コンテナイメージの分析にイメージスキャンを使用する

アプリケーションがビルドされ、パッケージ化されると、ライブラリ、依存するフレームワーク(Python、Nodeなど)、設定ファイルの最小限のセットを持つコンテナ内にコピーするのが一般的です。コンテナのビルドとランタイムに焦点を当てたベストプラクティスについては、「Dockerfileのベストプラクティス Top 20」をお読みください。 イメージスキャナーを使用してコンテナイメージを分析します。イメージスキャンツールは、コンテナイメージのベースディストリビューションが提供するオペレーティングシステムパッケージ(rpm、dpkg、apkなど)の脆弱性を発見します。また、前の段階で依存関係のスキャンを適用していなくても、Java、Node、Pythonなどのパッケージの依存関係にある脆弱性も発見されます。 Image Scanning Schemaイメージスキャンのスキーマ イメージスキャンは、自動化と実施が容易です。CI/CDパイプラインの一部として組み込んだり新しいイメージがレジストリにプッシュされたときにトリガーしたり、クラスターアドミッションコントローラーで検証して、非準拠のイメージの実行が許可されたことを確認したりすることができます。また、Sysdig Node Image Analyzerをインストールして、Sysdig Node Image Analyzerが稼働しているホストでイメージの実行が開始されると同時にスキャンするという方法もあります。 例としては、Sysdig Secure Inline Scan ActionとGithub Actionの統合があります。
name: "Security Scan"
on:
  push:
jobs:
  build-and-scan:
    runs-on: ubuntu-latest
    steps:
    - name: Build the Docker image
      run: docker build . --file Dockerfile --tag my-image:latest
    - name: Scan image
      id: scan
      uses: sysdiglabs/scan-action@v3
      with:
        image-tag: my-image:latest
        sysdig-secure-token: ${{ secrets.SYSDIG_SECURE_TOKEN }}
        input-type: docker-daemon
        run-as-user: root
前述の例では、Dockerイメージをビルドしてから、Dockerデーモンからローカルにスキャンしています。 スキャン結果はアクションの出力の一部として直接提供され、pull-requestはチェックステータスに応じてマージをブロックすることができます: List vulnerabilities脆弱性をリストアップ

4. イメージコンテンツの信頼性確保

コンテナイメージの完全性は、Docker Notaryなどを介してデジタル署名を追加することで強制することができ、アドミッションコントローラーやコンテナランタイムで検証することができます。 簡単な例を見てみましょう:
$ docker trust key generate example1
Generating key for example1...
Enter passphrase for new example1 key with ID 7d7b320:
Repeat passphrase for new example1 key with ID 7d7b320:
Successfully generated and loaded private key. Corresponding public key available: /Users/airadier/example1.pub
これで、「example1」という署名鍵ができました。公開部分は以下の場所にあります:
$HOME/example1.pub
秘密鍵は次の場所にあります:
$HOME/.docker/trust/private/<key ID>.key
他の開発者も自分の鍵を生成し、公開部分を共有することができます。 それでは、許可された署名者の鍵をリポジトリに追加することで、署名付きリポジトリを有効にします(例ではairadier/alpine):
$ docker trust signer add --key example1.pub example1 airadier/alpine
Adding signer "example1" to airadier/alpine...
Initializing signed repository for airadier/alpine...
...
Enter passphrase for new repository key with ID 16db658:
Repeat passphrase for new repository key with ID 16db658:
Successfully initialized "airadier/alpine"
Successfully added signer: example1 to airadier/alpine
そして、リポジトリのイメージに署名することができます:
$ docker trust sign airadier/alpine:latest
Signing and pushing trust data for local image airadier/alpine:latest, may overwrite remote trust data
The push refers to repository [docker.io/airadier/alpine]
bc276c40b172: Layer already exists
latest: digest: sha256:be9bdc0ef8e96dbc428dc189b31e2e3b05523d96d12ed627c37aa2936653258c size: 528
Signing and pushing trust metadata
Enter passphrase for example1 key with ID 7d7b320:
Successfully signed docker.io/airadier/alpine:latest
環境変数 DOCKER_CONTENT_TRUST  1に設定されていれば、プッシュされたイメージは自動的に署名されます:
$ export DOCKER_CONTENT_TRUST=1
$ docker push airadier/alpine:3.11
The push refers to repository [docker.io/airadier/alpine]
3e207b409db3: Layer already exists
3.11: digest: sha256:39eda93d15866957feaee28f8fc5adb545276a64147445c64992ef69804dbf01 size: 528
Signing and pushing trust metadata
Enter passphrase for example1 key with ID 7d7b320:
Successfully signed docker.io/airadier/alpine:3.11
イメージの署名者を確認するには、次のようにします:
$ docker trust inspect --pretty airadier/alpine:latest
Signatures for airadier/alpine:latest
SIGNED TAG   DIGEST                                                             SIGNERS
latest       be9bdc0ef8e96dbc428dc189b31e2e3b05523d9...   example1
List of signers and their keys for airadier/alpine:latest
SIGNER     KEYS
example1   7d7b320791b7
Administrative keys for airadier/alpine:latest
  Repository Key:       16db658159255bf0196...
  Root Key:             2308d2a487a1f2d499f184ba...
環境変数 DOCKER_CONTENT_TRUST  1に設定されていると、Docker CLIは信頼情報のないイメージのプルを拒否します:
$ export DOCKER_CONTENT_TRUST=1
$ docker pull airadier/alpine-ro:latest
Error: remote trust data does not exist for docker.io/airadier/alpine-ro: notary.docker.io does not have trust data for docker.io/airadier/alpine-ro
Connaisseurのようなアドミッションコントローラーを使うことで、Kubernetesクラスターでコンテンツの信頼性を確保することができます。

5. よくあるセキュリティの設定ミスと改善策

ホスト、コンテナランタイム、クラスター、クラウドのリソースが誤って設定されていると、攻撃への扉が開いたままになったり、特権を昇格させてラテラルムーブメントを行うための簡単な方法が生まれたりします。 ベンチマーク、ベストプラクティス、およびハードニングガイドでは、これらの誤設定を発見する方法、問題となる理由、および修正方法に関する情報を提供しています。様々な情報源の中でも、Center for Internet Security (CIS) は最も重要です。非営利団体であるCISは、様々な環境のベンチマークを無料で公開しており、個人や企業がその知識を活かしてコントリビュートすることができます。これは、セキュリティベンチマークのデファクトスタンダードとなっています。 コンテナのセキュリティに関するこのような設定を確実にチェックするには、できるだけ自動化するのが一番です。そのためのツールがいくつか存在し、主に静的な設定分析をベースに、さまざまなレベルの設定パラメータをチェックし、修正のガイダンスを提供することができます。 Sysdig Secureには、コンプライアンス&ベンチマーク機能があり、CISベンチマークをはじめ、PCI DSSSOC 2NIST 800-53NIST 800-190HIPAA、ISO 27001、GDPRなどのコンプライアンス基準に基づいて、すべてのインフラ(Linuxホスト、Docker、Kubernetes、EKS、GKE、Openshiftクラスターなど)をスケジュール、実行、分析することができ、すべてを1つの集中ダッシュボードで行うことができます。 Sysdig secure dashboardSysdigのセキュアダッシュボード 他にも、linux-benchdocker-benchkube-benchkube-hunterkube-strikerCloud CustodianOVALOS Queryなどのツールを利用することができます。

ホストベンチマークコントロール例

Linuxをインストールしたばかりの物理マシン、クラウドプロバイダーでプロビジョニングされた仮想マシン、またはオンプレミスの仮想マシンには、あなたが気付いていない安全でないアウトオブボックスの設定がいくつか含まれている可能性があります。長期間、本番環境で使用したり、インターネットに接続したりする場合は、特に注意しなければなりません。これはKubernetesやOpenShiftのノードにも言えることです。クラウドプロバイダーがプロビジョニングしたクラスターを使用しているからといって、そのクラスターが完全に保護されているとは思わないでください。 CISでは、ディストリビューションに依存しないLinuxのベンチマークを用意しており、Debian、CentOs、Red Hatなど多くのディストリビューションに対応しています。 検出できる設定ミスの例:

Linuxディストリビューションの例

次の図は、CIS Benchmark for Distribution Independant Linuxで提供されているもので、rshサーバが有効になっていないことを確認するための設定です。 CIS best practice example 1

コンテナランタイムのベンチマークコントロールの例

Dockerのようなコンテナランタイムを自分で所有するサーバにインストールする場合、ベンチマークを使ってデフォルトの安全でない構成が改善されていることを確認することが不可欠です。次の図は、Dockerクライアントコマンドの認証が有効になっていることを確認するための設定です。 CIS best practice example 2

オーケストレーターベンチマークコントロールの例

Kubernetesは、デフォルトでは、多くの認証メカニズムをサードパーティの統合によって管理するようになっています。ベンチマークにより、考えられるすべての不安要素に対処することができます。下の画像は、-anonymous-auth引数がfalseに設定されていることを確認するための設定を示しています。 CIS best practice example 3

クラウドベンチマークコントロールの例

クラウドプロバイダーのアカウントにおけるベンチマークは、CSPM(Cloud Security Posture Management)とも呼ばれ、アカウント上のすべての資産のセキュリティをチェックするため、必要不可欠なものです。攻撃につながる可能性のある設定や、プライベートであるべきなのに公開されているリソース(S3バケットなど)、暗号化されていないストレージなどはすべてこのようなベンチマークで定義されます。クラウドアカウントの資産は常に変化しており、すべてが可能な限り安全であることを常に監視しなければならないため、これは自動化が必須のベンチマークです。次の画像は、90日以上使われていない認証情報が無効になっていることを確認する設定チェックの例です。 CIS best practice example 4 part 1CIS best practice example 4 part 2

6. IaCスキャンの導入

クラウドのリソース管理は複雑な作業であり、TerraformやCloudFormationなどのツールはこの負担を軽減してくれます。インフラはコードとして宣言され、別名「Infrastructure as Code」として、リポジトリに保存され、バージョン管理されます。そして、定義の変更を適用して、既存のインフラを宣言に合わせて最新の状態にすることは、自動化によって行われます。 コードとしてのインフラストラクチャーを使用している場合、ApolicyCheckovtfseccfn_nagなどのIaCスキャンツールを組み込んで、インフラストラクチャーを作成または更新する前にその構成を検証します。他のリンティングツールと同様に、IaCスキャンツールをローカルおよびパイプラインに適用し、セキュリティ上の問題を引き起こす変更をブロックすることを検討してください。 checkovの実行例です:
$ pip install checkov
$ checkov --quiet -d .
       _               _
   ___| |__   ___  ___| | _______   __
  / __| '_ \ / _ \/ __| |/ / _ \ \ / /
 | (__| | | |  __/ (__|   < (_) \ V /
  \___|_| |_|\___|\___|_|\_\___/ \_/
By bridgecrew.io | version: 2.0.346
terraform scan results:
Passed checks: 314, Failed checks: 57, Skipped checks: 0
Check: CKV_AWS_108: "Ensure IAM policies does not allow data exfiltration"
        FAILED for resource: aws_iam_policy_document.cloudtrail_ingestor
        File: /modules/ingestor/main.tf:17-31
        Guide: https://docs.bridgecrew.io/docs/ensure-iam-policies-do-not-allow-data-exfiltration
                17 | data "aws_iam_policy_document" "ingestor" {
                18 |   statement {
                19 |     effect = "Allow"
                20 |     actions = [
                21 |       "s3:Get*",
                22 |       "s3:List*",
                23 |       "s3:Put*",
                24 |       "s3:Head*",
                25 |       "sqs:DeleteMessage",
                26 |       "sqs:DeleteMessageBatch",
                27 |       "sqs:ReceiveMessage",
                28 |     ]
                29 |     resources = ["*"]
                30 |   }
                31 | }
...

7. ホストスキャンによるホストの保護

ホストを保護することは、コンテナを保護することと同様に重要です。コンテナが実行されるホストは、通常、Linuxカーネル、一連のライブラリー、コンテナランタイム、その他の一般的なサービスやヘルパーがバックグラウンドで動作するオペレーティングシステムで構成されています。これらのコンポーネントには脆弱性や設定ミスがある可能性があり、実行中のコンテナにアクセスするためのエントリーポイントとして使用されたり、サービス拒否攻撃を受けたりする可能性があります。 例えば、今回のDoS攻撃のように、コンテナランタイム自体に問題があると、ホスト内で新しいコンテナを作成できなくなるなど、稼働中のコンテナに影響が出てしまうことがあります。 ホストの構成を強化することについては、「安全でない構成」のセクションですでに説明しました。しかし、脆弱なコンポーネントをどのようにして検出するのでしょうか。ホストスキャンツールは、カーネル、glibcなどの標準ライブラリ、サービス、さらにはホスト内のコンテナランタイムに存在する既知の脆弱性を検出することができます(コンテナイメージに対してイメージスキャンが行うのとよく似ています)。 Sysdig Host Analyzerは、ホストを透過的にスキャンし、発見された脆弱性をレポートします。 次の図は、ダッシュボード上で一目でリスクを検出することができることを示しています。 この情報を使って、OS、カーネル、パッケージなどをアップデートします。最も重要で悪用されやすい脆弱性を取り除くか、少なくともそれを認識し、ファイアウォール、ホストへのユーザーアクセスの制限、使用されていないサービスの停止など、他の保護メカニズムを適用してください。

8. 安全でないコンテナの実行を防ぐ

最終的な防御策として、Kubernetes Admission Controllerは、安全でないコンテナがクラスター内で実行されるのをブロックすることができます。 Sysdig アドミッションコントローラーでは、スキャン結果に基づいて、セキュリティポリシーに合格しないイメージを実行しているポッドの作成を拒否することができます。 Gatekeeperには強力な言語が用意されており、ポッドの仕様(アノテーションの強制、特権ポッドの検出、ホストパスの使用など)やクラスターの状態(すべてのingressホストがクラスター内でユニークであることを要求するなど)に基づいて、コンテナの受け入れや拒否を行う柔軟なルールを定義することができます。 例として、以下のGatekeeper ConstrainsTemplate (一部のデータは省略されています)は、必要なアノテーションを検出するためのテンプレートを定義しています。
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8srequiredannotations
  annotations:
    description: Requires all resources to contain a specified annotation(s) with a value
      matching a provided regular expression.
spec:
 ...
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredannotations
        violation[{"msg": msg, "details": {"missing_annotations": missing}}] {
            provided := {annotation | input.review.object.metadata.annotations[annotation]}
            required := {annotation | annotation := input.parameters.annotations[_].key}
            missing := required - provided
            count(missing) > 0
            msg := sprintf("you must provide annotation(s): %v", [missing])
        }
        violation[{"msg": msg}] {
          value := input.review.object.metadata.annotations[key]
          expected := input.parameters.annotations[_]
          expected.key == key
          expected.allowedRegex != ""
          not re_match(expected.allowedRegex, value)
          msg := sprintf("Annotation <%v: %v> does not satisfy allowed regex: %v", [key, value, expected.allowedRegex])
        }
このテンプレートを使用して、すべてのサービスがいくつかのアノテーションを持つことを強制することができます:
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredAnnotations
metadata:
  name: all-must-have-certain-set-of-annotations
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Service"]
  parameters:
    message: "All services must have a `a8r.io/owner` and `a8r.io/runbook` annotations."
    annotations:
      - key: a8r.io/owner
        # Matches email address or github user
        allowedRegex: ^([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}|[a-z]{1,39})$
      - key: a8r.io/runbook
        # Matches urls including or not http/https
        allowedRegex: ^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$
他にもたくさんの例が、OPA Gatekeeperライブラリープロジェクトで公開されています。 コンテンツの信頼性を確保し、信頼できるソースから署名されていないイメージを拒否する方法として、Connaisseur Admission Controllerを紹介しました。

プロテクション – コンテナを安全に稼働させる

Protection ビルド時や構成時のコンテナセキュリティのベストプラクティスをランタイムの直前まで遵守しても、コンテナを100%安全にすることはできません。コンテナの新しい脆弱性は日々発見されているため、現在は安全な実際のコンテナも、明日には新たに公開されたエクスプロイトの被害者になる可能性があります。 このセクションでは、コンテナの脆弱性管理と保護対策をワークロードに組み込むための、コンテナセキュリティのベストプラクティスを紹介します。

9. リソースの保護

お使いのコンテナやホストには脆弱性が含まれているかもしれませんし、新しい脆弱性は絶えず発見されています。しかし、危険なのはホストやコンテナの脆弱性そのものではなく、攻撃ベクトルや悪用可能性にあります。 例えば、ネットワークを悪用できる脆弱性の場合、実行中のコンテナや脆弱なサービスへの接続を妨げることで防御することができます。また、攻撃ベクトルがホストへのローカルアクセス(ホストにログインしていること)を必要とする場合、そのホストへのアクセスを制限することができます。 そこで、ホストやクラウドアカウント、リソースにアクセスできるユーザー数を制限し、さまざまな仕組みを使って不要なネットワークトラフィックを遮断します。
  • VM、VPC、インターネット間の通信を制限するために、クラウド事業者ではVPC、セキュリティグループ、ネットワークルール、ファイアウォールルールなどがあります。
  • ホストレベルのファイアウォールでは、必要最小限のサービスのみを公開します。
  • クラスターにはKubernetesのネットワークポリシーを適用し、Service MeshやAPI Gatewayなどのツールを追加することで、ネットワークリクエストをフィルタリングするための追加のセキュリティレイヤーを追加することができます。

10. イメージ署名の検証

イメージコンテンツの信頼性で述べたように、イメージ署名は、イメージが改ざんされていないことを保証する保護メカニズムです。また、イメージ署名を検証することで、タグが発行者によって署名された特定のダイジェストに対応していることを保証し、タグの可変型攻撃の一部を防ぐことができます。下図はこの攻撃の一例です。 Tag mutability attack

11. ランタイム時にコンテナの権限を制限する

コンテナ内で悪用された脆弱性の範囲または「爆発半径」は、コンテナの権限と、ホストや他のリソースからの隔離レベルに大きく依存します。ランタイム時の設定は、以下の方法で既存および将来の脆弱性の影響を軽減することができます。
  • 有効なユーザー:コンテナを root として実行しない。さらに良いのは、ホスト内の実際のユーザーにマッピングされないランダムなUID(Openshiftのような)を使用するか、DockerやKubernetesユーザーネームスペース機能を準備ができ次第使用することです(本記事公開時には利用できていません)。
  • コンテナの権限を制限する:DockerとKubernetesは、能力を落とす方法を提供し、特権的なコンテナを許可しません。SeccompAppArmorは、コンテナが実行できるアクションの範囲にさらに制限を加えることができます。
  • リソース制限を追加する:コンテナがすべてのメモリやCPUを消費して、他のアプリケーションが飢えてしまうことを避ける。
  • 共有ストレージやボリュームに注意する:具体的には、hostPath のようなもので、ホストからのファイルシステムを共有します。
  • hostNetwork、hostPID、hostIPCなどの他のオプション:Kubernetesはコンテナがホストとネームスペースを共有し、隔離性を低下させます。
  • Pod Security Policies(PSP)とSecurity Context Constraints(OpenshiftではSCC)を定義する:クラスターにガードレールを設定し、コンテナの設定ミスを防ぎます。PSPとSCCはアドミッションコントローラーで、セキュリティコンテキストが定義されたポリシーに準拠していない場合にポッドを拒否します。

12. コンテナの脆弱性を賢く管理する

脆弱性を賢く管理・評価しましょう。すべての脆弱性に修正プログラムが用意されているわけではありませんし、今なら簡単に適用できるかもしれません。 しかし、すべての脆弱性が簡単に悪用できるとは限りませんし、悪用するためにはホストへのローカルまたは物理的なアクセスが必要な場合もあります。 など、しっかりとした戦略を立てる必要があります:
  • 修正すべきものの優先順位をつける:ホストやコンテナの脆弱性のうち、スコアや深刻度が高いものに焦点を当てるべきです。これは、リモートから悪用可能であり、公開されたエクスプロイトが利用可能であることを意味することが多いです。脆弱性が古くてよく知られている場合は、自動化された方法で積極的に悪用されている可能性が高くなります。
  • あなたの環境における脆弱性の深刻度を評価してください:ベンダーや使用しているLinuxディストリビューションが提供するスコアや深刻度は良い出発点です。しかし、脆弱性がリモートから悪用可能で、インターネットにさらされていない内部ホストの未使用のパッケージに存在する場合、その脆弱性は高いスコアを得ることができます。そして、それは本番環境でも、開発者の遊び場や実験用のクラスターでも構いません。状況に応じて影響を評価し、それに応じた計画を立てましょう。
  • コンテナやホストを保護するための対策として、修正プログラムの適用を計画します:チケットを作成して追跡し、脆弱性管理を標準的な開発ワークフローの一部にしましょう。
  • 影響がないと判断した場合は、脆弱性の例外を作成する:これにより、ノイズを減らすことができます。例外を恒久的に追加するのではなく、スヌーズを検討し、後で再評価できるようにします。
あなたの戦略は、コンテナの脆弱性スキャナーが、いくつかの基準に従って検出された脆弱性に対して警告を発し、次のような異なるレベルで予防と保護を適用するために使用できるポリシーに反映されるべきです:
  • チケッティング:検出された脆弱性を開発者に通知し、開発者が修正プログラムを適用できるようにする。
  • イメージレジストリ:脆弱性のあるイメージが全て引き出されないようにする。
  • ホスト / カーネル / コンテナ:ランタイム中のコンテナをブロックしたり、保護手段を追加したり、重大な問題が発生したホストやコンテナをKill、隔離、シャットダウンして対応する。
また、継続的な脆弱性スキャンと再評価を行い、ランタイム中のコンテナに適用される新しい脆弱性が発見されたときにアラートを受け取るようにすることも重要です。Sysdig Secureは、脆弱性のフィードが更新されるたびにスキャンポリシーを再評価するので、ここでも役に立ちます。

検出 – 異常な振る舞いに対するアラート

Monitoring ここまでは、予防と保護に焦点を当て、コンテナを可能な限り最高の状態で稼働させ、潜在的な攻撃や既知の攻撃を予測してきました。コンテナのビルド、配布、ランタイム時に予防技術を適用して、正しい権限と保護機能を持たせたり、基盤となるスタックを確保したりすることで、攻撃者の行動範囲を制限することができます。しかし、だからといって、コンテナの実行を忘れて、適用されたセキュリティ対策を信用することはできません。セキュリティ対策が実行されると、攻撃される可能性が出てきます。是正措置を講じてセキュリティインシデントの再発を防ぐためには、アプリケーションの異常な動作や予期せぬ動作を検知する必要があります。 さまざまな攻撃ベクターが存在します。例えば、MITRE ATT&CK は、「実世界での観察に基づく」戦術と技術の広範なリストを提供しており、これを使用して防止策を適用することも、活動を分析して攻撃や侵入が行われていることを意味する異常な動作を検出することもできます。MITRE ATT&CK Matrix for Containersは、特にコンテナ技術を対象とした技術をカバーしています。 Mitre SchemaMitre Schema

13. リアルタイムのイベントおよびログ監査のセットアップ

コンテナセキュリティへの脅威は、さまざまなログやイベントのソースを監査し、異常なアクティビティを分析することで検出できます。イベントのソースには次のようなものがあります。
  • ホストおよびKubernetesのログ
  • クラウドログ(AWSのCloudTrail、GCPのActivity Auditなど)
  • コンテナ内のシステムコール
Falcoは、実行されたシステムコールを監視し、不審なアクティビティに対するアラートを生成することができます。コミュニティに寄贈されたルールのライブラリが含まれており、簡単な構文を使って独自のルールを作成することができます。また、Kubernetesの監査ログにも対応しています。 Falcoの動作例は、Detecting MITRE ATT&CKの記事で見ることができます: Sysdig SecureはFalcoの機能を拡張し、異なるクラウドプロバイダーからのイベントを取り込むこともできます。 例として、以下のルールは、新しいECSタスクがアカウントで実行されるたびにアラートをトリガします:
rule: ECS Task Run or Started
condition: aws.eventSource="ecs.amazonaws.com" and (aws.eventName="RunTask" or aws.eventName="StartTask") and not aws.errorCode exists
output: A new task has been started in ECS (requesting user=%aws.user, requesting IP=%aws.sourceIP, AWS region=%aws.region, cluster=%jevt.value[/requestParameters/cluster], task definition=%aws.ecs.taskDefinition)
source: aws_cloudtrail
description: Detect a new task is started in ECS.
また、Sysdigは、対応するコンプライアンス標準とコントロールでタグ付けされた増え続けるルールのセットを含み、インフラストラクチャーのすべてのセキュリティイベントを調査するための一元化されたダッシュボードを提供しています。 Sysdig Secure dashboard

14. リソースの監視

過剰なリソース使用量(CPU、メモリ、ネットワーク)、使用可能なディスク容量の急激な減少、平均以上のエラーレート、遅延の増加などは、システムで何か異変が起きていることを示すシグナルかもしれません。 Prometheusのようにメトリクスを収集してください。値が予想されるしきい値を超えたときに、すぐに通知されるようにアラートを設定します。意味のあるダッシュボードを使用して、メトリクスの変化を調べ、他のメトリクスの変化やシステムで発生しているイベントと関連付けることができます。 Sysdig Monitor metricsSysdigモニターのメトリクス この例では、リクエストレイテンシーが急激に増加し、リクエストレートが低下していることがわかります。これは、コンテナ内で何かが起こっていることを意味しています(例えば、クリプトマイナーが利用可能なCPUをすべて消費しているなど)。または、レスポンスの低下や潜在的なDoSを引き起こすエクスプロイトがあることを意味しています。同時期に発生した関連するクラスターイベントを確認すると、ポッドが交換されているので、悪意のあるバージョンや単に設定が間違っているバージョンがデプロイされた可能性もあります。

インシデント対応とフォレンジック

Response システムでセキュリティインシデントが発生していることを検知したら、脅威を止め、さらなる被害を抑えるために行動を起こします。単にコンテナを停止したり、ホストをシャットダウンしたりするのではなく、コンテナを隔離したり、一時停止したり、スナップショットを取ったりすることを検討します。優れたフォレンジック分析は、多くの手がかりを提供し、何が、いつ、どのように起こったかを明らかにします。特定することが重要です。
  • そのセキュリティインシデントが実際の攻撃なのか、それとも単なるコンポーネントの誤動作なのか。
  • 具体的に何が起こったのか、どこで発生したのか、影響を受ける可能性のあるコンポーネントは他にあるのか。
  • どのようにしてセキュリティインシデントの再発を防ぐことができるか。

15. 隔離と調査

セキュリティインシデントが検出されたら、それ以上の被害を抑えるために、まず迅速に停止させる必要があります。
  • 停止とスナップショット: 可能な限り、ホストやコンテナを隔離します。コンテナのランタイムが提供するのは、コンテナを「一時停止」するか(「docker pause」コマンドなど)、スナップショットを取ってから停止することでした。ホストの場合は、ファイルシステムレベルでスナップショットを取ってから停止させることが考えられます。EC2やVMインスタンスの場合は、インスタンスのスナップショットを取ることもできます。その後、隔離に進みます。スナップショットを、ネットワークのない安全なサンドボックス環境にコピーして、ホストやコンテナを再開することができます。
  • 探索とフォレンジック: 隔離が完了したら、理想的にはライブのコンテナやホストを探索して、実行中のプロセスを調査します。ホストやコンテナが生きていない場合は、ファイルシステムのスナップショットに注目してください。ログや変更されたファイルを調査します。Sysdig Secure captures のように、イベント発生時のシステムコールをすべて記録することでフォレンジック機能を大幅に強化するツールがありますので、コンテナやホストが死んだ後でも調査することができます。
  • 最後の手段として、侵害されたコンテナやホストを破壊します:疑わしいアクティビティを破壊するだけで、短期的にはさらなる被害を防ぐことができます。しかし、何が起こったのか詳細がわからないと、再発を防ぐことができません。また、次の攻撃が起こるのを待って、再びKillすることを繰り返すという、終わりのないモグラ叩きのような状況に陥る可能性があります。
フォレンジック調査の素晴らしい例を「脅威警報:人気のDiscordボットであるRinBotのサーバーを巻き込んだCrypto miner攻撃」でご覧ください。

16. 設定ミスの修正

調査では、攻撃を可能にした原因を明らかにする必要があります。攻撃原因が判明したら、再発防止のためのセキュリティ対策を行いましょう。ホスト、コンテナ、アプリケーションが危険にさらされる原因は、過剰なパーミッション、露出したポートやサービスなどの悪い設定、または悪用された脆弱性の場合があります。 前者の場合は、誤った設定を修正して、二度と起こらないようにします。後者の場合は、ファイアウォールなどの設定を変更したり、より制限の厳しいユーザーを使用したり、追加のパーミッションやACLなどでファイルやディレクトリを保護したりすることで、脆弱性が悪用されるのを防ぐ(あるいは少なくともその範囲を制限する)ことができるかもしれません。 この問題が環境内の他の資産にも適用される場合は、すべての資産に修正プログラムを適用してください。特に、リモートネットワーク接続を介してエクスプロイトを実行できる場合には、インターネットからアクセス可能なアプリケーションなど、公開される可能性があるものについては、修正を行うことが重要です。

17. 脆弱性へのパッチ

可能な限り、脆弱性そのものを修正してください:
  • オペレーティングシステムのパッケージ(dpkg、rpmなど)の場合:まず、配布ベンダーが修正プログラムを含むパッケージの更新版を提供しているかどうかを確認してください。パッケージまたはコンテナのベースイメージを更新してください。
  • 古いディストリビューションのバージョン:ベンダーが更新版やセキュリティフィックスの提供を停止します。手遅れになる前に、ホストやイメージをサポートされたバージョンにしておきましょう。
  • NodeJS、Go、Javaなどの言語パッケージの場合:依存関係の更新バージョンをチェックします。大きなバージョンの更新で起こりうる破壊的な変更の計画やテストに時間をかけられない場合は、セキュリティ問題を修正するだけのマイナーアップデートやパッチバージョンを探しましょう。しかし、古いバージョンが永遠に維持されるわけではありませんので、事前に計画を立ててください。
  • ディストリビューションがパッチ版を提供していない場合や、保守されていないパッケージの修正プログラムがない場合:修正プログラムが存在する可能性もあり、手動で適用したりバックポートしたりすることができます。これにはいくつかの追加作業が必要になりますが、システムにとって重要なパッケージや、公式の修正版がまだ存在しない場合には必要になることがあります。NVDのようなデータベースの脆弱性リンク、ベンダーのフィードやソース、バグレポートの公開情報などをチェックします。修正プログラムが提供されていれば、それを見つけることができるはずです。
影響を受けるパッケージに適用できる修正プログラムがない場合でも、設定や保護手段(ファイアウォール、隔離など)によって脆弱性の悪用を防ぐことができるかもしれません。また、複雑で脆弱性に関する深い知識が必要になるかもしれませんが、自分のコードで追加のチェックを加えることができます。例えば、Web APIサーバで使用されているJSON処理ライブラリのオーバーフローによる脆弱性は、HTTPリクエストレベルでいくつかのチェックを追加し、オーバーフローにつながる可能性のある文字列を含むリクエストをブロックすることで防ぐことができます。

18. ループを閉じる

残念ながら、ホストとコンテナのセキュリティは、一連のセキュリティコンテナのグッドプラクティスを一度適用するだけで永遠に忘れることができるような一方通行のものではありません。ソフトウェアやインフラは日々進化しているため、複雑さが増し、新たなエラーが発生します。これは、脆弱性や構成上の問題につながります。また、新たな攻撃や悪用方法も絶えず発見されています。 まずは予防とセキュリティのベストプラクティスを盛り込むことから始めましょう。そして、ホストやワークロードだけでなく、クラウドサービスも含めたリソースに保護対策を施します。監視を継続し、異常な動作を検出して、発見されたインシデントに対処、対応、調査、報告します。フォレンジックの証拠があれば、発見された脆弱性を修正し、保護対策を改善して、イメージの再ビルド、パッケージの更新、リソースの再設定を行い、将来のセキュリティインシデントに備えてインシデントレポートを作成する、というループを閉じることができます。 中間では、リスクを評価し、脆弱性を管理する必要があります。複雑で大きな環境で管理すべきインプットの数は圧倒的に多いので、分類して優先順位をつけ、最もリスクの高いものから集中的に管理します。 Diagram security container

まとめ

コンテナセキュリティのベストプラクティスが、DevOpsのワークフローに簡単に適用できることを確認しました。特に、以下のことを覚えておいてください:
  • シフトレフトセキュリティ、最初のステップは予防です。
  • すべての資産を守ること。
  • 組織内で起こっていることをすべて把握し、問題を可能な限り迅速に監視・検出する。
  • 攻撃は避けられないので、インシデント対応を計画する。
コンテナセキュリティのベストプラクティスは、配信されるアプリケーションやコンテナイメージそのものだけではないことを忘れないでください。また、コンテナのビルド、配布、実行に使用される完全なコンポーネントスタックも含める必要があります。 54%のコンテナの稼働時間は5分以内であり、異常な動作や違反を調査することは非常に困難です。 クラウドネイティブセキュリティの重要なポイントの1つは、コンテナのセキュリティリスクにできるだけ早く対処することです。開発ライフサイクルの後半に行うと、クラウド導入のペースが遅くなるだけでなく、セキュリティやコンプライアンスのリスクが高まります。
Sysdig Secureは、これらのコンテナセキュリティのベストプラクティスに従うことを支援します。脆弱性や設定ミスをチェックすることで、セキュリティをシフトレフトさせ、脅威が展開される前に行動できるようになります。わずか数分で設定が完了します。今すぐお試しください!