コンテナのセキュアな運用のために

2020年11月2日(月)
宮崎 悟
連載6回目となる今回は、これまでのまとめと最新の情報について説明いたします。

コンテナのセキュアな運用をするために

前回はコンテナ開発におけるDevSecOpsの適用について説明しました。今回は、これまでのまとめとして、コンテナのセキュアな運用するために必要なことを説明します。

セキュリティ方針の策定

まず重要なのは、サービス設計時の最初にセキュリティポリシーを策定し、それに沿って開発サイクル/運用サイクルの設計を行うことです。この設計で、どのフェーズでツールを使って自動化できるかまで決定することがベストです。できるだけ、自動で行えることは自動化しましょう。以下にセキュリティ要件について決定する方法を説明します。これによりセキュリティレベルが変わり、考慮するポイントも変わります。これは、今までのベアメタル/IaaSなどでサービスを提供する場合と同じです。

1. 会員情報

  • 会員IDとパスワードを保存
  • パスワード確認を平文保存しない
    • 例えばパスワードの片方向ハッシュを保存し、ログイン時に入力したパスワードと保存したハッシュ値の一致を確認すること認証可能
  • MFA(多要素認証=Multi Factor Authentication)の利用を検討する
  • GoogleやMicrosoftなどが提供するMFAに対応した外部のIdP(アイデンティティプロバイダ=Identity Provider)の利用を検討する

2. 購買履歴などの匿名情報

  • 会員情報と個人情報が紐付かない情報は秘匿する必要性が低い

3. 個人情報(氏名、メールアドレス、住所、電話番号などを紐付けた情報)

  • 個人情報はすべて暗号化することが望ましい
  • 暗号化しない場合は、個人情報を保存するサービスを分離する
  • 個人情報が必要な場合のみ、会員IDと紐付いた情報を取得し、使用後データを抹消する
  • 必要な業界標準のセキュリティ基準(GDPR/HIPPAなど)がある場合、それに準拠する

4. 銀行口座、クレジットカードなどの情報

  • データの保存はできるだけしない
  • ペイメント代行サービスを利用する方法が安全
  • サービスがペイメントサービスの場合
    • PCI-DSSなどの関連するセキュリティ基準に従う
    • DB/ファイル/ログ上の重要データを暗号化する

セキュアなコンテナ環境を定義する

セキュアなコンテナ環境というものはどのようなものか、これまでの連載を振り返りながら再定義します。

1. 機密情報を分離する

  1. リソースの分離
  2. シークレットの暗号化
  3. Volumeへの機密情報配置
  4. データベースによる暗号化

2. コンテナ環境を堅牢にする

  1. コンテナホストの堅牢化
  2. アカウント管理
  3. 不要なネットワーク通信の抑制
  4. データ通信の暗号化
  5. 不要なプロセス実行の抑制
  6. コンテナに含まれる脆弱性の検知
  7. 不要なコンテナ起動の抑制

機密情報を分離する

機密情報は、データのセキュリティレベルごとにリソースを分離する必要があります。

リソースの分離

同じKubernetesコントローラ管理下に、セキュリティレベルの異なる別のサービスを配置するのはお勧めできません。最低でもネームスペースは分けるべきです。このようにするべきなのは、以下の理由からです。

  • シークレットの非暗号化
    • etcdが管理するシークレットは、base64エンコードされた文字列であり、デフォルトでは暗号化されていません
  • Kubernetes内のネットワーク通信
    • Pod間の通信は、デフォルトで暗号化されていません
  • コンテナの特権昇格
    • バグや設定ミスによるコンテナの特権昇格(コンテナホストへのrootユーザアクセス権限取得)により、コンテナの起動や別コンテナの情報を取得できる可能性があります

よりセキュリティレベルが高いサービスでは、Kubernetesコントローラを分けるべきです。場合によっては、Podが使用するNodeや、ネームスペースの分離で良い場合もあります。これは、そのサービスが扱うセキュリティレベルによって考慮しましょう。

シークレットの暗号化

etcdが管理するKubernetesのシークレットは、ただのbase64エンコーディングされた文字列です。このためKubernetesを構築するYAMLファイルに、鍵情報などをシークレットへそのまま記述することはセキュリティリスクとなります。この解決策として、シークレットを暗号化するソリューションがあります。

ただしシークレットとして機密情報を管理することは、Kubernetesコントローラ以下すべてのリソースで使用可能になります。また、暗号化で使用する鍵と、復号で使用する鍵は別のKubernetesコントローラで管理すべきです。

