译者 | 李睿
审校 | 孙淑娟
API网关在公开微服务时,起着至关重要的作用。它们是网络中的一个附加跃点,传入请求必须通过该跃点才能与服务通信。API网关在收到来自客户端的请求之后会执行路由、组合、协议转换和用户策略实施,然后将其反向代理到适当的底层API。由于API网关能够执行上述任务,它们还可以配置为将传入的客户端请求发送到外部第三方授权(authz)服务器。然后,传入请求的命运取决于这一外部身份验证服务器对网关的响应。这正是开放策略代理(OPA)发挥作用的地方。
有许多开源的Kubernetes原生API网关,例如Contour、Kong Gateway、Traefik、Gloo等。以下深入了解一下Emissary Ingress。
什么是Emissary Ingress?
Emissary Ingress早期被称为Ambassar API网关;它是一个开源的Kubernetes原生API网关,目前是云原生应用计算基金会(CNCF)孵化项目。与许多其他Kubernetes网关一样,Emissary也被构建为与Envoy代理一起使用。它部署为完整的无状态架构,并支持多个插件,例如传统的SSO身份验证协议(例如OAuth、OpenIDConnect)、速率限制、日志记录和跟踪服务。Emissary在AuthService资源中利用其ExtAuth协议来配置传入请求的身份验证和授权。ExtAuth支持两种协议:gRPC和HTTP。对于gRPC接口,外部服务必须实现Envoy的external_auth.proto。
OPA
Open Policy Agent(OPA)是一个众所周知的通用策略引擎,并已成为跨堆栈的策略执行器,无论是API网关、服务网格、Kubernetes、微服务、CI/CD还是IAC。OPA将决策制定与策略执行分离,这样每当软件需要对传入请求做出决定时,它都会查询OPA。OPA-Envoy使用实现Envoy外部授权API的gRPC服务器扩展OPA,从而使其自身与Emissary的外部authz服务器兼容。
将Emissary Ingress与OPA集成
上图展示了Emissary和OPA集成的高层架构。当来自客户端的传入请求到达Emissary时,它会向OPA发送授权请求,其中包含输入JSON。OPA根据提供给它的Rego策略评估这个JSON并响应Emissary;如果来自OPA的这个结果JSON允许为真,那么只有客户端请求被进一步路由到API,否则请求被Emissary拒绝并且永远不会到达API。将安装Emissary Ingress并将其与OPA集成以进行外部授权。
(1)入门
首先,需要启动一个Minikube集群。如果没有Minikube,可以从这里安装它。
minikube start
- 1.
通过Helm将Emissary Ingress安装到minikube。
# Add the Repo:
helm repo add datawire https://app.getambassador.io
helm repo update
# Create Namespace and Install:
kubectl create namespace emissary && \
kubectl apply -f https://app.getambassador.io/yaml/emissary/2.2.2/emissary-crds.yaml
kubectl wait --timeout=90s --for=condition=available deployment emissary-apiext -n emissary-system
helm install emissary-ingress --namespace emissary datawire/emissary-ingress && \
kubectl -n emissary wait --for condition=available --timeout=90s deploy -lapp.kubernetes.io/instance=emissary-ingress
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
或者参考Emissary Ingress文档通过Kubernetes YAMLs安装它。
(2)为演示应用程序配置路由
不同的网关有自己的一组用于公开服务的配置。在Emissary中,需要通过映射和侦听器配置路由。
映射资源只是告诉Emissary将传入请求重定向到哪个服务。它像Ingress一样高度可配置。将创建一个简单的映射资源,它将所有传入请求重定向到演示应用程序的服务,即demo-svc。
cat <<EOF | kubectl apply -f -
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
name: demo-app-mapping
spec:
hostname: "*"
prefix: /
service: demo-svc
EOF
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
侦听器资源指示Emissary在网络上侦听传入请求。在这里,将创建一个侦听器来侦听端口8080和HTTP协议,并与所有命名空间中的主机关联。
cat <<EOF | kubectl apply -f -
apiVersion: getambassador.io/v3alpha1
kind: Listener
metadata:
name: demo-app-listener-8080
namespace: emissary
spec:
port: 8080
protocol: HTTP
securityModel: XFP
hostBinding:
namespace:
from: ALL
EOF
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
(3)安装echo应用程序
安装一个简单的echo服务器作为演示应用程序。
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-app
spec:
replicas: 1
selector:
matchLabels:
app: demo-app
template:
metadata:
labels:
app: demo-app
spec:
containers:
- name: http-svc
image: gcr.io/google_containers/echoserver:1.8
ports:
- containerPort: 8080
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
---
apiVersion: v1
kind: Service
metadata:
name: demo-svc
labels:
app: demo-app
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
selector:
app: demo-app
EOF
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
通过不同的路径与演示应用程序通信。
minikube service emissary-ingress -n emissary
- 1.
注意:上述公开方法可能不适用于macOS用户。他们可以使用一个忙框,并将其配置为命中Emissary本地端点。
使用目标端口80复制专用URL。URL必须为IP 192.168.49.2,后跟一个节点端口,如http://192.168.49.2:30329。将NodePort值导出为$NodePort环境变量,并将curl导出为路径处的值,如下所示:
curl http://192.168.49.2:$NODEPORT/public
curl http://192.168.49.2:$NODEPORT/secured
- 1.
- 2.
OPA尚未添加到设置中,并且上述curl请求直接发送到API,而无需任何策略强制。
(4)如何安装和配置OPA?
OPA将通过configmap读取提供给它的策略。创建以下configmap,其中包含一个策略,该策略只允许通过GET方法接收所有传入请求。
cat <<EOF | kubectl apply -n emissary -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: demo-policy
data:
policy.rego: |-
package envoy.authz
default allow = false
allow {
input.attributes.request.http.method == "GET"
}
EOF
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
通过将OPA部署为独立部署或作为emissary-ingress的sidecar,可以将OPA配置为外部授权服务器。在这里,将其添加为sidecar。将以下YAML保存为opa-patch.yaml。
spec:
template:
spec:
containers:
- name: opa
image: openpolicyagent/opa:latest-envoy
ports:
- containerPort: 9191
args:
- "run"
- "--server"
- "--addr=0.0.0.0:8181"
- "--set=plugins.envoy_ext_authz_grpc.addr=0.0.0.0:9191"
- "--set=plugins.envoy_ext_authz_grpc.query=data.envoy.authz.allow"
- "--set=decision_logs.console=true"
- "--ignore=.*"
- "/policy/policy.rego"
volumeMounts:
- mountPath: /policy
name: demo-policy
readOnly: true
volumes:
- name: demo-policy
configMap:
name: demo-policy
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
修补 emissary-ingress 部署并等待所有 emissary-ingress pod 重新启动。
kubectl patch deployment emissary-ingress -n emissary --patch-file opa-patch.yaml
- 1.
等到所有的emissary-ingresspod进入带有OPA sidecar的运行状态。
创建以下AuthService。AuthService是一种资源,它配置Emissary与外部服务进行通信,以获取传入请求的Authn和Authz。将其配置为与localhost上的OPA通信,因为OPA被部署为sidecar。
cat <<EOF | kubectl apply -f -
apiVersion: getambassador.io/v3alpha1
kind: AuthService
metadata:
name: opa-ext-authservice
namespace: emissary
labels:
product: aes
app: opa-ext-auth
spec:
proto: grpc
auth_service: localhost:9191
timeout_ms: 5000
tls: "false"
allow_request_body: true
protocol_version: v2
include_body:
max_bytes: 8192
allow_partial: true
status_on_error:
code: 504
failure_mode_allow: false
EOF
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
现在尝试curl;由于该策略接受来自GET方法的请求并且对路径没有限制,因此两个请求都将获得200个OK响应。
curl -i http://192.168.49.2:$NODEPORT/public
curl -i http://192.168.49.2:$NODEPORT/private
- 1.
- 2.
现在编辑策略以仅接受来自路径 /public 的传入请求,而对任何其他路径的请求都将被拒绝。
cat <<EOF | kubectl apply -n emissary -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: demo-policy
data:
policy.rego: |-
package envoy.authz
default allow = false
allow {
input.attributes.request.http.method == "GET"
input.attributes.request.http.path == "/public"
}
EOF
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
现在重新启动使者入口部署以使策略更改生效。
kubectl rollout restart deployment emissary-ingress -n emissary
- 1.
等到所有的Emissary-Ingresspod在重启后进入Running状态。
现在在路径/public处执行curl请求;它将被接受,但在路径/privat,e它将被OPA拒绝并返回403响应,因此请求不会到达演示API。
curl-ihttp://192.168.49.2:$NODEPORT/public
curl-ihttp://192.168.49.2:$NODEPORT/private
- 1.
- 2.
关于从客户端到公开API的传入请求的决策可以解耦到OPA作为Emissary Ingress设置中的外部授权服务器。OPA可以作为即插即用策略执行器添加到Emissary和任何其他支持Envoy外部授权API的网关。
原文标题:How Do You Integrate Emissary Ingress With OPA,作者:Tayyab Jamadar