保护 NGINX-ingress
本教程将详细介绍如何使用 NGINX 安装和保护对集群的 ingress。
步骤 1 - 安装 Helm
如果您已安装 helm,请跳过此部分。
安装 cert-manager
最简单的方法是使用 Helm
,这是一个用于 Kubernetes 资源的模板和部署工具。
首先,请按照 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 地址。完成之后,您可以使用 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
。
此快速入门假设您知道如何将 DNS 条目分配给 IP 地址,并将执行此操作。
步骤 4 - 部署示例服务
您的服务可能拥有自己的图表,或者您可能直接使用清单文件进行部署。此快速入门使用清单文件来创建和公开示例服务。示例服务使用 kuard
,一个演示应用程序。
快速入门示例使用三个清单文件作为示例。前两个是示例部署和相关服务
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 证书一起使用,因为 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
我们需要安装 cert-manager 来完成与 Kubernetes 的工作,以便请求证书并响应验证挑战。我们可以使用 Helm 或普通的 Kubernetes 清单文件来安装 cert-manager。
由于我们之前安装了 Helm,因此我们将假设您希望使用 Helm;请遵循 Helm 指南。对于其他方法,请阅读 cert-manager 的安装文档。
cert-manager 主要使用两种不同的自定义 Kubernetes 资源(称为 CRDs
)来配置和控制其操作方式,以及存储状态。这些资源是 Issuer 和 Certificate。
Issuer
Issuer 定义了 cert-manager 将如何请求 TLS 证书。Issuer 针对 Kubernetes 中的单个命名空间,但也有一个 ClusterIssuer
,它被认为是集群范围内的版本。
请确保您的 Issuer 创建在与您要创建的证书相同的命名空间中。您可能需要在 kubectl create
命令中添加 -n my-namespace
。
您的另一个选择是用 ClusterIssuers
替换您的 Issuers
;ClusterIssuer
资源适用于集群中的所有 Ingress 资源。如果使用 ClusterIssuer
,请记住将 Ingress 注释 cert-manager.io/issuer
更新为 cert-manager.io/cluster-issuer
。
如果您在 issuer 中遇到问题,请遵循 Issuer 颁发 ACME 证书故障排除 指南。
有关 Issuers
和 ClusterIssuers
之间的差异的更多信息(包括您何时可能选择使用每个信息)可以在 Issuer 概念 上找到。
证书
证书资源允许您指定您想要请求的证书的详细信息。它们引用一个 issuer 来定义将如何颁发它们。
有关更多信息,请参阅 证书概念。
步骤 6 - 配置 Let's Encrypt 发行者
在这个示例中,我们将为 Let's Encrypt 设置两个发行者:staging 和 production。
Let's Encrypt production 发行者有非常严格的速率限制。当你进行实验和学习时,很容易达到这些限制。考虑到这种风险,我们将从 Let's Encrypt staging 发行者开始,一旦我们确信它工作正常,我们将切换到 production 发行者。
请注意,您将看到有关 staging 发行者颁发的不可信证书的警告,但这完全是预期的。
在本地创建此定义,并将电子邮件地址更新为您的地址。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 registration# 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
还要创建一个 production 发行者并将其部署。与 staging 发行者一样,您需要更新此示例并添加自己的电子邮件地址。
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 registration# 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
这两个发行者都配置为使用HTTP01
挑战提供者。
创建发行者后,检查其状态
$ 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 protected]Private 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>
您应该看到发行者与注册的帐户一起列出。
步骤 7 - 部署 TLS Ingress 资源
所有先决条件配置到位后,我们现在可以执行请求 TLS 证书的步骤。主要有两种方法:使用 Ingress 上的注释和ingress-shim
或直接创建证书资源。
在本示例中,我们将向 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 中的注释以指定 production 发行者
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 正在监视它,这将导致它使用更新的发行者重新处理请求。
$ kubectl delete secret quickstart-example-tlssecret "quickstart-example-tls" deleted
这将启动获取新证书的过程,您可以使用 describe 查看状态。production 证书更新后,您应该看到示例 KUARD 在您的域名上运行,并具有签名的 TLS 证书。
$ 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 创建了 1 个“Challenge”资源来完成 Order。您可以通过在自动创建的 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 控制器。您应该注意 Challenge 资源上的新事件,因为大约一分钟后(取决于您的 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”资源将更新以反映颁发过程的状态。如果一切顺利,您应该能够“描述”证书并看到类似下面的内容
$ 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