また、以下のようにシークレットを外部のKMS(鍵管理システム=Key Management System)やpgpで管理できるリソースなどもあります。ただしこれらは、YAMLファイルなどでは値が暗号化されますが、動作中のシークレット内では復号されたbase64エンコードされた値として扱われている点に注意しましょう。

  • ExternalSecretリソース
    • ExternalSecretリソースは、GoDaddy社がオープンソースで開発しているもので、シークレットを外部のKMSを使用して暗号化するリソースです
  • kubesec
    • kubesecはオープンソースで開発されたコマンドです。シークレットを外部のKMSを使用して暗号化/復号できます。Secret YAMLファイルの値のみ暗号化できるのが特徴です。
  • SealedSecret
    • bitnami社がオープンソースで開発しているもので、シークレットをpgpで暗号化するリソースです。

Volumeへの機密情報配置

Kubernetesで起動するPod(コンテナ)内のファイルシステムは、起動しているNode内のディレクトリ以下に配置されます。Persistent Volumeは、同一リソースのPV(Persistent Volume)をマウントするため、複数Podからマウント可能です。

コンテナはそれ自体が不変(Immutable)であることを求められるため、動作中のコンテナへのファイル書き込みは避けるべきです。また、複数Podからマウント可能なPVに機密情報を配置するのは、情報漏洩の可能性が高くなります。

これらの理由から、ストレージへ暗号化保存するのは避けるべきでしょう。もしPVに機密情報を書き込まなければいけない場合は、暗号化した状態で書き込む必要があります。

データベースによる暗号化

データベースによるカラムベース/テーブルベースの暗号化は、MySQL/PostgreSQL/クラウドプロバイダが提供するマネージドデータベースなど、多くのデータベースで可能です。個人情報などの秘密情報を保管するには、データベースによる暗号化を使用するのが安全です。そして、Pod内で必要なときだけ復号するか、データベースで複号してTLSなどで暗号化した経路で取得すべきでしょう。また、復号したデータを使用後にメモリから削除することも考慮しましょう。

コンテナ環境を堅牢にする

コンテナ環境は、デフォルトの状態ではフラットなネットワークで誰でもアクセスできる状態です。そのため、コンテナ環境自体を堅牢にする必要があります。具体的には、第2回第3回で説明したようなセキュリティ対策を実施する必要があります。

ここでは前記の対策以外の、コンテナ環境を堅牢にするための補足情報を説明します。

コンテナホストの堅牢化

コンテナ環境を堅牢にするためには、まずコンテナホストの堅牢化が必要になります。

コンテナ環境のバージョン管理

現在使用されるコンテナ環境は多岐に渡ります。コンテナエンジンとして、containerdだけでなくCRI-Oが用いられこともあります。両者ともCNCFの基準に従った動作をしますが、異なるアプリケーションである以上、特性も違いますし、バージョンによる機能の違いも把握しなければいけません。また、コンテナエンジンのバージョンアップによって動作が変更されたり、重大な脆弱性のフィックスやバグフィックスが行われることもあります。このことを考慮して、コンテナ環境のバージョンも注意する必要があります。

コンテナのオーケストレーションツールも、いろいろな種類があります。最近はKubernetesがデファクトスタンダードになり、RancherやOpenShiftなどのオーケストレーションツールや、AKS/EKS/GKEなどのマネージドKubernetesも出てきています。Kubernetesもコンテナと同じく、バージョンアップによる機能の変更、脆弱性のフィックスやバグフィックスが行われます。

コンテナホストのOSも現在では、Container Linux(旧CoreOS Linux)のようなコンテナを動作させるのに最低限の機能のみを持たせたOSが使用されます。これらも通常のOSと同様にカーネルおよびアプリケーションのバージョンアップが必要になります。

マネージドKubernetesならばクラウドベンダーに任せることもできますが、彼らが最新のバージョンを使用しているとは限りません。Kubernetesの各リソースがどのバージョンを使用しているか、深刻な脆弱性があるかを把握する必要は依然としてあります。

CSPM(クラウドセキュリティポスチャマネジメント)

構築したKubernetes環境やマネージドKubernetes を使用する場合、Kubernetesやクラウドプロバイダのセキュリティが確かであることを担保する必要があります。CSPM(Cloud Security Posture Management)はKubernetesやクラウドプロバイダのセキュリティを担保し、継続的なセキュリティ診断を行うツールです。

CSPMは、Kubernetes環境について、例えば以下のような機能を提供します。

  • コンテナホストに対する脆弱性スキャン
  • セキュリティポリシー(CISベンチマーク/GDPR/NIST CSF/PCI-DSS)に対応した評価/監視
  • Kubernetes 設定の監査
  • コンテナホストへのアクセス監査
  • インシデント管理

