はじめに
GKEはGCPのサービスのひとつで、kubernetesのマネージドサービスになります。
GCPコンソールもしくはコマンドラインから、簡単にkubernetesクラスタを構築することができます。
リージョンの設定など初期設定を済ます必要はありますが、以下のコマンドを実行するだけでクラスタ構築が完了します。
gcloud container clusters create sample-cluster
趣味で触る場合はさておき、実際に業務でGKEを利用する場合はしっかりとセキュリティ面を考慮する必要があり、そのあたりを意識せずにGKEを利用するのは危険です。
本記事では、GKEのセキュリティに関するドキュメントを参考にし、それなりにセキュアなGKEクラスタの構築方法を紹介したいと思います。本来は最新情報などのキャッチアップも含め本家のサイトを参考にしていただくのが一番です。
このような機能があるんだなと、なんとなくの全体感を掴んでいただければ幸いです。
基本
Kubernetesのダッシュボードを無効にする
Kuberntesダッシュボードとは、クラスタをWebUIで管理できるようなツールになります。
この管理ツールを起動するにはサービスアカウントに強い権限を付与する必要がある為、代わりにGKEのコンソールを利用することが望ましいです。
GKEの新しめのバージョンであれば、デフォルトで無効になっており、有効にするには別途インストールが必要になるのでそれほど意識する必要はないのではと思います。
アクセス制御にはRBACを利用する
古いバージョンでのアクセス制御はABACと呼ばれる属性ベースのアクセスコントロール機能を利用していましたが、現在はRBACという役割ベースのアクセス制御機能を利用するのが一般的になっています。
GKE 1.8以降はデフォルトでABACは無効になっていますのであえて利用することはないでしょう。
Cloud IAMでも、ある程度リソースに対するアクセス制御は可能ですが、クラスターやnamespace内のリソースに対して細かいアクセス制御を行う場合はRBACを利用することになります。
まだベータ版ではありますが、GKEではロールをGoogle Groupに割りあてることができるようになっており、ユーザー管理が捗りそうです。
参考リンク
https://cloud.google.com/kubernetes-engine/docs/how-to/hardening-your-cluster?hl=ja#leave_abac_disabled_default_for_110
https://cloud.google.com/kubernetes-engine/docs/how-to/role-based-access-control?hl=ja
https://cloud.google.com/kubernetes-engine/docs/concepts/access-control?hl=ja
https://kubernetes.io/docs/reference/access-authn-authz/rbac/
古いクライアント認証方式を有効にしない
GKEでは現在、OAuthによるクライアント認証を推奨しています。以前に使われていたパスワード認証や証明書による認証は最新のクラスタではデフォルト無効になっています。不必要に有効にしないようにしましょう。
Googleは併せて認証情報のローテーションを定期的に行うことを推奨しています。
参考リンク
https://cloud.google.com/kubernetes-engine/docs/how-to/hardening-your-cluster?hl=ja#restrict_authn_methods
https://cloud.google.com/kubernetes-engine/docs/how-to/credential-rotation?hl=ja
https://kubernetes.io/docs/reference/access-authn-authz/authentication/
Pod間通信を制限する
ネットワークポリシーを利用することで、Pod間の通信を制御することができます。
例えば、データストアが稼働しているPodに対してどこからもアクセスを許可するわけではなく、限られたPodからのみアクセスを許可するといったことが可能になります。
何も設定しない場合は、Pod間での通信に何も制御はかからないので、アプリケーションの特性に応じて適切な通信制御を行いましょう。
ネットワークポリシーを有効にするには--enable-network-policy
を使用します。
gcloud container clusters create sample-cluster --enable-network-policy
参考リンク
https://cloud.google.com/kubernetes-engine/docs/how-to/network-policy?hl=ja
https://kubernetes.io/docs/concepts/services-networking/network-policies/
必要最低限のサービスアカウントを利用する
GKEのノードに付与されるデフォルトのサービスアカウントは必要のない権限も含まれている為、そのままでの利用は非推奨とされています。専用のサービスアカウントを作成しそちらを利用するようにしましょう。
クラスタ構築には最低限 monitoring.viewer、monitoring.metricWriter、logging.logWriterの3つのみあればOKです。Google Cloud APIへのアクセスが必要になった場合は、こちらに権限を追加するのも一つの手ですが、より安全な手段として後述のWorkload Identityの利用も視野に入れてください。
サービスアカウントを指定する場合は、クラスタ構築時--service-account
で専用のサービスアカウントを指定します。
gcloud container clusters create sample-cluster --service-account=[SA_NAME]@[PROJECT_ID].iam.gserviceaccount.com
GKEノードのバージョンを最新に保ち続ける
GKEのマスタはGoogleが自動でアップグレードを行ってくれますが、ノードのアップグレードはこちらが面倒を見ることになります。とはいえ、GKEノードの自動アップグレードを有効にすることで、セキュリティパッチが自動的にあたるようになりセキュリティが向上します。手動でアップグレードを行う場合は定期的に行うようにしましょう。
自動アップグレードを有効にするには--enable-autoupgrade
フラグを付与してクラスタを構築します。
$ gcloud beta container clusters create sample-cluster --enable-autoupgrade
なお、GUIでクラスタを作成する場合、ノードの自動アップグレードはデフォルトで有効になっています。
参考リンク
https://cloud.google.com/kubernetes-engine/docs/how-to/node-auto-upgrades?hl=ja
クラスタマスターにアクセスできるネットワークを限定する
マスター承認済みネットワークを指定することで、マスターにアクセスできるアクセスを特定のIPに制限することができます。どこからでもマスターにアクセスできてしまうのはセキュリティ的に非常によろしくないので、必ずこの機能を有効にして限られた経路からしかクラスタにアクセスできないようにするべきです。
限定公開クラスタと組み合わせることで、よりセキュアなクラスタを構築することができます。
マスター承認済みネットワークを指定するには--enable-master-authorized-networks
と--master-authorized-networks
をクラスタ構築時に指定します。
gcloud container clusters create sample-cluster --enable-master-authorized-networks --master-authorized-networks 111.111.111.111/32
ネットワークを複数指定する場合は、カンマで区切ります。
gcloud container clusters create sample-cluster --enable-master-authorized-networks --master-authorized-networks 111.111.111.111/32,111.111.111.0/24
参考リンク
https://cloud.google.com/kubernetes-engine/docs/how-to/authorized-networks?hl=ja
限定公開クラスタを作成する
デフォルトではクラスタのノードはpublicなネットワークに晒されることになりますが、ネイティブVPCを有効にすることで内部IPのみを持つノードでクラスタを構築することができます。インターネットから隔離されたノードは、インターネットに対するインバウンド・アウトバウンド通信に制限がかかります。
限定公開クラスタのマスターにアクセスするには、パブリックなエンドポイントとプライベートなエンドポイントのどちらかに対してリクエストを送ることになります。前者を無効にすることで、よりセキュアな構成にできますがアクセスできる経路がより限定的になるので、そこは運用面とのトレードオフになります。
仮にパブリックなエンドポイントを有効にしたとしても、マスタ承認済みネットワークを指定することで安全にマスタにアクセスすることは可能です。
次の例は、パブリックエンドポイントが有効な限定公開クラスタを構築するコマンドです。
gcloud container clusters create sample --enable-ip-alias --enable-private-nodes --master-ipv4-cidr 172.16.0.0/28 --enable-master-authorized-networks --master-authorized-networks 111.111.111.111/32
--enable-ip-alias
はVPCネイティブに切り替えます。
--enable-private-nodes
を指定すると、クラスタのノードに外部IPが付与されません。
--master-ipv4-cidr
はマスタのCIDRを指定します。--enable-private-nodes
を指定する場合は必須です。
パブリックエンドポイントを無効にしたさらにセキュアな限定公開クラスタ
gcloud container clusters create sample-cluster --enable-ip-alias --enable-private-nodes --master-ipv4-cidr 172.16.0.0/28 --enable-private-endpoint --enable-master-authorized-networks --master-authorized-networks 10.146.0.0/20
--enable-private-endpoint
により、マスタはプライベートエンドポイントのみ持つようになります。
外部からのアクセスは無効となり、クラスタのノードやPodからのみアクセスを受け付けます。それ以外の内部IPアドレスからアクセスさせたい場合は--master-authorized-networks
を指定します。
参考リンク
https://cloud.google.com/kubernetes-engine/docs/how-to/private-clusters?hl=ja
アプリケーションレイヤーでの秘匿情報の暗号化を行う
パスワードやトークンなどの秘匿情報は、kubenetesではSecretリソースとして取り扱います。この秘匿情報はetcdに平文で保存されます。より安全にSecretを取り扱いたい場合は、Google KMSを利用したアプリケーションレイヤでの暗号化を行いましょう。こうすることで例え悪意のあるマルウェアがetcdにアクセスできたとしても情報を守ることができます。
この機能を有効にするにはCloud KMSにて鍵を作成し、クラスタの作成時にdatabase-encryption-key
で指定するだけです。
gcloud container clusters create sample-cluster --database-encryption-key projects/[KEY_PROJECT_ID]/locations/[LOCATION]/keyRings/[RING_NAME]/cryptoKeys/[KEY_NAME]
参考リンク
https://cloud.google.com/kubernetes-engine/docs/how-to/encrypting-secrets?hl=ja
ベータ版の機能
以下の機能は2019年12月23日現在ベータ版の機能です。
ベータ版の機能はSLAやテクニカルサポートの義務がなく、変更が発生する場合があります。
これらの機能をコマンドから利用するにはgcloud beta
コマンドを使用しなければなりません。
ポッドセキュリティポリシーを利用する
ポッドセキュリティポリシーを利用することで、各Podで利用される機能を制限することができます。例えば、特権コンテナの利用を制限したり、安全でないsysctlを制限するなど、クラスタ全体に特定のポリシーを適用します。
この機能を利用するにはアドミッションコントローラーの該当プラグインを有効にする必要があり、以下のように--enable-pod-security-policy
を指定してクラスタを構築します。
gcloud beta container clusters create sample-cluster --enable-pod-security-policy
ポッドセキュリティポリシーを有効にする前に、ポリシーの定義ファイルを作成し承認しておく必要があります。これらの作業を行わず、上記のコマンドを実行した場合はポッドの作成が行えなくなるのでご注意ください。
参考リンク
https://cloud.google.com/kubernetes-engine/docs/how-to/pod-security-policies?hl=ja
https://kubernetes.io/docs/concepts/policy/pod-security-policy/
Shielded VMを利用する
Shielded VMとは、セキュリティ機能がより一層強化されたCompute Engine VMで、インスタンスが改ざんされていないかを確認できる機能を持っています。GKEノードをこのShielded VM上に構築することで、GKEノードがShileded VMの機能の恩恵を受けることができます。
--enable-shielded-nodes
を指定し、Shielded GKE Nodeを有効にします。
gcloud beta container clusters create sample-cluster --enable-shielded-nodes
デフォルトでセキュアブートは無効になっています。
セキュアブートとは、ブートコンポーネントの署名を検証し、異常があった場合はブートをキャンセルする機能です。--shielded-secure-boot
でセキュアブートを有効にできますが、ブートコンポーネントの中に未署名のモジュールが存在していた場合ブートが失敗します。
gcloud beta container clusters create sample-cluster --shielded-secure-boot
参考リンク
https://cloud.google.com/kubernetes-engine/docs/how-to/shielded-gke-nodes?hl=ja
https://cloud.google.com/security/shielded-cloud/shielded-vm?hl=ja
Workload Identityを利用する
Workload Identityは、Googleがもっとも推奨するGKEからGoogleのCloud APIにアクセスするための手段です。従来、サービスアカウントに対してAPIへのアクセス権を付与する形では、そのノードで稼働するコンテナ全てがその権限を持つことになります。
クレデンシャルをアプリケーションに埋め込む方法もありますが、Workload Identityを利用するとより安全にPodに対してAPIへのアクセス権を付与することができるようになります。
Workload Identityを利用するには--identity-namespace
を指定します。
gcloud beta container clusters create sample-cluster --identity-namespace=[PROJECT_ID].svc.id.goog
参考リンク
https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity?hl=ja
Binary Authorizationを利用する
Binary Authorizationは、署名を検証し不正なコンテナがGKE上にデプロイされることを防ぎます。CI/CDパイプラインにおいて、指定されたテストをパスしているか?正しい手順でビルドされたか?などを検証し、信頼できるイメージのみデプロイできるようなフローを実現することが可能になります。
参考リンク
https://cloud.google.com/binary-authorization/?hl=ja
https://cloud.google.com/solutions/binary-auth-with-cloud-build-and-gke?hl=ja
https://cloud.google.com/solutions/secure-software-supply-chains-on-google-kubernetes-engine?hl=ja
よりセキュアなノードイメージを利用する
コンテナ用に最適化されたイメージであるcos_containerdをノードイメージに指定できます。
以下のように--image-type=cos_containerd
をクラスタ構築時に付与します。
gcloud container clusters create sample-cluster --image-type=cos_containerd
参考リンク
https://cloud.google.com/kubernetes-engine/docs/concepts/using-containerd?hl=ja
https://cloud.google.com/container-optimized-os/docs/concepts/security?hl=ja
GKE Sandboxを利用する
ウェブホスティングサービスなど、ソースコードのアップロードを許可しているような信頼できないワークロードを運用する場合、GKE Sandboxの利用がおすすめです。GKE Sandboxは、アプリケーションとホストカーネルを分離し、信頼できないコードからノードを守ってくれます。この仕組みはgVisorを利用して実現されています。
GKE Sandbox環境下ではIstioを利用できないといった制限があるので複数ありますので制限事項を理解した上で用途に合うアプリケーションに適用するのが良いかと思います。
GKE Sandboxを利用するには、--sandbox type=gvisor
を指定し専用のノードプールを作成します。--image-type=cos_containerd
も併せて指定してください。
gcloud beta container node-pools create sample-sandbox-pool --cluster=sample-cluster --image-type=cos_containerd --sandbox type=gvisor
なお、デフォルトのノードプールではGKE Sandboxを利用できません。
参考リンク
https://cloud.google.com/kubernetes-engine/sandbox/?hl=ja
https://cloud.google.com/kubernetes-engine/docs/concepts/sandbox-pods?hl=ja
まとめ
セキュアなGKEを構築する上で用意されている機能概要を簡潔にまとめてみました。各項目に参考サイトのリンクが貼ってありますので、詳細な情報や具体的な設定方法はそちらを参考にしてください。
本記事では紹介しきれなかった機能もありますので、そちらも合わせて本家のセキュリティガイドに目を通してみることをオススメします。
参考リンク
https://cloud.google.com/kubernetes-engine/docs/concepts/security-overview
https://cloud.google.com/kubernetes-engine/docs/how-to/hardening-your-cluster