Kubernetes IngressでSSL/TLSを設定する
Peter De Tender
2022年11月17日
0 分で読めます現在、Webアプリやモバイルアプリ、APIベースのマイクロサービスエンドポイントが一般的になっています。これらのアプリケーションには、HTTPプロトコルを通じてアクセスできます。クライアントとサーバー間、およびAPIバックエンド間の通信を保護するには、Secure Sockets LayerまたはTransport Layer Security(SSL/TLS)による暗号化が欠かせません。
SSL/TLSは、証明書ベースの暗号化方式です。SSLは20年以上にわたって標準として使われてきました。TLSは同じ概念に基づきながら、より厳格な暗号化方式を採用した、より安全なSSLの拡張版です。
TLS証明書は、組織内の認証局による自己署名、またはGoDaddy、DigiCert、Symantec、GlobalSign、Let’s Encryptなど、数多くあるパブリック認証局のいずれかによる署名が可能です。IPベースの通信を暗号化すると、データパケットを盗み見る攻撃者からトラフィックを保護できます。
Kubernetes環境では、ワークロードのコンテナはKubernetesネットワーク内で実行されます。通常、HTTPベースのIngressコントローラー(トラフィックをPodにルーティングするAPIベースのサービス)を使用して、外部のオンライン環境に公開します。このシナリオでセキュリティを確保するには、KubernetesクラスターにSSL/TLS暗号化の設定を追加する必要があります。
ユーザー名とパスワードによる認証情報の送信、アプリケーションやストレージのエンドポイントアクセスキー、データベース接続文字列などの機密データの読み取りといった、データ交換が発生する一般的なシナリオでは、常に暗号化によるセキュリティが有効です。
この記事では、KubernetesのIngressコントローラーでTLS/SSL証明書を設定する方法を紹介します。NGINX Ingressコントローラーをセットアップし、自己署名SSL/TLS証明書を作成して、証明書をコントローラーに関連付けるためのルールを設定し、Kubernetesのサンプルアプリサービスに接続します。
TLS/SSL証明書の設定
始める前に、ローカルマシン(Kubernetesを有効にしたDocker、MiniKubeなど)またはAzure(AKS)、AWS(EKS)、GCP(GKS)、Ocean(DOKS)などのホスト型クラウド環境でKubernetesが実行されており、Helmがインストールされていることを確認してください。
このデモでは、Microsoft Learnの記事で紹介されている既定のAzure Kubernetes Serviceデプロイメントを、無料のAzureサブスクリプションを使って利用します。ただし、ほとんどの手順はクラウド固有ではなくKubernetesに共通するため、利用するKubernetesのホスティング環境にかかわらず実践できます。
Ingressコントローラーの作成
まず、Ingressコントローラーの設定をKubernetesクラスターに適用します。NGINX、Google Cloud Load Balancer、Traefik、Contourなど、いくつかの選択肢があります。この記事では、広く知られていて、比較的簡単にセットアップできるNGINXを使用します。これはGitHub上のKubernetesコミュニティ、ingress-nginxから提供されています。
Ingressコントローラーにはいくつかの種類があるほか、Helmやkubectlなど、セットアップ方法も複数あります。このデモでは、どのKubernetesアーキテクチャでも動作するHelmを使用します。
デプロイでは、次の手順を実行します。
Ingressコントローラーが使用する、新しいKubernetes名前空間の名前を指定します。変数
NAMESPACEは、この名前を設定するために使用します。helm repo addコマンドを使用して、ingress-nginxコントローラーパッケージをダウンロードします。helm repo updateを使用して、設定を更新します。helm installコマンドでパッケージをインストールします。
この例ではAzureとAzure Load Balancerを使用するため、helm installコマンドを拡張して、Azure Load Balancerのヘルスプローブとの連携を定義します。この設定は、Kubernetes環境(オンプレミス、Azure、AWS、GCPなど)によって異なります。
コマンドラインで、次のコマンドを実行します。
以下の画像にhelmコマンド全体を示します。

NGINXコントローラーの作成結果は、以下の画像のようになります。

次に、以下のコマンドでIngressコントローラーがインストールされたことを確認します。
以下の画像に、上記コマンドの実行結果を示します。

ブラウザーで、ingress-nginxcontrollerに表示されているEXTERNAL-IPに接続します。まだ実際のアプリサービスにルーティングするIngressルールを設定していないため、HTTPエラー404が表示されます。ただし、NGINXコントローラーが応答していることは確認できます。
Macでは、外部IPがIPアドレスではなくlocalhostとして表示される場合があります。

