这是关于在 Istio Ambient Mesh 中使用 Open Policy Agent (OPA) 的系列文章的第一篇。系列文章将涵盖如何使用 OPA 作为外部授权服务,建议的部署模式,以及提高可靠性和可扩展性的最佳架构。我们还将讨论使用 OPA 进行资源验证和控制 Istio 功能。
正如我在之前的文章中提到的,我对 Istio Ambient Mesh 感到非常兴奋。这是服务网格的显著进步,我致力于帮助大家理解如何利用 Ambient 来实现目标。我认为目前关于 Ambient 的用例和教程内容还比较少,我希望能帮助填补这个空白。
本文将介绍如何在 Istio Ambient Mesh 中设置 Open Policy Agent (OPA) 作为外部授权服务。授权是任何安全模型的重要组成部分,而 OPA 是实现细粒度访问控制策略的强大工具。通过将 OPA 用作外部授权服务,你可以强制执行比 Istio 内置授权策略更复杂的策略。
OPA 具有插件模型,允许在基础策略引擎之上添加额外功能。虽然这是一个复杂的用例,但幸运的是,OPA 社区已经创建并维护了实现 Envoy 外部授权 API 的 OPA 引擎版本。因此,你无需编写任何自定义代码即可在 Istio Ambient Mesh 中使用 OPA 作为外部授权服务。
在上图中,你可以看到我们集群中的资源架构。我们有三个命名空间:默认的 istio-system
命名空间(Istio 控制平面 istiod 和 ztunnel 代理运行的地方)、安装示例应用的 app
命名空间,以及 OPA 运行的 platform
命名空间。在这个例子中,我们将 OPA 部署为单个 Deployment。在后续文章中,我会介绍如何将 OPA 部署为 DaemonSet。
上图展示了与之前相同的集群,但此时有流量通过系统。在本教程中,我们将发送流量到 app
命名空间中的 Waypoint 代理,该代理会向 platform
命名空间中的 OPA 服务进行授权检查。OPA 服务根据定义的策略返回决策,允许或拒绝请求。如果请求被允许,Waypoint 代理会将请求转发到 app
命名空间中的目标服务,否则将返回 403 Forbidden 响应。
首先,让我们创建集群并使用 Ambient 模式安装 Istio,以及 Kubernetes Gateway API:
# 创建集群
kind create cluster --name istio-opa
# 使用 Ambient 模式安装 Istio
istioctl install --set profile=ambient --skip-confirmation
# 安装 gateway-api CRD
kubectl get crd gateways.gateway.networking.k8s.io &> /dev/null || \
{ kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.1.0/standard-install.yaml; }
接下来,创建 app
命名空间并安装 Istio 的 bookinfo 示例应用及 sleep
Pod,这将帮助我们进行集群内的测试:
# 创建命名空间
kubectl create namespace app
# 安装 bookinfo 示例应用
kubectl apply -n app -f https://raw.githubusercontent.com/istio/istio/release-1.23/samples/bookinfo/platform/kube/bookinfo.yaml
kubectl apply -n app -f https://raw.githubusercontent.com/istio/istio/release-1.23/samples/bookinfo/platform/kube/bookinfo-versions.yaml
# 安装 sleep 应用
kubectl apply -n app -f https://raw.githubusercontent.com/istio/istio/release-1.23/samples/sleep/sleep.yaml
我们还需要创建 Waypoint 代理,作为集群入口网关,并为 app
命名空间配置 Ambient 模式:
# 为 productpage 应用创建网关
kubectl apply -n app -f https://raw.githubusercontent.com/istio/istio/release-1.23/samples/bookinfo/gateway-api/bookinfo-gateway.yaml
istioctl waypoint apply -n app --enroll-namespace --wait
# 为网关添加 ClusterIP 类型
kubectl annotate gateway bookinfo-gateway networking.istio.io/service-type=ClusterIP --namespace=app
# 将命名空间标记为 Ambient 模式
kubectl label namespace app istio.io/dataplane-mode=ambient
接下来,创建 platform
命名空间来运行 OPA 服务:
kubectl create namespace platform
首先,部署 OPA:
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: opa-istio
namespace: platform
spec:
replicas: 1
selector:
matchLabels:
app: opa-istio
template:
metadata:
labels:
app: opa-istio
spec:
containers:
- name: opa-istio
image: openpolicyagent/opa:0.68.0-istio-4-static
ports:
- containerPort: 9191
- containerPort: 8282
- containerPort: 8181
args:
- "run"
- "--server"
- "--addr=0.0.0.0:8181"
- "--config-file=/config/config.yaml"
- "/policy/policy.rego"
volumeMounts:
- name: opa-istio-config
mountPath: /config
- name: opa-policy
mountPath: /policy
EOF
接着,我们需要定义两个 ConfigMap 来配置 OPA:
kubectl apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: opa-istio-config
namespace: platform
data:
config.yaml: |
plugins:
envoy_ext_authz_grpc:
addr: 0.0.0.0:9191
path: istio/authz/allow
decision_logs:
console: true
EOF
kubectl apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: opa-policy
namespace: platform
data:
policy.rego: |
package istio.authz
import input.attributes.request.http as http_request
import input.parsed_path
default allow = false
allow { roles_for_user[r] required_roles[r] }
roles_for_user[r] { r := user_roles[user_name][_] }
required_roles[r] { perm := role_perms[r][_] perm.method = http_request.method perm.path = http_request.path }
user_name = parsed { [_, encoded] := split(http_request.headers.authorization, " ") [parsed, _] := split(base64url.decode(encoded), ":") }
user_roles = { "alice": ["guest"], "bob": ["admin"] }
role_perms = { "guest": [ { "method": "GET", "path": "/productpage" }, ], "admin": [ { "method": "GET", "path": "/productpage" }, { "method": "GET", "path": "/api/v1/products" }, ], }
EOF
最后,为 OPA 创建服务并配置 Istio MeshConfig:
kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
name: opa-istio
namespace: platform
spec:
ports:
- name: grpc
port: 9191
targetPort: 9191
selector:
app: opa-istio
EOF
编辑 Istio MeshConfig
,将 OPA 注册为 extensionProvider
:
apiVersion: v1
kind: ConfigMap
metadata:
name: istio
namespace: istio-system
data:
mesh: |-
extensionProviders:
- name: opa-ext-authz-grpc
envoyExtAuthzGrpc:
service: opa-istio.platform.svc.cluster.local
port: 9191
通过 kubectl port-forward
命令,将 bookinfo-gateway
服务的端口转发到本地:
kubectl port-forward -n app svc/bookinfo-gateway-istio 8080:80
然后,使用 Alice 和 Bob 用户发送请求,验证不同权限的访问控制:
curl --user alice:password -vik http://localhost
:8080/api/v1/products # 应返回 403
curl --user alice:password -vik http://localhost:8080/productpage # 应返回 HTML 响应
curl --user bob:password -vik http://localhost:8080/api/v1/products # 应返回 JSON 响应
curl --user bob:password -vik http://localhost:8080/productpage # 应返回 HTML 响应
最后,应用 Istio 的 AuthorizationPolicy
:
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: ext-authz
namespace: app
spec:
action: CUSTOM
provider:
name: opa-ext-authz-grpc
rules:
- to:
- operation:
paths: ["*"]
EOF
通过上述步骤,你已经成功配置了 OPA 作为 Istio Ambient Mesh 中的外部授权服务。在后续文章中,我们将讨论 OPA 在 Waypoint 代理中的最佳实践。
最后更新于 2024/11/18