Securing Gateways with HTTPS(0.8)

Control Ingress Traffic task描述如何配置一个ingress gateway来为服务的外部流量暴露一个HTTP端口。这个task拓展那个task,使用普通或者相互TLS认证来开启HTTPS访问。

Before you begin

1.执行 Control Ingress Traffic task中的 Before you beginDetermining the ingress IP and ports 小节。完成这几步,你应该部署了Istio、httpbin 服务,设置了环境变量 INGRESS_HOSTSECURE_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_application4_client ,你将用它们来认证服务端和客户端。

Configure a TLS ingress gateway

这节你配置一个用443端口处理HTTPS流量的 ingress gateway。你用一个证书和私钥创建一个secret。然后创建一个包含443端口的 serverGateway 的定义。

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 modeMUTUAL 并指定 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_HOSTSECURE_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.crttls.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

猜你喜欢

转载自blog.csdn.net/Ybt_c_index/article/details/81004860