保護されていない通信というメッセージをクリックすると、証明書が使用されていないことがわかります。

同じIPアドレスにもう一度接続してみましょう。今度はHTTPSを使用します。以下のように、続行しても安全ではないことを知らせる警告がブラウザーに表示されます。

詳細設定ボタンをクリックし、次に次のサイトに進むをクリックします。

同じ保護されていない通信タブで、以下に示す証明書アイコンをクリックします。

以下のように、組み込みのIngress Controller Fake Certificateの詳細が表示されます。これから置き換えるのは、この証明書です。

SSL/TLS証明書の選択
SSL/TLS証明書は、さまざまな方法で取得できます。
自己署名:この種類の証明書は通常、内部利用を目的としており、独自のPKI(公開鍵基盤)認証局(CA)に基づいています。
パブリック認証局から取得:通常、パブリックインターネットに公開するアプリケーションに使用します。組織はGlobalSign、Symantec、DigiCert、GoDaddyなどのパブリック認証局からSSL/TLS証明書を購入します。パブリックCAを利用する最大のメリットは、発行されたすべての証明書を検証するルート証明書が、最新のブラウザーから信頼されていることです。証明書の有効期間は通常1~5年です。
Let’s Encrypt:Let’s Encryptは非営利プロジェクトです。パブリックCAとの主な違いは、SSL/TLS証明書が無料で取得できることです。また、Let’s Encryptの証明書の有効期間は3か月のみです。
SSL/TLS証明書の種類に加えて、証明書やキーのローテーションなどのメンテナンス作業も考慮する必要があります。この記事のKubernetesとIngressコントローラーのユースケースでは、定期タスクで新しいSSL/TLS証明書を作成し、KubernetesクラスターでCronジョブを実行して新しいSecretを作成する方法が考えられます。パブリックCAまたはLet’s Encryptの証明書の適切な有効期間を選ぶことも重要です。
SSL/TLS暗号化とセキュリティについては、暗号化をIngressコントローラーレベル、Podまたはアプリケーションレベル、あるいはその両方で行うかも検討が必要です。それぞれにメリットとデメリットがあります。Ingressレベルで暗号化すると、Ingressに到着するすべてのリクエストとバックエンドのKubernetesサービスを直接結び付けられます。
実行中のPodやアプリケーション内にSSL/TLS証明書を保存すると、Podやアプリケーションが複雑になります。ただし、コントローラー設定によって実現するインターネット向けトラフィックの暗号化に加え、IngressコントローラーとPodまたはアプリケーション間のトラフィックも暗号化したいというビジネス上の理由があるかもしれません。このデモでは自己署名証明書を作成しますが、他の2つの方法でも手順は同様です。
MacまたはLinuxマシン、あるいはクラウドプラットフォームのシェル(ここではCloud Shell)で、次のopensslコマンドを実行します。
以下の画像に、上記コマンドの実行結果を示します。

証明書要求に含める組織名、国コード、所在地、メールアドレスなどの組織情報を入力します。このデモでは、証明書の完全修飾ドメイン名(FQDN)としてwww.ingress-tls.comを使用します。
これにより、\certsフォルダーに証明書ファイル(CRT-extension)と証明書の秘密鍵ファイル(KEY-extension)が作成されます。
Kubernetes Secretの作成
次に、証明書とキーをKubernetes Secretに紐付けます。以下のコマンドを実行します。

kubectl get secretを使用すると、実際のSecretを取得できます。出力は以下の画像のようになります。

Ingress名前空間への新しいサンプルアプリの公開
次に、以下の構文を含む新しいsample-app.yamlファイルを作成します(YAMLのインデントレベルに注意してください)。
これにより、既存のingress-nginx名前空間内に、新しいサービスとサンプルアプリケーション(Googleのhello-appサンプルコンテナイメージを使用)が作成されます。このコードではSSL/TLS Secretをこの名前空間に割り当てるため、この名前空間内で実行されるアプリケーションとサービスのみで使用できます。
次に、以下のコマンドを実行して設定をKubernetesクラスターに適用します。

