Ingress安全网关

image-20231116075923273

目录

image-20231116075847222

文章目录

    • 目录
    • 本节实战
    • TCP 流量拆分
      • ==🚩 实战:TCP 流量拆分-2023.11.15(测试成功)==
    • Ingress安全网关
      • Kubernetes Ingress
        • ==🚩 实战:Kubernetes Ingress-2023.11.15(测试成功)==
      • Ingress Gateway
        • Ingress Gateway
          • ==🚩 实战:Ingress Gateway-2023.11.15(测试成功)==
        • 安全网关
          • ==🚩 实战:istio安全网关-2023.11.16(测试成功)==
            • 1.单主机配置 TLS Ingress Gateway
            • 2.多个主机配置 TLS Ingress Gateway
            • 3.双向 TLS Ingress Gateway
        • Ingress Gateway TLS 透传
          • 1.TLS Termination
          • 2.TLS Origination
          • 3.TLS 透传
            • ==🚩 实战:TLS 透传-2023.11.16(测试成功)==
    • 关于我
    • 最后

本节实战

实战名称
🚩 实战:TCP 流量拆分-2023.11.15(测试成功)
🚩 实战:Kubernetes Ingress-2023.11.15(测试成功)
🚩 实战:Ingress Gateway-2023.11.15(测试成功)
🚩 实战:istio安全网关-2023.11.16(测试成功)
🚩 实战:TLS 透传-2023.11.16(测试成功)

TCP 流量拆分

🚩 实战:TCP 流量拆分-2023.11.15(测试成功)

实验环境:

k8s v1.27.6(containerd://1.6.20)(cni:flannel:v0.22.2)[root@master1 ~]#istioctl version
client version: 1.19.3
control plane version: 1.19.3
data plane version: 1.19.3 (8 proxies)

实验软件:

链接:https://pan.baidu.com/s/1pMnJxgL63oTlGFlhrfnXsA?pwd=7yqb
提取码:7yqb
2023.11.5-实战:BookInfo 示例应用-2023.11.5(测试成功) --本节测试yaml在此目录里

image-20231105111842627

实验步骤:

image-20231115080020073

graph LRA[实战步骤] -->B(1、 部署应用)A[实战步骤] -->C(2、 创建Gatewy,vs,rs)A[实战步骤] -->D(3、 配置TCP 流量拆分)A[实战步骤] -->E(4、 验证)

前面我们试验了 HTTP 的流量拆分,那么 TCP 流量拆分如何实现呢?TCP 流量拆分是指将来自客户端的 TCP 流量分发到多个后端服务的过程。在 Istio 中,TCP 流量拆分是通过 VirtualServiceDestinationRule 对象来实现的。

这里我们来演示如何将 TCP 流量从微服务的一个版本迁移到另一个版本。我们将会把 100% 的 TCP 流量分配到 tcp-echo:v1,接着,再通过配置 Istio 路由权重把 20% 的 TCP 流量分配到 tcp-echo:v2

  • 首先部署 tcp-echo 服务的 v1v2 两个版本:
kubectl apply -f samples/tcp-echo/tcp-echo-services.yaml

查看:

[root@master1 istio-1.19.3]#kubectl get po -l app=tcp-echo
NAME                           READY   STATUS    RESTARTS   AGE
tcp-echo-v1-64c9b4bc95-hc5z7   2/2     Running   0          69s
tcp-echo-v2-5b5657b486-dlsqf   2/2     Running   0          69s
[root@master1 istio-1.19.3]#kubectl get svc tcp-echo
NAME       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)             AGE
tcp-echo   ClusterIP   10.99.200.47   <none>        9000/TCP,9001/TCP   71s

该资源对象中包含 tcp-echo 的两个 Deployment 对象,包含 9000、9001、9002 三个端口,但是通过 Service 只暴露了 9000 和 9001 两个端口,省略了 9002 端口是为了测试透传能力,内容如下所示:

apiVersion: v1
kind: Service
metadata:name: tcp-echolabels:app: tcp-echoservice: tcp-echo
spec:ports:- name: tcpport: 9000- name: tcp-otherport: 9001# Port 9002 is omitted intentionally for testing the pass through filter chain.selector:app: tcp-echo
---
apiVersion: apps/v1
kind: Deployment
metadata:name: tcp-echo-v1labels:app: tcp-echoversion: v1
spec:selector:matchLabels:app: tcp-echoversion: v1template:metadata:labels:app: tcp-echoversion: v1spec:containers:- name: tcp-echoimage: docker.io/istio/tcp-echo-server:1.2imagePullPolicy: IfNotPresentargs: ["9000,9001,9002", "one"]ports:- containerPort: 9000- containerPort: 9001
---
apiVersion: apps/v1
kind: Deployment
metadata:name: tcp-echo-v2labels:app: tcp-echoversion: v2
spec:selector:matchLabels:app: tcp-echoversion: v2template:metadata:labels:app: tcp-echoversion: v2spec:containers:- name: tcp-echoimage: docker.io/istio/tcp-echo-server:1.2imagePullPolicy: IfNotPresentargs: ["9000,9001,9002", "two"]ports:- containerPort: 9000- containerPort: 9001
  • 然后同样再部署一个 sleep 示例应用,作为发送请求的测试源:
kubectl apply -f samples/sleep/sleep.yaml

对应的 Pod 如下所示:

[root@master1 istio-1.19.3]#kubectl get pods
NAME                             READY   STATUS    RESTARTS   AGE
……
sleep-9454cc476-nx668            2/2     Running   0          11s
tcp-echo-v1-64c9b4bc95-hc5z7     2/2     Running   0          27m
tcp-echo-v2-5b5657b486-dlsqf     2/2     Running   0          27m
  • 接下来我们将所有 TCP 流量路由到微服务 tcp-echov1 版本,应用下面的资源清单即可:
$ kubectl apply -f samples/tcp-echo/tcp-echo-all-v1.yaml

查看:

[root@master1 istio-1.19.3]#kubectl get gateway
NAME               AGE
bookinfo-gateway   2d16h
tcp-echo-gateway   41s
[root@master1 istio-1.19.3]#kubectl get vs
NAME          GATEWAYS               HOSTS             AGE
bookinfo      ["bookinfo-gateway"]   ["*"]             2d16h
……
tcp-echo      ["tcp-echo-gateway"]   ["*"]             46s
[root@master1 istio-1.19.3]#kubectl get dr
NAME                   HOST          AGEtcp-echo-destination   tcp-echo      57s

该资源对象中包含了 tcp-echo 服务的 GatewayDestinationRuleVirtualService 对象,内容如下所示:

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:name: tcp-echo-gateway
spec:selector:istio: ingressgatewayservers:- port:number: 31400 # istio-ingressgateway 包含该端口name: tcpprotocol: TCPhosts:- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:name: tcp-echo-destination
spec:host: tcp-echosubsets:- name: v1labels:version: v1 # 匹配 tcp-echo-v1 的标签- name: v2labels:version: v2 # 匹配 tcp-echo-v2 的标签
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:name: tcp-echo
spec:hosts:- "*"gateways:- tcp-echo-gateway # 关联上面的 Gatewaytcp:- match:- port: 31400 # 匹配上面 Gateway 的端口route:- destination: # 路由导 tcp-echo 服务host: tcp-echoport:number: 9000subset: v1 # 全部路由到 v1 子集

上面的资源清单中单独定义了一个 Gateway 对象,用来暴露 TCP 流量的端口,然后通过 VirtualService 对象将 TCP 流量路由到 tcp-echo 服务的 v1 版本,这样所有的流量都会被路由到 tcp-echo:v1,需要注意的是 VirtualService 对象中配置的是 tcp 协议,而不是 http 协议了,因为我们这里要处理的是一个 TCP 服务,其他方式方法都是一样的。

查看下istio-ingressgateway内容:

[root@master1 istio-1.19.3]#kubectl get svc istio-ingressgateway -nistio-system -oyaml
……ports:- name: status-portnodePort: 31410port: 15021protocol: TCPtargetPort: 15021- name: http2nodePort: 31666port: 80protocol: TCPtargetPort: 8080- name: httpsnodePort: 32213port: 443protocol: TCPtargetPort: 8443- name: tcpnodePort: 30291 ##port: 31400 ##protocol: TCPtargetPort: 31400 ##证明容器里也有一个应用监听31400端口- name: tlsnodePort: 31787port: 15443protocol: TCPtargetPort: 15443
……
[root@master1 istio-1.19.3]#kubectl get po istio-ingressgateway-9c8b9b586-vj44l  -nistio-system -oyaml
……
image: docker.io/istio/proxyv2:1.19.3imagePullPolicy: IfNotPresentname: istio-proxyports:- containerPort: 15021protocol: TCP- containerPort: 8080 #httpprotocol: TCP- containerPort: 8443 #httpsprotocol: TCP- containerPort: 31400 #TCP流量protocol: TCP- containerPort: 15443protocol: TCP- containerPort: 15090name: http-envoy-promprotocol: TCP
……
  • 我们可以用下面的方式来测试,首先获得 Ingress Gateway 的访问入口地址和端口:
export TCP_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="tcp")].nodePort}')
export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n istio-system -o jsonpath='{.items[0].status.hostIP}')

查看:

echo $TCP_INGRESS_PORT #istio-ingressgateway svc的nodePort(监听器端口),因为这里的SVC是LoadBalancer类型的,因为我们通过NodePort来访问就行。
echo $INGRESS_HOST[root@master1 istio-1.19.3]#echo $TCP_INGRESS_PORT #svc的nodePort
30291
[root@master1 istio-1.19.3]#echo $INGRESS_HOST
172.29.9.63
  • 然后通过 sleep 容器中的 nc 命令来发送 TCP 流量:
[root@master1 istio-1.19.3]#export SLEEP=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
[root@master1 istio-1.19.3]#echo $SLEEP
sleep-9454cc476-nx668$ for i in {1..20}; dokubectl exec "$SLEEP" -c sleep -- sh -c "(date; sleep 1) | nc $INGRESS_HOST $TCP_INGRESS_PORT";
done
one Mon Nov 13 03:23:59 UTC 2023
one Mon Nov 13 03:24:00 UTC 2023
one Mon Nov 13 03:24:01 UTC 2023
# ......

可以看到所有时间戳都有一个前缀 one,说明所有流量都被路由到 tcp-echov1 版本,当然我们也可以在 v1 版本的 Pod 中查看到相应的日志。

image-20231115074521279

查看v1 版本的 Pod 中查看到相应的日志:

[root@master1 istio-1.19.3]#kubectl logs -f tcp-echo-v1-64c9b4bc95-hc5z7
listening on [::]:9002, prefix: one
listening on [::]:9000, prefix: one
listening on [::]:9001, prefix: onerequest: Tue Nov 14 23:44:32 UTC 2023
response: one Tue Nov 14 23:44:32 UTC 2023
request: Tue Nov 14 23:44:34 UTC 2023
response: one Tue Nov 14 23:44:34 UTC 2023
request: Tue Nov 14 23:44:35 UTC 2023
response: one Tue Nov 14 23:44:35 UTC 2023
request: Tue Nov 14 23:44:36 UTC 2023
response: one Tue Nov 14 23:44:36 UTC 2023
request: Tue Nov 14 23:44:37 UTC 2023
……
  • 接下来我们将 20% 的 TCP 流量路由到 tcp-echo:v2 版本,应用下面的资源清单即可:
kubectl apply -f samples/tcp-echo/tcp-echo-20-v2.yaml

该清单文件内容如下所示:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:name: tcp-echo
spec:hosts:- "*"gateways:- tcp-echo-gatewaytcp:- match:- port: 31400route:- destination:host: tcp-echoport:number: 9000subset: v1weight: 80 # 80% 的流量路由到 v1- destination:host: tcp-echoport:number: 9000subset: v2weight: 20 # 20% 的流量路由到 v2

这里我们更新了 VirtualService 对象,将 tcp-echo 服务的 v1 版本和 v2 版本的权重分别设置为 80% 和 20%,这样 20% 的流量就会被路由到 tcp-echo:v2 版本了,这和前面的 HTTP 基于权重的流量拆分是一样的方式。

  • 应用成功后,我们再次发送 TCP 流量来验证:
$ export SLEEP=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
$ for i in {1..20}; dokubectl exec "$SLEEP" -c sleep -- sh -c "(date; sleep 1) | nc $INGRESS_HOST $TCP_INGRESS_PORT";
done
one Mon Nov 13 03:29:32 UTC 2023
one Mon Nov 13 03:29:33 UTC 2023
one Mon Nov 13 03:29:34 UTC 2023
one Mon Nov 13 03:29:36 UTC 2023
one Mon Nov 13 03:29:37 UTC 2023
one Mon Nov 13 03:29:38 UTC 2023
one Mon Nov 13 03:29:39 UTC 2023
two Mon Nov 13 03:29:40 UTC 2023
one Mon Nov 13 03:29:41 UTC 2023
one Mon Nov 13 03:29:42 UTC 2023
two Mon Nov 13 03:29:43 UTC 2023
# ......

image-20231115075034970

输出结果中大约有 20% 的时间戳带有前缀 two,说明 80% 的 TCP 流量被路由到 tcp-echov1 版本,而 20% 的流量被路由到 v2 版本,证明我们的 TCP 服务基于权重的流量拆分配置成功了。

  • 当然最后我们同样可以去查看下 Envoy Sidecar 的具体配置,注意我们这里是通过 Istio Ingress Gateway 来暴露 TCP 流量的端口的,所以我们这里直接查看 31400 端口的监听器配置即可:
$ istioctl proxy-config listeners istio-ingressgateway-9c8b9b586-s6s48 -n istio-system --port 31400 -o yaml
- address:socketAddress:address: 0.0.0.0portValue: 31400# ......filterChains:- filters:# ......- name: envoy.filters.network.tcp_proxytypedConfig:'@type': type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy# ......statPrefix: tcp-echo.defaultweightedClusters:clusters:- name: outbound|9000|v1|tcp-echo.default.svc.cluster.localweight: 80- name: outbound|9000|v2|tcp-echo.default.svc.cluster.localweight: 20name: 0.0.0.0_31400trafficDirection: OUTBOUND

我们可以发现上面的监听器配置下面的过滤器链中直接使用的是一个 envoy.filters.network.tcp_proxy 过滤器,用来处理 TCP 流量,而不是 HTTP 流量了,而且直接在该过滤器下面配置了 weightedClusters 权重集群,用来实现基于权重的流量拆分,可以看到 v1v2 版本的权重分别为 80 和 20,符合我们的预期。

  • 最后测试完后可以清理下资源:
kubectl delete -f samples/tcp-echo/tcp-echo-all-v1.yaml
kubectl delete -f samples/sleep/sleep.yaml
kubectl delete -f samples/tcp-echo/tcp-echo-services.yaml

测试结束。😘

Ingress安全网关

image-20231116112434001

我们知道在 Kubernetes 中我们会使用 Ingress 来暴露 HTTP 流量的入口,在 Istio 中我们是通过 Gateway 来暴露流量入口的,那么我们是否可以使用 Ingress 对象来支持 Istio 的流量入口呢?答案是肯定的,但是我们还是建议使用 Gateway 而不是 Ingress 来使用 Istio 提供的完整功能集,例如丰富的流量管理和安全功能。

k8s gateway api。

Kubernetes Ingress

🚩 实战:Kubernetes Ingress-2023.11.15(测试成功)

实验环境:

k8s v1.27.6(containerd://1.6.20)(cni:flannel:v0.22.2)[root@master1 ~]#istioctl version
client version: 1.19.3
control plane version: 1.19.3
data plane version: 1.19.3 (8 proxies)

实验软件:

链接:https://pan.baidu.com/s/1VEYZ8jPDGsHXvnxwkKHzZA?pwd=062k
提取码:062k
2023.11.15-实战:Kubernetes Ingress-2023.11.15(测试成功)

image-20231115205557810

应用程序在以下链接里:

链接:https://pan.baidu.com/s/1pMnJxgL63oTlGFlhrfnXsA?pwd=7yqb
提取码:7yqb
2023.11.5-实战:BookInfo 示例应用-2023.11.5(测试成功)

image-20231105111842627

实验步骤:

image-20231115205734199

graph LRA[实战步骤] -->B(1、 部署服务端测试应用)A[实战步骤] -->C(2、 创建ingress)A[实战步骤] -->D(3、 测试)

下面我们来使用 Ingress 资源配置 Istio 的入口网关,使用 Kubernetes Ingress 可以暴露从集群外到集群内服务的 HTTP 和 HTTPS 路由。

  • 这里我们部署一个 httpbin 应用,用来测试:
kubectl apply -f samples/httpbin/httpbin.yaml

查看:

[root@master1 istio-1.19.3]#kubectl get po -l app=httpbin
NAME                       READY   STATUS    RESTARTS   AGE
httpbin-86869bccff-7lpjx   2/2     Running   0          2d14h
[root@master1 istio-1.19.3]#kubectl get svc
NAME          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE
httpbin       ClusterIP   10.111.57.195    <none>        8000/TCP            2d14h
……
  • 创建后我们就可以创建一个 Ingress 对象来暴露 httpbin 服务了:

⚠️ 特别注意:

image-20231115202149163

#httpbin-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:annotations:kubernetes.io/ingress.class: istioname: httpbin
spec:rules:- host: httpbin.k8s.localhttp:paths:- path: /statuspathType: Prefixbackend:service:name: httpbinport:number: 8000

可以看到这个 Ingress 对象和我们在 Kubernetes 中的使用方法没有什么区别,唯一不同的是我们这里使用了一个 kubernetes.io/ingress.class 注解来告知 Istio Ingress Gateway 它应该处理该 Ingress,否则它将被忽略。

我们应用上面的资源清单:

[root@master1 istio-1.19.3]#kubectl apply -f httpbin-ingress.yaml
ingress.networking.k8s.io/httpbin created
Warning: annotation "kubernetes.io/ingress.class" is deprecated, please use 'spec.ingressClassName' instead

image-20231115203434692

  • 我们可以通过 kubectl get ingress 命令来查看下 Ingress 对象的状态:
$ kubectl get ingress
NAME      CLASS    HOSTS              ADDRESS   PORTS   AGE
httpbin   <none>   httpbin.k8s.local            80      6s
  • 然后我们可以使用 curl 来访问 httpbin 服务:
# 获取 Ingress Gateway 的地址和端口
export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
export INGRESS_HOST=$(kubectl get pod -l istio=ingressgateway -n istio-system -o jsonpath='{.items[0].status.hostIP}')echo $INGRESS_PORT
echo $INGRESS_HOST# 访问 httpbin 服务
$ curl -s -I -HHost:httpbin.k8s.local "http://$INGRESS_HOST:$INGRESS_PORT/status/200"
HTTP/1.1 200 OK
server: istio-envoy
date: Mon, 13 Nov 2023 06:10:13 GMT
content-type: text/html; charset=utf-8
# .......

注意使用 -H 标志将 Host 的 HTTP 头设置为 httpbin.k8s.local, 因为 Ingress 中已经配置为处理访问该域名的请求,但是在测试环境中,该域名并没有相应的 DNS 绑定,当然我们也可以直接在 /etc/hosts 中添加一个映射(当然是istio-ingressgateway-9c8b9b586-vj44lpod所在node节点了)。

image-20231115204409741

  • 访问未指定的其他 URL 时,将返回 HTTP 404 错误:
$ curl -s -I -HHost:httpbin.k8s.local "http://$INGRESS_HOST:$INGRESS_PORT/headers"
HTTP/1.1 404 Not Found
#......

image-20231115204427150

  • 注意下:自己当前istio环境
[root@master1 istio-1.19.3]#export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
[root@master1 istio-1.19.3]#export INGRESS_HOST=$(kubectl get pod -l istio=ingressgateway -n istio-system -o jsonpath='{.items[0].status.hostIP}')
[root@master1 istio-1.19.3]#echo $INGRESS_PORT
31666
[root@master1 istio-1.19.3]#echo $INGRESS_HOST
172.29.9.63[root@master1 istio-1.19.3]#kubectl get po -owide -l istio=ingressgateway -nistio-system
NAME                                   READY   STATUS    RESTARTS   AGE    IP            NODE    NOMINATED NODE   READINESS GATES
istio-ingressgateway-9c8b9b586-vj44l   1/1     Running   0          3d6h   10.244.2.15   node2   <none>           <none>
[root@master1 istio-1.19.3]#kubectl get svc -nistio-system
NAME                   TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                                                                      AGE
istio-egressgateway    ClusterIP      10.109.85.119    <none>        80/TCP,443/TCP                                                               8d
istio-ingressgateway   LoadBalancer   10.105.233.167   <pending>     15021:31410/TCP,80:31666/TCP,443:32213/TCP,31400:30291/TCP,15443:31787/TCP   8d
istiod                 ClusterIP      10.109.185.251   <none>        15010/TCP,15012/TCP,443/TCP,15014/TCP                                        8d
  • 在 Kubernetes 1.18 中,添加了新资源 IngressClass,以替换 Ingress 资源上的 kubernetes.io/ingress.class 注解,我们也可以使用该资源来替换注解的方式,需要将 controller 字段设置为 istio.io/ingress-controller,如下所示:
#httpbin-ingress2.yaml
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:name: istio
spec:controller: istio.io/ingress-controller # 指定 Ingress Controller 为 istio
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:name: httpbin
spec:ingressClassName: istio # 指定 IngressClass 为 istiorules:- host: httpbin.k8s.localhttp:paths:- path: /pathType: Prefixbackend:service:name: httpbinport:number: 8000

上面这种方式更加简洁,而且可以避免使用注解的方式,但是需要注意的是,该资源对象只能在 Kubernetes 1.18 及以上版本中使用。

  • 应用上面ingress对象
#先删除旧的ingress对象
[root@master1 istio-1.19.3]#kubectl delete -f httpbin-ingress.yaml 
ingress.networking.k8s.io "httpbin" deleted[root@master1 istio-1.19.3]#kubectl apply -f httpbin-ingress2.yaml 
ingressclass.networking.k8s.io/istio created
ingress.networking.k8s.io/ingress created#查看
[root@master1 istio-1.19.3]#kubectl get ingressclass
NAME    CONTROLLER                    PARAMETERS   AGE
istio   istio.io/ingress-controller   <none>       27s
[root@master1 istio-1.19.3]#kubectl get ingress
NAME      CLASS   HOSTS               ADDRESS   PORTS   AGE
ingress   istio   httpbin.k8s.local             80      35s
  • 再次测试
[root@master1 istio-1.19.3]#curl -s -I -HHost:httpbin.k8s.local "http://$INGRESS_HOST:$INGRESS_PORT/status/200"
HTTP/1.1 200 OK
server: istio-envoy
date: Wed, 15 Nov 2023 12:51:24 GMT
content-type: text/html; charset=utf-8
access-control-allow-origin: *
access-control-allow-credentials: true
content-length: 0
x-envoy-upstream-service-time: 6[root@master1 istio-1.19.3]#curl -s -I -HHost:httpbin.k8s.local "http://$INGRESS_HOST:$INGRESS_PORT/headers"
HTTP/1.1 200 OK
server: istio-envoy
date: Wed, 15 Nov 2023 12:51:29 GMT
content-type: application/json
content-length: 597
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 12

符合预期,测试结束。😘

  • 记得回收掉刚才创建的资源
[root@master1 istio-1.19.3]#kubectl delete -f httpbin-ingress2.yaml 
ingressclass.networking.k8s.io "istio" deleted
ingress.networking.k8s.io "ingress" deleted

此外 Ingress 还可以进行 TLS 设置,Istio 支持此功能,但是引用的 Secret 必须存在于 istio-ingressgateway 部署的命名空间(通常是 istio-system)中。

通过 Kubernetes Ingress 我们可以将流量导入到 Istio 中,但是对于一些高级的流量管理功能,比如路由、熔断、限流等就很难实现了,所以我们还是建议使用 Istio 的 Gateway 资源来暴露流量入口。

Ingress Gateway

img

前面我们都是通过 Istio 提供的 Gateway 资源来暴露流量入口,与 Ingress 相比,Gateway 提供了更广泛的自定义和灵活性,并允许将 Istio 功能(例如监控和路由规则)应用于进入集群的流量。

Ingress Gateway
🚩 实战:Ingress Gateway-2023.11.15(测试成功)

实验环境:

k8s v1.27.6(containerd://1.6.20)(cni:flannel:v0.22.2)[root@master1 ~]#istioctl version
client version: 1.19.3
control plane version: 1.19.3
data plane version: 1.19.3 (8 proxies)

实验软件:

链接:https://pan.baidu.com/s/1C-ZlPHuXzzXGPAlNEYdySA?pwd=lpyx
提取码:lpyx
2023.11.15-实战:Ingress Gateway-2023.11.15(测试成功)

image-20231115215707041

应用程序在以下链接里:

链接:https://pan.baidu.com/s/1pMnJxgL63oTlGFlhrfnXsA?pwd=7yqb
提取码:7yqb
2023.11.5-实战:BookInfo 示例应用-2023.11.5(测试成功)

image-20231105111842627

实验步骤:

image-20231115205734199

graph LRA[实战步骤] -->B(1、 部署服务端测试应用)A[实战步骤] -->C(2、 创建ingress)A[实战步骤] -->D(3、 测试)

Ingress Gateway 描述在网格边界运作的负载均衡器,用于接收传入的 HTTP/TCP 连接。它会配置暴露的端口、协议等,但与 Kubernetes Ingress 资源不同,Gateway 对象不会包括任何流量路由配置,和路由规则相关的配置需要使用 VirtualServiceDestinationRule 资源来实现。

  • 比如上面的 httpbin 应用,如果通过 Gateway 对象来暴露流量入口,那么我们需要创建一个 Gateway 对象,然后再创建一个 VirtualService 对象来配置流量路由,内容如下所示:
#ingress-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:name: httpbin-gateway
spec:selector:istio: ingressgatewayservers:- port:number: 80name: httpprotocol: HTTPhosts:- "httpbin.k8s.local"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:name: httpbin
spec:hosts:- "httpbin.k8s.local"gateways:- httpbin-gatewayhttp:- match:- uri:prefix: /status- uri:prefix: /delayroute:- destination:port:number: 8000host: httpbin

上面的资源清单我们就通过 Gateway 对象暴露了 HTTP 流量的入口,然后通过 VirtualService 对象来配置流量路由,一共配置了两个路由规则,允许流量流向路径 /status/delaygateways 列表指定了哪些请求允许通 httpbin-gateway 网关,所有其他外部请求均被拒绝并返回 404 响应。

  • 直接应用上面的资源清单
kubectl apply -f ingress-gateway.yaml
  • 然后我们可以通过 curl 来访问 httpbin 服务:
# 获取 Ingress Gateway 的地址和端口
export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
export INGRESS_HOST=$(kubectl get pod -l istio=ingressgateway -n istio-system -o jsonpath='{.items[0].status.hostIP}')# 访问 httpbin 服务
$ curl -s -I -HHost:httpbin.k8s.local "http://$INGRESS_HOST:$INGRESS_PORT/status/200"
HTTP/1.1 200 OK
server: istio-envoy
date: Mon, 13 Nov 2023 06:32:58 GMT
content-type: text/html; charset=utf-8
# .......$ curl -s -I -HHost:httpbin.k8s.local "http://$INGRESS_HOST:$INGRESS_PORT/delay/2" #延迟2s

image-20231115215305487

  • 如果请求 /status/delay 以外的路径,将会返回 404 错误:
$ curl -s -I -HHost:httpbin.k8s.local "http://$INGRESS_HOST:$INGRESS_PORT/headers"
HTTP/1.1 404 Not Found
...

测试结束。😘

  • 回收刚才创建的资源
kubectl delete -f ingress-gateway.yaml

当然除了这最基本的功能之外,Gateway 还支持很多其他高级功能,比如 TLS、SNI 等。

安全网关

我们已经了解了如何使用 Gateway 对象来对外暴露 HTTP 服务,那么我们如何使用 TLS 或 mTLS 来暴露安全的 HTTPS 服务呢?

🚩 实战:istio安全网关-2023.11.16(测试成功)

实验环境:

k8s v1.27.6(containerd://1.6.20)(cni:flannel:v0.22.2)[root@master1 ~]#istioctl version
client version: 1.19.3
control plane version: 1.19.3
data plane version: 1.19.3 (8 proxies)

实验软件:

链接:https://pan.baidu.com/s/1jw67Xvj-2ZYl3uuq59kO1g?pwd=p2mr
提取码:p2mr
–来自百度网盘超级会员V8的分享
2023.11.16-实战:istio安全网关-2023.11.16(测试成功)

image-20231116075419904

应用程序在以下链接里:

链接:https://pan.baidu.com/s/1pMnJxgL63oTlGFlhrfnXsA?pwd=7yqb
提取码:7yqb
2023.11.5-实战:BookInfo 示例应用-2023.11.5(测试成功)

image-20231105111842627

前期准备:

  • 这里我们还是使用 httpbin 应用来演示:
kubectl apply -f samples/httpbin/httpbin.yaml

接下来我们需要使用 openssl 命令来生成客户端和服务器证书和密钥。

⚠️ 注意:

以下证书、私钥创建的有点多哦,注意下。

(0)

  • 首先创建用于服务签名的根证书和私钥:
mkdir example_certs1
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout example_certs1/example.com.key -out example_certs1/example.com.crt

image-20231116060013152

[root@master1 ~]#ll example_certs1/
total 8
-rw-r--r-- 1 root root 1164 Nov 16 05:59 example.com.crt
-rw-r--r-- 1 root root 1708 Nov 16 05:59 example.com.key

(1)

  • 接着为 httpbin.example.com 创建证书和私钥:
openssl req -out example_certs1/httpbin.example.com.csr -newkey rsa:2048 -nodes -keyout example_certs1/httpbin.example.com.key -subj "/CN=httpbin.example.com/O=httpbin organization"openssl x509 -req -sha256 -days 365 -CA example_certs1/example.com.crt -CAkey example_certs1/example.com.key -set_serial 0 -in example_certs1/httpbin.example.com.csr -out example_certs1/httpbin.example.com.crt

image-20231116060451784

image-20231116060524272

  • 创建第二组相同类型的证书和密钥:(用同一组根证书为一个域名签发了2套证书,用于后期测试)
mkdir example_certs2
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout example_certs2/example.com.key -out example_certs2/example.com.crtopenssl req -out example_certs2/httpbin.example.com.csr -newkey rsa:2048 -nodes -keyout example_certs2/httpbin.example.com.key -subj "/CN=httpbin.example.com/O=httpbin organization"
openssl x509 -req -sha256 -days 365 -CA example_certs2/example.com.crt -CAkey example_certs2/example.com.key -set_serial 0 -in example_certs2/httpbin.example.com.csr -out example_certs2/httpbin.example.com.crt

查看:

[root@master1 ~]#ll example_certs2/
total 20
-rw-r--r-- 1 root root 1164 Nov 16 06:08 example.com.crt
-rw-r--r-- 1 root root 1704 Nov 16 06:08 example.com.key
-rw-r--r-- 1 root root 1054 Nov 16 06:08 httpbin.example.com.crt
-rw-r--r-- 1 root root  948 Nov 16 06:08 httpbin.example.com.csr
-rw-r--r-- 1 root root 1704 Nov 16 06:08 httpbin.example.com.key

(2)

  • helloworld.example.com 生成证书和私钥:
openssl req -out example_certs1/helloworld.example.com.csr -newkey rsa:2048 -nodes -keyout example_certs1/helloworld.example.com.key -subj "/CN=helloworld.example.com/O=helloworld organization"openssl x509 -req -sha256 -days 365 -CA example_certs1/example.com.crt -CAkey example_certs1/example.com.key -set_serial 1 -in example_certs1/helloworld.example.com.csr -out example_certs1/helloworld.example.com.crt

image-20231116061020563

(3)

  • 生成客户端证书和私钥
openssl req -out example_certs1/client.example.com.csr -newkey rsa:2048 -nodes -keyout example_certs1/client.example.com.key -subj "/CN=client.example.com/O=client organization"openssl x509 -req -sha256 -days 365 -CA example_certs1/example.com.crt -CAkey example_certs1/example.com.key -set_serial 1 -in example_certs1/client.example.com.csr -out example_certs1/client.example.com.crt
  • 您可以通过运行以下命令确认您拥有所有需要的文件:
$ ls example_cert*
example_certs1:
client.example.com.crt          example.com.key                 httpbin.example.com.crt
client.example.com.csr          helloworld.example.com.crt      httpbin.example.com.csr
client.example.com.key          helloworld.example.com.csr      httpbin.example.com.key
example.com.crt                 helloworld.example.com.keyexample_certs2:
example.com.crt         httpbin.example.com.crt httpbin.example.com.key
example.com.key         httpbin.example.com.csr
1.单主机配置 TLS Ingress Gateway

接下来我们就可以在 Gateway 对象中配置 TLS 了。

  • 首先我们需要创建一个 Secret 对象,用来存储证书和密钥:
$ kubectl create -n istio-system secret tls httpbin-credential \--key=example_certs1/httpbin.example.com.key \--cert=example_certs1/httpbin.example.com.crt

查看:

[root@master1 ~]#kubectl get secret -nistio-system
NAME                 TYPE                DATA   AGE
httpbin-credential   kubernetes.io/tls   2      11s
……
  • 然后在 Gateway 对象中需要定义一个 443 端口的网关,并将 credentialName 的值设置为 httpbin-credential,该值与 Secret 的名称相同,TLS 模式的值应为 SIMPLE,内容如下所示:
#tls-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:name: mygateway
spec:selector:istio: ingressgateway # use istio default ingress gatewayservers:- port:number: 443name: httpsprotocol: HTTPStls:mode: SIMPLEcredentialName: httpbin-credential # 必须和 secret 对象名称一致hosts:- httpbin.example.com
  • 接下来,通过定义相应的 VirtualService 对象来配置网关的入口流量路由:
#tls-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:name: httpbin
spec:hosts:- "httpbin.example.com"gateways:- mygatewayhttp:- match:- uri:prefix: /status- uri:prefix: /delayroute:- destination:port:number: 8000host: httpbin
  • 部署上面2个对象

完整清单:

#tls-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:name: mygateway
spec:selector:istio: ingressgateway # use istio default ingress gatewayservers:- port:number: 443name: httpsprotocol: HTTPStls:mode: SIMPLEcredentialName: httpbin-credential # 必须和 secret 对象名称一致hosts:- httpbin.example.com---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:name: httpbin
spec:hosts:- "httpbin.example.com"gateways:- mygatewayhttp:- match:- uri:prefix: /status- uri:prefix: /delayroute:- destination:port:number: 8000host: httpbin

部署:

[root@master1 istio-1.19.3]#kubectl apply -f tls-gateway.yaml 
gateway.networking.istio.io/mygateway created
virtualservice.networking.istio.io/httpbin created

查看:

[root@master1 istio-1.19.3]#kubectl get gateway
NAME               AGE
……
mygateway          26s
[root@master1 istio-1.19.3]#kubectl get vs
NAME          GATEWAYS               HOSTS                     AGE
……
httpbin       ["mygateway"]          ["httpbin.example.com"]   26s
……
  • 应用上面的资源对象后,我们就可以向 httpbin 服务发送 HTTPS 请求了:

这里要用到的是istio-ingressgateway的443端口:

[root@master1 istio-1.19.3]#kubectl get svc -nistio-system
NAME                   TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                                                                      AGE
istio-egressgateway    ClusterIP      10.109.85.119    <none>        80/TCP,443/TCP                                                               8d
istio-ingressgateway   LoadBalancer   10.105.233.167   <pending>     15021:31410/TCP,80:31666/TCP,443:32213/TCP,31400:30291/TCP,15443:31787/TCP   8d
istiod                 ClusterIP      10.109.185.251   <none>        15010/TCP,15012/TCP,443/TCP,15014/TCP                                        8d
# 获取 Ingress Gateway 的地址和 HTTPS 端口
export INGRESS_HOST=$(kubectl get pod -l istio=ingressgateway -n istio-system -o jsonpath='{.items[0].status.hostIP}')
export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}')
echo $INGRESS_HOST
echo $SECURE_INGRESS_PORT
#[root@master1 istio-1.19.3]#echo $INGRESS_HOST
#172.29.9.63
#[root@master1 istio-1.19.3]#echo $SECURE_INGRESS_PORT
#32213# 访问 httpbin 服务
$ curl -v -HHost:httpbin.example.com --resolve "httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST" \--cacert example_certs1/example.com.crt "https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418"
# ......
* Initializing NSS with certpath: sql:/etc/pki/nssdb
*   CAfile: example_certs1/example.com.crtCApath: none
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
*       subject: O=httpbin organization,CN=httpbin.example.com
*       start date: Nov 13 06:58:40 2023 GMT
*       expire date: Nov 12 06:58:40 2024 GMT
*       common name: httpbin.example.com
*       issuer: CN=example.com,O=example Inc.
> GET /status/418 HTTP/1.1
> User-Agent: curl/7.29.0
> Accept: */*
> Host:httpbin.example.com
>
< HTTP/1.1 418 Unknown
< server: istio-envoy
# ......-=[ teapot ]=-_...._.'  _ _ `.| ."` ^ `". _,\_;`"---"`|//|       ;/\_     _/`"""`

image-20231116063024423

  • 接着我们可以删除网关的 Secret 然后使用不同的证书和密钥重新创建它来更改网关的凭据:
kubectl -n istio-system delete secret httpbin-credential# 创建新的证书和密钥
kubectl create -n istio-system secret tls httpbin-credential \--key=example_certs2/httpbin.example.com.key \--cert=example_certs2/httpbin.example.com.crt
  • 使用新的证书链和 curl 来访问 httpbin 服务:
$ curl -v -HHost:httpbin.example.com --resolve "httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST" \--cacert example_certs2/example.com.crt "https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418"
...
HTTP/1.1 418 Unknown
...-=[ teapot ]=-_...._.'  _ _ `.| ."` ^ `". _,\_;`"---"`|//|       ;/\_     _/`"""`

image-20231116063232207

  • 如果使用之前的证书链来访问 httpbin,则会失败:
$ curl -v -HHost:httpbin.example.com --resolve "httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST" \--cacert example_certs1/example.com.crt "https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418"
# ......
* Initializing NSS with certpath: sql:/etc/pki/nssdb
*   CAfile: example_certs1/example.com.crtCApath: none
* Server certificate:
*       subject: O=httpbin organization,CN=httpbin.example.com
*       start date: Nov 13 06:59:17 2023 GMT
*       expire date: Nov 12 06:59:17 2024 GMT
*       common name: httpbin.example.com
*       issuer: CN=example.com,O=example Inc.
* NSS error -8182 (SEC_ERROR_BAD_SIGNATURE)
* Peer's certificate has an invalid signature.
* Closing connection 0
curl: (60) Peer's certificate has an invalid signature.
# ......

测试结束。😘

2.多个主机配置 TLS Ingress Gateway

上面是为单个主机配置 TLS 入口网关的方法。

此外我们还可以为多个主机(例如 httpbin.example.comhelloworld-v1.example.com)配置入口网关,入口网关配置有与每个主机相对应的唯一凭据。

  • 首先删除并使用原始证书和密钥重新创建 Secret 来恢复上一个示例中的 httpbin 凭据:
kubectl -n istio-system delete secret httpbin-credentialkubectl create -n istio-system secret tls httpbin-credential \--key=example_certs1/httpbin.example.com.key \--cert=example_certs1/httpbin.example.com.crt
  • 然后我们启动 helloworld-v1 示例:

还可以这样搞哦:

# 创建 service=helloworld 的服务
$ kubectl apply -f samples/helloworld/helloworld.yaml -l service=helloworld# 创建 version=v1 的应用
$ kubectl apply -f samples/helloworld/helloworld.yaml -l version=v1
  • 然后创建 helloworld-credential Secret:
$ kubectl create -n istio-system secret tls helloworld-credential --key=example_certs1/helloworld.example.com.key --cert=example_certs1/helloworld.example.com.crt
  • 然后使用 httpbin.example.comhelloworld.example.com 主机配置入口网关,创建如下所示的 Gateway 对象:
#tls2-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:name: mygateway
spec:selector:istio: ingressgateway # use istio default ingress gatewayservers:- port:number: 443name: https-httpbinprotocol: HTTPStls:mode: SIMPLEcredentialName: httpbin-credentialhosts:- httpbin.example.com- port:number: 443name: https-helloworldprotocol: HTTPStls:mode: SIMPLEcredentialName: helloworld-credentialhosts:- helloworld.example.com

这里我们为 443 端口定义一个具有两个 server 配置的网关,将每个端口上的 credentialName 值分别设置为 httpbin-credentialhelloworld-credential,将 TLS 模式设置为 SIMPLE

  • 然后定义相应的 VirtualService 来配置网关的流量路由。
#tls2-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:name: helloworld
spec:hosts:- helloworld.example.comgateways:- mygatewayhttp:- match:- uri:exact: /helloroute:- destination:host: helloworldport:number: 5000
  • 直接应用上面的资源对象即可

完整清单如下:

#tls2-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:name: mygateway
spec:selector:istio: ingressgateway # use istio default ingress gatewayservers:- port:number: 443name: https-httpbinprotocol: HTTPStls:mode: SIMPLEcredentialName: httpbin-credentialhosts:- httpbin.example.com- port:number: 443name: https-helloworldprotocol: HTTPStls:mode: SIMPLEcredentialName: helloworld-credentialhosts:- helloworld.example.com---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:name: helloworld
spec:hosts:- helloworld.example.comgateways:- mygatewayhttp:- match:- uri:exact: /helloroute:- destination:host: helloworldport:number: 5000

部署:

kubectl apply -f tls2-gateway.yaml

查看:

[root@master1 ~]#kubectl get gateway
NAME               AGE
mygateway          20m
[root@master1 ~]#kubectl get vs
NAME          GATEWAYS               HOSTS                        AGE
helloworld    ["mygateway"]          ["helloworld.example.com"]   19s
httpbin       ["mygateway"]          ["httpbin.example.com"]      20m
  • 然后向 helloworld.example.com 发送 HTTPS 请求:
$ curl -v -HHost:helloworld.example.com --resolve "helloworld.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST" \--cacert example_certs1/example.com.crt "https://helloworld.example.com:$SECURE_INGRESS_PORT/hello"
# ......
* Initializing NSS with certpath: sql:/etc/pki/nssdb
*   CAfile: example_certs1/example.com.crtCApath: none
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
*       subject: O=helloworld organization,CN=helloworld.example.com
*       start date: Nov 13 07:01:57 2023 GMT
*       expire date: Nov 12 07:01:57 2024 GMT
*       common name: helloworld.example.com
*       issuer: CN=example.com,O=example Inc.
# ......
< HTTP/1.1 200 OK
# ......
Hello version: v1, instance: helloworld-v1-b6c45f55-85l49

image-20231116064325345

  • 同样向 httpbin.example.com 发送一个 HTTPS 请求,仍然返回一个茶壶:
$ curl -v -HHost:httpbin.example.com --resolve "httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST" \--cacert example_certs1/example.com.crt "https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418"
# ......-=[ teapot ]=-_...._.'  _ _ `.| ."` ^ `". _,\_;`"---"`|//|       ;/\_     _/`"""`

测试结束。😘

3.双向 TLS Ingress Gateway

同样我们还可以扩展网关的定义以支持双向 TLS。双向 TLS 简称 mTLS,是一种相互身份验证的方法。mTLS 通过验证他们都拥有正确的私人密钥来确保网络连接两端的各方都是他们声称的身份。他们各自的 TLS 证书中的信息提供了额外的验证。

k8s里很多地方都是一个双向认证。

image-20231116064819341

通常在 TLS 中,服务器有一个 TLS 证书和一个公钥/私钥对,而客户端没有,典型的 TLS 流程是这样运作的:

  • 客户端连接到服务器
  • 服务器出示其 TLS 证书
  • 客户端验证服务器的证书
  • 客户端和服务器通过加密的 TLS 连接交换信息

img

然而,在 mTLS 中,客户端和服务器都有一个证书,并且双方都使用它们的公钥/私钥对进行身份验证。与常规 TLS 相比,mTLS 中有一些额外步骤来验证双方。

  • 客户端连接到服务器
  • 服务器出示其 TLS 证书
  • 客户端验证服务器的证书
  • 客户端出示其 TLS 证书
  • 服务器验证客户端的证书
  • 服务器授予访问权限
  • 客户端和服务器通过加密的 TLS 连接交换信息

img

接下来我们就来使用 mTLS 来配置 Ingress Gateway。

  • 首先还是删除其 Secret 并创建一个新的来更改入口网关的凭据,需要注意的是服务器使用 CA 证书来验证其客户端,我们必须使用名称 cacert 来持有 CA 证书。
$ kubectl -n istio-system delete secret httpbin-credential$ kubectl create -n istio-system secret generic httpbin-credential \--from-file=tls.key=example_certs1/httpbin.example.com.key \--from-file=tls.crt=example_certs1/httpbin.example.com.crt \--from-file=ca.crt=example_certs1/example.com.crt
  • 接下来更改 Gateway 的定义将 TLS 模式设置为 MUTUAL
#tls3-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:name: mygateway
spec:selector:istio: ingressgateway # use istio default ingress gatewayservers:- port:number: 443name: httpsprotocol: HTTPStls:mode: MUTUAL # 设置为 MUTUAL,双向 TLScredentialName: httpbin-credentialhosts:- httpbin.example.com

部署:

kubectl apply -f tls3-gateway.yaml
  • 应用后我们来尝试使用之前的方法发送 HTTPS 请求:
$ curl -v -HHost:httpbin.example.com --resolve "httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST" \
--cacert example_certs1/example.com.crt "https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418"
# ......
*   CAfile: example_certs1/example.com.crtCApath: none
* NSS: client certificate not found (nickname not specified)
* NSS error -12227 (SSL_ERROR_HANDSHAKE_FAILURE_ALERT)
* SSL peer was unable to negotiate an acceptable set of security parameters.
* Closing connection 0
curl: (35) NSS: client certificate not found (nickname not specified)

image-20231116065925000

  • 从提示可以看出,客户端证书没有找到,由于我们这里配置的是双向 TLS 的方式,我们没有将客户端证书传递给 curl,我们可以通过 --cert--key 标志来进行传递:
$ curl -v -HHost:httpbin.example.com --resolve "httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST" \--cacert example_certs1/example.com.crt --cert example_certs1/client.example.com.crt --key example_certs1/client.example.com.key \"https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418"
# ......
* Initializing NSS with certpath: sql:/etc/pki/nssdb
*   CAfile: example_certs1/example.com.crtCApath: none
* NSS: client certificate from file
*       subject: O=client organization,CN=client.example.com
*       start date: Nov 13 07:02:22 2023 GMT
*       expire date: Nov 12 07:02:22 2024 GMT
*       common name: client.example.com
*       issuer: CN=example.com,O=example Inc.
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
*       subject: O=httpbin organization,CN=httpbin.example.com
*       start date: Nov 13 06:58:40 2023 GMT
*       expire date: Nov 12 06:58:40 2024 GMT
*       common name: httpbin.example.com
*       issuer: CN=example.com,O=example Inc.
< HTTP/1.1 418 Unknown
# ......
<-=[ teapot ]=-_...._.'  _ _ `.| ."` ^ `". _,\_;`"---"`|//|       ;/\_     _/`"""`

到这里我们就验证了通过 TLS 或 mTLS 将服务暴露到服务网格外。

  • 测试完成后记得清理下资源:(6)
# 删除网关配置和路由:
kubectl delete gateway mygateway
kubectl delete virtualservice httpbin helloworld# 删除 Secret、证书和密钥:
kubectl delete -n istio-system secret httpbin-credential helloworld-credential
rm -rf ./example_certs1 ./example_certs2# 关闭 httpbin 和 helloworld 服务:
kubectl delete -f samples/httpbin/httpbin.yaml
kubectl delete deployment helloworld-v1
kubectl delete service helloworld
Ingress Gateway TLS 透传

前面我们了解了如何为 HTTP 服务配置 HTTPS 访问入口,那如果我们的后台服务本身就是 HTTPS 的,那么如何为 HTTPS 服务配置 HTTPS 访问入口即配置 Ingress Gateway 执行 SNI 透传,而不是对传入请求进行 TLS 终止。

既然提到了 TLS 终止,那么我们可以先了解下什么是 TLS 终止(TLS Termination)。

image-20231116074500594

1.TLS Termination

它的主要作用是,作为一个前置代理服务器接收外部到达的加密 TLS 流量,然后将其解密为 HTTP 明文,最后再将流量转发到内部的某个服务。

img

在实际应用中,内部的服务通常是以 HTTP 明文的方式通信,然后通过一个边界入口网关(ingress gateway)统一处理所有的 TLS 流量。这样 TLS 对所有的内部服务都是透明的,无需对每个服务去配置证书和私钥。通过一个统一的入口配置,我们还可以做很多事情,如日志,路由,路由策略等。

当然,对于一些安全级别较高的内部服务来说,未加密的流量可能是不可接受的,我们也可以配置来将加密的流量透传到该服务中,也就是这里我们需要的 SNI 透传。

同样的如果反过来,就是 TLS Origination

2.TLS Origination

作为一个代理服务器,接收内部服务的 HTTP 明文流量,然后将其加密,最后转发到一个 HTTPS 服务上,该服务既可以是内部,也可以是外部的,但看起来就像是一个内部的服务,流程如下,

img

作为与边界入口网关对立的存在,出口网关也通常放置在网络的边界。所有的出口流量都被它接管,在这个节点上我们可以统一实施一些访问控制策略,或监控,或日志等,这和 Ingres Gateway 的功能其实是一样的,最大的不同在于将明文流量加密再转发。

3.TLS 透传
🚩 实战:TLS 透传-2023.11.16(测试成功)

实验环境:

k8s v1.27.6(containerd://1.6.20)(cni:flannel:v0.22.2)[root@master1 ~]#istioctl version
client version: 1.19.3
control plane version: 1.19.3
data plane version: 1.19.3 (8 proxies)

实验软件:

链接:https://pan.baidu.com/s/1tpP4vWjOUqNyW2rBLqzVZg?pwd=0l54
提取码:0l54
–来自百度网盘超级会员V8的分享
2023.11.16-实战:TLS 透传-2023.11.16(测试成功)

image-20231116075614341

接下来我们用一个 NGINX 服务来演示下 TLS 透传的配置。首先在 Kubernetes 集群中创建一个 NGINX 服务,然后通过 Gateway 给这个服务配置一个域名是 nginx.example.com 的访问入口。

首先生成客户端和服务端的证书和密钥,同样我们这里使用 openssl 命令来生成。

  • 创建根证书和私钥来为你的服务签名证书:
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout example.com.key -out example.com.crt
  • nginx.example.com 创建证书和私钥:
openssl req -out nginx.example.com.csr -newkey rsa:2048 -nodes -keyout nginx.example.com.key -subj "/CN=nginx.example.com/O=some organization"openssl x509 -req -sha256 -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in nginx.example.com.csr -out nginx.example.com.crt

查看:

[root@master1 ~]#ll nginx.example.com.*
-rw-r--r-- 1 root root 1050 Nov 16 07:24 nginx.example.com.crt
-rw-r--r-- 1 root root  940 Nov 16 07:24 nginx.example.com.csr
-rw-r--r-- 1 root root 1704 Nov 16 07:24 nginx.example.com.key
  • 接着创建一个 Kubernetes 的 Secret 资源来保存服务的证书:
kubectl create secret tls nginx-server-certs --key nginx.example.com.key --cert nginx.example.com.crt
  • 为 NGINX 服务创建一个配置文件:
cat <<\EOF > ./nginx.conf
events {
}http {log_format main '$remote_addr - $remote_user [$time_local]  $status ''"$request" $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';access_log /var/log/nginx/access.log main;error_log  /var/log/nginx/error.log;server {listen 443 ssl;root /usr/share/nginx/html;index index.html;server_name nginx.example.com;ssl_certificate /etc/nginx-server-certs/tls.crt;ssl_certificate_key /etc/nginx-server-certs/tls.key;}
}
EOF
  • 创建一个 Kubernetes 的 ConfigMap 资源来保存 NGINX 服务的配置:
kubectl create configmap nginx-configmap --from-file=nginx.conf=./nginx.conf
  • 部署 NGINX 服务
cat <<EOF | istioctl kube-inject -f - | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:name: my-nginxlabels:run: my-nginx
spec:ports:- port: 443protocol: TCPselector:run: my-nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:name: my-nginx
spec:selector:matchLabels:run: my-nginxtemplate:metadata:labels:run: my-nginxspec:containers:- name: my-nginximage: nginxports:- containerPort: 443volumeMounts:- name: nginx-configmountPath: /etc/nginxreadOnly: true- name: nginx-server-certsmountPath: /etc/nginx-server-certsreadOnly: truevolumes:- name: nginx-configconfigMap:name: nginx-configmap- name: nginx-server-certssecret:secretName: nginx-server-certs
EOF
  • 要测试 NGINX 服务是否已成功部署,需要从其 Sidecar 代理发送请求,并忽略检查服务端的证书(使用 curl-k 选项)。确保正确打印服务端的证书,即 common name (CN) 等于 nginx.example.com 即可:
$ kubectl get pods -l run=my-nginx
NAME                        READY   STATUS    RESTARTS   AGE
my-nginx-74df679cd5-5g7ss   2/2     Running   0          5m47s$ kubectl exec "$(kubectl get pod  -l run=my-nginx -o jsonpath={.items..metadata.name})" -c istio-proxy -- curl -sS -v -k --resolve nginx.example.com:443:127.0.0.1 https://nginx.example.com
# ......
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: CN=nginx.example.com; O=some organization
*  start date: Nov 13 08:27:26 2023 GMT
*  expire date: Nov 12 08:27:26 2024 GMT
*  issuer: O=example Inc.; CN=example.com
*  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
} [5 bytes data]> GET / HTTP/1.1
> User-Agent: curl/7.58.0
> Host: nginx.example.com
# ......
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
# ......

image-20231116073143833

到这里我们的 HTTPS 服务就准备好了。

  • 接下来我们就可以配置 Ingress Gateway 来将流量透传到 NGINX 服务中了,在 Gateway 对象中定义 443 端口的网关,需要注意的是将 TLS 模式设置为 PASSTHROUGH,该模式指示 Gateway 以透传方式传递入口流量,而不终止 TLS,内容如下所示:
#tls4-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:name: mygateway
spec:selector:istio: ingressgateway # use istio default ingress gatewayservers:- port:number: 443name: httpsprotocol: HTTPStls:mode: PASSTHROUGHhosts:- nginx.example.com
  • 然后为通过 Gateway 进入的流量配置路由规则:
#tls4-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:name: nginx
spec:hosts:- nginx.example.comgateways:- mygatewaytls:- match:- port: 443sniHosts: # 指定 SNI 主机名- nginx.example.comroute:- destination:host: my-nginxport:number: 443

需要注意的是,这里的 VirtualService 对象中我们配置的 tls 字段了,描述了用于路由未终止的 TLS 流量(TLS/HTTPS)的匹配条件和动作。它通过 sniHosts 指定了 SNI 主机名,以便 Gateway 可以将流量路由到正确的 VirtualService

  • 部署资源

完整清单如下:

#tls4-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:name: mygateway
spec:selector:istio: ingressgateway # use istio default ingress gatewayservers:- port:number: 443name: httpsprotocol: HTTPStls:mode: PASSTHROUGHhosts:- nginx.example.com---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:name: nginx
spec:hosts:- nginx.example.comgateways:- mygatewaytls:- match:- port: 443sniHosts: # 指定 SNI 主机名- nginx.example.comroute:- destination:host: my-nginxport:number: 443

部署:

[root@master1 ~]#kubectl apply -f tls4-gateway.yaml 
gateway.networking.istio.io/mygateway created
virtualservice.networking.istio.io/nginx created
  • 应用上面的资源对象后,我们就可以向 nginx.example.com 发送 HTTPS 请求了:
# 获取 Ingress Gateway 的地址和 HTTPS 端口
export INGRESS_HOST=$(kubectl get pod -l istio=ingressgateway -n istio-system -o jsonpath='{.items[0].status.hostIP}')
export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}')# 访问 nginx 服务
$ curl -v --resolve "nginx.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST" --cacert example.com.crt "https://nginx.example.com:$SECURE_INGRESS_PORT"
# ......
* SSL connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate:
*       subject: O=some organization,CN=nginx.example.com
*       start date: Nov 13 08:27:26 2023 GMT
*       expire date: Nov 12 08:27:26 2024 GMT
*       common name: nginx.example.com
*       issuer: CN=example.com,O=example Inc.
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: nginx.example.com:30808
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx/1.21.5
< Date: Mon, 13 Nov 2023 08:50:27 GMT
< Content-Type: text/html
< Content-Length: 615
< Last-Modified: Tue, 28 Dec 2021 15:28:38 GMT
< Connection: keep-alive
< ETag: "61cb2d26-267"
< Accept-Ranges: bytes
<
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p><p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p><p><em>Thank you for using nginx.</em></p>
</body>
</html>

image-20231116073853838

可以看到,我们成功访问了 NGINX 服务。

测试结束。😘

关于我

我的博客主旨:

  • 排版美观,语言精炼;
  • 文档即手册,步骤明细,拒绝埋坑,提供源码;
  • 本人实战文档都是亲测成功的,各位小伙伴在实际操作过程中如有什么疑问,可随时联系本人帮您解决问题,让我们一起进步!

🍀 微信二维码
x2675263825 (舍得), qq:2675263825。

image-20230107215114763

🍀 微信公众号
《云原生架构师实战》

image-20230107215126971

🍀 个人博客站点

http://onedayxyy.cn/

image-20231113073017981

image-20231113073039083

🍀 语雀

https://www.yuque.com/xyy-onlyone

image-20231113073101271

🍀 csdn

https://blog.csdn.net/weixin_39246554?spm=1010.2135.3001.5421

image-20230107215149885

🍀 知乎

https://www.zhihu.com/people/foryouone

image-20230107215203185

最后

好了,关于本次就到这里了,感谢大家阅读,最后祝大家生活快乐,每天都过的有意义哦,我们下期见!

image-20231116095556983

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/195443.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

m1 rvm install 3.0.0 Error running ‘__rvm_make -j8‘

在使用M1 在安装cocopods 前时&#xff0c;安装 rvm install 3.0.0遇到 rvm install 3.0.0 Error running __rvm_make -j8 备注: 该图片是借用其他博客图片&#xff0c;因为我的环境解决完没有保留之前错误信息。 解决方法如下&#xff1a; 1. brew uninstall --ignore-depe…

Java NIO 详解

一、NIO简介 NIO 是 Java SE 1.4 引入的一组新的 I/O 相关的 API&#xff0c;它提供了非阻塞式 I/O、选择器、通道、缓冲区等新的概念和机制。相比与传统的 I/O 多出的 N 不是单纯的 New&#xff0c;更多的是代表了 Non-blocking 非阻塞&#xff0c;NIO具有更高的并发性、可扩…

es head 新增字段、修改字段、批量修改字段、删除字段、删除数据、批量删除数据

目录 一、新增字段 二、修改字段值 三、批量修改字段值 ​四、删除字段 五、删除数据/文档 六、批量删除数据/文档 一、新增字段 put http://{ip}:{port}/{index}/_mapping/{type} 其中&#xff0c;index是es索引、type是类型 数据&#xff1a; {"_doc"…

数据结构与算法之美学习笔记:20 | 散列表(下):为什么散列表和链表经常会一起使用?

目录 前言LRU 缓存淘汰算法Redis 有序集合Java LinkedHashMap解答开篇 & 内容小结 前言 本节课程思维导图&#xff1a; 今天&#xff0c;我们就来看看&#xff0c;在这几个问题中&#xff0c;散列表和链表都是如何组合起来使用的&#xff0c;以及为什么散列表和链表会经常…

window 搭建 MQTT 服务器并使用

1. 下载 安装 mosquitto 下载地址&#xff1a; http://mosquitto.org/files/binary/ win 使用 win32 看自己电脑下载相应版本&#xff1a; 一直安装&#xff1a; 记住安装路径&#xff1a;C:\Program Files\mosquitto 修改配置文件&#xff1a; allow_anonymous false 设置…

【VSCode】Visual Studio Code 下载与安装教程

前言 Visual Studio Code&#xff08;简称 VS Code&#xff09;是一个轻量级的代码编辑器&#xff0c;适用于多种编程语言和开发环境。本文将介绍如何下载和安装 Visual Studio Code。 下载安装包 首先&#xff0c;我们需要从官方网站下载 Visual Studio Code 的安装包。请访…

Docker与VM虚拟机的区别以及Docker的特点

01、本质上的区别 VM(VMware)在宿主机器、宿主机器操作系统的基础上创建虚拟层、虚拟化的操作系统、虚拟化的仓库&#xff0c;然后再安装应用&#xff1b; Container(Docker容器)&#xff0c;在宿主机器、宿主机器操作系统上创建Docker引擎&#xff0c;在引擎的基础上再安装应…

sqli-labs(Less-4) extractvalue闯关

extractvalue() - Xpath类型函数 1. 确认注入点如何闭合的方式 2. 爆出当前数据库的库名 http://127.0.0.1/sqlilabs/Less-4/?id1") and extractvalue(1,concat(~,(select database()))) --3. 爆出当前数据库的表名 http://127.0.0.1/sqlilabs/Less-4/?id1") …

Prometheus+Grafana环境搭建(window)

PrometheusGrafana环境搭建 1&#xff1a;配置Prometheus 1.1: 下载Prometheus安装包 官方下载地址 找到对应的win版本进行下载并解压 1.2 下载Window数据采集 官方下载地址 下载以管理员运行&#xff0c;安装成功后在服务里会出现一个"windows_exporter"采集…

HCL设备启动失败——已经解决

摸索了一个多小时&#xff0c;终于搞定了&#xff0c;首先HCL这款软件是需要安装Oracle VM Visual Box的&#xff0c;小伙伴们安装的时候记得点击安装Visual Box&#xff1b; 安装完后显示设备不能启动&#xff0c;然后我根据这个 HCL模拟器中Server设备启动失败的解决办法_hc…

【原创】java+swing+mysql校园活动管理系统设计与实现

前言&#xff1a; 本文介绍了一个校园活动管理系统的设计与实现。该系统基于JavaSwing技术&#xff0c;采用C/S架构&#xff0c;使用Java语言开发&#xff0c;以MySQL作为数据库。系统实现了活动发布、活动报名、活动列表查看等功能&#xff0c;方便了校园活动的发布和管理&am…

虚幻C++ day5

角色状态的常见机制 创建角色状态设置到UI上 在MainPlayer.h中新建血量&#xff0c;最大血量&#xff0c;耐力&#xff0c;最大耐力&#xff0c;金币变量&#xff0c;作为角色的状态 //主角状态UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category "Playe Stats&…

Python in Visual Studio Code 2023年11月发布

排版&#xff1a;Alan Wang 我们很高兴地宣布 Visual Studio Code 的 Python 和 Jupyter 扩展将于 2023 年 11 月发布&#xff01; 此版本包括以下公告&#xff1a; 改进了使用 Shift Enter 在终端中运行当前行弃用内置 linting 和格式设置功能对 Python linting 扩展的改进重…

Appium移动自动化测试--安装Appium

Appium 自动化测试是很早之前就想学习和研究的技术了&#xff0c;可是一直抽不出一块完整的时间来做这件事儿。现在终于有了。 反观各种互联网的招聘移动测试成了主流&#xff0c;如果再不去学习移动自动化测试技术将会被淘汰。 web自动化测试的路线是这样的&#xff1a;编程语…

asp.net core mvc之 RAZOR共享指令和标签助手 TagHelpers

一、RAZOR共享指令 RAZOR共享指令&#xff1a;在视图中导入命名空间&#xff0c;执行依赖注入。 RAZOR共享指令是写在 Views目录下的 _ViewImports.cshtml 文件 支持指令如下&#xff1a; addTagHelper 增加标签助手 removeTagHelper 移除标签助手 tagHelperPrefix 标签助手…

防抖-节流-深拷贝-事件总线

一、防抖与节流 1.认识防抖与节流函数 防抖和节流的概念其实最早并不是出现在软件工程中&#xff0c;防抖是出现在电子元件中&#xff0c;节流出现在流体流动中 而JavaScript是事件驱动的&#xff0c;大量的操作会触发事件&#xff0c;加入到事件队列中处理。而对于某些频繁…

【Java 进阶篇】揭秘 JQuery 广告显示与隐藏:打造令人惊艳的用户体验

在当今互联网时代&#xff0c;广告已经成为网页中不可忽视的一部分。然而&#xff0c;如何通过巧妙的交互设计&#xff0c;使广告既能吸引用户的眼球&#xff0c;又不会给用户带来干扰&#xff0c;成为了许多前端开发者需要思考的问题之一。在这篇博客中&#xff0c;我们将深入…

长短期记忆(LSTM)与RNN的比较:突破性的序列训练技术

长短期记忆&#xff08;Long short-term memory, LSTM&#xff09;是一种特殊的RNN&#xff0c;主要是为了解决长序列训练过程中的梯度消失和梯度爆炸问题。简单来说&#xff0c;就是相比普通的RNN&#xff0c;LSTM能够在更长的序列中有更好的表现。 Why LSTM提出的动机是为了解…

创邻科技亮相ISWC 2023,国际舞台见证知识图谱领域研究突破

近日&#xff0c;第22届国际语义网大会 ISWC 2023 在雅典希腊召开&#xff0c;通过线上线下的形式&#xff0c;聚集了全球的顶级研究人员、从业人员和行业专家&#xff0c;讨论、发展和塑造语义网和知识图谱技术的未来。创邻科技CEO张晨博士作为知识图谱行业专家受邀参会&#…

最新完美版积分商城系统-奇偶商城系统源码+独立代理后台+附搭建教程

源码简介&#xff1a; 最新完美版积分商城系统&#xff0c;网购商城系统源码&#xff0c;是更新的奇偶商城系统源码&#xff0c;它拥有独立代理后台&#xff0c;而且内附搭建教程。 1.演示环境&#xff1a;Linux Centos7以上版本 宝塔 2.Nginx 1.18.0 PHP7.0 Mysql5.6 3…