NGINX イングレスの保護
このチュートリアルでは、NGINX を使用してクラスタにイングレスをインストールおよび保護する方法について詳しく説明します。
ステップ 1 - Helm のインストール
Helm が既にインストールされている場合は、このセクションをスキップしてください。
cert-manager
をインストールする最も簡単な方法は、Kubernetes リソースのテンプレート化とデプロイメントツールであるHelm
を使用することです。
まず、Helm のインストール手順に従って、Helm クライアントがインストールされていることを確認してください。
例:macOS の場合
brew install kubernetes-helm
ステップ 2 - NGINX Ingress コントローラーのデプロイ
Kubernetes Ingress コントローラー
は、クラスタ内で実行されているソフトウェアへの HTTP および HTTPS トラフィックのアクセスポイントとして設計されています。ingress-nginx-controller
は、クラウドプロバイダーのロードバランサーによってサポートされている HTTP プロキシサービスを提供することでこれを実現します。
ingress-nginx
の詳細と動作については、ingress-nginx のドキュメント
を参照してください。
ingress-nginx の最新の Helm リポジトリを追加します。
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
最新のチャートで Helm リポジトリを更新します。
$ helm repo updateHang tight while we grab the latest from your chart repositories......Skip local chart repository...Successfully got an update from the "stable" chart repository...Successfully got an update from the "ingress-nginx" chart repository...Successfully got an update from the "coreos" chart repositoryUpdate Complete. ⎈ Happy Helming!⎈
helm
を使用して NGINX Ingress コントローラーをインストールします。
$ helm install quickstart ingress-nginx/ingress-nginxNAME: quickstart... lots of output ...
クラウドプロバイダーがパブリックIPアドレスを提供してリンクするには、1~2分かかります。完了したら、kubectl
コマンドを使用して外部IPアドレスを確認できます。
$ kubectl get svcNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEkubernetes ClusterIP 10.0.0.1 <none> 443/TCP 13mquickstart-ingress-nginx-controller LoadBalancer 10.0.114.241 <pending> 80:31635/TCP,443:30062/TCP 8m16squickstart-ingress-nginx-controller-admission ClusterIP 10.0.188.24 <none> 443/TCP 8m16s
このコマンドは、クラスタ内のすべてのサービス(default
名前空間内)と、それらが持つ外部IPアドレスを表示します。コントローラーを最初に作成したとき、クラウドプロバイダーはまだLoadBalancer
を介してIPアドレスを割り当てていません。割り当てられるまでは、サービスの外部IPアドレスは<pending>
と表示されます。
クラウドプロバイダーには、Ingress コントローラーを作成する前に IP アドレスを予約し、プールから IP アドレスを割り当てるのではなく、その IP アドレスを使用するオプションがある場合があります。その方法については、クラウドプロバイダーのドキュメントを参照してください。
ステップ 3 - DNS 名の割り当て
Ingress コントローラーに割り当てられた外部IPアドレスは、すべての受信トラフィックをルーティングする必要があるIPアドレスです。これを有効にするには、管理するDNSゾーン(例:www.example.com
)に追加します。
このクイックスタートでは、IPアドレスにDNSエントリを割り当てる方法を理解していることを前提としています。
ステップ 4 - サンプルサービスのデプロイ
サービスには独自のチャートがある場合や、マニフェストを使用して直接デプロイする場合があります。このクイックスタートでは、マニフェストを使用してサンプルサービスを作成および公開します。サンプルサービスは、デモアプリケーションであるkuard
を使用します。
クイックスタートの例では、サンプルに3つのマニフェストを使用します。最初の2つは、サンプルデプロイメントとそれに関連付けられたサービスです。
apiVersion: apps/v1kind: Deploymentmetadata:name: kuardspec:selector:matchLabels:app: kuardreplicas: 1template:metadata:labels:app: kuardspec:containers:- image: gcr.io/kuar-demo/kuard-amd64:1imagePullPolicy: Alwaysname: kuardports:- containerPort: 8080
apiVersion: v1kind: Servicemetadata:name: kuardspec:ports:- port: 80targetPort: 8080protocol: TCPselector:app: kuard
これらのファイルをローカルにダウンロードして参照するか、このドキュメントのGitHubソースリポジトリから参照できます。チュートリアルフファイルからGitHubから直接サンプルサービスをインストールするには、次の手順を実行します。
kubectl apply -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/deployment.yaml# expected output: deployment.extensions "kuard" createdkubectl apply -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/service.yaml# expected output: service "kuard" created
Ingress リソース は、Kubernetes がこのサンプルサービスをクラスタ外部に公開するために使用するものです。この例を完了するには、所有または管理するドメインを反映するように、サンプルマニフェストをダウンロードして変更する必要があります。
開始できるサンプルIngressは次のとおりです。
apiVersion: networking.k8s.io/v1kind: Ingressmetadata:name: kuardannotations: {}#cert-manager.io/issuer: "letsencrypt-staging"spec:ingressClassName: nginxtls:- hosts:- example.example.comsecretName: quickstart-example-tlsrules:- host: example.example.comhttp:paths:- path: /pathType: Prefixbackend:service:name: kuardport:number: 80
GitHub からサンプルマニフェストをダウンロードし、編集して、以下のコマンドでマニフェストを Kubernetes に送信できます。エディターでファイルを編集し、保存したら
kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/ingress.yaml# expected output: ingress.networking.k8s.io/kuard created
注:上記で示したIngressの例には、
host
定義が含まれています。ingress-nginx-controller
は、要求されたホスト名がIngress内の定義と一致する場合にトラフィックをルーティングします。host
定義なしでIngressをデプロイすることはできますが、完全修飾ドメイン名を期待するTLS証明書では使用できません。
デプロイ後、kubectl get ingress
コマンドを使用して、Ingressのステータスを確認できます。
NAME HOSTS ADDRESS PORTS AGEkuard * 80, 443 17s
サービスプロバイダーによっては、Ingressが完全に作成されるまでに数分かかります。作成されて配置されると、Ingressにもアドレスが表示されます。
NAME HOSTS ADDRESS PORTS AGEkuard * 203.0.113.2 80 9m
注:IngressのIPアドレスは、
ingress-nginx-controller
のIPアドレスと一致しない場合があります。これは問題なく、Kubernetesクラスタをホストするサービスプロバイダーの特殊性/実装の詳細です。ingress-nginx-controller
をクラウドプロバイダー固有のIngressバックエンドではなく使用しているため、サービスのプライマリアクセスポイントとしてquickstart-ingress-nginx-controller
LoadBalancer
リソースに定義および割り当てられたIPアドレスを使用します。
上記で追加したドメイン名(例:http://www.example.com
)でサービスにアクセスできることを確認してください。最も簡単な方法は、ブラウザを開いてDNSで設定した名前を入力し、Ingressを追加するだけです。
curl
のようなコマンドラインツールを使用して、Ingressを確認することもできます。
$ curl -kivL -H 'Host: www.example.com' 'http://203.0.113.2'
このcurlコマンドのオプションは、詳細な出力を提供し、リダイレクトに従い、出力にTLSヘッダーを表示し、安全でない証明書でエラーを出力しません。ingress-nginx-controller
を使用すると、サービスはTLS証明書を使用して利用可能になりますが、ingress-nginx-controller
からデフォルトで提供される自己署名証明書を使用します。ブラウザには、これは無効な証明書であるという警告が表示されます。これは、まだcert-managerを使用してサイトの完全な信頼できる証明書を取得していないため、予想され、正常です。
警告:Ingressがインターネット上で利用可能であり、正しく応答していることを確認することが重要です。このクイックスタートの例では、Let's Encryptを使用して証明書を提供していますが、サービスが利用可能であることと、証明書を発行するプロセス中にその検証を使用して、ドメインの要求がドメインを十分に制御できる人に属していることを証明しています。
ステップ 5 - cert-manager のデプロイ
証明書を要求して検証の課題に対応するために、Kubernetesで作業を行うためにcert-managerをインストールする必要があります。HelmまたはプレーンKubernetesマニフェストを使用してcert-managerをインストールできます。
既にHelmをインストールしているので、Helmを使用したいと仮定します。Helmガイドに従ってください。その他の方法については、cert-managerのインストールドキュメントを参照してください。
cert-managerは主に、操作方法と状態の保存方法を構成および制御するために、CRD(Custom Resource Definitions)
として知られる2種類の異なるカスタムKubernetesリソースを使用します。これらのリソースは、IssuerとCertificateです。
Issuer
Issuerは、cert-managerがTLS証明書を要求する方法を定義します。IssuerはKubernetesの単一の名前空間に固有のものですが、クラスタ全体のバージョンのClusterIssuer
もあります。
Issuerが、作成する証明書と同じ名前空間に作成されていることを確認してください。kubectl create
コマンドに-n my-namespace
を追加する必要がある場合があります。
別のオプションとして、Issuers
を ClusterIssuers
に置き換えることができます。ClusterIssuer
リソースは、クラスタ内のすべてのIngressリソースに適用されます。ClusterIssuer
を使用する場合は、Ingress アノテーション cert-manager.io/issuer
を cert-manager.io/cluster-issuer
に更新してください。
Issuerに問題がある場合は、「ACME証明書の発行に関するトラブルシューティング」ガイドを参照してください。
Issuers
と ClusterIssuers
の違い(それぞれを使用する状況を含む)に関する詳細情報は、「Issuerの概念」を参照してください。
証明書
証明書リソースを使用すると、要求する証明書の詳細を指定できます。発行方法を定義するために、Issuerを参照します。
詳細については、「証明書の概念」を参照してください。
ステップ6 - Let's Encrypt Issuerの設定
この例では、Let's Encryptのためにステージングと本番環境の2つのIssuerを設定します。
Let's Encryptの本番Issuerは非常に厳しいレート制限があります。実験や学習中に、これらの制限に簡単に達してしまう可能性があります。そのため、まずLet's EncryptのステージングIssuerから開始し、正常に動作することを確認してから本番Issuerに切り替えます。
ステージングIssuerからの信頼されていない証明書に関する警告が表示されますが、これは想定どおりです。
この定義をローカルに作成し、メールアドレスを自分のアドレスに更新してください。このメールアドレスはLet's Encryptによって必要とされ、証明書の期限切れや更新に関する通知に使用されます。
apiVersion: cert-manager.io/v1kind: Issuermetadata:name: letsencrypt-stagingspec:acme:# The ACME server URLserver: https://acme-staging-v02.api.letsencrypt.org/directory# Email address used for ACME registrationemail: user@example.com# Name of a secret used to store the ACME account private keyprivateKeySecretRef:name: letsencrypt-staging# Enable the HTTP-01 challenge providersolvers:- http01:ingress:ingressClassName: nginx
編集後、カスタムリソースを適用します。
kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/staging-issuer.yaml# expected output: issuer.cert-manager.io "letsencrypt-staging" created
本番Issuerも作成してデプロイします。ステージングIssuerと同様に、この例を更新して自分のメールアドレスを追加する必要があります。
apiVersion: cert-manager.io/v1kind: Issuermetadata:name: letsencrypt-prodspec:acme:# The ACME server URLserver: https://acme-v02.api.letsencrypt.org/directory# Email address used for ACME registrationemail: user@example.com# Name of a secret used to store the ACME account private keyprivateKeySecretRef:name: letsencrypt-prod# Enable the HTTP-01 challenge providersolvers:- http01:ingress:ingressClassName: nginx
kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/production-issuer.yaml# expected output: issuer.cert-manager.io "letsencrypt-prod" created
これらのIssuerはどちらも、HTTP01
チャレンジプロバイダーを使用するように構成されています。
作成後、Issuerのステータスを確認します。
$ kubectl describe issuer letsencrypt-stagingName: letsencrypt-stagingNamespace: defaultLabels: <none>Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"cert-manager.io/v1","kind":"Issuer","metadata":{"annotations":{},"name":"letsencrypt-staging","namespace":"default"},(...)}API Version: cert-manager.io/v1Kind: IssuerMetadata:Cluster Name:Creation Timestamp: 2018-11-17T18:03:54ZGeneration: 0Resource Version: 9092Self Link: /apis/cert-manager.io/v1/namespaces/default/issuers/letsencrypt-stagingUID: 25b7ae77-ea93-11e8-82f8-42010a8a00b5Spec:Acme:Email: email@example.comPrivate Key Secret Ref:Key:Name: letsencrypt-stagingServer: https://acme-staging-v02.api.letsencrypt.org/directorySolvers:Http 01:Ingress:Class: nginxStatus:Acme:Uri: https://acme-staging-v02.api.letsencrypt.org/acme/acct/7374163Conditions:Last Transition Time: 2018-11-17T18:04:00ZMessage: The ACME account was registered with the ACME serverReason: ACMEAccountRegisteredStatus: TrueType: ReadyEvents: <none>
登録されたアカウントとともに、Issuerが表示されます。
ステップ7 - TLS Ingressリソースのデプロイ
すべての前提条件の構成が完了したので、TLS証明書を要求するための手順を実行できます。これには主に2つの方法があります。ingress-shim
を使用してIngressのアノテーションを使用するか、証明書リソースを直接作成します。
この例では、Ingressにアノテーションを追加し、ingress-shimを利用して代わりに証明書リソースを作成します。証明書を作成した後、cert-managerはIngressリソースを更新または作成し、それを使用してドメインを検証します。検証および発行されると、cert-managerは証明書に定義されているシークレットを作成または更新します。
注:Ingressで使用されるシークレットは、証明書に定義されているシークレットと一致する必要があります。明示的なチェックはないため、タイプミスにより
ingress-nginx-controller
が自己署名証明書にフォールバックします。この例では、Ingress(およびingress-shim)のアノテーションを使用しており、これにより適切なシークレットが作成されます。
Ingressを編集し、以前の例でコメントアウトされていたアノテーションを追加します。
apiVersion: networking.k8s.io/v1kind: Ingressmetadata:name: kuardannotations:cert-manager.io/issuer: "letsencrypt-staging"spec:ingressClassName: nginxtls:- hosts:- example.example.comsecretName: quickstart-example-tlsrules:- host: example.example.comhttp:paths:- path: /pathType: Prefixbackend:service:name: kuardport:number: 80
そして、適用します。
kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/ingress-tls.yaml# expected output: ingress.networking.k8s.io/kuard configured
cert-managerはこれらのアノテーションを読み取り、それらを使用して証明書を作成します。これは要求して確認できます。
$ kubectl get certificateNAME READY SECRET AGEquickstart-example-tls True quickstart-example-tls 16m
cert-managerは、すべての要求のプロセス状態を証明書オブジェクトに反映します。kubectl describe
コマンドを使用して、この情報を確認できます。
$ kubectl describe certificate quickstart-example-tlsName: quickstart-example-tlsNamespace: defaultLabels: <none>Annotations: <none>API Version: cert-manager.io/v1Kind: CertificateMetadata:Cluster Name:Creation Timestamp: 2018-11-17T17:58:37ZGeneration: 0Owner References:API Version: networking.k8s.io/v1Block Owner Deletion: trueController: trueKind: IngressName: kuardUID: a3e9f935-ea87-11e8-82f8-42010a8a00b5Resource Version: 9295Self Link: /apis/cert-manager.io/v1/namespaces/default/certificates/quickstart-example-tlsUID: 68d43400-ea92-11e8-82f8-42010a8a00b5Spec:Dns Names:www.example.comIssuer Ref:Kind: IssuerName: letsencrypt-stagingSecret Name: quickstart-example-tlsStatus:Acme:Order:URL: https://acme-staging-v02.api.letsencrypt.org/acme/order/7374163/13665676Conditions:Last Transition Time: 2018-11-17T18:05:57ZMessage: Certificate issued successfullyReason: CertIssuedStatus: TrueType: ReadyEvents:Type Reason Age From Message---- ------ ---- ---- -------Normal CreateOrder 9m cert-manager Created new ACME order, attempting validation...Normal DomainVerified 8m cert-manager Domain "www.example.com" verified with "http-01" validationNormal IssueCert 8m cert-manager Issuing certificate...Normal CertObtained 7m cert-manager Obtained certificate from ACME serverNormal CertIssued 7m cert-manager Certificate issued Successfully
describe
の結果の下部に表示されるこのリソースに関連付けられたイベントは、リクエストの状態を示しています。上記の例では、証明書は数分以内に検証および発行されました。
完了すると、cert-managerはIngressリソースで使用されているシークレットに基づいて、証明書の詳細を含むシークレットを作成します。describeコマンドを使用して、いくつかの詳細を確認することもできます。
$ kubectl describe secret quickstart-example-tlsName: quickstart-example-tlsNamespace: defaultLabels: cert-manager.io/certificate-name=quickstart-example-tlsAnnotations: cert-manager.io/alt-names=www.example.comcert-manager.io/common-name=www.example.comcert-manager.io/issuer-kind=Issuercert-manager.io/issuer-name=letsencrypt-stagingType: kubernetes.io/tlsData====tls.crt: 3566 bytestls.key: 1675 bytes
すべてが正しく構成されていることを確認したので、Ingressのアノテーションを更新して本番Issuerを指定できます。
apiVersion: networking.k8s.io/v1kind: Ingressmetadata:name: kuardannotations:cert-manager.io/issuer: "letsencrypt-prod"spec:ingressClassName: nginxtls:- hosts:- example.example.comsecretName: quickstart-example-tlsrules:- host: example.example.comhttp:paths:- path: /pathType: Prefixbackend:service:name: kuardport:number: 80
$ kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/ingress-tls-final.yamlingress.networking.k8s.io/kuard configured
また、既存のシークレットを削除する必要があります。cert-managerはこれを監視しており、更新されたIssuerを使用してリクエストを再処理します。
$ kubectl delete secret quickstart-example-tlssecret "quickstart-example-tls" deleted
これにより、新しい証明書を取得するプロセスが開始され、describeを使用してステータスを確認できます。本番証明書が更新されると、署名付きTLS証明書を使用して、例としてKUARDがドメインで実行されていることがわかります。
$ kubectl describe certificate quickstart-example-tlsName: quickstart-example-tlsNamespace: defaultLabels: <none>Annotations: <none>API Version: cert-manager.io/v1Kind: CertificateMetadata:Cluster Name:Creation Timestamp: 2018-11-17T18:36:48ZGeneration: 0Owner References:API Version: networking.k8s.io/v1Block Owner Deletion: trueController: trueKind: IngressName: kuardUID: a3e9f935-ea87-11e8-82f8-42010a8a00b5Resource Version: 283686Self Link: /apis/cert-manager.io/v1/namespaces/default/certificates/quickstart-example-tlsUID: bdd93b32-ea97-11e8-82f8-42010a8a00b5Spec:Dns Names:www.example.comIssuer Ref:Kind: IssuerName: letsencrypt-prodSecret Name: quickstart-example-tlsStatus:Conditions:Last Transition Time: 2019-01-09T13:52:05ZMessage: Certificate does not existReason: NotFoundStatus: FalseType: ReadyEvents:Type Reason Age From Message---- ------ ---- ---- -------Normal Generated 18s cert-manager Generated new private keyNormal OrderCreated 18s cert-manager Created Order resource "quickstart-example-tls-889745041"
cert-managerが証明書のために作成したOrderリソースでkubectl describe
を実行することで、ACME Orderの現在の状態を確認できます。
$ kubectl describe order quickstart-example-tls-889745041...Events:Type Reason Age From Message---- ------ ---- ---- -------Normal Created 90s cert-manager Created Challenge resource "quickstart-example-tls-889745041-0" for domain "www.example.com"
ここで、cert-managerがOrderを実行するために1つの「Challenge」リソースを作成したことがわかります。自動的に作成されたChallengeリソースでkubectl describe
を実行することで、現在のACMEチャレンジの状態を詳しく調べることができます。
$ kubectl describe challenge quickstart-example-tls-889745041-0...Status:Presented: trueProcessing: trueReason: Waiting for http-01 challenge propagationState: pendingEvents:Type Reason Age From Message---- ------ ---- ---- -------Normal Started 15s cert-manager Challenge scheduled for processingNormal Presented 14s cert-manager Presented challenge using http-01 challenge mechanism
上記から、チャレンジが「提示」され、cert-managerがチャレンジレコードがIngressコントローラーに伝播されるのを待機していることがわかります。チャレンジリソースの新しいイベントに注意してください。「成功」イベントは、1分後程度(Ingressコントローラーがルールを更新する速度によって異なります)に出力されるはずです。
$ kubectl describe challenge quickstart-example-tls-889745041-0...Status:Presented: falseProcessing: falseReason: Successfully authorized domainState: validEvents:Type Reason Age From Message---- ------ ---- ---- -------Normal Started 71s cert-manager Challenge scheduled for processingNormal Presented 70s cert-manager Presented challenge using http-01 challenge mechanismNormal DomainVerified 2s cert-manager Domain "www.example.com" verified with "http-01" validation
注:チャレンジが「有効」にならず、「保留中」の状態のままの場合(または「失敗」状態になる場合)、何らかの構成エラーが発生している可能性があります。失敗したチャレンジのデバッグに関する詳細については、「Challengeリソースリファレンスドキュメント」を参照してください。
チャレンジが完了すると、対応するチャレンジリソースが削除され、「Order」がOrderの新しい状態を反映するように更新されます。
$ kubectl describe order quickstart-example-tls-889745041...Events:Type Reason Age From Message---- ------ ---- ---- -------Normal Created 90s cert-manager Created Challenge resource "quickstart-example-tls-889745041-0" for domain "www.example.com"Normal OrderValid 16s cert-manager Order completed successfully
最後に、「Certificate」リソースが発行プロセスの状態を反映するように更新されます。すべてが正常であれば、「Certificate」を「describe」して、以下のようなものを見ることができるはずです。
$ kubectl describe certificate quickstart-example-tlsStatus:Conditions:Last Transition Time: 2019-01-09T13:57:52ZMessage: Certificate is up to date and has not expiredReason: ReadyStatus: TrueType: ReadyNot After: 2019-04-09T12:57:50ZEvents:Type Reason Age From Message---- ------ ---- ---- -------Normal Generated 11m cert-manager Generated new private keyNormal OrderCreated 11m cert-manager Created Order resource "quickstart-example-tls-889745041"Normal OrderComplete 10m cert-manager Order "quickstart-example-tls-889745041" completed successfully