これら機能の詳細は、CSPM製品によって異なります。CSPMを使用することで、コンテナの基盤となるコンテナホストを守り、Kubernetesやクラウドの設定ミスを防ぎます。

rootless コンテナの利用

最近、rootlessコンテナ技術の導入が始まりました。rootlessコンテナはその名のとおり、コンテナサービス自体を非特権ユーザとして動作するサービスです。実装例としてはRed Hat社のPodman、Dockerのrootlessモード、LXCが挙げられます。

コンテナ自体を非特権ユーザとして動作させることで、コンテナへの影響を弱めることができます。例えば、コンテナ内部で特権ユーザとして動作させても、コンテナ外からは非特権ユーザプロセスとして動作させることが可能です。

rootlessコンテナ

rootlessコンテナ

コンテナを非特権ユーザとして動作させるため、ネットワーク/ストレージ/cgroupsなどの機能をユーザ実装として持たなければいけません。ネットワーク実装にはlxc-user-nic/Slirpなどが、ストレージ実装にはFUSE-OverlayFS/VFSなどが、cgroupsにはcgoups v2 /PAMモジュール(pam_cgfs.so)があります。

これらの実装は最新のものですが、セキュリティ的に優れた機能です。今後の進化を見守り、採用を検討しましょう。

アカウント管理

コンテナやKubernetesを使用するアカウントは、セキュリティ上管理する必要があります。開発用と運用管理者のアカウント権限をロールベースで分離し、Kubernetesクラスタすべてを管理するユーザを用意するのは避けるべきです。これは、「root権限ですべての操作を行わない」というOSに関するルールと同様の意味合いを持ちます。

開発環境やサービス環境に、誰がどのようにアクセスできるかを設計/運用する必要があります。そのため開発/運用者は、以下のように個人ごとのアクセス要件を管理する必要があります。下記の項目のうち1~3については、外部のサービスに任せることもできます。

  1. 個人に1つのログインID
  2. パスワードマネージャの導入
  3. MFAによるログイン
  4. クラウドプロバイダ環境/Kubernetesに作成したユーザ/ロールとの紐付け

またコンテナセキュリティソフトウェアにアクセスする際のアカウントも、役割ベースにより「閲覧だけ」「設定変更可能」のように役割を分離できたほうが良いでしょう。

不要なネットワーク通信を抑制する

第2回で説明したとおり、DockerおよびKubernetesはデフォルトでは通信制限を行わないフラットなネットワークを使用します。

Kubernetesのサービスで、サービス間の通信を制限できるため、サービス単位でネットワーク通信を設計する必要があります。また多くのマルウェアは外部への通信を行うため、コンテナから外部への通信の抑制も必要です。外部へ通信する必要があるコンテナは、送信先IPアドレスやポート番号を制限するなどの制御の必要があります。

データ通信の暗号化

上記のとおり、コンテナ環境ではデフォルトで通信制御を行いません。同時に経路の暗号化も保証しません。暗号化可能なCNI(Container Networking Interface)もNode間の通信のみを暗号化するだけで、コンテナ間の通信は暗号化しません。

コンテナ間の通信を暗号化するには、以下の方法があります。

gRPCの使用

gRPCは、Google社が開発したRPC(Remote Procedure Call)の実装で、Web経由のAPIなどの実装としてよく使用されます。特徴として、HTTP/2を使用して暗号化しシリアライズされた通信を行うことが挙げられます。HTTP/2は経路をTLS暗号化して使用するため、コンテナ間の通信としてgRPCを使用すると、必然的に経路は暗号化されます。またセッション開始時に認証処理を行えるほか、トランザクション処理を1つのHTTP/2セッションで処理できるなど、通信の安全性に加えて高速化も見込めます。

Istioの使用

Istioは、マイクロサービスをセキュアにマネジメントするための、オープンソースソフトウェアです。CNCFのプロジェクトの1つで、Kubernetesに対応しています。Istioはネットワークポリシー/負荷状況の収集/認証の役割を担うコントロールプレーンと、Podにサイドカーパターンでコンテナを自動追加するEnvoyで構成されます。

Istio Architect

Istio Architect

Istio Securityより抜粋

Istio は、EnvoyからProxyをPod内に作成し、すべての通信をProxy経由で行うようにします。Proxyは、Podのすべての通信をmTLSにより暗号化します。Proxy間の通信は、KubernetesではなくIstioコントロールプレーンで制御されます。外部からの通信をIstio Ingressで制御すると、Kubernetesよりも高度な負荷状況を考慮したL7ロードバランサとして動作します。

