OSM 可以选择使用 Contour 入口控制器和基于 Envoy 的边缘代理来路由外部的流量到服务网格后端。这个指南将会演示如何为 OSM 服务网格管理的 service 配置 HTTP 和 HTTPS ingress。

先决条件

  • Kubernetes 集群运版本 v1.22.9 或者更高。
  • 使用 kubectl 与 API server 交互。
  • 未安装 OSM。如果已安装必须先删除。
  • 已安装 osm 或者 Helm 3 命令行工具,用于安装 OSM 和 Contour。
  • OSM 版本 >= v0.10.0。

演示

首先,在 osm-system 命名空间下安装 OSM 和 Contour,并将网格命名为 osm

  1. export osm_namespace=osm-system # Replace osm-system with the namespace where OSM will be installed
  2. export osm_mesh_name=osm # Replace osm with the desired OSM mesh name

使用 osm 命令行工具:

  1. osm install --set contour.enabled=true \
  2. --mesh-name "$osm_mesh_name" \
  3. --osm-namespace "$osm_namespace" \
  4. --set contour.configInline.tls.envoy-client-certificate.name=osm-contour-envoy-client-cert \
  5. --set contour.configInline.tls.envoy-client-certificate.namespace="$osm_namespace"

使用 Helm 安装:

  1. helm install "$osm_mesh_name" osm --repo https://openservicemesh.github.io/osm \
  2. --set contour.enabled=true \
  3. --set contour.configInline.tls.envoy-client-certificate.name=osm-contour-envoy-client-cert \
  4. --set contour.configInline.tls.envoy-client-certificate.namespace="$osm_namespace"

为了将后端的入口流量限制到授权客户端,我们将设置 IngressBackend 配置,以便只有来自 osm-contour-envoy service 端点的入口流量,才能访问到对应的服务后端。为了能够发现 osm-contour-envoy service 的端点,我们需要 OSM 控制器来监控相应的命名空间。 然而,为了 Contour 正常运行,其必须不能注入 Envoy sidecar。

  1. kubectl label namespace "$osm_namespace" openservicemesh.io/monitored-by="$osm_mesh_name"

保存入口网关的外部 IP 地址和端口,后面会用其测试访问后端应用。

  1. export ingress_host="$(kubectl -n "$osm_namespace" get service osm-contour-envoy -o jsonpath='{.status.loadBalancer.ingress[0].ip}')"
  2. export ingress_port="$(kubectl -n "$osm_namespace" get service osm-contour-envoy -o jsonpath='{.spec.ports[?(@.name=="http")].port}')"

接下来,我们将部署 httpbin 的 示例 service 。

  1. # Create a namespace
  2. kubectl create ns httpbin
  3. # Add the namespace to the mesh
  4. osm namespace add httpbin
  5. # Deploy the application
  6. kubectl apply -f https://raw.githubusercontent.com/openservicemesh/osm-docs/release-v1.2/manifests/samples/httpbin/httpbin.yaml -n httpbin

确认 httpbin service 和 pod 启动并运行。

  1. $ kubectl get pods -n httpbin
  2. NAME READY STATUS RESTARTS AGE
  3. httpbin-74677b7df7-zzlm2 2/2 Running 0 11h
  4. $ kubectl get svc -n httpbin
  5. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  6. httpbin ClusterIP 10.0.22.196 <none> 14001/TCP 11h

HTTP Ingress

下一步,我们将创建对应的 Ingress 和 IngressBackend 配置,来允许外部的客户端访问位于 httpbin 命名空间下 ,运行在 14001 端口上的 httpbin service 。由于我们没有使用 TLS,Contour 入口网关到 httpbin 后端 pod 的连接是没有进行加密。

  1. kubectl apply -f - <<EOF
  2. apiVersion: projectcontour.io/v1
  3. kind: HTTPProxy
  4. metadata:
  5. name: httpbin
  6. namespace: httpbin
  7. spec:
  8. virtualhost:
  9. fqdn: httpbin.org
  10. routes:
  11. - services:
  12. - name: httpbin
  13. port: 14001
  14. ---
  15. kind: IngressBackend
  16. apiVersion: policy.openservicemesh.io/v1alpha1
  17. metadata:
  18. name: httpbin
  19. namespace: httpbin
  20. spec:
  21. backends:
  22. - name: httpbin
  23. port:
  24. number: 14001 # targetPort of httpbin service
  25. protocol: http
  26. sources:
  27. - kind: Service
  28. namespace: "$osm_namespace"
  29. name: osm-contour-envoy
  30. EOF

现在,我们预期外部客户端可以访问 httpbin service ,HTTP 请求的 HOST 请求头为 httpbin.org

  1. $ curl -sI http://"$ingress_host":"$ingress_port"/get -H "Host: httpbin.org"
  2. HTTP/1.1 200 OK
  3. server: envoy
  4. date: Fri, 06 Aug 2021 17:39:43 GMT
  5. content-type: application/json
  6. content-length: 314
  7. access-control-allow-origin: *
  8. access-control-allow-credentials: true
  9. x-envoy-upstream-service-time: 3
  10. vary: Accept-Encoding

HTTPS 入口 (mTLS 和 TLS)

如果要将使用 HTTPS 的连接代理到 TLS 后端,后端服务必须要使用下面的方式将端口写入注解中:

  1. kubectl annotate service httpbin -n httpbin projectcontour.io/upstream-protocol.tls='14001' --overwrite

然后,我们需要创建 HTTPProxy 配置来使用 TLS 代理后端服务,同时提供 CA 证书对后端服务的服务器证书进行校验。为此,当在 httpbin 命名空间的 HTTPProxy 配置引用的时候,我们首先需要委托 Contour 访问 OSM 命名空间下 OSM CA 证书 secret 的权限。参考上游 TLS 了解上游证书校验的更多信息以及何时需要证书委托。此外,我们还要创建一个 IngressBackend 资源来说明路由到 httpbin service 的流量只能来自可信客户端,即我们部署的入口边缘代理中的 osm-contur-envoy。OSM 在安装时自动为 osm-contour-envoy 入口网关配置带有主题备用名称(Subject Alternative Name,SAN)为 osm-contour-envoy.$osm_namespace.cluster.local 的客户端证书,因此 IngressBackend 配置为 osm-contour-envoy 边缘与 httpbin 后端之间的 mTLS 认证需要引用同样的 SAN。

注意:<osm-namespace> 指安装 osm 控制平面的命名空间。

应用配置:

  1. kubectl apply -f - <<EOF
  2. apiVersion: projectcontour.io/v1
  3. kind: TLSCertificateDelegation
  4. metadata:
  5. name: ca-secret
  6. namespace: "$osm_namespace"
  7. spec:
  8. delegations:
  9. - secretName: osm-ca-bundle
  10. targetNamespaces:
  11. - httpbin
  12. ---
  13. apiVersion: projectcontour.io/v1
  14. kind: HTTPProxy
  15. metadata:
  16. name: httpbin
  17. namespace: httpbin
  18. spec:
  19. virtualhost:
  20. fqdn: httpbin.org
  21. routes:
  22. - services:
  23. - name: httpbin
  24. port: 14001
  25. validation:
  26. caSecret: "$osm_namespace/osm-ca-bundle"
  27. # subjectName for a service is of the form <service-account>.<namespace>.cluster.local
  28. # where the service account and namespace is that of the pod backing the service
  29. subjectName: httpbin.httpbin.cluster.local
  30. ---
  31. kind: IngressBackend
  32. apiVersion: policy.openservicemesh.io/v1alpha1
  33. metadata:
  34. name: httpbin
  35. namespace: httpbin
  36. spec:
  37. backends:
  38. - name: httpbin
  39. port:
  40. number: 14001 # targetPort of httpbin service
  41. protocol: https
  42. tls:
  43. skipClientCertValidation: false # mTLS (defaults to false)
  44. sources:
  45. - kind: Service
  46. namespace: "$osm_namespace"
  47. name: osm-contour-envoy
  48. - kind: AuthenticatedPrincipal
  49. name: "osm-contour-envoy.$osm_namespace.cluster.local"
  50. EOF

这时,我们预期外部的客户端可以访问 httpbin service ,在入口网关和后端服务之间通过 mTLS 进行 HTTPS 代理,发送 HTTP 请求的 Host: 请求头为 httpbin.org

  1. $ curl -sI http://"$ingress_host":"$ingress_port"/get -H "Host: httpbin.org"
  2. HTTP/1.1 200 OK
  3. server: envoy
  4. date: Fri, 06 Aug 2021 17:39:43 GMT
  5. content-type: application/json
  6. content-length: 314
  7. access-control-allow-origin: *
  8. access-control-allow-credentials: true
  9. x-envoy-upstream-service-time: 3
  10. vary: Accept-Encoding

为了验证未经授权的客户端是无权访问后端,我们可以更新 IngressBackend 配置中 sources 指定的内容。改成与入口网关中编码的 SAN 不同的内容:

  1. kubectl apply -f - <<EOF
  2. kind: IngressBackend
  3. apiVersion: policy.openservicemesh.io/v1alpha1
  4. metadata:
  5. name: httpbin
  6. namespace: httpbin
  7. spec:
  8. backends:
  9. - name: httpbin
  10. port:
  11. number: 14001 # targetPort of httpbin service
  12. protocol: https
  13. tls:
  14. skipClientCertValidation: false # mTLS (defaults to false)
  15. sources:
  16. - kind: Service
  17. namespace: "$osm_namespace"
  18. name: osm-contour-envoy
  19. - kind: AuthenticatedPrincipal
  20. name: "untrusted-client.cluster.local"
  21. EOF

确认请求被拒绝并收到 HTTP 403 Forbidden 响应:

  1. $ curl -sI http://"$ingress_host":"$ingress_port"/get -H "Host: httpbin.org"
  2. HTTP/1.1 403 Forbidden
  3. content-length: 19
  4. content-type: text/plain
  5. date: Fri, 06 Aug 2021 18:40:45 GMT
  6. server: envoy
  7. x-envoy-upstream-service-time: 8

接下来,我们通过更新 IngressBackend 配置 skipClientCertValidation: true 来演示对服务后端禁用客户端证书验证的支持,同时仍使用不受信任的客户端:

  1. kubectl apply -f - <<EOF
  2. kind: IngressBackend
  3. apiVersion: policy.openservicemesh.io/v1alpha1
  4. metadata:
  5. name: httpbin
  6. namespace: httpbin
  7. spec:
  8. backends:
  9. - name: httpbin
  10. port:
  11. number: 14001 # targetPort of httpbin service
  12. protocol: https
  13. tls:
  14. skipClientCertValidation: true
  15. sources:
  16. - kind: Service
  17. namespace: "$osm_namespace"
  18. name: osm-contour-envoy
  19. - kind: AuthenticatedPrincipal
  20. name: "untrusted-client.cluster.local"
  21. EOF

由于未经信任的已验证用户被允许连接后端服务,确认请求再次访问成功

  1. $ curl -sI http://"$ingress_host":"$ingress_port"/get -H "Host: httpbin.org"
  2. HTTP/1.1 200 OK
  3. server: envoy
  4. date: Fri, 06 Aug 2021 18:51:47 GMT
  5. content-type: application/json
  6. content-length: 314
  7. access-control-allow-origin: *
  8. access-control-allow-credentials: true
  9. x-envoy-upstream-service-time: 4
  10. vary: Accept-Encoding