安全认证
4 分钟阅读
简要概述
TODO;
证书验证
https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/transport_socket/transport_socket
配合上游使用
在 config.cluster.v3.Cluster 中的 transport_socket
配置使用,支持以下类型:
名称 | 类型 |
---|---|
envoy.transport_sockets.tls | extensions.transport_sockets.tls.v3.UpstreamTlsContext |
如在 clusters[_].transport_socket
中配置使用 “/tmp/http-ca.crt” 作为 ca 验证上游服务端:
static_resources:
......
clusters:
- name: oneops-syncds-v1
type: STATIC
......
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
# 通用 tls 配置,则不做校验仅做通讯加密
common_tls_context:
# 这说明需使用 "/tmp/http-ca.crt" 去验证上游集群
validation_context:
trusted_ca:
filename: /tmp/http-ca.crt
配合下游使用
在 config.listener.v3.FilterChain 中的 transport_socket
配置:
支持这几种类型:
名称 | 类型 |
---|---|
envoy.transport_sockets.alts | x |
envoy.transport_sockets.raw_buffer | x |
envoy.transport_sockets.starttls | x |
envoy.transport_sockets.tap | x |
envoy.transport_sockets.tcp_stats | x |
envoy.transport_sockets.tls | extensions.transport_sockets.tls.v3.DownstreamTlsContext |
static_resources:
listeners:
- name: listener_0
......
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
......
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
common_tls_context:
tls_certificates:
- certificate_chain:
filename: "./tls/example.pem"
private_key:
filename: "./tls/example.key"
......
内置鉴权模式
基于角色访问控制
基于角色的访问控制过滤器 (RBAC Filter) 负责验证传入请求的授权状态。该过滤器在 Envoy 进程中执行,根据预先配置的策略列表对每个请求进行检查。
可以在以下两个地方配置过滤器:
- Network filter,当鉴权不通过则直接关闭连接;
- HTTP filter,当鉴权不通过则以 403 返回。
策略(policy)由权限(permission)与主体(principal)组成:
- 权限:指定请求的操作,既做什么,例如 HTTP 请求的方法和路径;
- 主体:指定请求的下游客户端身份,既这是谁,例如 jwt 中的 sub 属性。
角色与策略配置示例如下,详细接口文档参考 config.rbac.v3.RBAC:
action: ALLOW
policies:
# 角色名称
"service-admin":
# 权限列表
permissions:
- any: true
# 用户主体
principals:
- authenticated:
principal_name:
exact: "cluster.local/ns/default/sa/admin"
- authenticated:
principal_name:
exact: "cluster.local/ns/default/sa/superuser"
"role-sal":
permissions:
- and_rules:
rules:
- header: { name: ":method", exact_match: "GET" }
- header: { name: "User", exact_match: "sal" }
- url_path:
path: { prefix: "/" }
principals:
- metadata:
filter: envoy.filters.http.jwt_authn
path:
- key: my_payload
- key: sub
value:
string_match:
exact: "admin@example.com"
"role-guest":
permissions:
- and_rules:
rules:
- url_path:
path:
prefix: "/guest"
principals:
- any: true
策略匹配的动作 (action) 说明:
- 当
action: ALLOW
时:当且仅当存在与请求匹配的策略时才允许该请求,也就是白名单; - 当
action: DENY
时:当且仅当没有与请求匹配的策略时才允许该请求,也就是黑名单; - 当
action: LOG
时:允许所有请求,当请求匹配策略时,更改 “access_log_hint” 为 “true”。
Network filter 配置示例
拒绝来自 “192.168.0.1” 且访问 “80” 端口的客户端,其他来源均允许:
static_resources:
listeners:
- name: listener_0
......
filter_chains:
- filters:
- name: envoy.filters.network.rbac
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.rbac.v3.RBAC
stat_prefix: network_filter
rules:
action: DENY
policies:
"guest":
permissions:
- and_rules:
rules:
- destination_port: 80
principals:
- remote_ip:
address_prefix: 192.168.0.1
prefix_len: 32
......
如果开启了 prometheus 则会产生相关 性能指标 项。
HTTP filter 配置示例
static_resources:
listeners:
- name: listener_0
......
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
http_filters:
- name: envoy.filters.http.rbac
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC
rules:
action: ALLOW
policies:
"admin":
permissions:
- any: true
principals:
- metadata:
filter: envoy.filters.http.jwt_authn
path:
- key: my_payload
- key: sub
value:
string_match:
exact: "admin@example.com"
"guest":
permissions:
- and_rules:
rules:
- url_path:
path:
prefix: "/guest"
principals:
- any: true
......
外部鉴权模式
基于 OPA 的访问控制
外部鉴权模式 同 内置鉴权模式 一样,也支持 “Network filter” 与 “HTTP filter” 两种过滤器。它的流程是当请求发生至 Envoy 时,由 Envoy 把请求的元信息(HTTP 请求头、源 IP 与端口、目标 IP 与端口等)传递给下游 OPA 服务端,由它判断鉴权是否通过。
这里 OPA 服务端由 opa-envoy-plugin 实现,启动与配置示例:
./main run \
--server \
--addr=0.0.0.0:8181 \
--log-level=debug \
--diagnostic-addr=0.0.0.0:8282 \
--ignore=.* \
--config-file=config.yaml \
authz/policy.rego
- 配置 “config.yaml” 内容
plugins:
envoy_ext_authz_grpc:
addr: :9191
path: envoy/authz/allow
dry-run: false
enable-reflection: true
grpc-max-recv-msg-size: 40194304
grpc-max-send-msg-size: 2147483647
skip-request-body-parse: false
enable-performance-metrics: false
decision_logs:
console: true
- 鉴权文件 “authz/policy.rego” 内容
package envoy.authz
import rego.v1
default allow := false
allow if {
input.attributes.source.address.socketAddress.address == "192.168.0.1"
}
默认不允许,因为 “path: envoy/authz/allow” 指向的 “authz/policy.rego” 文件中 “allow” 变量默认值为 false,当且仅当源 IP 为 “192.168.0.1” 时可访问。这个相比内置鉴权模式,存在更高的灵活性,能实现更加细粒度的控制,通过声明式编写策略文件即可。
Network filter 配置示例
用于实现源IP、源端口、目标IP、目标端口的限制,在 envoy 上配置使用外部验证服务地址:
static_resources:
listeners:
- name: listener_0
......
filter_chains:
- filters:
- name: envoy.filters.network.ext_authz
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.ext_authz.v3.ExtAuthz
transport_api_version: V3
stat_prefix: ext_authz
grpc_service:
envoy_grpc:
cluster_name: opa-envoy
include_peer_certificate: true
......
clusters:
- name: opa-envoy
connect_timeout: 1.25s
type: STATIC
http2_protocol_options: {}
load_assignment:
cluster_name: opa-envoy
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 192.168.0.1
port_value: 9191
......
以 opa-envoy-plugin 作为服务端接收到 envoy 数据,并转换为 opa 使用的 input
变量
{
"input": {
"attributes": {
"destination": {
"address": {
"socketAddress": {
"address": "192.168.0.2",
"portValue": 80
}
}
},
"source": {
"address": {
"socketAddress": {
"address": "192.168.0.1",
"portValue": 56695
}
}
}
},
"parsed_body": null,
"parsed_path": [
""
],
"parsed_query": {},
"truncated_body": false,
"version": {
"encoding": "protojson",
"ext_authz": "v3"
}
}
}
HTTP filter 配置示例
除IP、端口外,还可以实现对 HTTP 协议细节进行限制,在 envoy 上配置使用外部验证服务地址
static_resources:
listeners:
- name: listener_0
......
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
http_filters:
- name: envoy.ext_authz
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
transport_api_version: V3
failure_mode_allow: false
grpc_service:
envoy_grpc:
cluster_name: opa-envoy
with_request_body:
allow_partial_message: true
max_request_bytes: 1024
pack_as_bytes: true
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
......
以 opa-envoy-plugin 作为服务端接收到 envoy 数据,并转换为 opa 使用的 input
变量
{
"input": {
"attributes": {
"destination": {
"address": {
"socketAddress": {
"address": "192.168.0.2",
"portValue": 80
}
}
},
"metadataContext": {},
"request": {
"http": {
"headers": {
":authority": "hello.example.com",
":method": "GET",
":path": "/vw0tha/hello/test.jpg?arg1=test1&arg2=test2",
":scheme": "http",
"accept": "*/*",
"user-agent": "curl/8.4.0",
"x-forwarded-proto": "http",
"x-request-id": "ca5f65a7-e8e1-420a-adf6-466f04c623dd"
},
"host": "hello.example.com",
"id": "5149459733649565588",
"method": "GET",
"path": "/vw0tha/hello/test.jpg?arg1=test1&arg2=test2",
"protocol": "HTTP/1.1",
"scheme": "http"
},
"time": "2024-03-19T03:39:00.986466Z"
},
"source": {
"address": {
"socketAddress": {
"address": "192.168.0.1",
"portValue": 57372
}
}
}
},
"parsed_body": null,
"parsed_path": [
"vw0tha",
"hello",
"test.jpg"
],
"parsed_query": {
"arg1": [
"test1"
],
"arg2": [
"test2"
]
},
"truncated_body": false,
"version": {
"encoding": "protojson",
"ext_authz": "v3"
}
}
}