RBAC、IMDSの保護、監査ログでAmazon EKSのセキュリティを強化
Kamil Potrec
2021年7月7日
0 分で読めますInfrastructure as Code(IaC)の設定ミスは、コードの脆弱性と同じくらい危険です。設定の小さな間違いによって、機密データがインターネット上で閲覧可能になったり、プライベートエンドポイントやダッシュボードが匿名ユーザーからアクセス可能になり、侵害の足がかりとして悪用されたりするおそれがあります。最近のセキュリティ調査では、Kubernetesプラットフォームを標的とするマルウェアの増加が報告されており、安全な設定の必要性が浮き彫りになっています。
このブログシリーズでは、Amazon Elastic Kubernetes Service(EKS)のデプロイで使われるデフォルト設定を見ていきます。そして、小さな設定ミスや意図しない副作用が、どのようにクラスターをEKSのセキュリティ上の問題にさらすのかを解説します。
Amazon Elastic Kubernetes Serviceとは?
Amazon Elastic Kubernetes Serviceは、マネージドKubernetesサービスです。AWSはクラスターのコントロールプレーンコンポーネントの管理を担い、ユーザーはワーカーノードとクラスターリソースを管理します。
Amazon EKSは、コントロールプレーンの高可用性とスケーラビリティに加え、Identity and Access Managementとの連携によるロールベースアクセス制御の管理、KubernetesサービスアカウントとIAMロールの関連付け、需要に応じてワーカーのキャパシティを自動スケーリングするマネージドノードグループ、ログの一元管理などを提供します。機能の全一覧はAmazon EKS公式ドキュメントをご覧ください。
追加コスト以外にマネージドサービスを利用するデメリットとして、コントロールプレーンの設定を細かく制御できなくなることや、コントロールプレーンのデータベースに保存されるデータをAWSが所有するアカウントに置く必要があることが挙げられます。
EKSをすばやくデプロイする
Amazon EKSは、ウェブコンソール、専用のAmazon EKSコマンドラインツール、またはCloudFormationやTerraformなどのIaCツールを使って、さまざまな方法でデプロイできます。
ここではTerraformを使い、デフォルト値でクラスターをデプロイします。このデモで使用するTerraform設定ファイルはこちらのリポジトリにあります。Terraformコマンドの実行と状態変更の保存にはTerraform Cloudを使用します。
EKSクラスターはVPC内で実行する必要があります。このモジュールを使って、TerraformでVPCをデプロイできます。
デモ環境では、プライベートサブネットを3つ、パブリックサブネットを3つデプロイします。プライベートサブネットには、インターネットゲートウェイへのデフォルトルートがありません。NATゲートウェイを使って、プライベートサブネットからインターネットにアクセスできるようにします。注:デモ用にNATゲートウェイは1つだけデプロイします。デモ環境のネットワークアーキテクチャの概要を以下に示します。

EKSクラスターには、既存のVPCのIDと、ノードプールとの通信やサービスおよびIngressコントローラー用のロードバランサーのプロビジョニングに使うサブネットIDが必要です。デモ環境では、3つのインスタンスを持つセルフマネージドノードグループをデプロイします。
Terraform Cloudでは、UIまたはリモートオペレーションを使ってプランを実行できます。UIから操作を開始するには、バージョン管理システムにコードをコミットする必要があります。リモートオペレーションを使うと、ローカルの設定ファイルの状態をすばやく確認できます。内部では、Terraformがローカル設定ファイルのアーカイブをリモートサーバーにアップロードし、コマンドをリモートで実行して、結果をターミナルにストリーミングします。Terraform Cloudで管理される状態ファイルを使うには、正しいワークスペースと組織を指定したbackend設定を追加する必要があります。
また、Terraform CloudへのAPIアクセスも必要です。設定方法については、Terraform Cloud公式ドキュメントをご覧ください。
初回のプランでは、設定ファイルによって44個の新しいリソースが作成されることが示されます。
これでTerraform CloudのUIから環境をデプロイできます。完了すると、概要ページで新しいクラスターの出力情報を確認できるようになります。

