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
。
export osm_namespace=osm-system # Replace osm-system with the namespace where OSM will be installed
export osm_mesh_name=osm # Replace osm with the desired OSM mesh name
使用 osm
命令行工具:
osm install --set contour.enabled=true \
--mesh-name "$osm_mesh_name" \
--osm-namespace "$osm_namespace" \
--set contour.configInline.tls.envoy-client-certificate.name=osm-contour-envoy-client-cert \
--set contour.configInline.tls.envoy-client-certificate.namespace="$osm_namespace"
使用 Helm
安装:
helm install "$osm_mesh_name" osm --repo https://openservicemesh.github.io/osm \
--set contour.enabled=true \
--set contour.configInline.tls.envoy-client-certificate.name=osm-contour-envoy-client-cert \
--set contour.configInline.tls.envoy-client-certificate.namespace="$osm_namespace"
为了将后端的入口流量限制到授权客户端,我们将设置 IngressBackend 配置,以便只有来自 osm-contour-envoy
service 端点的入口流量,才能访问到对应的服务后端。为了能够发现 osm-contour-envoy
service 的端点,我们需要 OSM 控制器来监控相应的命名空间。 然而,为了 Contour 正常运行,其必须不能注入 Envoy sidecar。
kubectl label namespace "$osm_namespace" openservicemesh.io/monitored-by="$osm_mesh_name"
保存入口网关的外部 IP 地址和端口,后面会用其测试访问后端应用。
export ingress_host="$(kubectl -n "$osm_namespace" get service osm-contour-envoy -o jsonpath='{.status.loadBalancer.ingress[0].ip}')"
export ingress_port="$(kubectl -n "$osm_namespace" get service osm-contour-envoy -o jsonpath='{.spec.ports[?(@.name=="http")].port}')"
接下来,我们将部署 httpbin
的 示例 service 。
# Create a namespace
kubectl create ns httpbin
# Add the namespace to the mesh
osm namespace add httpbin
# Deploy the application
kubectl apply -f https://raw.githubusercontent.com/openservicemesh/osm-docs/release-v1.2/manifests/samples/httpbin/httpbin.yaml -n httpbin
确认 httpbin
service 和 pod 启动并运行。
$ kubectl get pods -n httpbin
NAME READY STATUS RESTARTS AGE
httpbin-74677b7df7-zzlm2 2/2 Running 0 11h
$ kubectl get svc -n httpbin
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpbin ClusterIP 10.0.22.196 <none> 14001/TCP 11h
HTTP Ingress
下一步,我们将创建对应的 Ingress 和 IngressBackend 配置,来允许外部的客户端访问位于 httpbin
命名空间下 ,运行在 14001
端口上的 httpbin
service 。由于我们没有使用 TLS,Contour 入口网关到 httpbin
后端 pod 的连接是没有进行加密。
kubectl apply -f - <<EOF
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
name: httpbin
namespace: httpbin
spec:
virtualhost:
fqdn: httpbin.org
routes:
- services:
- name: httpbin
port: 14001
---
kind: IngressBackend
apiVersion: policy.openservicemesh.io/v1alpha1
metadata:
name: httpbin
namespace: httpbin
spec:
backends:
- name: httpbin
port:
number: 14001 # targetPort of httpbin service
protocol: http
sources:
- kind: Service
namespace: "$osm_namespace"
name: osm-contour-envoy
EOF
现在,我们预期外部客户端可以访问 httpbin
service ,HTTP 请求的 HOST
请求头为 httpbin.org
:
$ curl -sI http://"$ingress_host":"$ingress_port"/get -H "Host: httpbin.org"
HTTP/1.1 200 OK
server: envoy
date: Fri, 06 Aug 2021 17:39:43 GMT
content-type: application/json
content-length: 314
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 3
vary: Accept-Encoding
HTTPS 入口 (mTLS 和 TLS)
如果要将使用 HTTPS 的连接代理到 TLS 后端,后端服务必须要使用下面的方式将端口写入注解中:
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 控制平面的命名空间。
应用配置:
kubectl apply -f - <<EOF
apiVersion: projectcontour.io/v1
kind: TLSCertificateDelegation
metadata:
name: ca-secret
namespace: "$osm_namespace"
spec:
delegations:
- secretName: osm-ca-bundle
targetNamespaces:
- httpbin
---
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
name: httpbin
namespace: httpbin
spec:
virtualhost:
fqdn: httpbin.org
routes:
- services:
- name: httpbin
port: 14001
validation:
caSecret: "$osm_namespace/osm-ca-bundle"
# subjectName for a service is of the form <service-account>.<namespace>.cluster.local
# where the service account and namespace is that of the pod backing the service
subjectName: httpbin.httpbin.cluster.local
---
kind: IngressBackend
apiVersion: policy.openservicemesh.io/v1alpha1
metadata:
name: httpbin
namespace: httpbin
spec:
backends:
- name: httpbin
port:
number: 14001 # targetPort of httpbin service
protocol: https
tls:
skipClientCertValidation: false # mTLS (defaults to false)
sources:
- kind: Service
namespace: "$osm_namespace"
name: osm-contour-envoy
- kind: AuthenticatedPrincipal
name: "osm-contour-envoy.$osm_namespace.cluster.local"
EOF
这时,我们预期外部的客户端可以访问 httpbin
service ,在入口网关和后端服务之间通过 mTLS 进行 HTTPS 代理,发送 HTTP 请求的 Host:
请求头为 httpbin.org
:
$ curl -sI http://"$ingress_host":"$ingress_port"/get -H "Host: httpbin.org"
HTTP/1.1 200 OK
server: envoy
date: Fri, 06 Aug 2021 17:39:43 GMT
content-type: application/json
content-length: 314
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 3
vary: Accept-Encoding
为了验证未经授权的客户端是无权访问后端,我们可以更新 IngressBackend 配置中 sources
指定的内容。改成与入口网关中编码的 SAN 不同的内容:
kubectl apply -f - <<EOF
kind: IngressBackend
apiVersion: policy.openservicemesh.io/v1alpha1
metadata:
name: httpbin
namespace: httpbin
spec:
backends:
- name: httpbin
port:
number: 14001 # targetPort of httpbin service
protocol: https
tls:
skipClientCertValidation: false # mTLS (defaults to false)
sources:
- kind: Service
namespace: "$osm_namespace"
name: osm-contour-envoy
- kind: AuthenticatedPrincipal
name: "untrusted-client.cluster.local"
EOF
确认请求被拒绝并收到 HTTP 403 Forbidden
响应:
$ curl -sI http://"$ingress_host":"$ingress_port"/get -H "Host: httpbin.org"
HTTP/1.1 403 Forbidden
content-length: 19
content-type: text/plain
date: Fri, 06 Aug 2021 18:40:45 GMT
server: envoy
x-envoy-upstream-service-time: 8
接下来,我们通过更新 IngressBackend 配置 skipClientCertValidation: true
来演示对服务后端禁用客户端证书验证的支持,同时仍使用不受信任的客户端:
kubectl apply -f - <<EOF
kind: IngressBackend
apiVersion: policy.openservicemesh.io/v1alpha1
metadata:
name: httpbin
namespace: httpbin
spec:
backends:
- name: httpbin
port:
number: 14001 # targetPort of httpbin service
protocol: https
tls:
skipClientCertValidation: true
sources:
- kind: Service
namespace: "$osm_namespace"
name: osm-contour-envoy
- kind: AuthenticatedPrincipal
name: "untrusted-client.cluster.local"
EOF
由于未经信任的已验证用户被允许连接后端服务,确认请求再次访问成功
$ curl -sI http://"$ingress_host":"$ingress_port"/get -H "Host: httpbin.org"
HTTP/1.1 200 OK
server: envoy
date: Fri, 06 Aug 2021 18:51:47 GMT
content-type: application/json
content-length: 314
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 4
vary: Accept-Encoding