[TOC]
本文介绍了在Istio中直接转发TLS请求的场景:外部服务通过Igress Gateway访问Mesh内部的TLS服务。
TLS类型的路由属于TCP,所以无Envoy route相关配置,路由均在listener中进行。
本文也为了对TCP类型的路由在Envoy中的配置进行一些解析。
- 外部客户端发送相关tls请求。
- 请求被发送至lb,并由lb转发至ingressgateway pod。
- ingressgateway中的istio-proxy container根据相关snihosts路由规则将请求转发至相关nginx pod。
- 请求被nginx pod中的istio-proxy container截获,并转发至nginx container。
- 因为tls类型的路由属于tcp,所以无envoy route相关配置,路由均在listener中进行。
- 2个nginx pod,label为别为version: v1和version: v2。
- 使用istio destinationrule为不同的label定义不同的subset。
- 使用istio gateway定义ingressgateway接收443端口的请求。
- 将ingressgateway的443端口的tls策略设置为passthrough。
- 在ingressgateway中使用istio virtualservice定义到两个节点的基于tls的envoy route。
- 指定sni名称为*.v1.nginx.internal.istio的请求被路由到subset v1。
- 指定sni名称为*.v2.nginx.internal.istio的请求被路由到subset v2。
openssl req \
-newkey rsa:4096 -nodes -sha256 -keyout 1st.nginx.key \
-out 1st.nginx.csr
echo subjectAltName = DNS:www.1st.nginx > 1st.nginx.cnf
openssl x509 \
-req -days 3655 -in 1st.nginx.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -extfile 1st.nginx.cnf -out 1st.nginx.crt
openssl req \
-newkey rsa:4096 -nodes -sha256 -keyout 2nd.nginx.key \
-out 2nd.nginx.csr
echo subjectAltName = DNS:www.2nd.nginx > 2nd.nginx.cnf
openssl x509 \
-req -days 3655 -in 2nd.nginx.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -extfile 2nd.nginx.cnf -out 2nd.nginx.crt
kubectl create secret tls sec-nginx-v1 --key ./1st.nginx.key --cert ./1st.nginx.crt
kubectl create secret tls sec-nginx-v2 --key ./2nd.nginx.key --cert ./2nd.nginx.crt
- 为nginx-v1 pod配置证书和私钥,并将证书和私钥生成k8s secret sec-nginx-v1。
- 为nginx-v2 pod配置证书和私钥,并将证书和私钥生成k8s secret sec-nginx-v2。
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-v1
spec:
replicas: 1
template:
metadata:
labels:
app: nginx
version: v1
spec:
containers:
- name: nginx
image: 192.168.0.61/istio-example/nginx
ports:
- containerPort: 443
volumeMounts:
- mountPath: /etc/nginx/conf.d/
readOnly: true
name: conf
- mountPath: /etc/nginx/html/
readOnly: true
name: index
- mountPath: /etc/nginx/certs
readOnly: true
name: certs
volumes:
- name: conf
configMap:
name: cm-nginx-v1
items:
- key: default.conf
path: default.conf
- name: index
configMap:
name: cm-nginx-v1
items:
- key: index.html
path: index.html
- name: certs
secret:
secretName: sec-nginx-v1
---
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-nginx-v1
data:
default.conf: |
server {
listen 443 ssl;
server_name loalhost;
location / {
root /etc/nginx/html/;
index index.html index.htm;
}
ssl_certificate /etc/nginx/certs/tls.crt;
ssl_certificate_key /etc/nginx/certs/tls.key;
ssl_verify_depth 2;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
index.html: |
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<h1>nginx01</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>
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-v2
spec:
replicas: 1
template:
metadata:
labels:
app: nginx
version: v2
spec:
containers:
- name: nginx
image: 192.168.0.61/istio-example/nginx
ports:
- containerPort: 443
volumeMounts:
- mountPath: /etc/nginx/conf.d/
readOnly: true
name: conf
- mountPath: /etc/nginx/html/
readOnly: true
name: index
- mountPath: /etc/nginx/certs
readOnly: true
name: certs
volumes:
- name: conf
configMap:
name: cm-nginx-v2
items:
- key: default.conf
path: default.conf
- name: index
configMap:
name: cm-nginx-v2
items:
- key: index.html
path: index.html
- name: certs
secret:
secretName: sec-nginx-v2
---
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-nginx-v2
data:
default.conf: |
server {
listen 443 ssl;
server_name loalhost;
location / {
root /etc/nginx/html/;
index index.html index.htm;
}
ssl_certificate /etc/nginx/certs/tls.crt;
ssl_certificate_key /etc/nginx/certs/tls.key;
ssl_verify_depth 2;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
index.html: |
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<h1>nginx02</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>
---
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
type: ClusterIP
ports:
- port: 443
name: https
selector:
app: nginx
- 使用configmap cm-nginx-v1定制nginx-v1的配置文件和测试页面。
- 使用configmap cm-nginx-v2定制nginx-v2的配置文件和测试页面。
- 配置nginx-v1 deployment,挂载configmap cm-nginx-v1和secret sec-nginx-v1。
- 配置nginx-v2 deployment,挂载configmap cm-nginx-v1和secret sec-nginx-v1。
- 配置nginx service,端口为443,名称为https。
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: dr-sni
spec:
host: nginx.default.svc.cluster.local
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
- destinationrule相关配置。
- 为cluster nginx.default.svc.cluster.local定义subset。
- 将label为version: v1的endpoint deployment定义为subset v1。
- 将label为version: v2的endpoint deployment定义为subset v2。
{
"name": "outbound|443|v1|nginx.default.svc.cluster.local",
"type": "EDS",
"edsClusterConfig": {
"edsConfig": {
"ads": {}
},
"serviceName": "outbound|443|v1|nginx.default.svc.cluster.local"
},
"connectTimeout": "1.000s",
"circuitBreakers": {
"thresholds": [
{}
]
}
}
{
"name": "outbound|443|v2|nginx.default.svc.cluster.local",
"type": "EDS",
"edsClusterConfig": {
"edsConfig": {
"ads": {}
},
"serviceName": "outbound|443|v2|nginx.default.svc.cluster.local"
},
"connectTimeout": "1.000s",
"circuitBreakers": {
"thresholds": [
{}
]
}
}
- envoy cluster相关配置。
- 在destinationrule定义完成后,envoy会生成2个subset相关的cluster,分别为outbound|443|v1|nginx.default.svc.cluster.local和outbound|443|v2|nginx.default.svc.cluster.local。
{"svc": "nginx.default.svc.cluster.local:https", "ep": [
{
"endpoint": {
"Family": 0,
"Address": "10.234.0.58",
"Port": 443,
"ServicePort": {
"name": "https",
"port": 443,
"protocol": "HTTPS"
},
…
"labels": {
"app": "nginx",
"pod-template-hash": "3875363210",
"version": "v2"
},
…
"endpoint": {
"Family": 0,
"Address": "10.234.0.59",
"Port": 443,
"ServicePort": {
"name": "https",
"port": 443,
"protocol": "HTTPS"
},
…
"labels": {
"app": "nginx",
"pod-template-hash": "1126943858",
"version": "v1"
},
- envoy endpoint相关配置。
- 这2个cluster会与envoy endpoint相关联。
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: gw-sni
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: PASSTHROUGH
hosts:
- "*"
- gateway相关配置。
- 为ingress gateway设置监听。
- 打开ingress gateway的443端口进行监听,端口类型为https。
- tls类型为passthrough。
- 所有host均可以注册到这个监听。
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: vs-sni-gw
spec:
hosts:
- "*.v1.nginx.internal.istio"
- "*.v2.nginx.internal.istio"
gateways:
- gw-sni
tls:
- match:
- sniHosts:
- "*.v1.nginx.internal.istio"
route:
- destination:
host: nginx.default.svc.cluster.local
port:
number: 443
subset: v1
- match:
- sniHosts:
- "*.v2.nginx.internal.istio"
route:
- destination:
host: nginx.default.svc.cluster.local
port:
number: 443
subset: v2
- ingress gateway层面virtualservice相关配置。
- ingress gateway在接收到外部lb转发的请求后,按照sni的信息,对请求进行路由。
- sni为*.v1.nginx.internall.istio的443端口的请求,被转发至nginx.default.svc.cluster.local的v1版本的443端口。
- sni为*.v2.nginx.internal.istio的443端口的请求,被转发至nginx.default.svc.cluster.local的v2版本的443端口。
{
"name": "0.0.0.0_443",
"address": {
"socketAddress": {
"address": "0.0.0.0",
"portValue": 443
}
},
"filterChains": [
{
"filterChainMatch": {
"serverNames": [
"*.v1.nginx.internal.istio"
]
},
…
{
"name": "envoy.tcp_proxy",
"config": {
"cluster": "outbound|443|v1|nginx.default.svc.cluster.local",
"stat_prefix": "outbound|443|v1|nginx.default.svc.cluster.local"
}
}
…
{
"filterChainMatch": {
"serverNames": [
"*.v2.nginx.internal.istio"
]
},
…
{
"name": "envoy.tcp_proxy",
"config": {
"cluster": "outbound|443|v2|nginx.default.svc.cluster.local",
"stat_prefix": "outbound|443|v2|nginx.default.svc.cluster.local"
}
}
- ingress gateway envoy listener相关配置。
- 因为virtualservice类型为tls,所以路由会在listener中直接进行。
- ingress gateway envoy listener的filterchain会将servername为*.v1.nginx.internal.istio的请求全部转发至outbound|443|v1|nginx.default.svc.cluster.local。
- egress gateway envoy listener的filterchain会将servername为*.v2.nginx.internal.istio的请求全部转发至outbound|443|v2|nginx.default.svc.cluster.local。
[~]$ curl https://api.v1.nginx.internal.istio -k
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<h1>nginx01</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>
[~]$
[~]$ curl https://api.v2.nginx.internal.istio -k
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<h1>nginx02</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>
[~]$
- 测试结果。
- 到api.v1.nginx.internal.istio的请求被正确转发至nginx-v1。
- 到api.v2.nginx.internal.istio的请求被正确转发至nginx-v2。