環境をデプロイしたら、AWS公式ドキュメントを参考にしてデモクラスターにアクセスできます。
このクラスターを評価のベースラインとします。まず、クラスターへの接続がいかに簡単だったか、最初の観察結果を見ていきましょう。
Kubernetes APIへのアクセスを制限する
EKSサービスでは、サービスエンドポイントを通じてKubernetes APIにアクセスできます。デフォルトでは、クラスターのエンドポイントはパブリックにアクセス可能です。つまり、インターネット上の誰もがアクセスを試みることができます。Kubernetes APIはデフォルトで匿名リクエストを受け付けますが、ABACとRBACの認可機構はどちらも、匿名ユーザーや未認証ユーザーに対する明示的な認可を必要とします。EKSクラスターではデフォルトでRBACが有効になっており、APIサーバーのフラグを確認すれば検証できます。
ログからは、EKSがWebhookトークン認証方式を実装していることもわかります。つまり、KubernetesユーザーはAWS APIから認証トークンを取得する必要があります。これはクラスターのKubernetes APIエンドポイントとは別のものです。Amazon EKSは、クラスターが行う認可の判断に影響を与えません。
さらに確かめるため、認証情報なしでクラスターへの接続を試すことができます。匿名ユーザーをシミュレートするには、認可ヘッダーを付けずにAPIへリクエストを送信します。kubectlには便利なデバッグオプションがあり、すべてのリクエストをCURLコマンドとして出力するため、そのまま再利用できます。
正しい認可ヘッダーを付けずに同じリクエストを送信すると、認可されなかったことがわかります。
デフォルトではリソースへのアクセスがある程度制限されていることを確認できました。ここで、多層防御について触れておきましょう。これは、セキュリティシステムにおける単一障害点をなくすため、さまざまな種類のセキュリティ制御を重ねるという考え方です。現在のデプロイでは、インターネット上の誰かによるクラスターへのアクセスを防ぐ制御はRBAC権限だけです。
この設定ファイルは、匿名アクセスを許可する方法を示しています。
この設定を適用すると、匿名リクエストが成功することを確認できます。
Kubernetesの開発者は、この種の設定を明示的に行う必要があるよう、いくつかの安全対策を導入しています。system:anonymousユーザーとsystem:unauthenticatedグループは、subjects属性に明示的に指定する必要があります。*などのワイルドカード文字を使っても、この2つのsubjectへのアクセスは許可されません。例のsubjectのnameを*に変更して、確認できます。
Kubernetes APIサーバーへのパブリックアクセスは、認証情報が漏えいした場合の影響も大きくします。APIがパブリックにアクセス可能だと、漏えいした認証情報が世界中のどこからでも悪用される可能性があります。また、認可フローでゼロデイ脆弱性が発見された場合も、APIサーバーにパケットを送信できるユーザーを制限する大きな理由になります。過去には、CVE-2019-11253やCVE-2020-8559などの脆弱性が報告されています。
アクセス可能なIPアドレスを制限すれば、パブリックエンドポイントのリスクを軽減できます。Terraformでは、モジュール定義にcluster_endpoint_public_access_cidrs属性を追加して設定できます。
もう1つの方法は、パブリックエンドポイントを完全に無効化し、プライベートVPCエンドポイントを有効にすることです。Terraformモジュールのcluster_endpoint_private_access属性とcluster_endpoint_public_access属性で設定できます。これにより、VPCネットワークにアクセスできるユーザーだけがクラスターにアクセスできます。
ただし、どちらの方法も運用コストに大きく影響します。Terraform Cloudのようなパブリックな継続的デプロイシステムを使う場合、パブリックエンドポイントがないと問題が生じる可能性があります。デモ環境でパブリックエンドポイントを無効にすると、次のアクセス拒否エラーが発生し、デプロイに失敗しました。

