Skip to main content

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など)によって異なります。

コマンドラインで、次のコマンドを実行します。

NAMESPACE=ingress-nginx

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

helm install ingress-nginx ingress-nginx/ingress-nginx \
  --create-namespace \
  --namespace $NAMESPACE \
  --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz

以下の画像にhelmコマンド全体を示します。

ingress-nginxリポジトリの追加と更新、およびingress-nginxチャートのインストールを行うHelmコマンドが表示されたターミナル。

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

ターミナル出力により、ingress-nginxコントローラーがingress-nginx名前空間にインストールされ、デプロイされたことが確認できます。

次に、以下のコマンドでIngressコントローラーがインストールされたことを確認します。

kubectl --namespace ingress-nginx get services -o wide -w ingress-nginx-controller

以下の画像に、上記コマンドの実行結果を示します。

HTTPおよびHTTPSポートを備えたingress-nginx-controllerのLoadBalancerサービスをkubectlで一覧表示したターミナル出力。

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

Macでは、外部IPがIPアドレスではなくlocalhostとして表示される場合があります。

nginxの「404 Not Found」エラーページと、アドレスバーに「保護されていません」と表示されたブラウザーウィンドウ。

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

証明書がないため、168.62.208.113のサイトに「保護されていない通信」とブラウザー警告が表示されている。

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

無効な認証局エラーが表示され、20.245.164.52への接続がプライベートではないことを示すブラウザーの警告ページ。

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

20.245.164.52のサーバーのセキュリティ証明書が信頼できないことを示すブラウザーの警告。「安全ではないサイトに進む」リンクが表示されている

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

https://20.245.164.52 に対して「安全ではありません」と無効な証明書のメッセージを表示するブラウザーの警告

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

Kubernetes Ingress Controllerの偽証明書について、「発行先」と「発行者」がAcme Co.と表示されている「全般」タブを示す証明書ビューア。

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コマンドを実行します。

mkdir certs

openssl req -x509 -nodes -days 9999 -newkey rsa:2048 -keyout certs/ingress-tls.key -out certs/ingress-tls.crt

以下の画像に、上記コマンドの実行結果を示します。

OpenSSLコマンドを実行し、2,048ビットのRSA秘密鍵を生成して証明書署名要求の詳細を入力し始めているターミナル。

証明書要求に含める組織名、国コード、所在地、メールアドレスなどの組織情報を入力します。このデモでは、証明書の完全修飾ドメイン名(FQDN)としてwww.ingress-tls.comを使用します。

これにより、\certsフォルダーに証明書ファイル(CRT-extension)と証明書の秘密鍵ファイル(KEY-extension)が作成されます。

Kubernetes Secretの作成

次に、証明書とキーをKubernetes Secretに紐付けます。以下のコマンドを実行します。

kubectl create secret tls ingress-cert --namespace dev --key=certs/ingress-tls.key --cert=certs/ingress-tls.crt -o yaml
keyファイルと証明書ファイルからingress-certという名前のTLSシークレットを作成するkubectlコマンドと、その後に表示されるエンコード済みYAMLデータを示すターミナル。

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

kubectl get secretコマンドとKubernetesのシークレットが表示されたターミナル。サービスアカウントトークンとTLS証明書を含む

Ingress名前空間への新しいサンプルアプリの公開

次に、以下の構文を含む新しいsample-app.yamlファイルを作成します(YAMLのインデントレベルに注意してください)。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-app
  namespace: default
spec:
  selector:
    matchLabels:
      app: sample
  replicas: 2
  template:
    metadata:
      labels:
        app: sample
    spec:
      containers:
      - name: sample
        image: "gcr.io/google-samples/hello-app:2.0"

---

apiVersion: v1
kind: Service
metadata:
  name: sample-app-service
  namespace: default
  labels:
    app: sample
spec:
  type: ClusterIP
  selector:
    app: sample
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP

これにより、既存のingress-nginx名前空間内に、新しいサービスとサンプルアプリケーション(Googleのhello-appサンプルコンテナイメージを使用)が作成されます。このコードではSSL/TLS Secretをこの名前空間に割り当てるため、この名前空間内で実行されるアプリケーションとサービスのみで使用できます。

次に、以下のコマンドを実行して設定をKubernetesクラスターに適用します。

kubectl apply -f sample-app.yaml:
kubectl applyでsample-appのデプロイメントとサービスを作成しているターミナル出力

Ingressコントローラーとサンプルアプリの間にSSL/TLS連携を設定する

最後に、sample-ingress.yamlというファイルを新たに作成し、以下のようにSSL/TLS設定パラメーターを使ってIngressリソースを宣言します。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: sample-app-ingress
  namespace: default
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - www.ingress-tls.com
    secretName: ingress-cert
  rules:
  - host: "www.ingress-tls.com"
    http:
      paths:
        - pathType: Prefix
          path: "/"
          backend:
            service:
              name: sample-app-service
              port:
                number: 80

上記の例では、次のパラメーターを使ってSSL/TLSを適用し、Secretに関連付けています。

tls:
  - hosts:
    - www.ingress-tls.com
    secretName: ingress-cert
  rules:
  - host: "www.ingress-tls.com"

ファイル末尾のpathsセクションでは、ホストへのすべての受信リクエストを、前の手順で作成したsample-app-service(Google hello-appコンテナアプリケーション)に転送するよう指定しています。

kubectlコマンドをもう一度実行して、設定をKubernetesクラスターに適用します。

kubectl apply -f sample-app-ingress.yaml

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に解決されます。

Kubernetes Ingress Controller用に、20.245.164.52をwww.ingress-tls.comに割り当てるHOSTSファイルの記述を表示したWindowsメモ帳。

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

「Hello, world!」アプリと、発行者や有効期間などの詳細が表示されたwww.ingress-tls.comのTLS証明書ビューアーを表示しているブラウザー。

ご覧のとおり、先ほど作成した自己署名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セキュリティとコンプライアンスを自動化し、構成ドリフトや不足しているリソースを検出します。

続きを読む

blog feature ai lilac
Blog

エージェント型修正で脆弱性バックログをプルリクエストに変える

Evo Remediation Agentがオープンプレビューで利用可能になり、Evo Agentic AppSecに依存関係の自動解決機能が加わりました。AppSecチームは継続的な修正キャンペーンを実施できるようになりました

blog feature snyk container custom base recommendations
Blog

Evo Agentic AppSecのご紹介:AI開発のスピードに追随するセキュリティ

AIを活用した開発は、従来のセキュリティワークフローを上回るスピードで進んでいます。SnykのAgentic AppSecは、セキュリティエージェントが脆弱性を継続的に検出、修正、検証し、人が基準を定められるようにします。

feature insights context
Blog

自律型攻撃はすでに始まっている。防御もそのスピードに追いつかなければならない。

自律型攻撃者によって、防御に使える時間は短くなっています。継続的な検出、修復、検証、予防で、セキュリティチームが攻撃に歩調を合わせる方法をご紹介します。