Ingressコントローラーとサンプルアプリの間にSSL/TLS連携を設定する
最後に、sample-ingress.yamlというファイルを新たに作成し、以下のようにSSL/TLS設定パラメーターを使ってIngressリソースを宣言します。
上記の例では、次のパラメーターを使ってSSL/TLSを適用し、Secretに関連付けています。
ファイル末尾のpathsセクションでは、ホストへのすべての受信リクエストを、前の手順で作成したsample-app-service(Google hello-appコンテナアプリケーション)に転送するよう指定しています。
kubectlコマンドをもう一度実行して、設定をKubernetesクラスターに適用します。
FQDNへの接続をテストするには、ローカルマシンのDNS hostsファイル(MacまたはLinuxでは通常/etc/hosts、WindowsではC:\Windows\System32\Drivers\Etc\Hosts)を更新し、IngressコントローラーのIPアドレスが、使用するFQDNに解決されるようにします。
注:ローカルのhostsファイルを更新したくない、または更新できない場合は、DNSリゾルバーhttps://nip.ioを使用できます。たとえば、Ingressコントローラーの名前は20.245.164.52.nip.ioで解決できます。このアドレスは、コントローラーのIPアドレス20.245.164.52に解決されます。

ブラウザーを開き、証明書に使用したFQDN(この例ではwww.ingress-tls.comまたは20.245.164.52.nip.io)に接続します。自己署名証明書はブラウザーから信頼されないため、「保護されていない通信」という警告が表示されます。詳細設定をクリックしてから続行をクリックし、アプリケーションのURLを開きます。

ご覧のとおり、先ほど作成した自己署名SSL/TLS証明書を使って、サンプルアプリ(左側の「Hello, world!」という挨拶)が期待どおりに動作しています。
詳しくは、CNCF Cert Managerツールをご覧ください。証明書をより高度に管理し、Secretを自動作成できます。
Ingressプロバイダーの比較
この手順では広く使われているNGINX Ingressコントローラーを使用しましたが、コントローラーはほかにも数多くあります。Kubernetesを使い始めたばかりなら、オープンソースのNGINXは、クラスターのワークロードの負荷分散と保護に使える、シンプルなソリューションです。NGINXには、よりエンタープライズ向けのNGINX Plusもあります。また、同じコードを基盤とする商用の代替製品Kongも利用できます。Traefikも商用ソリューションの一つで、幅広いプロトコルへの対応、高可用性などの機能を提供します。
選択するソリューションはどれも、Kubernetes Ingress APIと連携します。ただし今年初め、KubernetesはGateway APIのベータ版をリリースしました。これは、特にきめ細かなロールベースのアクセス制御機能を備えていることから、現在のIngress APIに代わる有力な選択肢になる可能性があります。HTTPやTCP/UDPなど複数の標準プロトコルをサポートするほか、Gateway APIの大きな利点の一つは、TLSを標準でサポートする点です。
Gateway APIは開発の初期段階(現在はベータ版)にあるため、Ingress APIとGateway APIの今後を判断するにはまだ早すぎます。Ingress APIの後継となるはずだったGateway APIは、Ingress APIの機能を模倣するだけでなく、さらに多くの機能を提供する可能性があります。しかし、他のベンダーや拡張機能がどのように対応するかは、現時点では不明です。一方で、セキュリティが最優先事項とされ、ルーティングの標準としてTLSが使用されるのは朗報です。
まとめ
インターネットに公開されるアプリケーションとしてKubernetesのワークロードやサービスを利用する場合、Ingressコントローラーが必要になります。リバースプロキシ機能に加え、Ingressアーキテクチャの一部としてSSL/TLS証明書を統合することを強くおすすめします。これにより、クライアント(ブラウザー)とサーバー(Kubernetes Serviceアプリケーション)間のトラフィックが暗号化されます。KubernetesはさまざまなIngressプロバイダーに対応し、複数のSSL/TLS証明書をSecretとして受け入れます。ベストプラクティスについては、Kubernetesセキュリティガイドをご覧ください。
Helmやkubectlなどの標準的なKubernetes管理コマンドを使えば、SSL/TLSの統合はKubernetes Serviceを起動するのと同じくらい簡単です。また、PythonでTLS/SSLを実装するためのガイドもご覧ください。
SSL/TLS証明書で外部とアプリケーション間の通信を保護することは、よりセキュアなアプリケーションを実行するための一歩にすぎません。ソフトウェア開発ライフサイクルの各段階も保護する必要があります。Snyk CodeとSnyk Open Sourceを活用して、作成したコードや利用するオープンソースプロジェクトに潜む脆弱性を特定・修正しましょう。また、Snyk Containerを活用すれば、よりセキュアなベースイメージから始められるほか、ビルドプロセスで新たに持ち込まれる脆弱性も特定できます。最後に、Snyk IaCを使って、デプロイするコードにセキュリティ上の欠陥が含まれていないことを確認しましょう。
ソースコードの段階からインフラを保護
Snykはワークフロー内のIaCセキュリティとコンプライアンスを自動化し、構成ドリフトや不足しているリソースを検出します。


