Istio 网关
Istio Gateway 在网格边缘运行的负载均衡器,接收入口或出口的流量到集群内部、
Istio网关新的Gateway资源和VirtualService资源来控制入口或出口流量,它们协同工作将流量路由到网格中。
- 客户端通过url发送请求
- LoadBalancer会进行监听接收到请求,并将请求转发到集群中
- 在集群内部,请求被路由到Istio IngressGateway服务的负载均衡器转发过来的端口上
- Istio IngressGateway服务将请求转发到对应的Pod上
- 在IngressGateway Pod上会根据Gateway资源和VirtualService资源定义的配置找到正确的服务
- Istio IngressGateway Pod会根据路由配置信息将请求路由到对应的应用Service上
- 应用Service将请求路由到对应的应用Pod上
Ingress Gateway
Ingress Gateway是一个基于Envoy代理的封装,它的配置方式与网格服务中使用的Sidecar配置相同(实际上是同样的容器镜像)。当我们创建或更改一个Gateway或VirtualService时,Istio Pilot控制器会检测到这些变更,并将这些变更信息转换为Envoy配置,然后将Envoy配置发送给相关Envoy代理,包括内部的Envoy和Ingress Gateway中的Envoy。
部署示例应用
[root@k8s-master01 istio-1.10.6]# kubectl apply -f samples/httpbin/httpbin.yaml
serviceaccount/httpbin created
service/httpbin configured
deployment.apps/httpbin created
[root@k8s-master01 istio-1.10.6]# cat samples/httpbin/httpbin.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: httpbin
---
apiVersion: v1
kind: Service
metadata:
name: httpbin
labels:
app: httpbin
service: httpbin
spec:
ports:
- name: http
port: 8000
targetPort: 80
selector:
app: httpbin
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
spec:
replicas: 1
selector:
matchLabels:
app: httpbin
version: v1
template:
metadata:
labels:
app: httpbin
version: v1
spec:
serviceAccountName: httpbin
containers:
- image: docker.io/kennethreitz/httpbin
imagePullPolicy: IfNotPresent
name: httpbin
ports:
- containerPort: 80
配置 Ingress
创建Istio Gateway:
[root@k8s-master01 istio-1.10.6]# kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: httpbin-gateway # Ingress Gateway名称
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80 # 定义端口
name: http
protocol: HTTP # 定义协议
hosts:
- "httpbin.kubesre.com" # 定义域名
EOF
为通过 Gateway
的入口流量配置路由:
[root@k8s-master01 istio-1.10.6]# kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- "httpbin.kubesre.com" # 定义域名
gateways:
- httpbin-gateway # 关联Gateway
http:
- match: # 定义路由
- uri:
prefix: /status
- uri:
prefix: /delay
route:
- destination:
port:
number: 8000
host: httpbin
EOF
使用curl命令访问httpbin服务:
[root@k8s-master01 istio-1.10.6]# curl -s -I -HHost:httpbin.kubesre.com "http://10.96.1.69/status/200"
HTTP/1.1 200 OK
server: istio-envoy
date: Sat, 12 Feb 2022 12:30:06 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: 44
# 访问其他没有被显式暴露的 URL 时,将看到 HTTP 404 错误:
[root@k8s-master01 istio-1.10.6]# curl -s -I -HHost:httpbin.kubesre.com "http://10.96.1.69/head"
HTTP/1.1 404 Not Found
date: Sat, 12 Feb 2022 12:31:14 GMT
server: istio-envoy
transfer-encoding: chunked
创建证书
# 创建一个根证书和私钥以为您的服务所用的证书签名:
[root@k8s-master01 istio-1.10.6]# 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
Generating a 2048 bit RSA private key
................................+++
...............................................................................+++
writing new private key to 'example.com.key'
-----
# 为 httpbin.example.com 创建一个证书和私钥:
[root@k8s-master01 istio-1.10.6]# openssl req -out httpbin.example.com.csr -newkey rsa:2048 -nodes -keyout httpbin.example.com.key -subj "/CN=httpbin.example.com/O=httpbin organization"
openssl x509 -req -sha256 -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in httpbin.example.com.csr -out httpbin.example.com.crt
Generating a 2048 bit RSA private key
...................................+++
.......................+++
writing new private key to 'httpbin.example.com.key'
-----
[root@k8s-master01 istio-1.10.6]# openssl x509 -req -sha256 -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in httpbin.example.com.csr -out httpbin.example.com.crt
Signature ok
subject=/CN=httpbin.example.com/O=httpbin organization
Getting CA Private Key
配置单向TLS Ingress网关
创建一个 Kubernetes secret 以保存服务器的证书和私钥
[root@k8s-master01 istio-1.10.6]# kubectl create -n istio-system secret tls istio-ingressgateway-certs --key httpbin.example.com.key --cert httpbin.example.com.crt
secret/istio-ingressgateway-certs created
为Ingress Gateway配置证书
[root@k8s-master01 istio-1.10.6]# kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: httpbin-gateway
spec:
selector:
istio: ingressgateway # use istio default ingress gateway
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: SIMPLE
serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
privateKey: /etc/istio/ingressgateway-certs/tls.key
hosts:
- "httpbin.example.com"
EOF
配置VirtualService:
[root@k8s-master01 istio-1.10.6]# kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- "httpbin.example.com"
gateways:
- httpbin-gateway
http:
- match:
- uri:
prefix: /status
- uri:
prefix: /delay
route:
- destination:
port:
number: 8000
host: httpbin
EOF
使用curl命令发送一个https请求进行验证:
[root@k8s-master01 istio-1.10.6]# curl -v -HHost:httpbin.example.com --resolve httpbin.example.com:443:10.96.1.69 --cacert example.com.crt https://httpbin.example.com:443/status/418
* Added httpbin.example.com:443:10.96.1.69 to DNS cache
* About to connect() to httpbin.example.com port 443 (#0)
* Trying 10.96.1.69...
* Connected to httpbin.example.com (10.96.1.69) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* CAfile: example.com.crt
CApath: none
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
* subject: O=httpbin organization,CN=httpbin.example.com
* start date: Feb 12 12:36:54 2022 GMT
* expire date: Feb 12 12:36:54 2023 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
< date: Sat, 12 Feb 2022 12:50:03 GMT
< x-more-info: http://tools.ietf.org/html/rfc2324
< access-control-allow-origin: *
< access-control-allow-credentials: true
< content-length: 135
< x-envoy-upstream-service-time: 34
<
-=[ teapot ]=-
_...._
.' _ _ `.
| ."` ^ `". _,
\_;`"---"`|//
| ;/
\_ _/
`"""`
* Connection #0 to host httpbin.example.com left intact
PS: --resolve标志让 curl 在通过 TLS 访问网关 IP 时支持 SNI 值 httpbin.example.com。 --cacert 选项则让 curl 使用您创建的证书来验证服务器。
配置双向TLS Ingress 网关
创建一个 Kubernetes Secret以保存服务端将用来验证它的客户端的CA证书:
[root@k8s-master01 istio-1.10.6]# kubectl create -n istio-system secret generic istio-ingressgateway-ca-certs --from-file=example.com.crt
secret/istio-ingressgateway-ca-certs created
修改Ingress Gateway配置:
# 修改 TLS 模式为 MUTUAL,并指定 caCertificates
[root@k8s-master01 istio-1.10.6]# kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: httpbin-gateway
spec:
selector:
istio: ingressgateway # use istio default ingress gateway
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: MUTUAL
serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
privateKey: /etc/istio/ingressgateway-certs/tls.key
caCertificates: /etc/istio/ingressgateway-ca-certs/example.com.crt
hosts:
- "httpbin.example.com"
EOF
创建客户端证书:
[root@k8s-master01 istio-1.10.6]# openssl req -out httpbin-client.example.com.csr -newkey rsa:2048 -nodes -keyout httpbin-client.example.com.key -subj "/CN=httpbin-client.example.com/O=httpbin's client organization"
openssl x509 -req -sha256 -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in httpbin-client.example.com.csr -out httpbin-client.example.com.crt
Generating a 2048 bit RSA private key
..........+++
.......................+++
writing new private key to 'httpbin-client.example.com.key'
-----
[root@k8s-master01 istio-1.10.6]# openssl x509 -req -sha256 -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in httpbin-client.example.com.csr -out httpbin-client.example.com.crt
Signature ok
subject=/CN=httpbin-client.example.com/O=httpbin's client organization
Getting CA Private Key
使用curl命令发送一个https请求进行验证:
[root@k8s-master01 istio-1.10.6]# curl -v -HHost:httpbin.example.com --resolve httpbin.example.com:443:10.96.1.69 --cacert example.com.crt --cert ./httpbin-client.example.com.crt --key ./httpbin-client.example.com.key https://httpbin.example.com/status/418
* Added httpbin.example.com:443:10.96.1.69 to DNS cache
* About to connect() to httpbin.example.com port 443 (#0)
* Trying 10.96.1.69...
* Connected to httpbin.example.com (10.96.1.69) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* CAfile: example.com.crt
CApath: none
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
* subject: O=httpbin organization,CN=httpbin.example.com
* start date: Feb 12 12:36:54 2022 GMT
* expire date: Feb 12 12:36:54 2023 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
< date: Sat, 12 Feb 2022 12:50:03 GMT
< x-more-info: http://tools.ietf.org/html/rfc2324
< access-control-allow-origin: *
< access-control-allow-credentials: true
< content-length: 135
< x-envoy-upstream-service-time: 34
<
-=[ teapot ]=-
_...._
.' _ _ `.
| ."` ^ `". _,
\_;`"---"`|//
| ;/
\_ _/
`"""`
* Connection #0 to host httpbin.example.com left intact
为多主机配置TLS Ingress网关
为 bookinfo.com
创建服务器证书和私钥:
[root@k8s-master01 istio-1.10.6]# openssl req -out bookinfo.com.csr -newkey rsa:2048 -nodes -keyout bookinfo.com.key -subj "/CN=bookinfo.com/O=bookinfo organization"
Generating a 2048 bit RSA private key
......+++
.....+++
writing new private key to 'bookinfo.com.key'
-----
[root@k8s-master01 istio-1.10.6]# openssl x509 -req -sha256 -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in bookinfo.com.csr -out bookinfo.com.crt
Signature ok
subject=/CN=bookinfo.com/O=bookinfo organization
Getting CA Private Key
使用新证书重新部署 istio-ingressgateway
:
# 创建一个新的 secret 以保存 bookinfo.com 的证书:
[root@k8s-master01 istio-1.10.6]# kubectl create -n istio-system secret tls istio-ingressgateway-bookinfo-certs --key bookinfo.com.key --cert bookinfo.com.crt
secret/istio-ingressgateway-bookinfo-certs created
# 更新 istio-ingressgateway deployment 以挂载新创建的 secret。创建如下 gateway-patch.json 文件以更新 istio-ingressgateway deployment:
[root@k8s-master01 istio-1.10.6]# cat > gateway-patch.json <<EOF
[{
"op": "add",
"path": "/spec/template/spec/containers/0/volumeMounts/0",
"value": {
"mountPath": "/etc/istio/ingressgateway-bookinfo-certs",
"name": "ingressgateway-bookinfo-certs",
"readOnly": true
}
},
{
"op": "add",
"path": "/spec/template/spec/volumes/0",
"value": {
"name": "ingressgateway-bookinfo-certs",
"secret": {
"secretName": "istio-ingressgateway-bookinfo-certs",
"optional": true
}
}
}]
EOF
# 使用以下命令应用 istio-ingressgateway deployment 更新:
[root@k8s-master01 istio-1.10.6]# kubectl -n istio-system patch --type=json deploy istio-ingressgateway -p "$(cat gateway-patch.json)"
deployment.apps/istio-ingressgateway patched
# 验证 istio-ingressgateway pod 已成功加载私钥和证书:
[root@k8s-master01 istio-1.10.6]# kubectl exec -it -n istio-system $(kubectl -n istio-system get pods -l istio=ingressgateway -o jsonpath='{.items[0].metadata.name}') -- ls -al /etc/istio/ingressgateway-bookinfo-certs
total 0
drwxrwsrwt. 3 root istio-proxy 120 Feb 12 13:14 .
drwxr-xr-x. 1 root root 140 Feb 12 13:14 ..
drwxr-sr-x. 2 root istio-proxy 80 Feb 12 13:14 ..2022_02_12_13_14_13.407844833
lrwxrwxrwx. 1 root root 31 Feb 12 13:14 ..data -> ..2022_02_12_13_14_13.407844833
lrwxrwxrwx. 1 root root 14 Feb 12 13:14 tls.crt -> ..data/tls.crt
lrwxrwxrwx. 1 root root 14 Feb 12 13:14 tls.key -> ..data/tls.key
配置 bookinfo.com
主机的流量:
# 部署Bookinfo示例应用
[root@k8s-master01 istio-1.10.6]# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
service/details unchanged
serviceaccount/bookinfo-details unchanged
deployment.apps/details-v1 unchanged
service/ratings unchanged
serviceaccount/bookinfo-ratings unchanged
deployment.apps/ratings-v1 unchanged
service/reviews unchanged
serviceaccount/bookinfo-reviews unchanged
deployment.apps/reviews-v1 unchanged
deployment.apps/reviews-v2 unchanged
deployment.apps/reviews-v3 unchanged
service/productpage unchanged
serviceaccount/bookinfo-productpage unchanged
deployment.apps/productpage-v1 unchanged
# 配置网关
[root@k8s-master01 istio-1.10.6]# kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: bookinfo-gateway
spec:
selector:
istio: ingressgateway # use istio default ingress gateway
servers:
- port:
number: 443
name: https-bookinfo
protocol: HTTPS
tls:
mode: SIMPLE
serverCertificate: /etc/istio/ingressgateway-bookinfo-certs/tls.crt
privateKey: /etc/istio/ingressgateway-bookinfo-certs/tls.key
hosts:
- "bookinfo.com"
EOF
# 配置VirtualService
[root@k8s-master01 istio-1.10.6]# kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: bookinfo
spec:
hosts:
- "bookinfo.com"
gateways:
- bookinfo-gateway
http:
- match:
- uri:
exact: /productpage
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
route:
- destination:
host: productpage
port:
number: 9080
EOF
发送到 Bookinfo productpage
的进行验证:
[root@k8s-master01 istio-1.10.6]# curl -o /dev/null -s -v -w "%{http_code}\n" -HHost:bookinfo.com --resolve bookinfo.com:443:10.96.1.69 --cacert example.com.crt -HHost:bookinfo.com https://bookinfo.com:443/productpage
* Added bookinfo.com:443:10.96.1.69 to DNS cache
* About to connect() to bookinfo.com port 443 (#0)
* Trying 10.96.1.69...
* Connected to bookinfo.com (10.96.1.69) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* CAfile: example.com.crt
CApath: none
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
* subject: O=bookinfo organization,CN=bookinfo.com
* start date: Feb 12 13:10:28 2022 GMT
* expire date: Feb 12 13:10:28 2023 GMT
* common name: bookinfo.com
* issuer: CN=example.com,O=example Inc.
> GET /productpage HTTP/1.1
> User-Agent: curl/7.29.0
> Accept: */*
> Host:bookinfo.com
> Host:bookinfo.com
>
...
200
修改Ingress Gateway:
[root@k8s-master01 istio-1.10.6]# kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: httpbin-gateway
spec:
selector:
istio: ingressgateway # use istio default ingress gateway
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: SIMPLE
serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
privateKey: /etc/istio/ingressgateway-certs/tls.key
hosts:
- "httpbin.example.com"
EOF
发送到httpbin.example.com进行验证访问:
[root@k8s-master01 istio-1.10.6]# curl -v -HHost:httpbin.example.com --resolve httpbin.example.com:443:10.96.1.69 --cacert example.com.crt https://httpbin.example.com/status/418
* Added httpbin.example.com:443:10.96.1.69 to DNS cache
* About to connect() to httpbin.example.com port 443 (#0)
* Trying 10.96.1.69...
* Connected to httpbin.example.com (10.96.1.69) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* CAfile: example.com.crt
CApath: none
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
* subject: O=httpbin organization,CN=httpbin.example.com
* start date: Feb 12 12:36:54 2022 GMT
* expire date: Feb 12 12:36:54 2023 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
< date: Sat, 12 Feb 2022 13:31:06 GMT
< x-more-info: http://tools.ietf.org/html/rfc2324
< access-control-allow-origin: *
< access-control-allow-credentials: true
< content-length: 135
< x-envoy-upstream-service-time: 46
<
-=[ teapot ]=-
_...._
.' _ _ `.
| ."` ^ `". _,
\_;`"---"`|//
| ;/
\_ _/
`"""`
* Connection #0 to host httpbin.example.com left intact
SNI透传TLS
生成证书:
# 创建根证书和私钥来为您的服务签名证书
[root@k8s-master01 istio-1.10.6]# 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
Generating a 2048 bit RSA private key
...+++
.....+++
writing new private key to 'example.com.key'
-----
# 为 nginx.example.com 创建证书和私钥:
[root@k8s-master01 istio-1.10.6]# openssl req -out nginx.example.com.csr -newkey rsa:2048 -nodes -keyout nginx.example.com.key -subj "/CN=nginx.example.com/O=some organization"
Generating a 2048 bit RSA private key
.......+++
.......+++
writing new private key to 'nginx.example.com.key'
-----
[root@k8s-master01 istio-1.10.6]# 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
Signature ok
subject=/CN=nginx.example.com/O=some organization
Getting CA Private Key
部署一个Nginx服务:
# 创建一个 Kubernetes 的 Secret 资源来保存服务的证书:
[root@k8s-master01 istio-1.10.6]# kubectl create secret tls nginx-server-certs --key nginx.example.com.key --cert nginx.example.com.crt
secret/nginx-server-certs created
# 为 NGINX 服务创建一个配置文件:
[root@k8s-master01 istio-1.10.6]# 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 服务的配置:
[root@k8s-master01 istio-1.10.6]# kubectl create configmap nginx-configmap --from-file=nginx.conf=./nginx.conf
# 部署 NGINX 服务
[root@k8s-master01 istio-1.10.6]# cat <<EOF | istioctl kube-inject -f - | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
name: my-nginx
labels:
run: my-nginx
spec:
ports:
- port: 443
protocol: TCP
selector:
run: my-nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 1
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 443
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx
readOnly: true
- name: nginx-server-certs
mountPath: /etc/nginx-server-certs
readOnly: true
volumes:
- name: nginx-config
configMap:
name: nginx-configmap
- name: nginx-server-certs
secret:
secretName: nginx-server-certs
EOF
配置Gateway:
PASSTHROUGH tls
TLS 模式,该模式指示 Gateway 以 AS IS 方式传递入口流量,而不终止 TLS。
[root@k8s-master01 istio-1.10.6]# kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: mygateway
spec:
selector:
istio: ingressgateway # use istio default ingress gateway
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: PASSTHROUGH
hosts:
- nginx.example.com
EOF
为通过 Gateway
进入的流量配置路由:
[root@k8s-master01 istio-1.10.6]# kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: nginx
spec:
hosts:
- nginx.example.com
gateways:
- mygateway
tls:
- match:
- port: 443
sniHosts:
- nginx.example.com
route:
- destination:
host: my-nginx
port:
number: 443
EOF
访问验证:
[root@k8s-master01 istio-1.10.6]# curl -v --resolve "nginx.example.com:443:10.96.1.69" --cacert example.com.crt "https://nginx.example.com:443"
* Added nginx.example.com:443:10.96.1.69 to DNS cache
* About to connect() to nginx.example.com port 443 (#0)
* Trying 10.96.1.69...
* Connected to nginx.example.com (10.96.1.69) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* CAfile: example.com.crt
CApath: none
* SSL connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate:
* subject: O=some organization,CN=nginx.example.com
* start date: Feb 12 16:23:43 2022 GMT
* expire date: Feb 12 16:23:43 2023 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
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx/1.21.6
< Date: Sat, 12 Feb 2022 16:35:08 GMT
< Content-Type: text/html
< Content-Length: 615
< Last-Modified: Tue, 25 Jan 2022 15:03:52 GMT
< Connection: keep-alive
< ETag: "61f01158-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>
* Connection #0 to host nginx.example.com left intact
Egress Gateway
由于默认情况下,来自 Istio-enable Pod 的所有出站流量都会重定向到其 Sidecar 代理,集群外部 URL 的可访问性取决于代理的配置。默认情况下,Istio 将 Envoy 代理配置为允许传递未知服务的请求。尽管这为入门 Istio 带来了方便,但是,通常情况下,配置更严格的控制是更可取的。
这个任务向你展示了三种访问外部服务的方法:
- 允许 Envoy 代理将请求传递到未在网格内配置过的服务。
- 配置 service entries 以提供对外部服务的受控访问。
- 对于特定范围的 IP,完全绕过 Envoy 代理。
访问外部服务
部署示例应用:
[root@k8s-master01 istio-1.10.6]# cat samples/sleep/sleep.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: sleep
---
apiVersion: v1
kind: Service
metadata:
name: sleep
labels:
app: sleep
service: sleep
spec:
ports:
- port: 80
name: http
selector:
app: sleep
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: sleep
spec:
replicas: 1
selector:
matchLabels:
app: sleep
template:
metadata:
labels:
app: sleep
spec:
terminationGracePeriodSeconds: 0
serviceAccountName: sleep
containers:
- name: sleep
image: curlimages/curl
command: ["/bin/sleep", "3650d"]
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /etc/sleep/tls
name: secret-volume
volumes:
- name: secret-volume
secret:
secretName: sleep-secret
optional: true
---
[root@k8s-master01 istio-1.10.6]# kubectl apply -f samples/sleep/sleep.yaml
serviceaccount/sleep unchanged
service/sleep created
deployment.apps/sleep created
Envoy 转发流量到外部服务
开启Egress并配置不控制对外部服务的访问:
[root@k8s-master01 istio-1.10.6]# istioctl install --set meshConfig.outboundTrafficPolicy.mode=ALLOW_ANY
[root@k8s-master01 istio-1.10.6]# kubectl get istiooperator installed-state -n istio-system -o jsonpath='{.spec.meshConfig.outboundTrafficPolicy.mode}'
ALLOW_ANY
从 SOURCE_POD
向外部 HTTPS 服务发出两个请求,确保能够得到状态码为 200
的响应:
[root@k8s-master01 istio-1.10.6]# export SOURCE_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
[root@k8s-master01 istio-1.10.6]# kubectl exec "$SOURCE_POD" -c sleep -- curl -sSI https://www.baidu.com | grep "HTTP/"; kubectl exec "$SOURCE_POD" -c sleep -- curl -sI https://edition.cnn.com | grep "HTTP/"
HTTP/1.1 200 OK
HTTP/2 200
恭喜!你已经成功地从网格中发送了 egress 流量。
控制对外部服务的访问
执行以下命令来将 global.outboundTrafficPolicy.mode
选项改为 REGISTRY_ONLY
:
[root@k8s-master01 istio-1.10.6]# istioctl install --set meshConfig.outboundTrafficPolicy.mode=REGISTRY_ONLY
从 SOURCE_POD
向外部 HTTPS 服务发出几个请求,验证它们现在是否被阻止:
[root@k8s-master01 istio-1.10.6]# kubectl exec "$SOURCE_POD" -c sleep -- curl -sSI https://www.baidu.com | grep "HTTP/"; kubectl exec "$SOURCE_POD" -c sleep -- curl -sI https://edition.cnn.com | grep "HTTP/"
curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to www.baidu.com:443
command terminated with exit code 35
command terminated with exit code 35
访问一个外部的 HTTP 服务
创建一个 ServiceEntry
,以允许访问一个外部的 HTTP 服务:
[root@k8s-master01 istio-1.10.6]# kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: httpbin-ext
spec:
hosts:
- httpbin.org
ports:
- number: 80
name: http
protocol: HTTP
resolution: DNS
location: MESH_EXTERNAL
EOF
从 SOURCE_POD
向外部的 HTTP 服务发出一个请求:
[root@k8s-master01 istio-1.10.6]# kubectl exec -it $SOURCE_POD -c sleep -- curl http://httpbin.org/headers
{
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
"User-Agent": "curl/7.81.0-DEV",
"X-Amzn-Trace-Id": "Root=1-6207e915-6fea3ceb26d238311ca6d68e",
"X-B3-Sampled": "0",
"X-B3-Spanid": "6afb8a8e94eeade9",
"X-B3-Traceid": "f216a91c0454a97a6afb8a8e94eeade9",
"X-Envoy-Attempt-Count": "1",
"X-Envoy-Decorator-Operation": "httpbin.org:80/*",
"X-Envoy-Peer-Metadata": "ChkKDkFQUF9DT05UQUlORVJTEgcaBXNsZWVwChoKCkNMVVNURVJfSUQSDBoKS3ViZXJuZXRlcwoZCg1JU1RJT19WRVJTSU9OEggaBjEuMTAuNgrfAQoGTEFCRUxTEtQBKtEBCg4KA2FwcBIHGgVzbGVlcAoZCgxpc3Rpby5pby9yZXYSCRoHZGVmYXVsdAohChFwb2QtdGVtcGxhdGUtaGFzaBIMGgo1NTc3NDc0NTVmCiQKGXNlY3VyaXR5LmlzdGlvLmlvL3Rsc01vZGUSBxoFaXN0aW8KKgofc2VydmljZS5pc3Rpby5pby9jYW5vbmljYWwtbmFtZRIHGgVzbGVlcAovCiNzZXJ2aWNlLmlzdGlvLmlvL2Nhbm9uaWNhbC1yZXZpc2lvbhIIGgZsYXRlc3QKGgoHTUVTSF9JRBIPGg1jbHVzdGVyLmxvY2FsCiAKBE5BTUUSGBoWc2xlZXAtNTU3NzQ3NDU1Zi00OGJkNQoWCglOQU1FU1BBQ0USCRoHZGVmYXVsdApJCgVPV05FUhJAGj5rdWJlcm5ldGVzOi8vYXBpcy9hcHBzL3YxL25hbWVzcGFjZXMvZGVmYXVsdC9kZXBsb3ltZW50cy9zbGVlcAoXChFQTEFURk9STV9NRVRBREFUQRICKgAKGAoNV09SS0xPQURfTkFNRRIHGgVzbGVlcA==",
"X-Envoy-Peer-Metadata-Id": "sidecar~100.125.152.48~sleep-557747455f-48bd5.default~default.svc.cluster.local"
}
}
注意由 Istio sidecar 代理添加的 headers: X-Envoy-Decorator-Operation
访问外部 HTTPS 服务
# 创建一个 ServiceEntry,允许对外部服务的访问
[root@k8s-master01 istio-1.10.6]# kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: baidu
spec:
hosts:
- www.baidu.com
ports:
- number: 443
name: https
protocol: HTTPS
resolution: DNS
location: MESH_EXTERNAL
EOF
# 从 SOURCE_POD 往外部 HTTPS 服务发送请求
[root@k8s-master01 istio-1.10.6]# kubectl exec -it $SOURCE_POD -c sleep -- curl -I https://www.baidu.com | grep "HTTP/"
HTTP/1.1 200 OK
管理到外部服务的流量
# 设置对 httpbin.org 服务访问的超时规则(请求大约在 5 秒内返回 200 (OK))
[root@k8s-master01 istio-1.10.6]# kubectl exec "$SOURCE_POD" -c sleep -- time curl -o /dev/null -sS -w "%{http_code}\n" http://httpbin.org/delay/5
200
real 0m 5.45s
user 0m 0.00s
sys 0m 0.00s
# 退出测试源 pod,使用 kubectl 设置调用外部服务 httpbin.org 的超时时间为 3 秒。
[root@k8s-master01 istio-1.10.6]# kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin-ext
spec:
hosts:
- httpbin.org
http:
- timeout: 3s
route:
- destination:
host: httpbin.org
weight: 100
EOF
# 重新发出 curl 请求:
[root@k8s-master01 istio-1.10.6]# kubectl exec "$SOURCE_POD" -c sleep -- time curl -o /dev/null -sS -w "%{http_code}\n" http://httpbin.org/delay/5
504
real 0m 3.04s
user 0m 0.00s
sys 0m 0.00s
通过 egress 网关发起 TLS 连接
TLS 的发起过程由 egress 网关完成,而不是像之前示例演示的那样由 sidecar 完成
# 为 edition.cnn.com 定义一个 ServiceEntry:
[root@k8s-master01 istio-1.10.6]# kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: cnn
spec:
hosts:
- edition.cnn.com
ports:
- number: 80
name: http
protocol: HTTP
- number: 443
name: https
protocol: HTTPS
resolution: DNS
EOF
# 发送一个请求至 http://edition.cnn.com/politics,验证 ServiceEntry 已被正确应用。
[root@k8s-master01 istio-1.10.6]# kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics
HTTP/1.1 301 Moved Permanently
server: envoy
retry-after: 0
content-length: 0
cache-control: public, max-age=300
location: https://edition.cnn.com/politics
accept-ranges: bytes
date: Sat, 12 Feb 2022 17:26:14 GMT
via: 1.1 varnish
set-cookie: countryCode=CN; Domain=.cnn.com; Path=/; SameSite=Lax
set-cookie: stateCode=SH; Domain=.cnn.com; Path=/; SameSite=Lax
set-cookie: geoData=shanghai|SH|200000|CN|AS|800|broadband|31.240|121.480; Domain=.cnn.com; Path=/; SameSite=Lax
x-served-by: cache-nrt18325-NRT
x-cache: HIT
x-cache-hits: 0
x-envoy-upstream-service-time: 242
HTTP/2 200
content-type: text/html; charset=utf-8
x-servedbyhost: ::ffff:127.0.0.1
access-control-allow-origin: *
cache-control: max-age=60
content-security-policy: default-src 'self' blob: https://*.cnn.com:* http://*.cnn.com:* *.cnn.io:* *.cnn.net:* *.turner.com:* *.turner.io:* *.ugdturner.com:* courageousstudio.com *.vgtf.net:*; script-src 'unsafe-eval' 'unsafe-inline' 'self' *; style-src 'unsafe-inline' 'self' blob: *; child-src 'self' blob: *; frame-src 'self' *; object-src 'self' *; img-src 'self' data: blob: *; media-src 'self' data: blob: *; font-src 'self' data: *; connect-src 'self' data: *; frame-ancestors 'self' https://*.cnn.com:* http://*.cnn.com:* https://*.cnn.io:* http://*.cnn.io:* *.turner.com:* https://www.google.com https://news.google.com https://www.google.co.uk https://amp-cnn-com.cdn.ampproject.org courageousstudio.com;
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
via: 1.1 varnish, 1.1 varnish
accept-ranges: bytes
date: Sat, 12 Feb 2022 17:26:15 GMT
age: 273
set-cookie: countryCode=CN; Domain=.cnn.com; Path=/; SameSite=None; Secure
set-cookie: stateCode=SH; Domain=.cnn.com; Path=/; SameSite=None; Secure
set-cookie: geoData=shanghai|SH|200000|CN|AS|800|broadband|31.240|121.480; Domain=.cnn.com; Path=/; SameSite=None; Secure
set-cookie: FastAB=0=6645,1=3296,2=5969,3=0326,4=5810,5=7055,6=7674,7=8126,8=2236,9=5177; Domain=.cnn.com; Path=/; Expires=Sat Jul 01 2023 00:00:00 GMT; SameSite=Lax
x-served-by: cache-iad-kcgs7200115-IAD, cache-hnd18720-HND
x-cache: HIT, MISS
x-cache-hits: 1, 0
x-timer: S1644686775.198386,VS0,VE211
vary: , Accept-Encoding
content-length: 1223432
# 为 edition.cnn.com 创建一个 egress Gateway,端口 443,以及一个 sidecar 请求的目标规则,sidecar 请求被直接导向 egress 网关。
[root@k8s-master01 istio-1.10.6]# kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: istio-egressgateway
spec:
selector:
istio: egressgateway
servers:
- port:
number: 80
name: https-port-for-tls-origination
protocol: HTTPS
hosts:
- edition.cnn.com
tls:
mode: ISTIO_MUTUAL
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: egressgateway-for-cnn
spec:
host: istio-egressgateway.istio-system.svc.cluster.local
subsets:
- name: cnn
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN
portLevelSettings:
- port:
number: 80
tls:
mode: ISTIO_MUTUAL
sni: edition.cnn.com
EOF
# 定义一个 VirtualService 来引导流量流经 egress 网关,以及一个 DestinationRule 为访问 edition.cnn.com 的请求发起 TLS 连接:
[root@k8s-master01 istio-1.10.6]# kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: direct-cnn-through-egress-gateway
spec:
hosts:
- edition.cnn.com
gateways:
- istio-egressgateway
- mesh
http:
- match:
- gateways:
- mesh
port: 80
route:
- destination:
host: istio-egressgateway.istio-system.svc.cluster.local
subset: cnn
port:
number: 80
weight: 100
- match:
- gateways:
- istio-egressgateway
port: 80
route:
- destination:
host: edition.cnn.com
port:
number: 443
weight: 100
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: originate-tls-for-edition-cnn-com
spec:
host: edition.cnn.com
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN
portLevelSettings:
- port:
number: 443
tls:
mode: SIMPLE # initiates HTTPS for connections to edition.cnn.com
EOF
# 发送一个 HTTP 请求至 http://edition.cnn.com/politics。
[root@k8s-master01 istio-1.10.6]# kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics
HTTP/1.1 200 OK
date: Sat, 12 Feb 2022 17:28:51 GMT
server: envoy
content-length: 0
通过 egress 网关发起双向 TLS 连接
配置一个 egress 网关,为外部服务发起 TLS 连接,只是这次服务要求双向 TLS
生成客户端和服务器的证书与密钥
# 为您的服务签名证书创建根证书和私钥
[root@k8s-master01 istio-1.10.6]# 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
Generating a 2048 bit RSA private key
...........+++
.............................................+++
writing new private key to 'example.com.key'
-----
# 为 my-nginx.mesh-external.svc.cluster.local 创建证书和私钥
[root@k8s-master01 istio-1.10.6]# openssl req -out my-nginx.mesh-external.svc.cluster.local.csr -newkey rsa:2048 -nodes -keyout my-nginx.mesh-external.svc.cluster.local.key -subj "/CN=my-nginx.mesh-external.svc.cluster.local/O=some organization"
openssl x509 -req -sha256 -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in my-nginx.mesh-external.svc.cluster.local.csr -out my-nginx.mesh-external.svc.cluster.local.crt
Generating a 2048 bit RSA private key
...................................................+++
...............................................................................................+++
writing new private key to 'my-nginx.mesh-external.svc.cluster.local.key'
-----
[root@k8s-master01 istio-1.10.6]# openssl x509 -req -sha256 -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in my-nginx.mesh-external.svc.cluster.local.csr -out my-nginx.mesh-external.svc.cluster.local.crt
Signature ok
subject=/CN=my-nginx.mesh-external.svc.cluster.local/O=some organization
Getting CA Private Key
# 生成客户端证书和私钥
[root@k8s-master01 istio-1.10.6]# openssl req -out client.example.com.csr -newkey rsa:2048 -nodes -keyout client.example.com.key -subj "/CN=client.example.com/O=client organization"
Generating a 2048 bit RSA private key
....openssl x509 -req -sha256 -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 1 -in client.example.com.csr -out client.example.com.crt
.........+++
..........................................................................................+++
writing new private key to 'client.example.com.key'
-----
[root@k8s-master01 istio-1.10.6]# openssl x509 -req -sha256 -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 1 -in client.example.com.csr -out client.example.com.crt
Signature ok
subject=/CN=client.example.com/O=client organization
Getting CA Private Key
部署一个双向 TLS 服务器
为了模拟一个真实的支持双向 TLS 协议的外部服务, 在 Kubernetes 集群中部署一个 NGINX 服务器,该服务器运行在 Istio 服务网格之外,譬如:运行在一个没有开启 Istio sidecar proxy 注入的命名空间中。
# 创建一个命名空间,表示 Istio 网格之外的服务,mesh-external。注意在这个命名空间中,sidecar 自动注入是没有开启的,不会在 pods 中自动注入 sidecar proxy
[root@k8s-master01 istio-1.10.6]# kubectl create namespace mesh-external
namespace/mesh-external created
# 创建 Kubernetes Secrets ,保存服务器和 CA 的证书
[root@k8s-master01 istio-1.10.6]# kubectl create -n mesh-external secret tls nginx-server-certs --key my-nginx.mesh-external.svc.cluster.local.key --cert my-nginx.mesh-external.svc.cluster.local.crt
kubectl create -n mesh-external secret generic nginx-ca-certs --from-file=example.com.crt
secret/nginx-server-certs created
[root@k8s-master01 istio-1.10.6]# kubectl create -n mesh-external secret generic nginx-ca-certs --from-file=example.com.crt
secret/nginx-ca-certs created
# 生成 NGINX 服务器的配置文件
[root@k8s-master01 istio-1.10.6]# 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 my-nginx.mesh-external.svc.cluster.local;
ssl_certificate /etc/nginx-server-certs/tls.crt;
ssl_certificate_key /etc/nginx-server-certs/tls.key;
ssl_client_certificate /etc/nginx-ca-certs/example.com.crt;
ssl_verify_client on;
}
}
EOF
# 生成 Kubernetes ConfigMap 保存 NGINX 服务器的配置文件
[root@k8s-master01 istio-1.10.6]# kubectl create configmap nginx-configmap -n mesh-external --from-file=nginx.conf=./nginx.conf
configmap/nginx-configmap created
# 部署 NGINX 服务器
[root@k8s-master01 istio-1.10.6]# kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
name: my-nginx
namespace: mesh-external
labels:
run: my-nginx
spec:
ports:
- port: 443
protocol: TCP
selector:
run: my-nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
namespace: mesh-external
spec:
selector:
matchLabels:
run: my-nginx
replicas: 1
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 443
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx
readOnly: true
- name: nginx-server-certs
mountPath: /etc/nginx-server-certs
readOnly: true
- name: nginx-ca-certs
mountPath: /etc/nginx-ca-certs
readOnly: true
volumes:
- name: nginx-config
configMap:
name: nginx-configmap
- name: nginx-server-certs
secret:
secretName: nginx-server-certs
- name: nginx-ca-certs
secret:
secretName: nginx-ca-certs
EOF
# 为 nginx.example.com 定义一个 ServiceEntry 和一个 VirtualService,指示 Istio 引导目标为 nginx.example.com 的流量流向 NGINX 服务器:
[root@k8s-master01 istio-1.10.6]# kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: nginx
spec:
hosts:
- nginx.example.com
ports:
- number: 80
name: http
protocol: HTTP
- number: 443
name: https
protocol: HTTPS
resolution: DNS
endpoints:
- address: my-nginx.mesh-external.svc.cluster.local
ports:
https: 443
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: nginx
spec:
hosts:
- nginx.example.com
tls:
- match:
- port: 443
sni_hosts:
- nginx.example.com
route:
- destination:
host: nginx.example.com
port:
number: 443
weight: 100
EOF
使用客户端证书重新部署 egress 网关
# 生成 Kubernetes Secrets 保存客户端和 CA 的证书
[root@k8s-master01 istio-1.10.6]# kubectl create -n istio-system secret tls nginx-client-certs --key client.example.com.key --cert client.example.com.crt
kubectl create -n istio-system secret generic nginx-ca-certs --from-file=example.com.crt
secret/nginx-client-certs created
[root@k8s-master01 istio-1.10.6]# kubectl create -n istio-system secret generic nginx-ca-certs --from-file=example.com.crt
secret/nginx-ca-certs created
# 部署 istio-egressgateway 挂载新生成的 Secrets 的 Volume。使用的参数选项与生成 istio.yaml 中的一致,创建下面的 gateway-patch.json 文件:
[root@k8s-master01 istio-1.10.6]# cat > gateway-patch.json <<EOF
[{
"op": "add",
"path": "/spec/template/spec/containers/0/volumeMounts/0",
"value": {
"mountPath": "/etc/istio/nginx-client-certs",
"name": "nginx-client-certs",
"readOnly": true
}
},
{
"op": "add",
"path": "/spec/template/spec/volumes/0",
"value": {
"name": "nginx-client-certs",
"secret": {
"secretName": "nginx-client-certs",
"optional": true
}
}
},
{
"op": "add",
"path": "/spec/template/spec/containers/0/volumeMounts/1",
"value": {
"mountPath": "/etc/istio/nginx-ca-certs",
"name": "nginx-ca-certs",
"readOnly": true
}
},
{
"op": "add",
"path": "/spec/template/spec/volumes/1",
"value": {
"name": "nginx-ca-certs",
"secret": {
"secretName": "nginx-ca-certs",
"optional": true
}
}
}]
EOF
# 通过以下命令部署应用 istio-egressgateway
[root@k8s-master01 istio-1.10.6]# kubectl -n istio-system patch --type=json deploy istio-egressgateway -p "$(cat gateway-patch.json)"
# 验证密钥和证书被成功装载入 istio-egressgateway pod:
[root@k8s-master01 istio-1.10.6]# kubectl exec -n istio-system "$(kubectl -n istio-system get pods -l istio=egressgateway -o jsonpath='{.items[0].metadata.name}')" -- ls -al /etc/istio/nginx-client-certs /etc/istio/nginx-ca-certs
为 egress 流量配置双向 TLS
# 为 my-nginx.mesh-external.svc.cluster.local 创建一个 egress Gateway 端口为 443,以及目标规则和虚拟服务来引导流量流经 egress 网关并从 egress 网关流向外部服务。
[root@k8s-master01 istio-1.10.6]# kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: istio-egressgateway
spec:
selector:
istio: egressgateway
servers:
- port:
number: 443
name: https
protocol: HTTPS
hosts:
- my-nginx.mesh-external.svc.cluster.local
tls:
mode: ISTIO_MUTUAL
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: egressgateway-for-nginx
spec:
host: istio-egressgateway.istio-system.svc.cluster.local
subsets:
- name: nginx
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN
portLevelSettings:
- port:
number: 443
tls:
mode: ISTIO_MUTUAL
sni: my-nginx.mesh-external.svc.cluster.local
EOF
# 定义一个 VirtualService 引导流量流经 egress 网关
[root@k8s-master01 istio-1.10.6]# kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: direct-nginx-through-egress-gateway
spec:
hosts:
- my-nginx.mesh-external.svc.cluster.local
gateways:
- istio-egressgateway
- mesh
http:
- match:
- gateways:
- mesh
port: 80
route:
- destination:
host: istio-egressgateway.istio-system.svc.cluster.local
subset: nginx
port:
number: 443
weight: 100
- match:
- gateways:
- istio-egressgateway
port: 443
route:
- destination:
host: my-nginx.mesh-external.svc.cluster.local
port:
number: 443
weight: 100
EOF
# 添加 DestinationRule 执行双向 TLS
[root@k8s-master01 istio-1.10.6]# kubectl apply -n istio-system -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: originate-mtls-for-nginx
spec:
host: my-nginx.mesh-external.svc.cluster.local
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN
portLevelSettings:
- port:
number: 443
tls:
mode: MUTUAL
clientCertificate: /etc/istio/nginx-client-certs/tls.crt
privateKey: /etc/istio/nginx-client-certs/tls.key
caCertificates: /etc/istio/nginx-ca-certs/example.com.crt
sni: my-nginx.mesh-external.svc.cluster.local
EOF
# 发送一个 HTTP 请求至 http://my-nginx.mesh-external.svc.cluster.local:
[root@k8s-master01 istio-1.10.6]# kubectl exec "$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})" -c sleep -- curl -sS http://my-nginx.mesh-external.svc.cluster.local
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
评论区