Istioはコンテナ環境のサービスを関数群のように扱うサービスメッシュですが、マイクロサービスであることを意識しなくてもIstioによってコンテナの安全な通信が可能になります。

不要なプロセス実行の抑制

コンテナ内での不要なプロセス実行を行うべきではありません。不要なパッケージを含まないディストリビューションやbusyboxをベースにコンテナを作ることで、不要なコマンドを排除することが第一歩になります。使用すべきでないコマンドを削除したり、動的コンテナスキャンで不要なソフトウェアの起動を防ぐべきです。不要なコマンドとしては、以下のようなものが挙げられます。

curl、wget、openssl、ncなどの通信コマンド、bashやzshなどの高級なシェル、sshd

特定ポートでLISTENしているようなコンテナでは、通信コマンドは不要です。また高級なシェルでは、シェル自体がTCP/IP通信機能を備えるため、使用すべきではありません。sshdもコンテナ環境では不要です。

ps、which、unameなど、コンテナの状態を確認するコマンド

これらのコマンドは攻撃者にとっては有用ですが、実際にコンテナで使用することはほとんどありません

また、コンテナ起動後に作成したファイルの実行を許さないことや、プロセスの再起動を抑制することも重要です。コンテナへの攻撃は、既知の脆弱性もしくは一見マルウェアと判断できないプロセスを使用して、攻撃コードを外部から取得することがあるためです。外部から取得したコードの実行や、設定ファイルを上書きした状態でのプロセス再起動はとても危険です。

対策としては、以下のものが考えられます。

  • コンテナへのファイル書き込みを禁止する
  • コンテナに書き込まれたことを検知し、コンテナを停止する
  • 書き込まれたファイルの実行を許可しない

コンテナに含まれる脆弱性の検知

第3回でも説明したように、ソフトウェアの脆弱性は発生し続けます。そのため使用しているイメージを日々静的スキャンし、新たな脆弱性をいち早く発見し、脆弱性への迅速な対処が必要です。

またユーザが作成したアプリケーションも、他のソフトウェアと同様に脆弱性の有無をチェックする必要があります。アプリケーションに対する静的スキャンや、定期的なペネトレーションテストの実施が必要です。

不要なコンテナ起動を抑制する

Pod内のコンテナは1つのホストとして扱われます。そのためPodに未知のコンテナが追加されることは、第三者からの攻撃である可能性があります。通常そのようなことは不可能ですが、ソーシャルハックなどによりKubernetesのコントロールを奪われた場合は実行可能になります。またクリプトマイニング(暗号通貨の採掘)やbotとして、リソースを不正利用する目的で起動するPodも考えられます。そのため多層防御の観点からも、静的スキャン済でセキュリティソフトウェアに「使用可能」と登録されていないイメージは、起動を禁止すべきです。

IstioなどPodへ自動的にコンテナ追加を行うサービスはありますが、それらはコントロールプレーンで制御されます。使用されたコンテナもセキュリティソフトウェアによって登録されたイメージを使用することで、Istioによる不正イメージの実行も抑制できます。

その他、コンテナ環境のセキュリティ施策

コンテナは、仕組み上セキュアにアプリケーション単体を動作させることが容易になります。しかし、運用を間違うとセキュリティに穴が発生するのは、今までのオンプレ/IaaSの環境と同じです。以下では、コンテナ開発/運用で気をつけるべき事項を追記します。

スタティックリンクバイナリ

Go言語などで書かれたプログラムを、スタティックリンクバイナリ(使用するライブラリを内蔵し「.so」ファイルを使用しない実行形式)として生成し、コンテナ内で実行可能です。この方法ではベースOSも必要としないため、バイナリ1つを含むコンテナを作成可能です。ただし気をつけなければいけないのは、スタティックリンクバイナリで使用するライブラリに脆弱性が見つかった場合、その検知が難しいことです。この場合、脆弱性を検知するためには、バイナリの特定パターンを見つけるしかありません。実行形式に対し、strip(関数名などシンボル情報の削除)を行っている場合は、さらにその難易度が上がります。

この方法はメリットも多いですが、使用する際はアプリケーション作成者がイメージ作成時に使用するライブラリの脆弱性を検知する必要があります。

既知のWebサイトへの攻撃手法

コンテナでは必要なポートしか通信を受け付けないため、安全であるという説明をしました。しかしWebサイトに対する攻撃手法(SQLやHTTPに対するインジェクション)などへの対応は、コンテナへの攻撃とは別の話です。今までのWebアプリケーション開発と同様に、これらの対処は必要です。また、未知の攻撃手法などもありえるでしょう。

