本指南将演示如何在使用 Kubernetes Nginx 入口控制器 时将 HTTP 和 HTTPS 入口配置到 OSM 托管服务网格的部分服务。
先决条件
- Kubernetes 集群运行版本 v1.22.9 或者更高。
- 使用
kubectl
与 API server 交互。 - 已安装的 OSM 版本不低于 v0.10.0。
- 已安装
osm
命令行工具,用于管理服务网格。
演示
首先,明确有关 OSM 和 Nginx 入口控制器的安装细节:
osm_namespace=osm-system # Replace osm-system with the namespace where OSM is installed
osm_mesh_name=osm # replace osm with the mesh name (use `osm mesh list` command)
nginx_ingress_namespace=<nginx-namespace> # replace <nginx-namespace> with the namespace where Nginx is installed
nginx_ingress_service=<nginx-ingress-controller-service> # replace <nginx-ingress-controller-service> with the name of the nginx ingress controller service
nginx_ingress_host="$(kubectl -n "$nginx_ingress_namespace" get service "$nginx_ingress_service" -o jsonpath='{.status.loadBalancer.ingress[0].ip}')"
nginx_ingress_port="$(kubectl -n "$nginx_ingress_namespace" get service "$nginx_ingress_service" -o jsonpath='{.spec.ports[?(@.name=="http")].port}')"
为了将后端的入口流量限制到授权客户端,我们将设置 IngressBackend 配置,以便只有来自 Nginx 入口控制器 service 的流量,才能访问到对应的服务后端。为了能够发现该 service 的端点,我们需要 OSM 控制器来监控相应的命名空间。 然而,为了 Nginx 正常运行,其必须不能注入 Envoy sidecar。
osm namespace add "$nginx_ingress_namespace" --mesh-name "$osm_mesh_name" --disable-sidecar-injection
接下来,我们将部署 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 和 IngressBackend 配置,来允许外部的客户端访问位于 httpbin
命名空间下 ,运行在 14001
端口上的 httpbin
service 。由于我们没有使用 TLS,Nginx 入口 service 到 httpbin
后端 pod 的连接是没有进行加密。
kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: httpbin
namespace: httpbin
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: httpbin
port:
number: 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: "$nginx_ingress_namespace"
name: "$nginx_ingress_service"
EOF
现在,我们预期外部的客户端可以通过 HTTP 的方式访问 httpbin
service :
$ curl -sI http://"$nginx_ingress_host":"$nginx_ingress_port"/get
HTTP/1.1 200 OK
Date: Wed, 18 Aug 2021 18:12:35 GMT
Content-Type: application/json
Content-Length: 366
Connection: keep-alive
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 2
HTTPS 出口 (mTLS 和 TLS)
为了将连接代理到 HTTPS 后端,我们将在 Ingress 和 IngressBackend 配置中指定使用 https
作为后端协议,同时由 OSM 颁发证书,Nginx 将使用该证书作为客户端证书,来将 HTTPS 连接代理到 TLS 后端。客户端证书和 CA 证书将保存在 Kubernetes secret 中,Nginx 将使用该证书来认证服务网格后端。
为了给 Nginx 入口 service 颁发一个客户端证书,需要更新 osm-mesh-config
MeshConfig
资源。
kubectl edit meshconfig osm-mesh-config -n "$osm_namespace"
在 spec.certificate
下添加字段 ingressGateway
:
certificate:
ingressGateway:
secret:
name: osm-nginx-client-cert
namespace: <osm-namespace> # replace <osm-namespace> with the namespace where OSM is installed
subjectAltNames:
- ingress-nginx.ingress-nginx.cluster.local
validityDuration: 24h
注意:主体备用名称(Subject Alternative Name,SAN)使用类似
<service-account>.<namespace>.cluster.local
格式,sevice account 和 namespace 为 Nginx service 对应的信息。
接下来,我们需要创建一个 Ingress 和 IngressBackend 配置以使用 TLS 代理到后端服务,同时通过 mTLS 启用到后端的代理。为此,我们必须创建一个 IngressBackend 资源,指定指向 httpbin
service 的 HTTPS 入口流量只能接受来自受信任客户端的流量。OSM 使用 主体备用名称(Subject Alternative Name,SAN)ingress-nginx.ingress-nginx.cluster.local
为 Nginx 入口 service 提供了一个客户端证书,因此 IngressBackend 配置需要引用相同的 SAN 用于 Nginx 入口 service 和 httpbin
后端之间的 mTLS 身份验证。
应用配置:
kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: httpbin
namespace: httpbin
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
# proxy_ssl_name for a service is of the form <service-account>.<namespace>.cluster.local
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_ssl_name "httpbin.httpbin.cluster.local";
nginx.ingress.kubernetes.io/proxy-ssl-secret: "osm-system/osm-nginx-client-cert"
nginx.ingress.kubernetes.io/proxy-ssl-verify: "on"
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: httpbin
port:
number: 14001
---
apiVersion: policy.openservicemesh.io/v1alpha1
kind: IngressBackend
metadata:
name: httpbin
namespace: httpbin
spec:
backends:
- name: httpbin
port:
number: 14001 # targetPort of httpbin service
protocol: https
tls:
skipClientCertValidation: false
sources:
- kind: Service
name: "$nginx_ingress_service"
namespace: "$nginx_ingress_namespace"
- kind: AuthenticatedPrincipal
name: ingress-nginx.ingress-nginx.cluster.local
EOF
现在,我们预期外部客户端能够通过入口网关和服务后端之间的 mTLS 上的 HTTPS 代理访问 httpbin
service 。
$ curl -sI http://"$nginx_ingress_host":"$nginx_ingress_port"/get
HTTP/1.1 200 OK
Date: Wed, 18 Aug 2021 18:12:35 GMT
Content-Type: application/json
Content-Length: 366
Connection: keep-alive
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 2
为了验证未经授权的客户端是无权访问后端,我们可以更新 IngressBackend 配置中 sources
指定的内容。让我们将主题更新为 Nginx 客户端证书中编码的 SAN 以外的其他内容。
kubectl apply -f - <<EOF
apiVersion: policy.openservicemesh.io/v1alpha1
kind: IngressBackend
metadata:
name: httpbin
namespace: httpbin
spec:
backends:
- name: httpbin
port:
number: 14001 # targetPort of httpbin service
protocol: https
tls:
skipClientCertValidation: false
sources:
- kind: Service
name: "$nginx_ingress_service"
namespace: "$nginx_ingress_namespace"
- kind: AuthenticatedPrincipal
name: untrusted-client.cluster.local # untrusted
EOF
确认请求被拒绝并收到 HTTP 403 Forbidden
响应:
$ curl -sI http://"$nginx_ingress_host":"$nginx_ingress_port"/get
HTTP/1.1 403 Forbidden
Date: Wed, 18 Aug 2021 18:36:09 GMT
Content-Type: text/plain
Content-Length: 19
Connection: keep-alive
接下来,我们通过更新 IngressBackend 配置 skipClientCertValidation: true
来演示对在服务后端禁用客户端证书验证的支持,同时仍使用不受信任的客户端:
kubectl apply -f - <<EOF
apiVersion: policy.openservicemesh.io/v1alpha1
kind: IngressBackend
metadata:
name: httpbin
namespace: httpbin
spec:
backends:
- name: httpbin
port:
number: 14001 # targetPort of httpbin service
protocol: https
tls:
skipClientCertValidation: true
sources:
- kind: Service
name: "$nginx_ingress_service"
namespace: "$nginx_ingress_namespace"
- kind: AuthenticatedPrincipal
name: untrusted-client.cluster.local # untrusted
EOF
由于未经信任的已验证用户被允许连接后端服务,确认请求再次访问成功
$ curl -sI http://"$nginx_ingress_host":"$nginx_ingress_port"/get
HTTP/1.1 200 OK
Date: Wed, 18 Aug 2021 18:36:49 GMT
Content-Type: application/json
Content-Length: 364
Connection: keep-alive
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 2