istio-ingress网关安全-为 Gateway 提供 HTTPS 加密支持
为服务器和客户端生成证书
可以使用各种常用工具来生成证书和私钥。这个例子中用了一个来自 https://github.com/nicholasjackson/mtls-go-example 的脚本来完成工作。
1、克隆示例代码库:
git clone https://github.com/nicholasjackson/mtls-go-example
2、进入代码库文件夹
pushd mtls-go-example
3、为 httpbin.example.com 生成证书。注意要把下面命令中的 password 替换为其它值。
./generate.sh httpbin.example.com <password>
看到提示后,所有问题都输入 Y 即可。这个命令会生成四个目录:1_root、2_intermediate、3_application 以及 4_client。这些目录中包含了后续过程所需的客户端和服务端证书。
4、把证书移动到 httpbin.example.com 目录之中:
mkdir ../httpbin.example.com && mv 1_root 2_intermediate 3_application 4_client ../httpbin.example.com
为单一主机配置 TLS Ingress Gateway
1、启动 httpbin 样例:
cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Service metadata: name: httpbin labels: app: httpbin spec: ports: - name: http port: 8000 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: containers: - image: docker.io/citizenstig/httpbin imagePullPolicy: IfNotPresent name: httpbin ports: - containerPort: 8000 EOF
2、为 Ingress Gateway 创建 Secret:
kubectl create -n istio-system secret generic httpbin-credential \ --from-file=key=httpbin.example.com/3_application/private/httpbin.example.com.key.pem \ --from-file=cert=httpbin.example.com/3_application/certs/httpbin.example.com.cert.pem
secret name 不能 以 istio 或者 prometheus为开头, 且 secret 不能 包含 token 字段。
3、创建一个 Gateway ,其 servers: 字段的端口为 443,设置 credentialName 的值为 httpbin-credential。这个值就是 Secret 的名字。TLS 模式设置为 SIMPLE。
cat <<EOF | kubectl apply -f - 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: SIMPLE credentialName: "httpbin-credential" # must be the same as secret hosts: - "httpbin.example.com" EOF
4、配置 Gateway 的 Ingress 流量路由,并配置对应的 VirtualService:
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: httpbin spec: hosts: - "httpbin.example.com" gateways: - mygateway http: - match: - uri: prefix: /status - uri: prefix: /delay route: - destination: port: number: 8000 host: httpbin EOF
5、用 HTTPS 协议访问 httpbin 服务:
curl -v -HHost:httpbin.example.com \ --resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST \ --cacert httpbin.example.com/2_intermediate/certs/ca-chain.cert.pem \ https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418
httpbin 服务会返回 418 I’m a Teapot。
6、删除 Gateway 的 Secret,并新建另外一个,然后修改 Ingress Gateway 的凭据:
kubectl -n istio-system delete secret httpbin-credential pushd mtls-go-example ./generate.sh httpbin.example.com <password> mkdir ../httpbin.new.example.com && mv 1_root 2_intermediate 3_application 4_client ../httpbin.new.example.com kubectl create -n istio-system secret generic httpbin-credential \ --from-file=key=httpbin.new.example.com/3_application/private/httpbin.example.com.key.pem \ --from-file=cert=httpbin.new.example.com/3_application/certs/httpbin.example.com.cert.pem
7、使用 curl 访问 httpbin 服务:
curl -v -HHost:httpbin.example.com \ --resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST \ --cacert httpbin.new.example.com/2_intermediate/certs/ca-chain.cert.pem \ https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418 ... HTTP/2 418 ... -=[ teapot ]=- _...._ .' _ _ `. | ."` ^ `". _, \_;`"---"`|// | ;/ \_ _/ `"""`
8、如果尝试使用之前的证书链来再次访问 httpbin,就会得到失败的结果:
curl -v -HHost:httpbin.example.com \ --resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST \ --cacert httpbin.example.com/2_intermediate/certs/ca-chain.cert.pem \ https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418 ... * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (OUT), TLS alert, Server hello (2): * SSL certificate problem: unable to get local issuer certificate
为 TLS Ingress Gateway 配置多个主机名
可以把多个主机名配置到同一个 Ingress Gateway 上,例如 httpbin.example.com 和 helloworld-v1.example.com。Ingress Gateway 会为每个 credentialName 获取一个唯一的凭据。
1、要恢复 “httpbin” 的凭据,请删除对应的 secret 并重新创建。
kubectl -n istio-system delete secret httpbin-credential kubectl create -n istio-system secret generic httpbin-credential \ --from-file=key=httpbin.example.com/3_application/private/httpbin.example.com.key.pem \ --from-file=cert=httpbin.example.com/3_application/certs/httpbin.example.com.cert.pem
2、启动 hellowworld-v1 示例:
cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Service metadata: name: helloworld-v1 labels: app: helloworld-v1 spec: ports: - name: http port: 5000 selector: app: helloworld-v1 --- apiVersion: apps/v1 kind: Deployment metadata: name: helloworld-v1 spec: replicas: 1 selector: matchLabels: app: helloworld-v1 version: v1 template: metadata: labels: app: helloworld-v1 version: v1 spec: containers: - name: helloworld image: istio/examples-helloworld-v1 resources: requests: cpu: "100m" imagePullPolicy: IfNotPresent #Always ports: - containerPort: 5000 EOF
3、为 Ingress Gateway 创建一个 Secret。如果已经创建了 httpbin-credential,就可以创建 helloworld-credential Secret 了。
./generate.sh helloworld-v1.example.com <password> mkdir ../helloworld-v1.example.com && mv 1_root 2_intermediate 3_application 4_client ../helloworld-v1.example.com kubectl create -n istio-system secret generic helloworld-credential \ --from-file=key=helloworld-v1.example.com/3_application/private/helloworld-v1.example.com.key.pem \ --from-file=cert=helloworld-v1.example.com/3_application/certs/helloworld-v1.example.com.cert.pem
4、定义一个 Gateway ,其中包含了两个 server,都开放了 443 端口。两个 credentialName 字段分别赋值为 httpbin-credential 和 helloworld-credential。设置 TLS 的 mode 为 SIMPLE 。
cat <<EOF | kubectl apply -f - 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-httpbin protocol: HTTPS tls: mode: SIMPLE credentialName: "httpbin-credential" hosts: - "httpbin.example.com" - port: number: 443 name: https-helloworld protocol: HTTPS tls: mode: SIMPLE credentialName: "helloworld-credential" hosts: - "helloworld-v1.example.com" EOF
5、配置 Gateway 的流量路由,配置 VirtualService:
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: helloworld-v1 spec: hosts: - "helloworld-v1.example.com" gateways: - mygateway http: - match: - uri: exact: /hello route: - destination: host: helloworld-v1 port: number: 5000 EOF
6、向 helloworld-v1.example.com 发送 HTTPS 请求:
curl -v -HHost:helloworld-v1.example.com \ --resolve helloworld-v1.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST \ --cacert helloworld-v1.example.com/2_intermediate/certs/ca-chain.cert.pem \ https://helloworld-v1.example.com:$SECURE_INGRESS_PORT/hello HTTP/2 200
7、发送 HTTPS 请求到 httpbin.example.com,还是会看到茶壶:
curl -v -HHost:httpbin.example.com \ --resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST \ --cacert httpbin.example.com/2_intermediate/certs/ca-chain.cert.pem \ https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418 -=[ teapot ]=- _...._ .' _ _ `. | ."` ^ `". _, \_;`"---"`|// | ;/ \_ _/ `"""`
配置双向 TLS Ingress Gateway
可以对 Gateway 的定义进行扩展,加入双向 TLS 的支持。要修改 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=key=httpbin.example.com/3_application/private/httpbin.example.com.key.pem \ --from-file=cert=httpbin.example.com/3_application/certs/httpbin.example.com.cert.pem \ --from-file=cacert=httpbin.example.com/2_intermediate/certs/ca-chain.cert.pem
1、修改 Gateway 定义,设置 TLS 的模式为 MUTUAL:
cat <<EOF | kubectl apply -f - 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: MUTUAL credentialName: "httpbin-credential" # must be the same as secret hosts: - "httpbin.example.com" EOF
2、使用前面的方式尝试发出 HTTPS 请求,会看到失败的过程:
curl -v -HHost:httpbin.example.com \ --resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST \ --cacert httpbin.example.com/2_intermediate/certs/ca-chain.cert.pem \ https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418 * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8): * TLSv1.3 (IN), TLS handshake, Request CERT (13): * TLSv1.3 (IN), TLS handshake, Certificate (11): * TLSv1.3 (IN), TLS handshake, CERT verify (15): * TLSv1.3 (IN), TLS handshake, Finished (20): * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.3 (OUT), TLS handshake, Certificate (11): * TLSv1.3 (OUT), TLS handshake, Finished (20): * TLSv1.3 (IN), TLS alert, unknown (628): * OpenSSL SSL_read: error:1409445C:SSL routines:ssl3_read_bytes:tlsv13 alert certificate required, errno 0
3、在 curl 命令中加入客户端证书和私钥的参数,重新发送请求。(客户端证书参数为 --cert,私钥参数为 --key)
curl -v -HHost:httpbin.example.com \ --resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST \ --cacert httpbin.example.com/2_intermediate/certs/ca-chain.cert.pem \ --cert httpbin.example.com/4_client/certs/httpbin.example.com.cert.pem \ --key httpbin.example.com/4_client/private/httpbin.example.com.key.pem \ https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418 -=[ teapot ]=- _...._ .' _ _ `. | ."` ^ `". _, \_;`"---"`|// | ;/ \_ _/
4、
如果不想用 httpbin-credential secret 来存储所有的凭据, 可以创建两个单独的 secret :
httpbin-credential用来存储服务器的秘钥和证书httpbin-credential-cacert用来存储客户端的 CA 证书且一定要有-cacert后缀
使用以下命令创建两个单独的 secret :
kubectl -n istio-system delete secret httpbin-credential kubectl create -n istio-system secret generic httpbin-credential \ --from-file=key=httpbin.example.com/3_application/private/httpbin.example.com.key.pem \ --from-file=cert=httpbin.example.com/3_application/certs/httpbin.example.com.cert.pem kubectl create -n istio-system secret generic httpbin-credential-cacert \ --from-file=cacert=httpbin.example.com/2_intermediate/certs/ca-chain.cert.pem
参考:
https://preliminary.istio.io/latest/zh/docs/tasks/traffic-management/ingress/secure-ingress-sds/

浙公网安备 33010602011771号