点击上方“程序猿技术大咖”,关注并选择“设为星标”
回复“加群”获取入群讨论资格!
初识Istio Authorization
我们都知道认证(Authentication、Authn)与授权(Authorization、Authz)一同构建了起网络应用安全的基本屏障。通常,授权对认证有一定的依赖。比如我们熟悉的OAuth或者基于JWT Token的授权。
Istio授权充分利用了Envoy的授权插件,基本覆盖业界主流的访问控制策略。Istio Authz功能提供了服务网格、命名空间以及工作负载范围的访问控制,多种粒度的访问控制具有以下好处:
1. 工作负载到工作负载以及最终用户到工作负载授权
2. 简单的API:Istio利用声明式的AuthorizationPolicy,对用户来说简单易用。
3. 灵活的语法:用户可以基于Istio的访问属性(身份,命名控制等)自定义控制策略(ALLOW, DENY,CUSTOM)
4. 高性能:Istio本地授权在envoy进程内部执行
5. 灵活扩展性:外部授权支持更加复杂的访问控制,外部授权支持HTTP、gRPC协议,后面重点讲解。
Istio Authorization架构及原理
授权架构
授权策略强制对服务器端 Envoy 代理中Inboud流量进行访问控制。每个 Envoy 代理运行一个授权引擎,在运行时授权请求。当请求到达代理时,授权引擎根据当前授权策略评估请求上下文,并返回授权结果,允许或拒绝。用户可以通过AuthorizationPolicy指定访问控制策略。
本地授权基于Envoy RBAC(Role Based Access Control)过滤器实现。RBAC Filter可以用来对识别到的下游客户(Principals)进行授权。这对于显式管理应用程序的调用者并保护应用程序很有用。RBAC本地授权支持使用连接属性(IP,端口,SSL subject)以及HTTP头配置ALLOW或DENY列表。
External Authorization
External Authorization
Envoy (v1.7.0+) 支持外部授权过滤器,它调用授权服务来检查传入请求是否被授权。External Authz可以将授权决策委托给外部服务,并将请求上下文传递给授权服务。请求上下文包含诸如网络请求的来源、网络请求的目的地、网络请求(例如http请求)等信息。外部服务可以使用所有这些信息来对 Envoy 收到的传入请求的命运做出明智的决定。
Envoy外部授权过滤器有两种:一种是TCP的网络过滤器,另一种是HTTP过滤器。理论上可以配置任意的外部过滤器,当请求被TCP的外部授权拒绝时,网络连接自动断开,当网络请求被HTTP外部授权过滤器拒绝时,则会返回403 HTTP响应码。
目前有一些成熟的开源外部授权服务器实现,比如Open Policy Agent, oauth2-proxy。当然也可以实现自己的授权服务器,参考Istio例子:https://github.com/istio/istio/blob/master/samples/extauthz/src/main.go
外部授权接口支持gRPC和HTTP两种协议。Envoy通过CheckRequest定义了传递给授权服务的请求上下文属性,供其进行决策。请求上下文主要分为:
● Source :源地址,身份principal(Istio从x509证书SAN中提取)
● Destination:目的地址,身份principal(Istio从x509证书SAN中提取)
● Request:网络请求,HTTP头,方法,请求参数,协议等信息
授权API External AuthorizationPolicy
AuthorizationPolicy与Istio其他的API一样也是通过CRD定义的,声明式的API。其优点是简单易用。首先简单了解一下AuthorizationPolicy:
type AuthorizationPolicy struct {
// Optional. The selector decides where to apply the authorization policy. The selector will match with workloads
// in the same namespace as the authorization policy. If the authorization policy is in the root namespace, the selector
// will additionally match with workloads in all namespaces.
//
// If not set, the selector will match all workloads.
Selector *v1beta1.WorkloadSelector
// Optional. A list of rules to match the request. A match occurs when at least one rule matches the request.
//
// If not set, the match will never occur. This is equivalent to setting a default of deny for the target workloads if
// the action is ALLOW.
Rules[]*Rule
// Optional. The action to take if the request is matched with the rules. Default is ALLOW if not specified.
Action AuthorizationPolicy_Action // Types that are valid to be assigned to ActionDetail:
// *AuthorizationPolicy_Provider
ActionDetail isAuthorizationPolicy_ActionDetail
Selector: 决定此授权策略应用到哪个工作负载。
授权策略语义分析
Rules:一组匹配策略,当任意策略匹配上的时候,执行下面的Action。Rule支持三种匹配,
1. From,即匹配请求源
2. To,匹配请求的操作,比如访问路径,方法
3. When,指定执行这条规则的条件,例如当request.auth.claims[iss]
Action:决策结果:ALLOW、DENY、CUSTOM,CUSTOM则是指定外部授权方式,同时必须指定下面的ActionDetail
ActionDetail:授权服务provider
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: httpbin
namespace: foo
spec:
selector:
matchLabels:
app: httpbin
version: v1
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/default/sa/sleep"]
- source:
namespaces: ["default"]
to:
- operation:
methods: ["GET"]
when:
- key: request.auth.claims[iss]
values: ["https://accounts.google.com"]
上面的例子表示Istio使用本地授权,当网络请求使用JWT认证,签发者是google时,允许服务账户为“cluster.local/ns/default/sa/sleep”,来自default命名空间的服务,访问httbin-v1服务的GET接口。否则,决绝访问httpbin-v1。
Istio允许用户为同一个服务指定多个授权策略,为了避免不同的AuthorizationPolicy相互冲突,Istio定义了一定的优先级策略,如下所示:
1. 首先执行CUSTOM的外部授权,如果外部授权结果为ALLOW,则继续执行本地授权当结果为DENY时,则直接返回DENY决策,退出授权链。
2. 执行DENY的本地授权规则,当请求匹配DENY条件时,返回DENY决策,退出授权链。否则继续执行ALLOW的本地授权规则
3. 执行ALLOW的本地授权策略,当请求匹配ALLOW Rule时,返回ALLOW,否则不能匹配ALLOW Rule,直接返回DENY。
授权策略优先级
参考链接:
https://www.openpolicyagent.org/docs/latest/envoy-introduction/
Open Policy Agent介绍
OPA是为云原生环境设计的策略引擎,目前已经是CNCF的毕业项目。OPA的愿景打造云原生乃至整个业界策略控制的事实标准。
“停止为您使用的每种产品和服务使用不同的策略语言、策略模型和策略 API。将 OPA 用于云原生堆栈的统一工具集和策略框架。
无论是针对一项服务还是针对您的所有服务,都可以使用 OPA 将策略与服务代码分离,这样您就可以在不牺牲可用性或性能的情况下发布、分析和审查策略(安全和合规团队喜欢的策略)。”
OPA是一种声明式的策略引擎,使用rego表示策略。OPA-Envoy Plugin扩展了OPA,实现了Envoy的外部授权gRPC服务。因此Istio外部授权可以直接使用OPA-Envoy插件。
Istio与OPA集成
将OPA-Envoy以Sidecar的形式部署在应用旁是一种更为推荐的方式,这样远程调用的时延最小。然而这也不是必须的,OPA也可以中心式部署。
Istio外部授权-集成OPA
OPA官网https://www.openpolicyagent.org/docs/latest/envoy-tutorial-istio/提供了如何利用Istio Envoyfilter配置由OPA-Envoy执行授权访问控制。由于OPA-Envoy以边车的形式部署,所以没有使用AuthorizationPolicy,而是直接通过EnvoyFilter,控制外部授权服务的地址。
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: ext-authz
namespace: istio-system
spec:
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
subFilter:
name: "envoy.filters.http.router"
patch:
operation: INSERT_BEFORE
value:
name: envoy.ext_authz
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
transport_api_version: V3
status_on_error:
code: ServiceUnavailable
with_request_body:
max_request_bytes: 8192
allow_partial_message: true
grpc_service:
# NOTE(tsandall): when this was tested with the envoy_grpc client the gRPC
# server was receiving check requests over HTTP 1.1. The gRPC server in
# OPA-Istio would immediately close the connection and log that a bogus
# preamble was sent by the client (it expected HTTP 2). Switching to the
# google_grpc client resolved this issue.
google_grpc:
target_uri: 127.0.0.1:9191
stat_prefix: "ext_authz"
上述Envoyfilter样例向Envoy中插入一个HTTP外部授权过滤器,控制所有的请求都向127.0.0.1:9191这个服务发起授权请求。实际上这正是OPA-Envoy边车监听的地址。
OPA-Envoy的策略声明如下:
apiVersion: v1
kind: ConfigMap
metadata:
name: opa-policy
data:
policy.rego: |
package istio.authz
import input.attributes.request.http as http_request
import input.parsed_path
default allow = false
allow {
parsed_path[0] == "health"
http_request.method == "GET"
}
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"},
],
}
● 用户alice被授予guest角色,具有发起GET请求/productpage的权限。
● 用户bob被授予admin角色,具有发起GET请求/productpage和/api/v1/products的权限。
在典型的部署中,策略要么内置到 OPA 容器映像中,要么通过 Bundle API 动态获取。在这里是通过Configmap挂载到容器中。
参考链接:
1.https://istio.io/latest/docs/tasks/security/authorization/authz-custom/
2. https://istio.io/latest/docs/concepts/security/#authoriz
ation
3.https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/security/ext_authz_filter.html
4. https://www.openpolicyagent.org/docs/latest/envoy-tutorial-istio/
感谢您的阅读,也欢迎您发表关于这篇文章的任何建议,关注我,技术不迷茫!
喜欢就点个"在看"呗,留言、转发朋友圈