Control Ingress Traffic task描述如何配置一个ingress gateway来为服务的外部流量暴露一个HTTP端口。这个task拓展那个task,使用普通或者相互TLS认证来开启HTTPS访问。
Before you begin
1.执行 Control Ingress Traffic task中的 Before you begin 和 Determining the ingress IP and ports 小节。完成这几步,你应该部署了Istio、httpbin 服务,设置了环境变量 INGRESS_HOST
和 SECURE_INGRESS_PORT
。
2.对于mac系统用户,确保你使用 LibreSSL 库编译的 curl :
curl --version | grep LibreSSL
curl 7.54.0 (x86_64-apple-darwin17.0) libcurl/7.54.0 LibreSSL/2.0.20 zlib/1.2.11 nghttp2/1.24.0
如果 LibreSSL 的版本如上输出那样,你的 curl 应该能在这个task中正确的执行指令。否则,尝试安装其他 curl ,比如在一台Linux机器上。
Generate client and server certificates and keys
这个task你可以使用你最喜欢的工具去生成证书和密钥。我们使用 https://github.com/nicholasjackson/mtls-go-example 库的一个脚本。
1.克隆库:
git clone https://github.com/nicholasjackson/mtls-go-example
2.切换克隆库的目录:
cd mtls-go-example
3.生成证书(使用任何密码):
generate.sh httpbin.example.com <password>
这个命令会生成四个目录: 1_root
, 2_intermediate
, 3_application
和 4_client
,你将用它们来认证服务端和客户端。
Configure a TLS ingress gateway
这节你配置一个用443端口处理HTTPS流量的 ingress gateway。你用一个证书和私钥创建一个secret。然后创建一个包含443端口的 server
的 Gateway
的定义。
1.创建一个k8s Secret
持有服务端的证书和私钥。使用 kubectl
在命名空间 istio-system
创建secret istio-ingressgateway-certs
。Istio gateway将会自动加载secret。
secret必须在命名空间
istio-system
中命名为istio-ingressgateway-certs
,否则将不会被Istio gateway安装和使用。
kubectl create -n istio-system secret tls istio-ingressgateway-certs --key 3_application/private/httpbin.example.com.key.pem --cert 3_application/certs/httpbin.example.com.cert.pem
secret “istio-ingressgateway-certs” created
注意:默认命名空间 istio-system
的所有服务账户都可以访问这个secret,因此私钥可能被泄漏。你可以改变 Role-Based Access Control (RBAC) 规则来保护它。
2.定义一个 server
部分端口为443的 Gateway
。
证书和私钥的位置必须为 /etc/istio/ingressgateway-certs, 否则gateway无法加载。
cat <<EOF | istioctl create -f -
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
3.配置通过 Gateway
进入流量的路由。定义和 Control Ingress Traffic task 中相同的 VirtualService
:
cat <<EOF | istioctl create -f -
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
4.通过使用 curl 到 SECURE_INGRESS_PORT
发送一个 https
请求来通过HTTPS访问httpbin 服务。
--resolve
flag 用来指导 curl 在通过TLS访问gateway IP时提供SNI值 “httpbin.example.com” 。 --cacert
选项指示 curl 使用你生成的证书来验证服务端。
通过发送请求到 /status/418
URL路径,你会得到一个很棒的视觉效果来保证你的 httpbin 服务的确被访问到了。 httpbin 服务将会返回 418 I’m a Teapot code.
curl -v --resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST --cacert 2_intermediate/certs/ca-chain.cert.pem https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418
...
Server certificate:
subject: C=US; ST=Denial; L=Springfield; O=Dis; CN=httpbin.example.com
start date: Jun 24 18:45:18 2018 GMT
expire date: Jul 4 18:45:18 2019 GMT
common name: httpbin.example.com (matched)
issuer: C=US; ST=Denial; O=Dis; CN=httpbin.example.com
SSL certificate verify ok.
...
HTTP/2 418
...
-=[ teapot ]=-
_...._
.' _ _ `.
| ."` ^ `". _,
\_;`"---"`|//
| ;/
\_ _/
`"""`
注意:gateway定义可能需要一段时间传播,你可能会收到如下错误: Failed to connect to httpbin.example.com port <your secure port>: Connection refused
. 等几分钟再使用curl调用。
观察 Server certificate 部分 curl 的输出,注意到匹配 common name 的那行: common name: httpbin.example.com (matched)
. 根据curl输出的 SSL certificate verify ok
这行,你能确定服务端验证成功。注意返回的418状态以及一个非常棒的茶壶画像。
如果你需要支持 mutual TLS ,继续进行下节。
Configure a mutual TLS ingress gateway
这节你将扩展你上节的gateway定义来支持外部客户和gateway之间的 mutual TLS .
1.对于Istio 0.8.0,重新部署一个带有服务端用来验证它的客户端 CA 证书的 volume 的 istio-ingressgateway
。
kubectl apply -f <(helm template install/kubernetes/helm/istio --name istio --namespace istio-system -x charts/ingressgateway/templates/deployment.yaml --set ingressgateway.deployment.secretVolumes[0].name=ingressgateway-certs,ingressgateway.deployment.secretVolumes[0].secretName=istio-ingressgateway-certs,ingressgateway.deployment.secretVolumes[0].mountPath=/etc/istio/ingressgateway-certs,ingressgateway.deployment.secretVolumes[1].name=ingressgateway-ca-certs,ingressgateway.deployment.secretVolumes[1].secretName=istio-ingressgateway-ca-certs,ingressgateway.deployment.secretVolumes[1].mountPath=/etc/istio/ingressgateway-ca-certs)
deployment “istio-ingressgateway” configured
2.创建一个k8s Secret
来持有 CA 证书,在命名空间istio-system
命名为 istio-ingressgateway-ca-certs
。Istio gateway将自动加载secret。
secret必须在命名空间
istio-system
中命名为istio-ingressgateway-certs
,否则将不会被Istio gateway安装和使用。
kubectl create -n istio-system secret generic istio-ingressgateway-ca-certs --from-file=2_intermediate/certs/ca-chain.cert.pem
secret “istio-ingressgateway-ca-certs” created
3.重定义你之前的Gateway
,并更改 tls mode
到 MUTUAL
并指定 caCertificates
:
证书和私钥的位置必须为
/etc/istio/ingressgateway-certs
, 否则gateway无法加载。证书的名字必须和你创建secret的文件名相同,这里是ca-chain.cert.pem
.
cat <<EOF | istioctl replace -f -
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/ca-chain.cert.pem
hosts:
- "httpbin.example.com"
EOF
4.像上一节那样通过HTTPS访问httpbin 服务:
curl --resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST --cacert 2_intermediate/certs/ca-chain.cert.pem https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418
curl: (35) error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure
getaway定义需要时间传播,你可能还会得到418.等几分钟再试curl调用。
这次你得到了错误信息,因为服务端拒绝接受未认证的请求。你不得不发送客户端证书,通过curl你的私钥来签署请求。
5.通过curl再次发送上一个请求,这次作为参数传递你的客户端证书(--cert
选项)和私钥(--key
选项)
curl --resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST --cacert 2_intermediate/certs/ca-chain.cert.pem --cert 4_client/certs/httpbin.example.com.cert.pem --key 4_client/private/httpbin.example.com.key.pem https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418
-=[ teapot ]=-
_...._
.' _ _ `.
| ."` ^ `". _,
\_;`"---"`|//
| ;/
\_ _/
`"""`
这次服务端成功认证客户端,你也再次受到漂亮的茶壶画。
Troubleshooting
1.检查环境变量 INGRESS_HOST
和 SECURE_INGRESS_PORT
的值。确保它们值有效,通过命令输出:
kubectl get svc -n istio-system
echo INGRESS_HOST=$INGRESS_HOST, SECURE_INGRESS_PORT=$SECURE_INGRESS_PORT
2.验证key和证书在 istio-ingressgateway
pod中成功装载:
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-certs
tls.crt
和 tls.key
应该存在于目录内容中。
3.检查 istio-ingressgateway
日志的错误信息:
kubectl logs -n istio-system -l istio=ingressgateway
4.对于相互TLS认证,确认CA证书在 istio-ingressgateway
pod中成功装载:
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-ca-certs
ca-chain.cert.pem
应该存在于目录内容中。
5.对于mac系统用户,确保你使用 LibreSSL 库编译的 curl ,如 Before you begin 小节中描述的那样。
Cleanup
1.删除 Gateway
配置, VirtualService
及secrets:
istioctl delete gateway httpbin-gateway
istioctl delete virtualservice httpbin
kubectl delete --ignore-not-found=true -n istio-system secret istio-ingressgateway-certs istio-ingressgateway-ca-certs
2.关闭 httpbin 服务:
kubectl delete --ignore-not-found=true -f samples/httpbin/httpbin.yaml