分类: 安全 Nginx Let's Encrypt 服务器 网络安全 其他 Kubernetes
2018-12-14 22:07:20
Kubernetes Ingresses允许您灵活地将来自Kubernetes集群外部的流量路由到集群内的服务。 这是使用Ingress Resources完成的,Ingress Resources定义用于将HTTP和HTTPS流量路由到Kubernetes服务的规则,以及Ingress 控制器 ,它通过负载平衡流量并将其路由到适当的后端服务来实现规则。 流行的Ingress控制器包括Nginx , Contour , HAProxy和Traefik 。 Ingresses为设置多个LoadBalancer服务提供了更高效和灵活的替代方案,每个服务都使用自己的专用Load Balancer。
在本指南中,我们将设置Kubernetes维护的Nginx入口控制器 ,并创建一些入口资源以将流量路由到多个虚拟后端服务。 一旦我们设置了Ingress,我们就会在我们的集群中安装cert-manager来管理和配置TLS证书,以加密到Ingress的HTTP流量。
在开始本指南之前,您应该可以使用以下内容:
kubectl
命令行工具安装在本地计算机上并配置为连接到您的群集。 您可以在官方文档中阅读有关安装kubectl
更多信息。 wget
命令行实用程序安装在本地计算机上。 您可以使用操作系统内置的软件包管理器安装wget
。 设置好这些组件后,您就可以开始使用本指南了。
在我们部署Ingress Controller之前,我们将首先创建并推出两个虚拟echo服务,我们将使用Ingress路由外部流量。 echo服务将运行hashicorp/http-echo
Web服务器容器,该容器返回包含在启动Web服务器时传入的文本字符串的页面。 要了解有关http-echo
更多信息,请参阅其GitHub Repo ,并了解有关Kubernetes服务的更多信息,请参阅官方Kubernetes文档中的服务。
在本地计算机上,使用nano
或您喜欢的编辑器创建和编辑名为echo1.yaml
的文件:
nano echo1.yaml
粘贴以下服务和部署清单:
apiVersion: v1
kind: Service
metadata:
name: echo1
spec:
ports:
- port: 80
targetPort: 5678
selector:
app: echo1
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo1
spec:
selector:
matchLabels:
app: echo1
replicas: 2
template:
metadata:
labels:
app: echo1
spec:
containers:
- name: echo1
image: hashicorp/http-echo
args:
- "-text=echo1"
ports:
- containerPort: 5678
在此文件中,我们定义了一个名为echo1
的服务,它使用app: echo1
标签选择器将流量路由到app: echo1
。 它接受端口80
上的TCP流量,并将其路由到端口5678
, http-echo
的默认端口。
然后我们定义一个Deployment,也称为echo1
,它使用app: echo1
Label Selector管理Pods。 我们指定部署应该有2个Pod副本,并且Pod应该启动一个名为echo1
的容器来运行hashicorp/http-echo
图像。 我们传入text
参数并将其设置为echo1
,以便http-echo
Web服务器返回echo1
。 最后,我们在Pod容器上打开端口5678
。
一旦您对虚拟服务和部署清单感到满意,请保存并关闭该文件。
然后,使用带有-f
标志的kubectl create
创建Kubernetes资源,指定刚刚保存为参数的文件:
kubectl create -f echo1.yaml
您应该看到以下输出:
service/echo1 created
deployment.apps/echo1 created
通过确认它具有ClusterIP(服务所在的内部IP)来验证服务是否正确启动:
kubectl get svc echo1
您应该看到以下输出:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
echo1 ClusterIP 10.245.222.129 <none> 80/TCP 60s
这表示echo1
服务现在可在内部在端口80
上的10.245.222.129
处10.245.222.129
。 它会将流量转发到它选择的5678
上的containerPort 5678
。
既然echo1
服务已启动并正在运行,请对echo2
服务重复此过程。
创建并打开一个名为echo2.yaml
的文件:
apiVersion: v1
kind: Service
metadata:
name: echo2
spec:
ports:
- port: 80
targetPort: 5678
selector:
app: echo2
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo2
spec:
selector:
matchLabels:
app: echo2
replicas: 1
template:
metadata:
labels:
app: echo2
spec:
containers:
- name: echo2
image: hashicorp/http-echo
args:
- "-text=echo2"
ports:
- containerPort: 5678
在这里,我们基本上使用与上面相同的服务和部署清单,但命名并重新标记服务和部署echo2
。 另外,为了提供一些变化,我们只创建了1个Pod副本。 我们确保将text
参数设置为echo2
以便Web服务器返回文本echo2
。
保存并关闭该文件,并使用kubectl
创建Kubernetes资源:
kubectl create -f echo2.yaml
您应该看到以下输出:
service/echo2 created
deployment.apps/echo2 created
再次确认服务已启动并正在运行:
kubectl get svc
您应该看到带有已分配的ClusterIP的echo1
和echo2
服务:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
echo1 ClusterIP 10.245.222.129 <none> 80/TCP 6m6s
echo2 ClusterIP 10.245.128.224 <none> 80/TCP 6m3s
kubernetes ClusterIP 10.245.0.1 <none> 443/TCP 4d21h
现在我们的虚拟echoWeb服务已经启动并运行,我们可以继续推出Nginx入口控制器。
在这一步中,我们将推出Kubernetes维护的Nginx入口控制器 。 请注意,有几个 Nginx入口控制器; Kubernetes社区维护本指南中使用的一个,Nginx Inc.维护kubernetes-ingress 。 本教程中的说明基于官方Kubernetes Nginx Ingress Controller 安装指南中的说明 。
Nginx Ingress控制器由一个Pod组成,该Pod运行Nginx Web服务器并监视Kubernetes控制平面以获取新的和更新的Ingress Resource对象。 入口资源本质上是后端服务的流量路由规则列表。 例如,Ingress规则可以指定到达路径/web1
HTTP流量应该指向web1
后端Web服务器。 使用Ingress Resources,您还可以执行基于主机的路由:例如,将web1.your_domain.com
请求路由到后端Kubernetes Service web1
。
在这种情况下,由于我们正在将Ingress Controller部署到DigitalOcean Kubernetes集群,因此Controller将创建一个LoadBalancer服务,该服务可以旋转DigitalOcean负载均衡器,所有外部流量都将被引导到该负载均衡器。 此负载均衡器将外部流量路由到运行Nginx的Ingress Controller Pod,然后Nginx将流量转发到相应的后端服务。
我们首先创建Nginx Ingress Controller所需的Kubernetes资源。 它们包括包含Controller配置的ConfigMaps,用于授予Controller访问Kubernetes API的基于角色的访问控制(RBAC)角色以及实际的Ingress Controller部署。 要查看这些所需资源的完整列表,请参阅Kubernetes Nginx Ingress Controller的GitHub存储库中的清单 。
要创建这些必需资源,请使用kubectl apply
和-f
标志指定GitHub上托管的清单文件:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml
我们在这里使用apply
而不是create
,以便将来我们可以逐步apply
更改应用于Ingress Controller对象,而不是完全覆盖它们。 要了解有关apply
更多信息,请参阅官方Kubernetes文档中的管理资源 。
您应该看到以下输出:
namespace/ingress-nginx created
configmap/nginx-configuration created
configmap/tcp-services created
configmap/udp-services created
serviceaccount/nginx-ingress-serviceaccount created
clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole created
role.rbac.authorization.k8s.io/nginx-ingress-role created
rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding created
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding created
deployment.extensions/nginx-ingress-controller created
此输出还可作为从mandatory.yaml
清单创建的所有Ingress Controller对象的便捷摘要。
接下来,我们将创建Ingress Controller LoadBalancer服务,该服务将创建一个DigitalOcean负载均衡器,它将负载平衡并将HTTP和HTTPS流量路由到上一个命令中部署的Ingress Controller Pod。
要创建LoadBalancer服务, kubectl apply
再次kubectl apply
包含服务定义的清单文件:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/cloud-generic.yaml
您应该看到以下输出:
service/ingress-nginx created
现在,通过使用kubectl
获取服务详细信息,确认已成功创建DigitalOcean Load Balancer:
kubectl get svc --namespace=ingress-nginx
您应该看到一个外部IP地址,对应于DigitalOcean Load Balancer的IP地址:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx LoadBalancer 10.245.247.67 203.0.113.0 80:32486/TCP,443:32096/TCP 20h
记下Load Balancer的外部IP地址,因为您将在以后的步骤中使用它。
此负载平衡器接收HTTP和HTTPS端口80和443上的流量,并将其转发到Ingress Controller Pod。 然后,Ingress Controller将流量路由到适当的后端服务。
我们现在可以在此外部负载均衡器上指出我们的DNS记录,并创建一些Ingress资源来实现流量路由规则。
让我们首先创建一个最小的Ingress资源,将指向给定子域的流量路由到相应的后端服务。
在本指南中,我们将使用测试域example.com 。 您应该使用您拥有的域名替换它。
我们将首先创建一个简单的规则来路由指向echo1的流量。 example.com到echo1
后端服务和指向echo2的流量。 example.com到echo2
后端服务。
首先在您喜欢的编辑器中打开一个名为echo_ingress.yaml
的文件:
nano echo_ingress.yaml
粘贴以下入口定义:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: echo-ingress
spec:
rules:
- host: echo1.example.com
http:
paths:
- backend:
serviceName: echo1
servicePort: 80
- host: echo2.example.com
http:
paths:
- backend:
serviceName: echo2
servicePort: 80
完成编辑Ingress规则后,保存并关闭文件。
在这里,我们已经指定我们要创建一个名为echo-ingress
的入口资源,并根据Host头路由流量。 HTTP请求主机头指定目标服务器的域名。 要了解有关主机请求标头的更多信息,请参阅Mozilla开发人员网络定义页面 。 主机echo1的请求。 example.com将被定向到第1步中设置的echo1
后端,并使用主机echo2进行请求。 example.com将被定向到echo2
后端。
您现在可以使用kubectl
创建Ingress:
kubectl apply -f echo_ingress.yaml
您将看到以下输出确认Ingress创建:
ingress.extensions/echo-ingress created
要测试Ingress,请导航到DNS管理服务,并为echo1.example.com
和echo2.example.com
创建A记录,指向DigitalOcean Load Balancer的外部IP。 Load Balancer的外部IP是ingress-nginx
服务的外部IP地址,我们在上一步中获取了该地址。 如果您使用DigitalOcean管理域的DNS记录,请参阅如何管理DNS记录以了解如何创建A记录。
一旦创建了必要的echo1.example.com
和echo2.example.com
DNS记录,就可以使用curl
命令行实用程序测试您创建的Ingress Controller和Resource。
从本地计算机, curl
echo1
服务:
curl echo1.example.com
您应该从echo1
服务获得以下响应:
echo1
这确认您对echo1.example.com
的请求正在通过Nginx入口正确路由到echo1
后端服务。
现在,对echo2
服务执行相同的测试:
curl echo2.example.com
您应该从echo2
服务获得以下响应:
echo2
这确认您对echo2.example.com
的请求正在通过Nginx入口正确路由到echo2
后端服务。
此时,您已成功设置基本Nginx Ingress以执行基于虚拟主机的路由。 在下一步中,我们将使用Helm安装cert-manager为我们的Ingress配置TLS证书,并启用更安全的HTTPS协议。
在此步骤中,我们将使用Helm将cert-manager安装到我们的集群中。 cert-manager是一个Kubernetes服务,它提供来自Let's Encrypt和其他证书颁发机构的TLS证书并管理它们的生命周期。 可以通过使用certmanager.k8s.io/issuer
注释注释Ingress资源,在Ingress规范中附加tls
部分以及配置一个或多个发行者来指定首选证书颁发机构来请求和配置证书。 要了解有关Issuer对象的更多信息,请参阅有关Issuers的官方证书管理器文档。
我们首先使用Helm将installcert-manager安装到我们的集群中:
helm install --name cert-manager --namespace kube-system --version v0.4.1 stable/cert-manager
您应该看到以下输出:
. . .
NOTES:
cert-manager has been deployed successfully!
In order to begin issuing certificates, you will need to set up a ClusterIssuer
or Issuer resource (for example, by creating a 'letsencrypt-staging' issuer).
More information on the different types of issuers and how to configure them
can be found in our documentation:
https://cert-manager.readthedocs.io/en/latest/reference/issuers.html
For information on how to configure cert-manager to automatically provision
Certificates for Ingress resources, take a look at the `ingress-shim`
documentation:
https://cert-manager.readthedocs.io/en/latest/reference/ingress-shim.html
这表明cert-manager安装成功。
在我们开始为Ingress主机颁发证书之前,我们需要创建一个Issuer,它指定可以从中获取签名的x509证书的证书颁发机构。 在本指南中,我们将使用Let的加密证书颁发机构,该机构提供免费的TLS证书,并提供用于测试证书配置的登台服务器和用于推出可验证TLS证书的生产服务器。
让我们创建一个测试颁发者,以确保证书配置机制正常运行。 在您喜欢的文本编辑器中打开名为staging_issuer.yaml
的文件:
nano staging_issuer.yaml
粘贴在以下ClusterIssuer清单中:
apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
# The ACME server URL
server: https://acme-staging-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: your_email_address_here
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-staging
# Enable the HTTP-01 challenge provider
http01: {}
这里我们指定我们要创建一个名为letsencrypt-staging
的ClusterIssuer对象,并使用Let的加密登台服务器。 我们稍后将使用生产服务器来推出我们的证书,但生产服务器可能会对针对它的请求进行速率限制,因此出于测试目的,最好使用暂存URL。
然后,我们指定一个电子邮件地址来注册证书,并创建一个名为letsencrypt-staging
的Kubernetes Secret来存储证书的私钥。 我们还启用了HTTP-01
质询机制。 要了解有关这些参数的更多信息,请参阅有关发布者的官方证书管理员文档。
使用kubectl
推出ClusterIssuer:
kubectl create -f staging_issuer.yaml
您应该看到以下输出:
clusterissuer.certmanager.k8s.io/letsencrypt-staging created
现在我们已经创建了Let's Encrypt staging Issuer,我们已经准备好修改上面创建的Ingress资源,并为echo1.example.com
和echo2.example.com
路径启用TLS加密。
在你最喜欢的编辑器中再次打开echo_ingress.yaml
:
nano echo_ingress.yaml
将以下内容添加到Ingress资源清单中:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: echo-ingress
annotations:
kubernetes.io/ingress.class: nginx
certmanager.k8s.io/cluster-issuer: letsencrypt-staging
spec:
tls:
- hosts:
- echo1.example.com
- echo2.example.com
secretName: letsencrypt-staging
rules:
- host: echo1.example.com
http:
paths:
- backend:
serviceName: echo1
servicePort: 80
- host: echo2.example.com
http:
paths:
- backend:
serviceName: echo2
servicePort: 80
这里我们添加一些注释来指定ingress.class
,它确定应该用于实现Ingress规则的Ingress Controller。 此外,我们将cluster-issuer
定义为letsencrypt-staging
,即我们刚刚创建的证书颁发者。
最后,我们添加一个tls
块来指定我们要获取证书的主机,并指定我们之前创建的私钥。
完成更改后,保存并关闭文件。
我们现在将使用kubectl apply
更新现有的Ingress资源:
kubectl apply -f echo_ingress.yaml
您应该看到以下输出:
ingress.extensions/echo-ingress configured
您可以使用kubectl describe
来跟踪刚刚应用的Ingress更改的状态:
kubectl describe ingress
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal CREATE 14m nginx-ingress-controller Ingress default/echo-ingress
Normal UPDATE 1m (x2 over 13m) nginx-ingress-controller Ingress default/echo-ingress
Normal CreateCertificate 1m cert-manager Successfully created Certificate "letsencrypt-staging"
成功创建证书后,您可以对其运行其他describe
以进一步确认其成功创建:
kubectl describe certificate
您应该在“ Events
部分中看到以下输出:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal CreateOrder 50s cert-manager Created new ACME order, attempting validation...
Normal DomainVerified 15s cert-manager Domain "echo2.example.com" verified with "http-01" validation
Normal DomainVerified 3s cert-manager Domain "echo1.example.com" verified with "http-01" validation
Normal IssueCert 3s cert-manager Issuing certificate...
Normal CertObtained 1s cert-manager Obtained certificate from ACME server
Normal CertIssued 1s cert-manager Certificate issued successfully
这确认已成功发布TLS证书,并且对于配置的两个域,HTTPS加密现在处于活动状态。
我们现在准备向后端echo
服务器发送请求以测试HTTPS是否正常运行。
运行以下wget
命令向echo1.example.com
发送请求并将响应头打印到STDOUT
:
wget --save-headers -O- echo1.example.com
您应该看到以下输出:
URL transformed to HTTPS due to an HSTS policy
--2018-12-11 14:38:24-- https://echo1.example.com/
Resolving echo1.example.com (echo1.example.com)... 203.0.113.0
Connecting to echo1.example.com (echo1.example.net)|203.0.113.0|:443... connected.
ERROR: cannot verify echo1.example.com's certificate, issued by ‘CN=Fake LE Intermediate X1’:
Unable to locally verify the issuer's authority.
To connect to echo1.example.com insecurely, use `--no-check-certificate'.
这表示已成功启用HTTPS,但无法验证证书,因为它是Let's Encrypt登台服务器发出的伪造临时证书。
现在我们已经使用这个临时假证书测试了一切正常,我们可以为两个主机echo1.example.com
和echo2.example.com
推出生产证书。
在此步骤中,我们将修改用于提供登台证书的过程,并为我们的Ingress主机生成有效的,可验证的生产证书。
首先,我们将首先创建一个生产证书ClusterIssuer。
在您喜欢的编辑器中打开一个名为prod_issuer.yaml
的文件:
nano prod_issuer.yaml
粘贴在以下清单中:
apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
# The ACME server URL
server: https://acme-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: your_email_address_here
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-prod
# Enable the HTTP-01 challenge provider
http01: {}
请注意不同的ACME服务器URL和letsencrypt-prod
密钥名称。
完成编辑后,保存并关闭文件。
现在,使用kubectl
推出此Issuer:
kubectl create -f prod_issuer.yaml
您应该看到以下输出:
clusterissuer.certmanager.k8s.io/letsencrypt-prod created
更新echo_ingress.yaml
以使用此新颁发者:
nano echo_ingress.yaml
对文件进行以下更改:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: echo-ingress
annotations:
kubernetes.io/ingress.class: nginx
certmanager.k8s.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- echo1.example.com
- echo2.example.com
secretName: letsencrypt-prod
rules:
- host: echo1.example.com
http:
paths:
- backend:
serviceName: echo1
servicePort: 80
- host: echo2.example.com
http:
paths:
- backend:
serviceName: echo2
servicePort: 80
在这里,我们将ClusterIssuer和密钥更新为letsencrypt-prod
。
对更改满意后,保存并关闭文件。
使用kubectl apply
推出更改:
kubectl apply -f echo_ingress.yaml
ingress.extensions/echo-ingress configured
等待几分钟让Let's Encrypt生产服务器颁发证书。 您可以使用certificate
对象上的kubectl describe
跟踪其进度:
kubectl describe certificate letsencrypt-prod
看到以下输出后,证书已成功发出:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal CreateOrder 4m4s cert-manager Created new ACME order, attempting validation...
Normal DomainVerified 3m30s cert-manager Domain "echo2.example.com" verified with "http-01" validation
Normal DomainVerified 3m18s cert-manager Domain "echo1.example.com" verified with "http-01" validation
Normal IssueCert 3m18s cert-manager Issuing certificate...
Normal CertObtained 3m16s cert-manager Obtained certificate from ACME server
Normal CertIssued 3m16s cert-manager Certificate issued successfully
我们现在将使用curl
执行测试以验证HTTPS是否正常工作:
curl echo1.example.com
你应该看到以下内容:
<html>
<head><title>308 Permanent Redirect</title></head>
<body>
<center><h1>308 Permanent Redirect</h1></center>
<hr><center>nginx/1.15.6</center>
</body>
</html>
这表示正在重定向HTTP请求以使用HTTPS。
在https://echo1.example.com
上运行curl
:
curl https://echo1.example.com
您现在应该看到以下输出:
echo1
您可以使用verbose -v
标志运行上一个命令,以深入了解证书握手并验证证书信息。
此时,您已使用适用于Nginx Ingress的Let's Encrypt证书成功配置了HTTPS。
在本指南中,您将设置Nginx Ingress以对Kubernetes集群内的后端服务进行负载均衡和路由。 您还通过安装cert-manager证书配置程序并为两个主机路径设置Let's Encrypt证书来保护Ingress。
Nginx Ingress控制器有很多替代品。 要了解更多信息,请参阅官方Kubernetes文档中的Ingress控制器 。
关注云架构公众号
Linux入门
QQ交流群:308781113