- 一.系統環境
- 二.前言
- 三.對稱加密和非對稱加密簡介
- 四.什麼是HTTPS
- 五.Ingress簡介
- 六.配置ingress對外發布服務
- 6.1 安裝NGINX ingress controller控制器
- 6.2 建立pod
- 6.3 為pod建立svc服務
- 6.4 使用ingress釋出服務
- 6.5 訪問服務
- 6.5.1 使用Linux客戶端來訪問服務
- 6.5.2 使用Windows客戶端訪問服務
- 七.配置Ingress支援HTTPS訪問
- 7.1 使用ingress-nginx-controller自帶的證書
- 7.2 使用cfssl工具生成證書
- 7.2.1 安裝cfssl
- 7.2.2 生成CA
- 7.2.3 生成使用者證書
- 7.2.4 使用自定義的證書
- 八.總結
一.系統環境
本文主要基於Kubernetes1.22.2和Linux作業系統Ubuntu 18.04。
伺服器版本 | docker軟體版本 | Kubernetes(k8s)叢集版本 | kube-bench版本 | CPU架構 |
---|---|---|---|---|
Ubuntu 18.04.5 LTS | Docker version 20.10.14 | v1.22.2 | 0.6.7 | x86_64 |
Kubernetes叢集架構:k8scludes1作為master節點,k8scludes2,k8scludes3作為worker節點。
伺服器 | 作業系統版本 | CPU架構 | 程序 | 功能描述 |
---|---|---|---|---|
k8scludes1/192.168.110.128 | Ubuntu 18.04.5 LTS | x86_64 | docker,kube-apiserver,etcd,kube-scheduler,kube-controller-manager,kubelet,kube-proxy,coredns,calico | k8s master節點 |
k8scludes2/192.168.110.129 | Ubuntu 18.04.5 LTS | x86_64 | docker,kubelet,kube-proxy,calico | k8s worker節點 |
k8scludes3/192.168.110.130 | Ubuntu 18.04.5 LTS | x86_64 | docker,kubelet,kube-proxy,calico | k8s worker節點 |
二.前言
HTTPS是安全的HTTP協議,它透過SSL/TLS協議為客戶端與伺服器之間的通訊提供加密。在Kubernetes叢集中,Ingress資源管理叢集外的訪問,透過配置Ingress,我們可以為服務提供安全的HTTPS訪問。
在Kubernetes叢集中配置Ingress以支援HTTPS訪問的前提是已經有一套可以正常執行的Kubernetes叢集,關於Kubernetes(k8s)叢集的安裝部署,可以檢視部落格《Ubuntu 安裝部署Kubernetes(k8s)叢集》https://www.cnblogs.com/renshengdezheli/p/17632858.html。
三.對稱加密和非對稱加密簡介
資料加密的型別有:
- 對稱加密:使用相同的金鑰進行加密和解密。優點是演算法公開、計算量小、加密速度快、加密效率高,但金鑰分發是一個挑戰,如果金鑰在協商過程中被洩露,那麼密文就可能被破解。常見的對稱加密演算法有des,aes,des256,des512等
- 非對稱加密:使用一對金鑰,一個用於加密(公鑰(可公開)),另一個用於解密(私鑰(私有的))。優點是安全性高,即使密文被攔截、公鑰被獲取,由於無法獲取到私鑰,攻擊者也無法破譯密文。常見的非對稱加密演算法有RSA、DSA、ECC等。但是非對稱加密的計算過程複雜,加解密效率相對較低,舉個例子:A給B傳輸檔案,A先使用B的公鑰加密,然後把加密檔案傳送給B,B使用自己的私鑰進行解密。
- 雜湊函式:輸入不定長的值,總能得到一個定長的值。
另外非對稱加密除了可以用來做資料加密(公鑰加密,私鑰解密),還可以用來做數字簽名(私鑰加密,公鑰解密),數字簽名用來驗證身份,舉個例子:A要給B傳送一個資料,A需要向B證明這資料就是A傳送的,不是別人傳送的。A對需要傳輸的檔案生成一個雜湊值,檔案內容不發生變化,雜湊值就不會發生變化,A使用私鑰加密雜湊值,然後把資料和加密後的雜湊值傳送給B, B使用A的公鑰解密雜湊值,B將收到的資料生成一個雜湊值,如果檔案在傳輸的過程中沒有被修改,則兩個雜湊值應該是一樣的 ,這樣就可以驗證資料是不是A傳送的,以及資料有沒有被修改過。
混合加密即對稱加密和非對稱加密的混合使用,有時會把檔案先進行對稱加密再非對稱加密,再傳輸,這樣對稱加密的金鑰傳輸過程就是安全的,但是存在中間人攻擊,B把公鑰發給A,途中被中間人C截獲了,然後把C的公鑰發給A,A自以為使用了“正確的B的公鑰”,其實收到的是C偽裝的公鑰,A加密之後把加密檔案發給B,C截獲了加密檔案,並使用C的私鑰解密得到明文,最後使用正確的B公鑰加密檔案,把檔案發給B,這就是中間人攻擊。
解決中間人攻擊的方法是使用CA,認證中心(CA)是一個權威的、受信任的第三方機構,其核心職能是發放和管理數字證書,用於證明和確認交易參與者的身份,保證電子商務交易過程中身份可認證性。舉個例子:B傳送csr(證書請求檔案)給CA證書中心,CA稽核透過之後,給B頒發證書,證書上有CA的蓋章(數字簽名),說明這個證書是CA認證過的沒問題,B把證書發給A,A使用CA的公鑰驗證證書的數值簽名,驗證是不是CA頒發的證 書,瀏覽器裡也儲存著證書資訊,確定這是CA給B頒發的證書之後,使用證書加密金鑰,傳輸給B。
注意:證書的本質就是公鑰。
總的來說,對稱加密和非對稱加密各有優缺點,具體使用哪種方式取決於實際需求和場景。
四.什麼是HTTPS
HTTPS,全稱Hypertext Transfer Protocol Secure,是超文字傳輸安全協議。它是一種透過計算機網路進行安全通訊的傳輸協議,以安全為目標的 HTTP 通道。在HTTP的基礎上,HTTPS透過傳輸加密和身份認證保證了傳輸過程的安全性。
HTTPS的誕生是為了解決HTTP通訊使用明文的問題,驗證通訊方的身份,以及證明報文的完整性。在HTTP與TCP之間,HTTPS加入了SSL(Secure Sockets Layer)/TLS(Transport Layer Security)協議來為資料傳輸提供加密和身份驗證。如果進行更具體的解釋,可以將HTTPS理解為身披SSL/TLS協議這層外殼的HTTP,即https=http+tls/ssl,ssl是tls的前身。
HTTPS解決資料傳輸安全問題的方案就是使用加密演算法,具體來說是混合加密演算法,也就是對稱加密和非對稱加密的混合使用。
五.Ingress簡介
Ingress是Kubernetes中的一個API物件,用於管理對叢集內服務的外部訪問。Ingress資源允許您定義如何路由外部HTTP(S)流量到叢集中的不同服務。
kubernetes服務的釋出方式有:NodePort,LoadBalancer,Ingress,關於使用NodePort或者LoadBalancer釋出Kubernetes服務,詳情請檢視部落格《Kubernetes(k8s)服務service:service的發現和service的釋出》,Kubernetes(k8s)使用ingress釋出服務,我們在部落格《Kubernetes(k8s)使用ingress釋出服務》中也做了詳細介紹。但是之前使用ingress釋出服務,使用的是http的方式,是以明文的方式訪問的,這樣不安全。
本文配置Ingress支援HTTPS訪問,提高安全性,避免流量被劫持,提高搜尋站點的權重。
六.配置ingress對外發布服務
6.1 安裝NGINX ingress controller控制器
要使用Ingress,需要先安裝一個Ingress控制器來處理Ingress物件。本次使用Nginx Ingress Controller控制器,Nginx Ingress Controller控制器本質上是一個nginx的反向代理(根據訪問地址的不同,轉發到不同的伺服器)。Nginx Ingress Controller的官網為:https://kubernetes.github.io/ingress-nginx/deploy/。
下載ingress-nginx的部署yaml檔案。
root@k8scludes1:~/TLS-ingress# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.1/deploy/static/provider/cloud/deploy.yaml
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.109.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 19299 (19K) [text/plain]
Saving to: ‘deploy.yaml’
deploy.yaml 100%[====================================================================================================================>] 18.85K 35.5KB/s in 0.5s
2022-04-20 15:09:22 (35.5 KB/s) - ‘deploy.yaml’ saved [19299/19299]
檢視ingress-nginx所需的映象。
root@k8scludes1:~/TLS-ingress# grep image deploy.yaml
image: k8s.gcr.io/ingress-nginx/controller:v1.1.1@sha256:0bc88eb15f9e7f84e8e56c14fa5735aaa488b840983f87bd79b1054190e660de
imagePullPolicy: IfNotPresent
image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660
imagePullPolicy: IfNotPresent
image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660
imagePullPolicy: IfNotPresent
因為k8s.gcr.io/ingress-nginx/controller:v1.1.1映象下載不了,我們搜尋可用的映象。
root@k8scludes1:~# docker search controller:v1.1.1 --no-trunc
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
loging/ingress-nginx-controller k8s.gcr.io/ingress-nginx/controller:v1.1.1 1
jhonsun777/controller k8s.gcr.io/ingress-nginx/controller:v1.1.1 0
root@k8scludes1:~/TLS-ingress# docker search kube-webhook-certgen:v1.1.1 --no-trunc
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
lianyuxue1020/kube-webhook-certgen new pull lianyuxue1020/kube-webhook-certgen:v1.1.1 1
xyz349925756/ingress-nginx-kube-webhook-certgen k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1 0
freemankevin/kube-webhook-certgen correspond:k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1 0
longjianghu/ingress-nginx-kube-webhook-certgen k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1原版映象 0
caihy/ingress-nginx-kube-webhook-certgen FROM k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1 0
在worker節點下載controller映象和kube-webhook-certgen映象。
root@k8scludes2:~# docker pull willdockerhub/ingress-nginx-controller:v1.0.0
root@k8scludes2:~# docker pull docker.io/liangjw/kube-webhook-certgen:v1.1.1
root@k8scludes3:~# docker pull willdockerhub/ingress-nginx-controller:v1.0.0
root@k8scludes3:~# docker pull docker.io/liangjw/kube-webhook-certgen:v1.1.1
把deploy.yaml檔案裡的映象修改為我們下載好的映象,注意ingress-nginx-controller和kube-webhook-certgen映象的版本不要差太多,不然部署失敗。
root@k8scludes1:~/TLS-ingress# grep image deploy.yaml
image: willdockerhub/ingress-nginx-controller:v1.0.0
imagePullPolicy: IfNotPresent
image: docker.io/liangjw/kube-webhook-certgen:v1.1.1
imagePullPolicy: IfNotPresent
image: docker.io/liangjw/kube-webhook-certgen:v1.1.1
imagePullPolicy: IfNotPresent
應用ingress-nginx-controller。
root@k8scludes1:~/TLS-ingress# kubectl apply -f deploy.yaml
namespace/ingress-nginx created
serviceaccount/ingress-nginx created
configmap/ingress-nginx-controller created
clusterrole.rbac.authorization.k8s.io/ingress-nginx created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created
role.rbac.authorization.k8s.io/ingress-nginx created
rolebinding.rbac.authorization.k8s.io/ingress-nginx created
service/ingress-nginx-controller-admission created
service/ingress-nginx-controller created
deployment.apps/ingress-nginx-controller created
ingressclass.networking.k8s.io/nginx created
validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created
serviceaccount/ingress-nginx-admission created
clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
role.rbac.authorization.k8s.io/ingress-nginx-admission created
rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
job.batch/ingress-nginx-admission-create created
job.batch/ingress-nginx-admission-patch created
顯示如下,則ingress-nginx-controller控制器部署成功。
root@k8scludes1:~/TLS-ingress# kubectl get pod -n ingress-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx-admission-create--1-t5hqt 0/1 Completed 0 23s 10.244.218.147 k8scludes2 <none> <none>
ingress-nginx-admission-patch--1-wzb6x 0/1 Completed 1 23s 10.244.218.146 k8scludes2 <none> <none>
ingress-nginx-controller-6b64bc6f47-dgjdq 1/1 Running 0 23s 10.244.218.148 k8scludes2 <none> <none>
注意deploy.yaml檔案裡- --watch-ingress-without-class=true引數加不加都沒有影響。
root@k8scludes1:~/TLS-ingress# grep -A12 arg deploy.yaml
args:
- /nginx-ingress-controller
- --election-id=ingress-controller-leader
- --controller-class=k8s.io/ingress-nginx
- --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
- --validating-webhook=:8443
- --validating-webhook-certificate=/usr/local/certificates/cert
- --validating-webhook-key=/usr/local/certificates/key
#- --watch-ingress-without-class=true
6.2 建立pod
NGINX ingress controller控制器搭建成功之後建立pod。
在worker節點提前下載好nginx映象。
root@k8scludes2:~# docker pull hub.c.163.com/library/nginx:latest
root@k8scludes3:~# docker pull hub.c.163.com/library/nginx:latest
pod配置檔案如下,功能為使用Nginx映象建立pod。
root@k8scludes1:~/TLS-ingress# vim pod.yaml
#使用nginx映象建立pod
root@k8scludes1:~/TLS-ingress# cat pod.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
test: podtest
name: podtest
spec:
#當需要關閉容器時,立即殺死容器而不等待預設的30秒優雅停機時長。
terminationGracePeriodSeconds: 0
containers:
- name: nginx
image: hub.c.163.com/library/nginx:latest
#imagePullPolicy: IfNotPresent:表示如果本地已經存在該映象,則不重新下載;否則從遠端 Docker Hub 下載該映象
imagePullPolicy: IfNotPresent
生成三個pod用於ingress訪問。
root@k8scludes1:~/TLS-ingress# sed 's/podtest/nginx1/' pod.yaml | kubectl apply -f -
pod/nginx1 created
root@k8scludes1:~/TLS-ingress# sed 's/podtest/nginx2/' pod.yaml | kubectl apply -f -
pod/nginx2 created
root@k8scludes1:~/TLS-ingress# sed 's/podtest/nginx3/' pod.yaml | kubectl apply -f -
pod/nginx3 created
檢視pod。
root@k8scludes1:~/TLS-ingress# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx1 1/1 Running 0 31s 10.244.218.149 k8scludes2 <none> <none>
nginx2 1/1 Running 0 21s 10.244.218.150 k8scludes2 <none> <none>
nginx3 1/1 Running 0 12s 10.244.1.81 k8scludes3 <none> <none>
修改nginx的index.html檔案,用於辨別每個pod。
root@k8scludes1:~/TLS-ingress# kubectl exec -it nginx1 -- sh -c "echo 111 >/usr/share/nginx/html/index.html"
root@k8scludes1:~/TLS-ingress# kubectl exec -it nginx2 -- sh -c "echo 222 >/usr/share/nginx/html/index.html"
root@k8scludes1:~/TLS-ingress# kubectl exec -it nginx3 -- sh -c "mkdir /usr/share/nginx/html/ingress; echo 333 >/usr/share/nginx/html/ingress/index.html"
6.3 為pod建立svc服務
給每個pod建立一個svc服務。
root@k8scludes1:~/TLS-ingress# kubectl expose --name=nginx1svc pod nginx1 --port=80
service/nginx1svc exposed
root@k8scludes1:~/TLS-ingress# kubectl expose --name=nginx2svc pod nginx2 --port=80
service/nginx2svc exposed
root@k8scludes1:~/TLS-ingress# kubectl expose --name=nginx3svc pod nginx3 --port=80
service/nginx3svc exposed
檢視svc。
root@k8scludes1:~/TLS-ingress# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
nginx1svc ClusterIP 10.98.119.83 <none> 80/TCP 24s test=nginx1
nginx2svc ClusterIP 10.106.4.10 <none> 80/TCP 17s test=nginx2
nginx3svc ClusterIP 10.101.154.93 <none> 80/TCP 9s test=nginx3
訪問svc。
root@k8scludes1:~/TLS-ingress# curl 10.98.119.83
111
root@k8scludes1:~/TLS-ingress# curl 10.106.4.10
222
root@k8scludes1:~/TLS-ingress# curl 10.101.154.93/ingress/index.html
333
6.4 使用ingress釋出服務
建立ingress規則。
root@k8scludes1:~/TLS-ingress# vim ingress-rule.yaml
#注意在annotations中需要指定你的ingress是何種,此處使用的nginx-ingress所以是Nginx,否則無法透過配置的域名www.nginx13.com訪問
#訪問www.nginx13.com就相當於訪問nginx1svc服務
root@k8scludes1:~/TLS-ingress# cat ingress-rule.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: www.nginx13.com
http:
paths:
#訪問網址目錄
- path: /
pathType: Prefix
backend:
service:
name: nginx1svc
port:
number: 80
- path: /ingress
pathType: Prefix
backend:
service:
name: nginx3svc
port:
number: 80
- host: www.nginx2.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx2svc
port:
number: 80
應用ingress規則。
root@k8scludes1:~/TLS-ingress# kubectl apply -f ingress-rule.yaml
ingress.networking.k8s.io/my-ingress created
檢視ingress。
root@k8scludes1:~/TLS-ingress# kubectl get ingress -o wide
NAME CLASS HOSTS ADDRESS PORTS AGE
my-ingress <none> www.nginx13.com,www.nginx2.com 80 10s
root@k8scludes1:~/TLS-ingress# kubectl get ing -o wide
NAME CLASS HOSTS ADDRESS PORTS AGE
my-ingress <none> www.nginx13.com,www.nginx2.com 80 34s
可以發現svc的80埠被對映為32253埠。
root@k8scludes1:~/TLS-ingress# kubectl get svc -n ingress-nginx -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
ingress-nginx-controller NodePort 10.96.184.210 <none> 80:32253/TCP,443:30876/TCP 22m app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
ingress-nginx-controller-admission ClusterIP 10.102.52.109 <none> 443/TCP 22m app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
當在其他名稱空間建立相同的ingress規則時,會提醒重複。
root@k8scludes1:~/TLS-ingress# kubectl apply -f ingress-rule.yaml -n default
Error from server (BadRequest): error when creating "ingress-rule.yaml": admission webhook "validate.nginx.ingress.kubernetes.io" denied the request: host "www.nginx13.com" and path "/" is already defined in ingress tls-ingress/my-ingress
6.5 訪問服務
6.5.1 使用Linux客戶端來訪問服務
ingress規則建立之後,我們使用Linux客戶端來訪問服務。
我們使用etcd2機器作為客戶端,因為ingress-nginx-controller控制器在k8scludes2上,k8scludes2的IP地址為192.168.110.129。
root@k8scludes1:~/TLS-ingress# kubectl get pod -o wide -n ingress-nginx
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx-admission-create--1-t5hqt 0/1 Completed 0 23m 10.244.218.147 k8scludes2 <none> <none>
ingress-nginx-admission-patch--1-wzb6x 0/1 Completed 1 23m 10.244.218.146 k8scludes2 <none> <none>
ingress-nginx-controller-6b64bc6f47-dgjdq 1/1 Running 0 23m 10.244.218.148 k8scludes2 <none> <none>
我們配置客戶端etcd2機器的 /etc/hosts檔案,ingress-nginx-controller控制器IP和域名的對映。
[root@etcd2 ~]# vim /etc/hosts
ingress-nginx-controller控制器IP和域名的對映
[root@etcd2 ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.110.133 etcd1
192.168.110.131 etcd2
192.168.110.132 etcd3
192.168.110.129 www.nginx13.com
192.168.110.129 www.nginx2.com
直接訪問域名的80埠被拒絕了。
[root@etcd2 ~]# curl www.nginx13.com
curl: (7) Failed connect to www.nginx13.com:80; 拒絕連線
[root@etcd2 ~]# curl www.nginx2.com
curl: (7) Failed connect to www.nginx2.com:80; 拒絕連線
ingress-nginx-controller服務把80埠被對映為32253埠,所以外界需要訪問32253埠。
root@k8scludes1:~/TLS-ingress# kubectl get svc -n ingress-nginx -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
ingress-nginx-controller NodePort 10.96.184.210 <none> 80:32253/TCP,443:30876/TCP 22m app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
ingress-nginx-controller-admission ClusterIP 10.102.52.109 <none> 443/TCP 22m app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
現在透過域名就可以訪問nginx的不同服務了。
[root@etcd2 ~]# curl www.nginx13.com:32253
111
[root@etcd2 ~]# curl www.nginx2.com:32253/
222
[root@etcd2 ~]# curl www.nginx13.com:32253/ingress/index.html
333
6.5.2 使用Windows客戶端訪問服務
我們也可以使用Windows機器作為客戶端訪問服務。修改Windows機器的C:\Windows\System32\drivers\etc\HOSTS檔案的IP域名對映。
192.168.110.129 www.nginx13.com
192.168.110.129 www.nginx2.com
然後使用瀏覽器透過域名訪問nginx服務。
自此ingress對外發布服務成功,但是現在使用的是http://www.nginx13.com訪問的,http是明文傳輸,不安全。
七.配置Ingress支援HTTPS訪問
7.1 使用ingress-nginx-controller自帶的證書
此時pod,svc沒有做任何https配置,客戶端使用https訪問ingress-nginx-controller,瀏覽器會發出警告,這是因為ingress-nginx-controller也有證書,但是客戶端一核實,不是CA頒發的證書,瀏覽器就報警了。
https埠為443,對應的埠為30876。
root@k8scludes1:~/TLS-ingress# kubectl get svc -n ingress-nginx -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
ingress-nginx-controller NodePort 10.96.184.210 <none> 80:32253/TCP,443:30876/TCP 22m app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
ingress-nginx-controller-admission ClusterIP 10.102.52.109 <none> 443/TCP 22m app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
瀏覽器訪問https://www.nginx2.com:31473/,檢視證書,點選證書無效。
可以看到,證書為ingress自帶的證書。
![image-20230728164634801](https://typorablogimage.oss-cn-hangzhou.aliyuncs.com/image-20230728164634801.png)
繼續訪問。
![image-20230728164721194](https://typorablogimage.oss-cn-hangzhou.aliyuncs.com/image-20230728164721194.png)
使用https可以訪問服務,但是證書是ingress自帶的證書。
ingress-nginx-controller給不同的域名提供域名解析服務,證書是各個域名共享的,即所有的站點共享這個證書。
7.2 使用cfssl工具生成證書
7.2.1 安裝cfssl
現在我們想申請自己專屬的證書,而不是ingress-nginx-controller共享的證書,可以使用cfssl工具自己生成一個證書。
cfssl下載地址:https://github.com/cloudflare/cfssl/releases 。
下載這三個檔案:cfssl_1.6.1_linux_amd64 , cfssl-certinfo_1.6.1_linux_amd64 , cfssljson_1.6.1_linux_amd64 。
![image-20230728164902561](https://typorablogimage.oss-cn-hangzhou.aliyuncs.com/image-20230728164902561.png)
把下載好的cfssl檔案放到 /usr/local/bin/目錄下。
root@k8scludes1:~/TLS-ingress# cd /usr/local/bin/
root@k8scludes1:/usr/local/bin# ls
root@k8scludes1:/usr/local/bin# pwd
/usr/local/bin
root@k8scludes1:/usr/local/bin# rz -E
rz waiting to receive.
root@k8scludes1:/usr/local/bin# ls
cfssl_1.6.1_linux_amd64 cfssl-certinfo_1.6.1_linux_amd64 cfssljson_1.6.1_linux_amd64
檔案重新命名。
root@k8scludes1:/usr/local/bin# mv cfssl_1.6.1_linux_amd64 cfssl
root@k8scludes1:/usr/local/bin# mv cfssl-certinfo_1.6.1_linux_amd64 cfssl-certinfo
root@k8scludes1:/usr/local/bin# mv cfssljson_1.6.1_linux_amd64 cfssljson
root@k8scludes1:/usr/local/bin# ll -h
total 40M
drwxr-xr-x 2 root root 4.0K Apr 21 19:45 ./
drwxr-xr-x 10 root root 4.0K Nov 27 2020 ../
-rw-r--r-- 1 root root 16M Apr 21 17:39 cfssl
-rw-r--r-- 1 root root 13M Apr 21 17:50 cfssl-certinfo
-rw-r--r-- 1 root root 11M Apr 21 17:42 cfssljson
賦予可執行許可權。
root@k8scludes1:/usr/local/bin# chmod +x ./*
7.2.2 生成CA
建立tls目錄存放證書檔案。
root@k8scludes1:/usr/local/bin# cd
root@k8scludes1:~/TLS-ingress# mkdir tls
root@k8scludes1:~/TLS-ingress# cd tls/
root@k8scludes1:~/TLS-ingress/tls# pwd
/root/TLS-ingress/tls
使用cfssl工具生成證書的原理是:自己模擬一套完整的環境,包括CA也是自己搭建,需要CA(ca公鑰,ca私鑰),我們自己的私鑰和ca給我們頒發的證書,申請ca證書還需要證書請求檔案csr。
生成CA配置檔案。
- ca-config.json:可以定義多個 profiles,分別指定不同的過期時間、使用場景等引數;後續在簽名證書時使用某個profile;www,client都是profile。
- signing:表示該證書可用於簽名其它證書;生成的ca.pem證書中 CA=TRUE;
- server auth:表示client可以用該 CA 對server提供的證書進行驗證;
- client auth:表示server可以用該CA對client提供的證書進行驗證 ;
root@k8scludes1:~/TLS-ingress/tls# cfssl print-defaults config > ca-config.json
root@k8scludes1:~/TLS-ingress/tls# cat ca-config.json
{
"signing": {
"default": {
"expiry": "168h"
},
"profiles": {
"www": {
"expiry": "8760h",
"usages": [
"signing",
"key encipherment",
"server auth"
]
},
"client": {
"expiry": "8760h",
"usages": [
"signing",
"key encipherment",
"client auth"
]
}
}
}
}
修改CA配置檔案,這裡只設定一個profiles:www。
root@k8scludes1:~/TLS-ingress/tls# vim ca-config.json
root@k8scludes1:~/TLS-ingress/tls# cat ca-config.json
{
"signing": {
"default": {
"expiry": "1680h"
},
"profiles": {
"www": {
"expiry": "8760h",
"usages": [
"signing",
"key encipherment",
"server auth"
]
}
}
}
}
現在生成ca的證書請求檔案csr。
- CN: Common Name,瀏覽器使用該欄位驗證網站是否合法,一般寫的是域名;
- C: Country, 國家;
- L: Locality,地區,城市;
- O: Organization Name,組織名稱,公司名稱;
- OU: Organization Unit Name,組織單位名稱,公司部門;
- ST: State,州,省。
root@k8scludes1:~/TLS-ingress/tls# cfssl print-defaults csr > ca-csr.json
root@k8scludes1:~/TLS-ingress/tls# cat ca-csr.json
{
"CN": "example.net",
"hosts": [
"example.net",
"www.example.net"
],
"key": {
"algo": "ecdsa",
"size": 256
},
"names": [
{
"C": "US",
"ST": "CA",
"L": "San Francisco"
}
]
}
ca的證書請求檔案ca-csr.json,修改域名為nginxx.com,城市資訊換成廣州,algo表示加密演算法,size表示演算法長度。
root@k8scludes1:~/TLS-ingress/tls# vim ca-csr.json
root@k8scludes1:~/TLS-ingress/tls# cat ca-csr.json
{
"CN": "nginxx.com",
"key": {
"algo": "ecdsa",
"size": 256
},
"names": [
{
"C": "CN",
"ST": "guangdon",
"L": "guangzhou"
}
]
}
下面生成CA權威機構。
root@k8scludes1:~/TLS-ingress/tls# cfssl gencert -initca ca-csr.json | cfssljson -bare ca
2022/04/22 15:42:54 [INFO] generating a new CA key and certificate from CSR
2022/04/22 15:42:54 [INFO] generate received request
2022/04/22 15:42:54 [INFO] received CSR
2022/04/22 15:42:54 [INFO] generating key: ecdsa-256
2022/04/22 15:42:54 [INFO] encoded CSR
2022/04/22 15:42:54 [INFO] signed certificate with serial number 361660789191812789469217914317150175823294603356
生成了一個自簽名的證書,CA的證書(ca.pem),CA的私鑰(ca-key.pem)。
root@k8scludes1:~/TLS-ingress/tls# ls
ca-config.json ca.csr ca-csr.json ca-key.pem ca.pem
7.2.3 生成使用者證書
生成使用者test的證書請求檔案。
root@k8scludes1:~/TLS-ingress/tls# cfssl print-defaults csr >test-csr.json
root@k8scludes1:~/TLS-ingress/tls# cat test-csr.json
{
"CN": "example.net",
"hosts": [
"example.net",
"www.example.net"
],
"key": {
"algo": "ecdsa",
"size": 256
},
"names": [
{
"C": "US",
"ST": "CA",
"L": "San Francisco"
}
]
}
修改test-csr.json,"www.nginxx.com"表示申請的證書只給www.nginxx.com使用,hosts引數為空的話,便是所有的站點都可以使用該證書。
root@k8scludes1:~/TLS-ingress/tls# vim test-csr.json
root@k8scludes1:~/TLS-ingress/tls# cat test-csr.json
{
"CN": "nginxx.com",
"key": {
"algo": "ecdsa",
"size": 256
},
"hosts":[
"www.nginxx.com"
],
"names": [
{
"C": "CN",
"ST": "guangdon",
"L": "guangzhou"
}
]
}
root@k8scludes1:~/TLS-ingress/tls# ls
ca-config.json ca.csr ca-csr.json ca-key.pem ca.pem test-csr.json
把test使用者的證書請求檔案發給CA,讓CA審批,ca.pem是ca公鑰,ca-key.pem是ca私鑰,ca-config.json是ca配置檔案,profile指定為www,最後的使用者名稱test是給使用者頒發證書名字的字首。
root@k8scludes1:~/TLS-ingress/tls# cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=www test-csr.json | cfssljson -bare test
2022/04/22 16:05:02 [INFO] generate received request
2022/04/22 16:05:02 [INFO] received CSR
2022/04/22 16:05:02 [INFO] generating key: ecdsa-256
2022/04/22 16:05:02 [INFO] encoded CSR
2022/04/22 16:05:02 [INFO] signed certificate with serial number 468422675225780030350363273085193709570812230921
root@k8scludes1:~/TLS-ingress/tls# ls
ca-config.json ca.csr ca-csr.json ca-key.pem ca.pem test.csr test-csr.json test-key.pem test.pem
test-key.pem是test使用者的私鑰,test.pem是ca給test頒發的證書(也就是公鑰)。
root@k8scludes1:~/TLS-ingress/tls# ls test*
test.csr test-csr.json test-key.pem test.pem
7.2.4 使用自定義的證書
接下來要替換掉ingress-nginx-controller自帶的證書,使用我們生成的證書。
檢視secret。
root@k8scludes1:~/TLS-ingress/tls# kubectl get secrets
NAME TYPE DATA AGE
default-token-mxb4r kubernetes.io/service-account-token 3 3d23h
建立一個tls型別的secret,裡面包含test使用者的私鑰和證書,檢視tls型別的secret的語法。
root@k8scludes1:~/TLS-ingress/tls# kubectl create secret tls --help
Create a TLS secret from the given public/private key pair.
The public/private key pair must exist beforehand. The public key certificate must be .PEM encoded and match the given
private key.
Examples:
# Create a new TLS secret named tls-secret with the given key pair
kubectl create secret tls tls-secret --cert=path/to/tls.cert --key=path/to/tls.key
Options:
--allow-missing-template-keys=true: If true, ignore any errors in templates when a field or map key is missing in
the template. Only applies to golang and jsonpath output formats.
--append-hash=false: Append a hash of the secret to its name.
--cert='': Path to PEM encoded public key certificate.
--dry-run='none': Must be "none", "server", or "client". If client strategy, only print the object that would be
sent, without sending it. If server strategy, submit server-side request without persisting the resource.
--field-manager='kubectl-create': Name of the manager used to track field ownership.
--key='': Path to private key associated with given certificate.
-o, --output='': Output format. One of:
json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-as-json|jsonpath-file.
--save-config=false: If true, the configuration of current object will be saved in its annotation. Otherwise, the
annotation will be unchanged. This flag is useful when you want to perform kubectl apply on this object in the future.
--show-managed-fields=false: If true, keep the managedFields when printing objects in JSON or YAML format.
--template='': Template string or path to template file to use when -o=go-template, -o=go-template-file. The
template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
--validate=true: If true, use a schema to validate the input before sending it
Usage:
kubectl create secret tls NAME --cert=path/to/cert/file --key=path/to/key/file [--dry-run=server|client|none]
[options]
Use "kubectl options" for a list of global command-line options (applies to all commands).
建立一個tls型別的secret,裡面包含test使用者的私鑰和證書。
root@k8scludes1:~/TLS-ingress/tls# ls
ca-config.json ca.csr ca-csr.json ca-key.pem ca.pem test.csr test-csr.json test-key.pem test.pem
root@k8scludes1:~/TLS-ingress/tls# kubectl create secret tls test-tls-secret --cert=test.pem --key=test-key.pem
secret/test-tls-secret created
secrets建立成功。
root@k8scludes1:~/TLS-ingress/tls# kubectl get secrets
NAME TYPE DATA AGE
default-token-mxb4r kubernetes.io/service-account-token 3 3d23h
test-tls-secret kubernetes.io/tls 2 8s
刪除現有的ingress規則。
root@k8scludes1:~/TLS-ingress/tls# pwd
/root/TLS-ingress/tls
root@k8scludes1:~/TLS-ingress/tls# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
my-ingress <none> www.nginx13.com,www.nginx2.com 192.168.110.129 80 46h
root@k8scludes1:~/TLS-ingress/tls# cd ../
root@k8scludes1:~/TLS-ingress# ls
bak certgen15.tar controller1.tar deploy.yaml deploy.yaml.1 deploy.yml ingress-rule.yaml pod.yaml tls vim
root@k8scludes1:~/TLS-ingress# kubectl delete -f ingress-rule.yaml
ingress.networking.k8s.io "my-ingress" deleted
root@k8scludes1:~/TLS-ingress# kubectl get ingress
No resources found in tls-ingress namespace.
修改ingress規則,ingress-rule.yaml裡指定了tls的域名資訊和secret,secret裡包含了證書。
root@k8scludes1:~/TLS-ingress# vim ingress-rule.yaml
root@k8scludes1:~/TLS-ingress# cat ingress-rule.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
tls:
- hosts:
- www.nginxx.com
secretName: test-tls-secret
rules:
- host: www.nginx13.com
http:
paths:
#訪問網址目錄
- path: /
pathType: Prefix
backend:
service:
name: nginx1svc
port:
number: 80
- path: /ingress
pathType: Prefix
backend:
service:
name: nginx3svc
port:
number: 80
- host: www.nginx2.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx2svc
port:
number: 80
應用ingress規則。
root@k8scludes1:~/TLS-ingress# kubectl apply -f ingress-rule.yaml
ingress.networking.k8s.io/my-ingress created
檢視ingress規則,現在已經有443埠了,http對應80埠,https對應443埠。
root@k8scludes1:~/TLS-ingress# kubectl get ingress -o wide
NAME CLASS HOSTS ADDRESS PORTS AGE
my-ingress <none> www.nginx13.com,www.nginx2.com 80, 443 16s
443埠對應的是31473埠,因為secret裡包含了證書,會自動覆蓋ingress-nginx-control裡面的證書。
root@k8scludes1:~/TLS-ingress# kubectl get svc -o wide -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
ingress-nginx-controller NodePort 10.98.61.146 <none> 80:31853/TCP,443:31473/TCP 46h app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
ingress-nginx-controller-admission ClusterIP 10.102.212.60 <none> 443/TCP 46h app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
下面使用Linux客戶端進行訪問,客戶端的/etc/hosts如下:
[root@etcd2 ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.110.133 etcd1
192.168.110.131 etcd2
192.168.110.132 etcd3
192.168.110.129 www.nginx13.com
192.168.110.129 www.nginx2.com
使用https訪問,可以發現證書為ingress自帶的證書:CN=Kubernetes Ingress Controller Fake Certificate。
[root@etcd2 ~]# curl -kv https://www.nginx13.com:31473/ingress/index.html
* About to connect() to www.nginx13.com port 31473 (#0)
* Trying 192.168.110.129...
* Connected to www.nginx13.com (192.168.110.129) port 31473 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
* subject: CN=Kubernetes Ingress Controller Fake Certificate,O=Acme Co
* start date: 4月 22 04:09:27 2022 GMT
* expire date: 4月 22 04:09:27 2023 GMT
* common name: Kubernetes Ingress Controller Fake Certificate
* issuer: CN=Kubernetes Ingress Controller Fake Certificate,O=Acme Co
> GET /ingress/index.html HTTP/1.1
> User-Agent: curl/7.29.0
> Host: www.nginx13.com:31473
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Fri, 22 Apr 2022 08:51:08 GMT
< Content-Type: text/html
< Content-Length: 4
< Connection: keep-alive
< Last-Modified: Fri, 22 Apr 2022 07:17:09 GMT
< ETag: "62625675-4"
< Accept-Ranges: bytes
< Strict-Transport-Security: max-age=15724800; includeSubDomains
<
333
* Connection #0 to host www.nginx13.com left intact
Windows客戶端使用https訪問服務,瀏覽器輸入https://www.nginx13.com:31473/ingress/index.html,我們檢視證書。
發現證書是ingress自帶的證書。
![image-20230728165213137](https://typorablogimage.oss-cn-hangzhou.aliyuncs.com/image-20230728165213137.png)
繼續訪問。
![image-20230728165248610](https://typorablogimage.oss-cn-hangzhou.aliyuncs.com/image-20230728165248610.png)
可以發現,現在可以https訪問ingress了,但是證書不是我們自己生成的那個證書,而是ingress自帶的證書,是因為我們自己生成的證書只給域名www.nginxx.com使用,其他域名訪問只能使用ingress自帶的證書。
現在修改ingress規則,使其使用我們自己生成的證書。
刪除ingress規則。
root@k8scludes1:~/TLS-ingress# ls
bak certgen15.tar controller1.tar deploy.yaml deploy.yaml.1 deploy.yml ingress-rule.yaml pod.yaml tls vim
root@k8scludes1:~/TLS-ingress# kubectl delete -f ingress-rule.yaml
ingress.networking.k8s.io "my-ingress" deleted
root@k8scludes1:~/TLS-ingress# kubectl get ingress
No resources found in tls-ingress namespace.
修改ingress規則,host域名只有www.nginxx.com。
root@k8scludes1:~/TLS-ingress# vim ingress-rule.yaml
root@k8scludes1:~/TLS-ingress# cat ingress-rule.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
tls:
- hosts:
- www.nginxx.com
secretName: test-tls-secret
rules:
- host: www.nginxx.com
http:
paths:
#訪問網址目錄
- path: /
pathType: Prefix
backend:
service:
name: nginx1svc
port:
number: 80
- path: /ingress
pathType: Prefix
backend:
service:
name: nginx3svc
port:
number: 80
- path: /n2
pathType: Prefix
backend:
service:
name: nginx2svc
port:
number: 80
應用ingress規則。
root@k8scludes1:~/TLS-ingress# kubectl apply -f ingress-rule.yaml
ingress.networking.k8s.io/my-ingress created
root@k8scludes1:~/TLS-ingress# kubectl get ingress -o wide
NAME CLASS HOSTS ADDRESS PORTS AGE
my-ingress <none> www.nginxx.com 192.168.110.129 80, 443 2m6s
root@k8scludes1:~/TLS-ingress# kubectl get svc -o wide -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
ingress-nginx-controller NodePort 10.98.61.146 <none> 80:31853/TCP,443:31473/TCP 47h app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
ingress-nginx-controller-admission ClusterIP 10.102.212.60 <none> 443/TCP 47h app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
首先修改Linux客戶端的/etc/hosts,新增IP域名對映:192.168.110.129 www.nginxx.com。
[root@etcd2 ~]# vim /etc/hosts
[root@etcd2 ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.110.133 etcd1
192.168.110.131 etcd2
192.168.110.132 etcd3
192.168.110.129 www.nginx13.com
192.168.110.129 www.nginx2.com
192.168.110.129 www.nginxx.com
使用Linux客戶端訪問服務,使用https訪問,發現證書變為我們自定義的nginxx.com。
[root@etcd2 ~]# curl -kv https://www.nginxx.com:31473/ingress/index.html
* About to connect() to www.nginxx.com port 31473 (#0)
* Trying 192.168.110.129...
* Connected to www.nginxx.com (192.168.110.129) port 31473 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* SSL connection using TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
* Server certificate:
* subject: CN=nginxx.com,L=guangzhou,ST=guangdon,C=CN
* start date: 4月 22 08:00:00 2022 GMT
* expire date: 4月 22 08:00:00 2023 GMT
* common name: nginxx.com
* issuer: CN=nginxx.com,L=guangzhou,ST=guangdon,C=CN
> GET /ingress/index.html HTTP/1.1
> User-Agent: curl/7.29.0
> Host: www.nginxx.com:31473
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Fri, 22 Apr 2022 09:26:31 GMT
< Content-Type: text/html
< Content-Length: 4
< Connection: keep-alive
< Last-Modified: Fri, 22 Apr 2022 07:17:09 GMT
< ETag: "62625675-4"
< Accept-Ranges: bytes
< Strict-Transport-Security: max-age=15724800; includeSubDomains
<
333
* Connection #0 to host www.nginxx.com left intact
下面使用Windows客戶端訪問服務,檢視證書。
證書為我們自定義的證書。
![image-20230728174049992](https://typorablogimage.oss-cn-hangzhou.aliyuncs.com/image-20230728174049992.png)
繼續訪問。
![image-20230728174122626](https://typorablogimage.oss-cn-hangzhou.aliyuncs.com/image-20230728174122626.png)
現在既可以使用https訪問服務,又使用了我們自定義的證書了。
八.總結
透過本文,您應該瞭解瞭如何在Kubernetes叢集中為Ingress配置HTTPS。透過使用TLS證書和適當的Ingress配置,您可以確保服務與客戶端之間的通訊是安全和加密的。