開発するWebアプリケーションに対して、既存の攻撃手法への対処は依然必要となります。これらは最新のアプリケーションライブラリにより対処可能です。アプリケーションライブラリへの脆弱性も、コンテナの静的スキャンで検知可能な場合があります。

そして、必要であればふるまい検知などを備えたWAFの導入を検討すべきでしょう。これは、今までのWebサイトへの攻撃対策とまったく同じです。

マルウェアのインジェクション

実行中のコンテナへのマルウェアのインジェクション(注入)も、日々新しい方法が発見されています。脆弱性や設定ミスを使用した攻撃などが知られていますが、コンテナ独自の攻撃手法もあります。これらの攻撃の発見は、実際にブラックボックス内で実行しての解析で発見されました。これらの攻撃は、コンテナ/Kubernetes環境設定の検査や、コンテナの動的スキャンによって防げるものもあります。いくつか例を上げていきます。

コンテナ環境を対象としたマルウェアKinsing

コンテナ環境を対象としたマルウェアKinsing日本語訳)は、Dockerの設定ミスを突いたマルウェアです。Kinsingは、間違って設定されたオープン状態のDocker Daemon APIポートを攻撃対象としています。公開されたAPIポートを使用して、マルウェアを含むコンテナを実行し続けることで、以下の攻撃を行います。

  • セキュリティ対策の無効化とログのクリア
  • 多数のアプリケーション(クリプトマイナーを含む)を停止
  • Kinsingと競合するクリプトマイナーソフトウェアの削除
  • 競合する悪意のある Docker コンテナを強制終了し、そのイメージを削除
  • Kinsingマルウェアのダウンロードと実行

Kinsingマルウェアは、クリプトマイニングを実行し、他ホストへのKinsing攻撃も行います。攻撃者によるクリプトマイニングにより、攻撃者に計算リソースを横取りされる形になります。

DzMLTによるクリプトマイニング

DzMLTによるクリプトマイニング日本語訳)攻撃が発見されました。この攻撃は、DockerHub上に存在するイメージを使用します。このイメージに含まれるプログラムは、静的スキャンでは検知されないことが特徴です。コンテナのENTRYPOINTでsshdを起動したり、コンテナ起動後にGitHubから悪意のあるプログラムをダウンロードし実行します。sshによるバックドアを用意したり、ダウンロードしたプログラムによってクリプトマイニングを行います。

攻撃者が悪意あるイメージをホスト上に直接ビルド

攻撃者が悪意あるイメージをホスト上に直接ビルド日本語訳))する攻撃が発見されました。この攻撃は、間違って設定されたオープン状態のDocker Daemon APIポートを攻撃対象としています。Kinsingと異なるのは、コンテナイメージを攻撃対象のホストでビルドすることです。そのため、イメージはどこのレジストリにも保存されず、誰からも確認/対応されることがありません。またイメージの名前/IDをランダムに生成し、各ホストに固有のものにすることで、さらに発見されにくくしています。この攻撃では、ビルドしたイメージを実行することでクリプトマイニングを実施します。

おわりに

今回は、コンテナのセキュアな運用するために必要なことを説明しました。外部からの攻撃は脆弱性/設定ミスなどを突いて行われます。しかし、これまでのオンプレミス/IaaSなどと同じセキュリティ施策や、ソーシャルハックによる権限奪取などの危険性は同じく存在します。特にセキュリティ要件の高いサービスは、今まで同様に正しくセキュリティ運用サイクルを回すことで、セキュアな状態を保ち続ける必要があります。セキュリティ要件の低いサービスでも、すでにコンテナがクリプトマイニングなどのターゲットとなっていることを忘れず、最低限のセキュリティ対策を適用決定しましょう。

今回で、この連載は最後になります。連載の機会を頂いたThinkIT様と、読者の皆様に感謝を述べさせていただきます。ありがとうございました。

国立函館高専を卒業後、UNIX、Windowsアプリケーションの開発、 Solaris/Linuxでのシステム構築に従事した。 OS、仮想化技術、セキュリティを得意とする。 https://www.slideshare.net/satorumiyazaki
https://speakerdeck.com/smiyaza/

連載バックナンバー

セキュリティ技術解説
第6回

コンテナのセキュアな運用のために

2020/11/2
連載6回目となる今回は、これまでのまとめと最新の情報について説明いたします。
セキュリティ技術解説
第5回

コンテナ開発へのDevSecOpsの適用

2020/8/4
連載5回目となる今回は、コンテナ開発におけるDevSecOpsの適用について解説します。
セキュリティ技術解説
第4回

コンテナのネットワーク制限

2020/7/2
連載4回目となる今回は、コンテナのネットワーク通信の制限について解説します。

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています