Istio Ext Authz 外部鉴权服务示例:从协议机制到部署验证的完整实践指南

Istio Ext Authz 外部鉴权服务示例:从协议机制到部署验证的完整实践指南
Istio Ext Authz 外部鉴权服务示例从协议机制到部署验证的完整实践指南【免费下载链接】istioConnect, secure, control, and observe services.项目地址: https://gitcode.com/GitHub_Trending/is/istio导读Istio 内置的授权策略基于源/目标工作负载与属性做判定而当业务需要对接自研的权限系统如 OPA、内部 IAM 或定制的策略引擎时需要借助 Envoy 的 ext_authz 过滤器将鉴权请求外发给独立的外部授权服务。samples/extauthz/README.md 与配套源码提供了一套可直接运行的 Ext Authz 外部鉴权服务器示例同时支持 HTTP 与 gRPC v2/v3 三种协议。本文将以该示例为核心梳理其授权判定模型、部署与验证步骤、本地同 Pod 部署方式、源码级实现细节帮助你在自己的网格中快速搭建并验证一条完整的外部鉴权链路。示例在 Istio 生态中的定位外部鉴权Ext Authz是 Envoy 提供的一种 HTTP/网络级鉴权扩展机制代理在转发请求前把请求的属性来源身份、请求头、路径等打包为 Check 请求发送给外部鉴权服务由外部服务返回 allow/deny 决定并可携带自定义响应头回写。本示例位于 samples/extauthz目录结构如下cmd/extauthz/main.go鉴权服务器核心实现HTTP gRPC v2/v3单二进制同时监听两个端口cmd/extauthz/main_test.go对 HTTP、gRPC v2、gRPC v3 三种 API 的 allow/deny 行为测试ext-authz.yaml在网格中以独立 Pod 部署的 Service/Deployment 清单local-ext-authz.yaml与业务应用容器同 Pod 部署的示例配合 ServiceEntry 使用docker/Dockerfile镜像构建定义。该服务器实现的是 Envoy ext_authz 过滤器Istio 通过AuthorizationPolicy的CUSTOMaction 配合网格extensionProviders配置把外部鉴权服务转换为 Envoy 的 ext_authz 过滤器相关转换逻辑可参见 pilot/pkg/security/authz/builder/extauthz.go所对应的外部服务端 API。它同时暴露三个入口端口协议说明8000HTTP实现基于 HTTP 原始请求的鉴权 Checkext_authz 过滤器以 HTTP 模式调用9000gRPC注册了 v2 与 v3 两个版本的AuthorizationService可验证新旧两种 gRPC 协议授权判定模型示例服务器采用请求头优先、来源身份兜底的简单判定规则便于在集成测试中精确控制 allow/deny 的结果。判定逻辑的核心常量与 flag 定义在 main.goconst ( checkHeader x-ext-authz allowedValue allow ... ) var ( serviceAccount flag.String(allow_service_account, a, allowed service account, matched against the service account in the source principal from the client certificate) httpPort flag.String(http, 8000, HTTP server port) grpcPort flag.String(grpc, 9000, gRPC server port) denyBody fmt.Sprintf(denied by ext_authz for not found header %s: %s in the request, checkHeader, allowedValue) )allow 的判定条件以 gRPC v3 的Check为例main.go若 Check 请求中携带 HTTP 请求头x-ext-authz: allow则直接放行若不存在该请求头则检查请求中attributes.source.principal来源工作负载的 SPIFFE 身份是否以/sa/serviceAccount结尾默认serviceAccount为字符串a可通过启动参数-allow_service_account覆盖——这是为测试准备的默认值其余情况一律拒绝。被拒绝时gRPC 响应携带PermissionDenied状态码与 HTTP 403响应体为固定的denyBody文案见 main.go。说明判定规则刻意保持启发式目的是服务于样例演示与集成测试并非生产级鉴权策略。生产环境请将 ext-authz 作为占位/参考在真实业务中对接权威授权服务。独立 Pod 方式部署与验证1. 部署 Ext Authz 服务在集群中应用 ext-authz.yaml$ kubectl apply -f ext-authz.yaml service/ext-authz created deployment.apps/ext-authz created清单内容要点ext-authz.yaml创建一个名为ext-authz的 Service暴露http: 8000与grpc: 9000两个命名端口selector 匹配app: ext-authzDeployment 运行registry.istio.io/testing/ext-authz:latest镜像生产环境请替换为你自己的镜像仓库与 tagreplicas: 1容器打标sidecar.istio.io/inject: false即该 Pod不注入 sidecar。原因在于外部鉴权服务本身是独立于代理之外的权威决策点不应再由另一个代理进行流量劫持与二次鉴权这也避免了请求被自身 sidecar 的 ext_authz 过滤器递归转发造成死循环。Dockerfiledocker/Dockerfile展示了镜像结构以registry.istio.io/release/base:version为基础镜像把编译好的extauthz二进制放入/usr/local/bin/extauthz并作为入口。除了独立 Pod 部署也可以让 ext-authz 与业务应用容器位于同一 Pod参见下文本地部署小节中的 local-ext-authz.yaml。2. 验证服务器可用先部署一个用于发请求的 sleep Pod$ kubectl apply -f ../sleep/sleep.yaml该文件位于 samples/sleep/sleep.yaml。从 sleep Pod 发起一个带x-ext-authz: allow头的 Check 请求观察 ext-authz 服务器HTTP 8000 端口的处理结果$ kubectl exec -it $(kubectl get pod -l appsleep -o jsonpath{.items..metadata.name}) -c sleep -- curl -v ext-authz:8000 -H x-ext-authz: allow * Trying 10.97.88.183:8000... * Connected to ext-authz-server (10.97.88.183) port 8000 (#0) GET / HTTP/1.1 Host: ext-authz-server:8000 User-Agent: curl/7.73.0-DEV Accept: */* x-ext-authz: allow * Mark bundle as not supporting multiuse HTTP/1.1 200 OK x-ext-authz-result: allowed date: Tue, 03 Nov 2020 03:06:11 GMT content-length: 0 x-envoy-upstream-service-time: 19 server: envoy * Connection #0 to host ext-authz-server left intact当请求携带x-ext-authz: allow时服务器返回200 OK并附带响应头x-ext-authz-result: allowed。再发送一个不带该头、或头值为其他内容的请求$ kubectl exec -it $(kubectl get pod -l appsleep -o jsonpath{.items..metadata.name}) -c sleep -- curl -v ext-authz:8000 -H x-ext-authz: bla GET / HTTP/1.1 Host: ext-authz-server:8000 User-Agent: curl/7.73.0-DEV Accept: */* x-ext-authz: allowx * Mark bundle as not supporting multiuse HTTP/1.1 403 Forbidden x-ext-authz-check-result: denied date: Tue, 03 Nov 2020 03:14:02 GMT content-length: 76 content-type: text/plain; charsetutf-8 x-envoy-upstream-service-time: 44 server: envoy * Connection #0 to host ext-authz-server left intact denied by ext_authz for not found header x-ext-authz: allow in the request请求被拒绝返回403 Forbidden响应体为固定的拒绝说明文案与源码中denyBody的定义完全一致。3. 清理$ kubectl delete -f ../sleep/sleep.yaml $ kubectl delete -f ext-authz.yaml高级调试特性回显与响应头覆盖为了便于验证 Istio/Envoy 侧 ext_authz 过滤器的行为服务器内置了两个针对测试场景设计的响应头特性详见 README.md 的 Advanced features 一节x-ext-authz-check-received服务器会把收到的 Check 请求内容属性/头的 dump作为同名响应头写回。由于该头只出现在 Check 响应中过滤器会把它合并进原始用户请求因此可以用来核对 ext_authz 过滤器究竟发送了什么内容给外部服务器——当过滤器配置的with_request_body、metadata_context_namespaces等选项不符合预期时这是最直接的排障手段。x-ext-authz-additional-header-override该响应头用于验证 ext_authz 过滤器的响应头覆盖header override行为。值取决于服务器类型HTTP 服务器把收到的 Check 请求中同名请求头x-ext-authz-additional-header-override的值原样回写见 main.go 与 main.gogRPC v2/v3 服务器无论请求内容如何固定设置为常量grpc-additional-header-override-value见 main.go。值得注意的工程细节v3 路径在把 attributes dump 写入响应头之前调用了returnIfNotTooLongmain.go。由于 Envoy 可接受的单头最大尺寸约为 60KiB超过 60KB 的内容会被替换为too-long占位符否则过大的响应头会导致 Envoy 拒绝并向上游客户端返回 431。从该实现可以看出对外部鉴权服务的响应头体积进行约束是接入 Envoy 时必须考虑的现实限制。同 Pod 本地部署local-ext-authz 清单解析当外部鉴权服务与应用容器共存于同一 Pod通常配合 sidecar 的本地调用模式时local-ext-authz.yaml 给出了完整示例。由于同 Pod 内通过127.0.0.1通信Istio 无法感知该服务因此需要先用ServiceEntry手工声明apiVersion: networking.istio.io/v1 kind: ServiceEntry metadata: name: httpbin-ext-authz-http spec: hosts: - ext-authz-http.local endpoints: - address: 127.0.0.1 ports: - name: http number: 8000 protocol: HTTP resolution: STATIC同理还有面向 9000 端口、host 为ext-authz-grpc.local、协议为GRPC的第二个 ServiceEntrylocal-ext-authz.yaml。注意两个 ServiceEntry 的endpoints都指向127.0.0.1且resolution: STATIC这样 mesh 内其他工作负载才能通过虚拟 host 访问本地 ext-authz 端点。随后定义 Deploymenthttpbingo-httpbin应用监听 8080与ext-authz监听 8000/9000作为同一 Pod 的两个容器共同调度并配套同名的 Servicelocal-ext-authz.yaml。这与独立 Pod 部署形成对照独立部署时 ext-authz 由 Service 独立暴露同 Pod 部署时 ext-authz 只服务于本 Pod/本机命名空间内的调用更适合延迟敏感或需要紧耦合的测试场景。源码级实现三种 Check API 的内部机制理解实现可以帮你准确判断该示例能测试什么、不能测试什么。进程模型。main()main.go解析 flag 后创建ExtAuthzServer以两个 goroutine 同时启动 HTTP 与 gRPC serverrun并阻塞等待 SIGINT/SIGTERM 优雅退出。NewExtAuthzServermain.go为测试暴露了两个端口 channelhttpPort/grpcPort测试代码可以通过监听 channel 拿到随机分配的端口。HTTP APIServeHTTP。直接把x-ext-authz: allow的判定应用在原始 HTTP 请求上命中则写x-ext-authz-result: allowed头并返回 200未命中则写x-ext-authz-check-result: denied头、写回拒绝文案并返回 403。HTTP 模式下 override 头取自请求头原值上面已述。gRPC v2/v3。v2 与 v3 的Check实现逻辑几乎完全一致分别对应 main.go 与 main.go差异只在于使用的 proto 版本envoy/service/auth/v2vsv3。核心判定复用同一段逻辑attrs : request.GetAttributes() allow : false checkHeaderValue, contains : attrs.GetRequest().GetHttp().GetHeaders()[checkHeader] if contains { allow checkHeaderValue allowedValue } else { allow attrs.Source ! nil strings.HasSuffix(attrs.Source.Principal, /sa/*serviceAccount) }即先从attributes.request.http.headers取x-ext-authz取不到时回退检查attributes.source.principal的来源身份后缀。响应上allow 返回codes.OKdeny 返回codes.PermissionDenied同时携带 HTTP 状态与动态头v3 对 dump 内容做了 60KB 截断保护。测试佐证。main_test.go 中的TestExtAuthz在同一进程内启动随机端口的服务器构造了 6 个用例HTTP-allow/HTTP-deny、GRPCv3-allow/GRPCv3-deny、GRPCv2-allow/GRPCv2-deny分别断言 HTTP 状态码与 gRPC 返回码——这正是上文三种协议行为等价性最直接的单元级证据。此外Istio 的集成测试 tests/integration/security/authz_test.go 中也大量使用x-ext-authz系列头与 ext-authz 服务器配合验证 CUSTOM action 扩展鉴权端到端链路。快速试跑与后续接入方向在本地无需 Kubernetes快速验证三种协议行为可以直接运行单元测试$ go test ./samples/extauthz/cmd/extauthz/...或按 docker/Dockerfile 的流程构建镜像后按上文两种 YAML 方式之一部署。若你希望把该示例真正接入网格流量而不只是验证服务器本身后续需要在 mesh 配置中声明extensionProvidersHTTP 或 gRPC 类型的 ext-authz providerPilot 侧的处理逻辑可参考 pilot/pkg/security/authz/builder/extauthz.go其processExtensionProvider会完成 provider 名称的合法性校验name 非空且唯一定义action: CUSTOM的AuthorizationPolicy把该 provider 挂在目标工作负载上即可让 Envoy 代理在转发前把请求交给本文的 ext-authz 服务器进行判定并通过x-ext-authz-check-received头观察过滤器实际发送的属性内容从而逐步把示例替换为你自己的授权逻辑。以上步骤均基于当前仓库源码可验证的行为不同 Istio 版本对 extensionProviders 的 schema 与字段支持存在差异实际操作前请核对所部署版本的文档与 CRD 定义。小结本文围绕 samples/extauthz 示例完整覆盖了它的授权判定模型x-ext-authz: allow头与-allow_service_account兜底、HTTP/gRPC v2/v3 三协议同构实现、独立 Pod 与同 Pod 两种部署形态、针对 Envoy 排障设计的两个回显/覆盖响应头以及 60KB 响应头限制等工程细节并补充了单元测试与 Pilot 侧 provider 转换源码作为佐证。无论你是要验证自研外部鉴权服务与 Istio 的兼容性还是要为团队搭建 ext_authz 集成的测试脚手架这份示例与源码都提供了可直接复用的起点。【免费下载链接】istioConnect, secure, control, and observe services.项目地址: https://gitcode.com/GitHub_Trending/is/istio创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

最新新闻

日新闻

周新闻

月新闻