feat: Add ext-auth plugin support for authentication blacklists/whitelists (#1694)

This commit is contained in:
韩贤涛
2025-01-21 14:28:49 +08:00
committed by GitHub
parent cfa3baddf8
commit 0259eaddbb
14 changed files with 1126 additions and 425 deletions

View File

@@ -16,70 +16,114 @@ description: Ext 认证插件实现了调用外部授权服务进行认证鉴权
## 配置字段
| 名称 | 数据类型 | 必填 | 默认值 | 描述 |
| ------------------------------- | -------- | ---- | ------ |------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `http_service` | object | 是 | - | 外部授权服务配置 |
| `failure_mode_allow` | bool | 否 | false | 当设置为 true 时,即使与授权服务的通信失败,或者授权服务返回了 HTTP 5xx 错误,仍会接受客户端请求 |
| `failure_mode_allow_header_add` | bool | 否 | false | 当 `failure_mode_allow``failure_mode_allow_header_add` 都设置为 true 时,若与授权服务的通信失败,或授权服务返回了 HTTP 5xx 错误,那么请求头中将会添加 `x-envoy-auth-failure-mode-allowed: true` |
| `status_on_error` | int | 否 | 403 | 当授权服务无法访问或状态码为 5xx 时,设置返回给客户端的 HTTP 状态码。默认状态码是 `403` |
| 名称 | 数据类型 | 必填 | 默认值 | 描述 |
| ------------------------------- | ------------------ | ---- | ------ | ------------------------------------------------------------ |
| `http_service` | object | 是 | - | 外部授权服务配置 |
| `match_type` | string | 否 | | 可选 `whitelist``blacklist` |
| `match_list` | array of MatchRule | 否 | | 一个包含 (`match_rule_domain`, `match_rule_path`, `match_rule_type`) 的列表 |
| `failure_mode_allow` | bool | 否 | false | 当设置为 true 时,即使与授权服务的通信失败,或者授权服务返回了 HTTP 5xx 错误,仍会接受客户端请求 |
| `failure_mode_allow_header_add` | bool | 否 | false | 当 `failure_mode_allow``failure_mode_allow_header_add` 都设置为 true 时,若与授权服务的通信失败,或授权服务返回了 HTTP 5xx 错误,那么请求头中将会添加 `x-envoy-auth-failure-mode-allowed: true` |
| `status_on_error` | int | 否 | 403 | 当授权服务无法访问或状态码为 5xx 时,设置返回给客户端的 HTTP 状态码。默认状态码是 `403` |
`http_service`中每一项的配置字段说明
`http_service` 中每一项的配置字段说明
| 名称 | 数据类型 | 必填 | 默认值 | 描述 |
| ------------------------ | -------- | ---- | ------ | ------------------------------------- |
| `endpoint_mode` | string | 否 | envoy | `envoy` , `forward_auth` 中选填一项 |
|--------------------------|----------|------|--------|---------------------------------------|
| `endpoint_mode` | string | 否 | envoy | 可选 `envoy` `forward_auth` |
| `endpoint` | object | 是 | - | 发送鉴权请求的 HTTP 服务信息 |
| `timeout` | int | 否 | 1000 | `ext-auth` 服务连接超时时间,单位毫秒 |
| `authorization_request` | object | 否 | - | 发送鉴权请求配置 |
| `authorization_response` | object | 否 | - | 处理鉴权响应配置 |
| `authorization_response` | object | 否 | - | 处理鉴权响应配置 |
`endpoint`中每一项的配置字段说明
`endpoint` 中每一项的配置字段说明
| 名称 | 数据类型 | 必填 | 默认值 | 描述 |
| -------- | -------- | -- | ------ | ----------------------------------------------------------------------------------------- |
| `service_name` | string | 必填 | - | 输入授权服务名称,带服务类型的完整 FQDN 名称,例如 `ext-auth.dns``ext-auth.my-ns.svc.cluster.local` |
| `service_port` | int | 否 | 80 | 输入授权服务的服务端口 |
| `service_host` | string | 否 | - | 请求授权服务时设置的Host头不填时和FQDN保持一致 |
| `path_prefix` | string | `endpoint_mode``envoy`时必填 | | `endpoint_mode``envoy` 时,客户端向授权服务发送请求的请求路径前缀 |
| `request_method` | string | 否 | GET | `endpoint_mode``forward_auth`客户端向授权服务发送请求的HTTP Method |
| `path` | string | `endpoint_mode``forward_auth`时必填 | - | `endpoint_mode``forward_auth` 时,客户端向授权服务发送请求的请求路径 |
| 名称 | 数据类型 | 必填 | 默认值 | 描述 |
|------------------|----------|----------------------------------------|--------|--------------------------------------------------------------|
| `service_name` | string | | - | 输入授权服务名称,带服务类型的完整 FQDN 名称,例如 `ext-auth.dns``ext-auth.my-ns.svc.cluster.local` |
| `service_port` | int | 否 | 80 | 输入授权服务的服务端口 |
| `service_host` | string | 否 | - | 请求授权服务时设置的 Host 头,不填时和 FQDN 保持一致 |
| `path_prefix` | string | `endpoint_mode` `envoy` 时必填 | - | `endpoint_mode` `envoy` 时,客户端向授权服务发送请求的请求路径前缀 |
| `request_method` | string | 否 | GET | `endpoint_mode` `forward_auth` 时,客户端向授权服务发送请求的 HTTP Method |
| `path` | string | `endpoint_mode` `forward_auth` 时必填 | - | `endpoint_mode` `forward_auth` 时,客户端向授权服务发送请求的请求路径 |
`authorization_request`中每一项的配置字段说明
`authorization_request` 中每一项的配置字段说明
| 名称 | 数据类型 | 必填 | 默认值 | 描述 |
| ------------------------ | ---------------------- | ---- | ------ |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `allowed_headers` | array of StringMatcher | 否 | - | 设置后,具有相应匹配项的客户端请求头将添加到授权服务请求中的请求头中。除了用户自定义的头部匹配规则外,授权服务请求中会自动包含 `Authorization` 这个HTTP头 `endpoint_mode``forward_auth` 时,会把原始请求的请求路径设置到 `X-Original-Uri` 原始请求的HTTP Method设置到 `X-Original-Method` |
| `headers_to_add` | `map[string]string` | 否 | - | 设置将包含在授权服务请求中的请求头列表。请注意,同名的客户端请求头将被覆盖 |
| `with_request_body` | bool | 否 | false | 缓冲客户端请求体并将其发送至鉴权请求中HTTP Method为GET、OPTIONS、HEAD请求时不生效 |
| `max_request_body_bytes` | int | 否 | 10MB | 设置在内存中保存客户端请求体的最大尺寸。当客户端请求体达到在此字段中设置的数值时将会返回HTTP 413状态码并且不会启动授权过程。注意这个设置会优先于 `failure_mode_allow` 的配置 |
| 名称 | 数据类型 | 必填 | 默认值 | 描述 |
|--------------------------|------------------------|------|--------|--------------------------------------------------------------|
| `allowed_headers` | array of StringMatcher | 否 | - | 设置后,匹配项的客户端请求头将添加到授权服务请求中的请求头中。除了用户自定义的头部匹配规则外,授权服务请求中会自动包含 `Authorization` 这个HTTP头`endpoint_mode``forward_auth` 时,会添加 `X-Forwarded-*` 的请求头 |
| `headers_to_add` | map[string]string | 否 | - | 设置将包含在授权服务请求中的请求头列表。请注意,同名的客户端请求头将被覆盖 |
| `with_request_body` | bool | 否 | false | 缓冲客户端请求体并将其发送至鉴权请求中HTTP Method为GET、OPTIONS、HEAD请求时不生效 |
| `max_request_body_bytes` | int | 否 | 10MB | 设置在内存中保存客户端请求体的最大尺寸。当客户端请求体达到在此字段中设置的数值时将会返回HTTP 413状态码并且不会启动授权过程。注意这个设置会优先于 `failure_mode_allow` 的配置 |
`authorization_response`中每一项的配置字段说明
`authorization_response` 中每一项的配置字段说明
| 名称 | 数据类型 | 必填 | 默认值 | 描述 |
| -------------------------- | ---------------------- | ---- | ------ |---------------------------------------------------------------------------------|
| `allowed_upstream_headers` | array of StringMatcher | 否 | - | 当设置后,具有相应匹配项的鉴权请求的响应头将添加到原始的客户端请求头中。请注意,同名的请求头将被覆盖 |
| `allowed_client_headers` | array of StringMatcher | 否 | - | 如果不设置,在请求被拒绝时,所有的鉴权请求的响应头将添加到客户端的响应头中。当设置后,在请求被拒绝时,具有相应匹配项的鉴权请求的响应头将添加到客户端的响应头中 |
| 名称 | 数据类型 | 必填 | 默认值 | 描述 |
|----------------------------|------------------------|------|--------|--------------------------------------------------------------|
| `allowed_upstream_headers` | array of StringMatcher | 否 | - | 匹配项的鉴权请求的响应头将添加到原始的客户端请求头中。请注意,同名的请求头将被覆盖 |
| `allowed_client_headers` | array of StringMatcher | 否 | - | 如果不设置,在请求被拒绝时,所有的鉴权请求的响应头将添加到客户端的响应头中。当设置后,在请求被拒绝时,匹配项的鉴权请求的响应头将添加到客户端的响应头中 |
`StringMatcher`类型每一项的配置字段说明,在使用`array of StringMatcher`时会按照数组中定义的StringMatcher顺序依次进行配置
`StringMatcher` 类型每一项的配置字段说明,在使用 `array of StringMatcher` 时会按照数组中定义的 StringMatcher 顺序依次进行配置
| 名称 | 数据类型 | 必填 | 默认值 | 描述 |
| ---------- | -------- | ------------------------------------------------------------ | ------ | -------- |
|------------|----------|-------------------------------------------------------------|--------|----------|
| `exact` | string | 否,`exact` , `prefix` , `suffix`, `contains`, `regex` 中选填一项 | - | 精确匹配 |
| `prefix` | string | 否,`exact` , `prefix` , `suffix`, `contains`, `regex` 中选填一项 | - | 前缀匹配 |
| `suffix` | string | 否,`exact` , `prefix` , `suffix`, `contains`, `regex` 中选填一项 | - | 后缀匹配 |
| `contains` | string | 否,`exact` , `prefix` , `suffix`, `contains`, `regex` 中选填一项 | - | 是否包含 |
| `regex` | string | 否,`exact` , `prefix` , `suffix`, `contains`, `regex` 中选填一项 | - | 正则匹配 |
MatchRule 类型每一项的配置字段说明,在使用 `array of MatchRule` 时会按照数组中定义的 MatchRule 顺序依次进行配置
| 名称 | 数据类型 | 必填 | 默认值 | 描述 |
| ------------------- | -------- | ---- | ------ | ------------------------------------------------------------ |
| `match_rule_domain` | string | 否 | - | 匹配规则域名,支持通配符模式,例如 `*.bar.com` |
| `match_rule_path` | string | 否 | - | 匹配请求路径的规则 |
| `match_rule_type` | string | 否 | - | 匹配请求路径的规则类型,可选 `exact` , `prefix` , `suffix`, `contains`, `regex` |
### 两种 `endpoint_mode` 的区别
`endpoint_mode``envoy` 时,鉴权请求会使用原始请求的 HTTP Method和配置的 `path_prefix` 作为请求路径前缀拼接上原始的请求路径
`endpoint_mode``forward_auth` 时,鉴权请求会使用配置的 `request_method` 作为 HTTP Method和配置的 `path` 作为请求路径,并且 Higress 会自动生成并发送以下 header 至鉴权服务:
| Header | 说明 |
| -------------------- | ------------------------------------------------------ |
| `x-forwarded-proto` | 原始请求的scheme比如 http/https |
| `x-forwarded-method` | 原始请求的方法,比如 get/post/delete/patch |
| `x-forwarded-host` | 原始请求的host |
| `x-forwarded-uri` | 原始请求的path包含路径参数比如 `/v1/app?test=true` |
### 黑白名单模式
支持黑白名单模式配置,默认为白名单模式,白名单为空,即所有请求都需要经过验证,匹配域名支持泛域名例如 `*.bar.com` ,匹配规则支持 `exact` , `prefix` , `suffix`, `contains`, `regex`
**白名单模式**
```yaml
match_type: 'whitelist'
match_list:
- match_rule_domain: '*.bar.com'
match_rule_path: '/foo'
match_rule_type: 'prefix'
```
泛域名 `*.bar.com` 下前缀匹配 `/foo` 的请求无需验证
**黑名单模式**
```yaml
match_type: 'blacklist'
match_list:
- match_rule_domain: '*.bar.com'
match_rule_path: '/headers'
match_rule_type: 'prefix'
```
只有泛域名 `*.bar.com` 下前缀匹配 `/header` 的请求需要验证
## 配置示例
下面假设 `ext-auth` 服务在KubernetesserviceName为 `ext-auth`,端口 `8090`,路径为 `/auth`,命名空间为 `backend`
支持两种 `endpoint_mode`
- `endpoint_mode``envoy`鉴权请求会使用原始请求的HTTP Method和配置的 `path_prefix` 作为请求路径前缀拼接上原始的请求路径
- `endpoint_mode``forward_auth` 时,鉴权请求会使用配置的 `request_method` 作为HTTP Method和配置的 `path` 作为请求路径
下面假设 `ext-auth` 服务在 KubernetesserviceName `ext-auth`,端口 `8090`,路径为 `/auth`,命名空间为 `backend`
### endpoint_mode为envoy时
@@ -198,7 +242,7 @@ http_service:
使用如下请求网关,当开启 `ext-auth` 插件后:
```shell
curl -i http://localhost:8082/users?apikey=9a342114-ba8a-11ec-b1bf-00163e1250b5 -X GET -H "foo: bar" -H "Authorization: xxx"
curl -i http://localhost:8082/users?apikey=9a342114-ba8a-11ec-b1bf-00163e1250b5 -X GET -H "foo: bar" -H "Authorization: xxx" -H "Host: foo.bar.com"
```
**请求 `ext-auth` 服务成功:**
@@ -209,8 +253,10 @@ curl -i http://localhost:8082/users?apikey=9a342114-ba8a-11ec-b1bf-00163e1250b5
POST /auth HTTP/1.1
Host: ext-auth.backend.svc.cluster.local
Authorization: xxx
X-Original-Uri: /users?apikey=9a342114-ba8a-11ec-b1bf-00163e1250b5
X-Original-Method: GET
X-Forwarded-Proto: HTTP
X-Forwarded-Host: foo.bar.com
X-Forwarded-Uri: /users?apikey=9a342114-ba8a-11ec-b1bf-00163e1250b5
X-Forwarded-Method: GET
Content-Length: 0
```
@@ -261,7 +307,7 @@ http_service:
使用如下请求网关,当开启 `ext-auth` 插件后:
```shell
curl -i http://localhost:8082/users?apikey=9a342114-ba8a-11ec-b1bf-00163e1250b5 -X GET -H "foo: bar" -H "Authorization: xxx" -H "X-Auth-Version: 1.0"
curl -i http://localhost:8082/users?apikey=9a342114-ba8a-11ec-b1bf-00163e1250b5 -X GET -H "foo: bar" -H "Authorization: xxx" -H "X-Auth-Version: 1.0" -H "Host: foo.bar.com"
```
`ext-auth` 服务将接收到如下的鉴权请求:
@@ -270,22 +316,13 @@ curl -i http://localhost:8082/users?apikey=9a342114-ba8a-11ec-b1bf-00163e1250b5
POST /auth HTTP/1.1
Host: my-domain.local
Authorization: xxx
X-Original-Uri: /users?apikey=9a342114-ba8a-11ec-b1bf-00163e1250b5
X-Original-Method: GET
X-Forwarded-Proto: HTTP
X-Forwarded-Host: foo.bar.com
X-Forwarded-Uri: /users?apikey=9a342114-ba8a-11ec-b1bf-00163e1250b5
X-Forwarded-Method: GET
X-Auth-Version: 1.0
x-envoy-header: true
Content-Length: 0
```
`ext-auth` 服务返回响应头中如果包含 `x-user-id``x-auth-version`网关调用upstream时的请求中会带上这两个请求头
#### x-forwarded-* header
在endpoint_mode为forward_auth时higress会自动生成并发送以下header至鉴权服务。
| Header | 说明 |
|--------------------|-------------------------------------|
| x-forwarded-proto | 原始请求的scheme比如http/https |
| x-forwarded-method | 原始请求的方法比如get/post/delete/patch |
| x-forwarded-host | 原始请求的host |
| x-forwarded-uri | 原始请求的path包含路径参数比如/v1/app?test=true |
| x-forwarded-for | 原始请求的客户端IP地址 |
`ext-auth` 服务返回响应头中如果包含 `x-user-id``x-auth-version`网关调用upstream时的请求中会带上这两个请求头