このエラーが発生するのは、Terraformモジュールが内部でaws-auth ConfigMapを更新しようとするためです。この更新はKubernetes API経由でしか行えません。ご覧のとおり、APIサーバーのFQDNはプライベートIPアドレスに解決されており、プロバイダーから接続できません。TerraformモジュールでConfigMapの管理を無効にすれば、このエラーを解決できます。ただし、それ以降は別の方法で認可用ConfigMapを管理する必要があります。
パブリックエンドポイントを完全に無効にするには、VPC内で実行してプライベートエンドポイントにアクセスするCDシステムを実装するか、接続をプロキシする必要があります。AWS CodePipelineで実現する方法を解説したこちらの記事は参考になります。また、こちらのTerraformモジュールを使えば、AWS Fargateサービス内でAtlantisを実行できます。
開発者のアクセスも複雑になる可能性があります。プライベートエンドポイントへのアクセスを提供するには、踏み台サーバーまたはVPNサービスを用意する必要があるためです。
インスタンスメタデータサービスへのアクセスを制限する
EKSはインスタンスプロファイルを使って、ノード上で実行されるkubeletにAWS権限を付与します。この認証情報には、インスタンスメタデータサービス(IMDS)を介してkubeletがアクセスできます。IMDSには、リンクローカルIPアドレスへのHTTPリクエストでアクセスできます。デフォルトでは、ノード上のすべてのPodからこのメタデータサービスに到達できます。Podを実行してSTSトークンを取得すれば確認できます。
上記の方法では、ノードに割り当てられたすべての権限を使えます。これは明らかな権限昇格のセキュリティ問題です。デフォルトでは、PodがAWSへのアクセスを必要とするべきではありません。
この問題を緩和するには、PodからIMDSへのネットワークアクセスを制限するしかありません。IMDSには2つのバージョンがあります。バージョン1はリクエストとレスポンスの方式で、リンクローカルアドレスにパケットを送信できるプロセスなら誰でもクエリできます。バージョン2はセッション方式で、レスポンスメッセージの有効期間(TTL)を任意に設定できます。AWSのドキュメントによると、IMDSv1はIMDSv2と併存する形で引き続き利用できます。
AWS標準の設定でこの問題の影響を抑えるには、IMDSv1を完全に無効化する必要があります。ワーカーノードのmetadata_http_tokens属性をrequiredに設定すれば無効化できます。次に、レスポンスパケットのTTLを1に制限します。これはサービスのデフォルトの動作です。TTLを1にすると、KubernetesのネットワークレイヤーはパケットをPodのネットワーク名前空間に転送できなくなります。
Amazon EKS用のTerraformモジュールは、ノードの作成にオートスケーリンググループと起動テンプレートを使用します。そのため、メタデータサービスの設定を更新した場合、インスタンスを更新する必要があります。
この解決策には、hostNetworking属性がtrueに設定されたPodは、引き続き認証情報を取得できるという制限があります。
Kubernetes標準のネットワークポリシーを使ってリンクローカルIPアドレスへのアクセスを制限し、IMDSへのアクセスを防ぐこともできます。AWS Calicoのドキュメントに、Calico CNIプラグインのインストール手順が記載されています。以下のネットワークポリシーでIMDSへのアクセスを防止できます。CalicoプラグインはhostNetworkがtrueに設定されたPodを隔離しないため、IMDSv1を無効化して最大TTLを1に設定する標準的な方法と同じ制約があります。ただし、ネットワークポリシーならノードの入れ替えは不要で、Pod内でIMDSが必要な場合も、特定のPodに適用できます。
ログを有効にする
EKSクラスターが外部および内部の脅威にさらされる可能性のある設定ミスをいくつか確認しました。次に、こうしたイベントを監査できるか見てみましょう。Kubernetesの監査ログを使うと、管理者はクラスターのユーザーやサービスが実行した操作を監視できます。残念ながら、EKSではデフォルトで有効になっていません。デフォルトのTerraformモジュール設定でも同様です。ログを有効にするには、cluster_enabled_log_types属性を使用し、必要なログタイプを指定します。
EKSでは、複数の種類のログをそれぞれ個別に有効にできます。セキュリティの観点では、主にauditログとauthenticatorログが重要です。
監査ログを使うと、Kubernetesへのリクエストを監視し、それらを実行したエンティティを特定できます。監査ログはクラスターで行われた操作ごとにイベントを生成するため、デフォルトの送信先であるCloudWatchに対して、大量のデータがストリーミングされる点に注意してください。auditとauthenticatorに絞ることで、データ量を抑えられます。
たとえば、aws-configマップへの更新を検索し、改ざんがないか確認できます。次のフィルターを使うと、aws-authという名前のオブジェクトに関連するすべてのパッチイベントを取得できます。
監査イベントには、誰が変更したのか、どこから接続したのかなどを特定するのに役立つ情報が含まれています。
また、これらのログは権限のないユーザーによるリソースへのアクセス試行の検知にも役立ちます。次のクエリを使うと、匿名ユーザーから送信されたリクエストを検索できます。
一方、authenticatorログを使うと、クラスターへのログインを試みているユーザーを追跡し、これらのエンティティをKubernetesのグループやユーザーと関連付けられます。前の例から、キーIDがAROAYREY3WYOBFHU7VIRMのユーザーがConfigMapを変更したことは分かりますが、このキーIDがどのAWSエンティティに属するのかは分かりません。
次回:Amazon EKSの高度なハードニング
今回のブログ記事では、Amazon Elastic Kubernetes Serviceの利用時に発生する可能性のある、認証・認可やインスタンスメタデータサービスへのアクセスなどのセキュリティ上の問題をいくつか取り上げました。また、本番環境でこれらの問題を軽減する方法も紹介しました。このシリーズの次回の記事では、Amazon EKSクラスターを分離するための重要なステップであるマルチアカウントアーキテクチャや、Amazon EKSクラスターの作成時に専用のIAMロールを使用することの重要性、Amazon EKSコントロールプレーンに保存されたシークレットをさらに保護する方法について解説します。次回の記事をお待ちいただくか、公開時のお知らせを受け取るためにTwitterで@snkysecをフォローしてください。
Snyk Infrastructure as Code (Snyk IaC)のスキャンを利用すると、CloudFormationやTerraformを使ったAmazon EKSの利用に伴うセキュリティ上の問題を軽減できます。デプロイコードが本番環境に反映される前に、セキュリティ上の問題を特定できます。無料アカウントに登録して、スキャンを始めましょう。
ソースコードの段階からインフラを保護
Snykはワークフロー内のIaCセキュリティとコンプライアンスを自動化し、構成ドリフトや不足しているリソースを検出します。
