Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spring Cloud Alibaba Istio XDS Auth System Design | Spring Cloud Alibaba 对接ISTIO XDS实现鉴权功能方案 #2708

Closed
123liuziming opened this issue Aug 12, 2022 · 2 comments
Labels

Comments

@123liuziming
Copy link
Collaborator

123liuziming commented Aug 12, 2022

背景

目前 Spring Cloud Alibaba 在微服务治理的能力上还是偏弱,服务网格作为当下热门的云原生项目,istio是服务网格中最突出的实现,istio定义的很多规则成为了服务治理领域的一个通用描述,通过istio + sidecar的模式可以实现如金丝雀发布、服务发现、鉴权、可观测等,但是考虑到sidecar模式在资源成本和RT上的一些缺点,ProxylessMesh成为一个当下都在探索的方向,Spring Cloud Alibaba 首先需要实现对接istio的鉴权的能力

评审背景

除了对接istio的能力,我们最好可以抽象出一套统一的规则,不管我们对接的是istio,opensergo或者是其他的任何框架,我们只需要把对应的鉴权或其他治理数据转化成为统一的格式来使用即可

Istio相关CRD介绍

RequestAuthentication

RequestAuthentication定义工作负载支持哪些请求身份验证方法。当请求中包含无效的认证信息时,根据配置的认证规则拒绝该请求。不包含任何身份验证凭据的请求将被接受,但不包含任何经过身份验证的身份。要将访问限制为只访问经过身份验证的请求,应该附带一个授权规则(AuthorizationPolicy)
CRD的字段定义如下

Field Type Description Required
selector WorkloadSelector Optional. The selector decides where to apply the request authentication policy. The selector will match with workloads in the same namespace as the request authentication policy. If the request authentication 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.
No
jwtRules JWTRule[] Define the list of JWTs that can be validated at the selected workloads’ proxy. A valid token will be used to extract the authenticated identity. Each rule will be activated only when a token is presented at the location recognized by the rule. The token will be validated based on the JWT rule config. If validation fails, the request will be rejected. Note: Requests with multiple tokens (at different locations) are not supported, the output principal of such requests is undefined. No

AuthorizationPolicy

一个授权策略主要包含以下几个部分:

  • name:授权策略的名称,仅用于标识授权策略本身,不会影响规则的匹配和执行。
  • namespace:当前授权策略对象所在的 namespace ,可以使用这个字段配置不同作用范围的授权策略,详见授权策略的作用范围
  • selector:使用 label 来选择当前授权策略作用于哪些 pod 上。注意,这里设置的是服务端的 pod ,因为最终这些规则会转换成 Envoy 规则由服务端的 Envoy Proxy 来具体执行。例如有 client 和 server 两个 service ,它们的 pod 对应的 label 分别为 app: client 和 app: server ,为了针对从 client 到 server 的请求进行配置授权策略,这里的 selector 应该设置为 app: server。
  • action:可以为 ALLOW(默认值)或者 DENY。
  • rules:匹配规则,如果匹配成功,就会执行对应的 action

授权策略针对某一个请求,会按照一定的匹配算法来执行相应的授权策略:

  1. 如果有任何一条 DENY 授权策略匹配当前请求,则拒绝当前请求。
  2. 针对当前 pod,如果没有任何 ALLOW 授权策略,则放行当前请求。
  3. 如果有任何一条 ALLOW 授权策略匹配当前请求,则放行当前请求。
  4. 拒绝当前请求。

授权策略中最重要的是其中的 rule 字段,它指定了如何针对当前的请求进行匹配。如果一个授权策略中指定了多条 rule 规则,则它们之间是或的关系,即只要其中任意一条规则匹配成功,那么整个授权策略匹配成功,就会执行相应的 action ,下面是概述中提到的一个授权策略的例子:

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: httpbin-policy
 namespace: foo
spec:
  selector:
    matchLabels:
      app: httpbin
  action: ALLOW
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/default/sa/sleep"]
    to:
    - operation:
        methods: ["GET"]
        paths: ["/info*"]
    when:
    - key: request.auth.claims[iss]
      values: ["https://foo.com"]

这里的 rules 是一个 rule 的列表。每一条 rule 规则包括三部分: from 、 to 和 when 。类似于防火墙规则,from 和 to 匹配当前请求从哪里来、到哪里去,when 会增加一些额外的检测,当这些条件都满足时,就会认为当前规则匹配成功。如果其中某一部分未进行配置,则认为其可以匹配成功。
在 rule 中进行配置时,所有的字符串类型都支持类似于通配符的匹配模式,例如 abc* 匹配 "abc" 和 "abcd" 等,*xyz 匹配 "xyz" 和 "axyz" 等,单独的 * 匹配非空的字符串。
下面针对具体的字段详细进行说明。

  • from。针对请求的发送方进行匹配,主要包括 principals 、 requestPrincipals 、 namespaces 和 ipBlocks 四个部分。
    • principals。匹配发送方的身份,在 Kubernetes 中可以认为是 podService Account。使用这个字段时,首先需要开启 mTLS 功能,关于这部分内容可参见对等认证。例如,当前请求是从 default namespace 中的 pod 中发出,且 pod 使用的 Service Account 名为 sleep,针对这个请求进行匹配,可将 principals 配置为[cluster.local/ns/default/sa/sleep]。
    • requestPrincipals。匹配请求中的 JWT Token 的 / 字段组合。
    • namespaces。匹配发送方 pod 所在的 namespace。
    • ipBlocks。匹配请求的源 IP 地址段。
  • to。针对请求的接收方进行匹配。除了请求接收方,还会对请求本身进行匹配。包括以下字段:
    • hosts。目的 host。
    • ports。目的 port。
    • methods。是指当前请求执行的 HTTP Method。针对 gRPC 服务,这个字段需要设置为 POST。注意这个字段必须在 HTTP 协议时才进行匹配,如果请求不是 HTTP 协议,则认为匹配失败。
    • paths。当前请求执行的 HTTP URL Path。针对 gRPC 服务,需要配置为 /package.service/method 格式。
  • when。这是一个 key/value 格式的 list 。这个字段会针对请求进行一些额外的检测,当这些检测全部匹配时才会认证当前规则匹配成功。例如 key: request.headers[User-Agent] 可以匹配 HTTP Header 中的 User-Agent 字段。所有可配置项可参见 Istio 官网上的 Authorization Policy Conditions 说明。

针对以上字段,还有对应的反向匹配操作,即“取反”匹配,包括 notPrincipals、notNamespaces 等。例如 notNamespaces: ["bar"] 表示当发送请求的 pod 不位于 "bar" 这个 namespace 中的时候匹配成功。

方案设计

JWT

JWT声明

有关JWT相关的元信息我们放在JWT的声明处,字段为JWTRules,定义如下

Field Type Description Required
issuer string Identifies the issuer that issued the JWT. See issuer A JWT with different iss claim will be rejected.
Example: https://foobar.auth0.com Example: 1234567-compute@developer.gserviceaccount.com
Yes
audiences string[] The list of JWT audiences. that are allowed to access. A JWT containing any of these audiences will be accepted.
The service name will be accepted if audiences is empty.
Example:
audiences: - bookstore_android.apps.example.com bookstore_web.apps.example.com
No
jwksUri string URL of the provider’s public key set to validate signature of the JWT. See OpenID Discovery.
Optional if the key set document can either (a) be retrieved from OpenID Discovery of the issuer or (b) inferred from the email domain of the issuer (e.g. a Google service account).
Example: https://www.googleapis.com/oauth2/v1/certs
Note: Only one of jwksUri and jwks should be used.
No
jwks string JSON Web Key Set of public keys to validate signature of the JWT. See https://auth0.com/docs/jwks.
Note: Only one of jwksUri and jwks should be used.
No
fromHeaders JWTHeader[] List of header locations from which JWT is expected. For example, below is the location spec if JWT is expected to be found in x-jwt-assertion header, and have “Bearer ” prefix:
fromHeaders: - name: x-jwt-assertion prefix: "Bearer "
Note: Requests with multiple tokens (at different locations) are not supported, the output principal of such requests is undefined.
No
fromParams string[] List of query parameters from which JWT is expected. For example, if JWT is provided via query parameter my_token (e.g /path?my_token=), the config is:
fromParams: - "my_token"
Note: Requests with multiple tokens (at different locations) are not supported, the output principal of such requests is undefined.
No
outputPayloadToHeader string This field specifies the header name to output a successfully verified JWT payload to the backend. The forwarded data is base64_encoded(jwt_payload_in_JSON). If it is not specified, the payload will not be emitted. No
forwardOriginalToken bool If set to true, the original token will be kept for the upstream request. Default is false. No

其中,JWTHeader的定义如下

Field Type Description Required
name string The HTTP header name. Yes
prefix string The prefix that should be stripped before decoding the token. For example, for “Authorization: Bearer ”, prefix=“Bearer ” with a space at the end. If the header doesn’t have this exact prefix, it is considered invalid. No

使用案例如下

$ kubectl apply -f - <<EOF
apiVersion: "security.istio.io/v1beta1"
kind: "RequestAuthentication"
metadata:
  name: "jwt-example"
  namespace: $NS
spec:
  selector:
    matchLabels:
      app: httpbin
  jwtRules:
  - issuer: "testing@secure.istio.io"
    jwksUri: "https://raw.githubusercontent.com/istio/istio/release-1.5/security/tools/jwt/samples/jwks.json"
EOF

JWT授权

添加 RequestAuthentication 后,并不是要求所有请求都要带有 JWT token,因为 RequestAuthentication 只负责验证 token 的有效性,token 的有无以及是否授权访问由 AuthorizationPolicy 的 JWT 授权策略决定。所以在只有 RequestAuthentication 时,可以同时支持无 token 请求和带有有效 token 的请求,而带有无效 token 的请求将被拒绝,此时 JWT 认证是一个非必要条件
所以为了实现更细粒度的控制,我们还需要定义JWT的授权策略,定义在Istio的AuthorizationPolicy CRD中
AuthorizationPolicy rule 规则中与 JWT 相关的字段包括:

field sub field JWT claims
from.source requestPrincipals iss/sub
from.source notRequestPrincipals iss/sub
when.key request.auth.principal iss/sub
when.key request.auth.audiences aud
when.key request.auth.presenter azp
when.key request.auth.claims[key] JWT 全部属性

使用例子如下

$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: require-jwt
 namespace: $NS
spec:
 selector:
   matchLabels:
     app: httpbin
 action: ALLOW
 rules:
 - from:
   - source:
       requestPrincipals: ["testing@secure.istio.io/testing@secure.istio.io"]
EOF
$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: require-jwt
 namespace: $NS
spec:
  selector:
   matchLabels:
     app: httpbin
  action: ALLOW
  rules:
  - from:
    - source:
        requestPrincipals: ["testing@secure.istio.io/testing@secure.istio.io"]
    when:
    - key: request.auth.claims[groups]
      values: ["group1"]

用户身份

在K8s中,用户身份指的就是Service Account,定义如下

Type Description Required
principals string[] Optional. A list of peer identities derived from the peer certificate. The peer identity is in the format of "<TRUST_DOMAIN>/ns//sa/<SERVICE_ACCOUNT>", for example, "cluster.local/ns/default/sa/productpage". This field requires mTLS enabled and is the same as the source.principal attribute.
If not set, any principal is allowed.
No
notPrincipals string[] Optional. A list of negative match of peer identities. No

使用案例

$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: httpbin-allow-policy
  namespace: foo
spec:
  selector:
    matchLabels:
      app: httpbin
  action: ALLOW
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/foo/sa/sleep"]
    to:
    - operation:
        methods: ["GET"]
EOF

IP黑白名单

在AuthorizationPolicy的rules.from.source中可以配置来源IP的选项,如下所示

Field Type Description Required
ipBlocks string[] Optional. A list of IP blocks, populated from the source address of the IP packet. Single IP (e.g. “1.2.3.4”) and CIDR (e.g. “1.2.3.0/24”) are supported. This is the same as the source.ip attribute.
If not set, any IP is allowed.
No
notIpBlocks string[] Optional. A list of negative match of IP blocks. No
remoteIpBlocks string[] Optional. A list of IP blocks, populated from X-Forwarded-For header or proxy protocol. To make use of this field, you must configure the numTrustedProxies field of the gatewayTopology under the meshConfig when you install Istio or using an annotation on the ingress gateway. See the documentation here: Configuring Gateway Network Topology. Single IP (e.g. “1.2.3.4”) and CIDR (e.g. “1.2.3.0/24”) are supported. This is the same as the remote.ip attribute.
If not set, any IP is allowed.
No
notRemoteIpBlocks string[] Optional. A list of negative match of remote IP blocks. No

同时,在AuthorizationPolicy的rules.when中也可以配置目的IP的值

字段 字段含义 支持的协议 例子
source.ip 源 IP 地址,支持单个 IP 或 CIDR HTTP and TCP key: source.ip
values: ["10.1.2.3"]
destination.ip 目标 IP 地址,支持单个 IP 或 CIDR HTTP and TCP key: destination.ip
values: ["10.1.2.3", "10.2.0.0/16"]

使用案例

kubectl apply -f - << EOF
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: httpbin-policy
 namespace: foo
spec:
  action: ALLOW
  rules:
  - from:
    - source:
        ipBlocks: ["10.0.0.1"]
    to:
    - operation:
        hosts: ["www.baidu.com","www.google.com"]
    when:
    - key: destination.ip
      values: ["127.0.0.1"]
EOF

HTTP请求信息鉴权

在AuthorizationPolicy的rules.to.operation中定义了与这条策略能够匹配的HTTP请求的信息,CRD的信息如下

Field Type Description Required
hosts string[] Optional. A list of hosts as specified in the HTTP request. The match is case-insensitive. See the security best practices for recommended usage of this field.
If not set, any host is allowed. Must be used only with HTTP.
No
notHosts string[] Optional. A list of negative match of hosts as specified in the HTTP request. The match is case-insensitive. No
ports string[] Optional. A list of ports as specified in the connection.
If not set, any port is allowed.
No
notPorts string[] Optional. A list of negative match of ports as specified in the connection. No
methods string[] Optional. A list of methods as specified in the HTTP request. For gRPC service, this will always be “POST”.
If not set, any method is allowed. Must be used only with HTTP.
No
notMethods string[] Optional. A list of negative match of methods as specified in the HTTP request. No
paths string[] Optional. A list of paths as specified in the HTTP request. See the Authorization Policy Normalization for details of the path normalization. For gRPC service, this will be the fully-qualified name in the form of “/package.service/method”.
If not set, any path is allowed. Must be used only with HTTP.
No
notPaths string[] Optional. A list of negative match of paths. No

使用案例如下

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: httpbin
  namespace: foo
spec:
  action: ALLOW
  rules:
  - from:
    to:
    - operation:
        methods: ["GET"]
        paths: ["/info*"]
		hosts: ["www.baidu.com"]

拦截点

对于使用Spring MVC的应用,使用Interceptor对所有发向这个应用的请求做拦截
对于使用Spring WebFlux的应用,使用WebFilter对所有发向这个应用的请求做拦截
因为类似SCG或者ZUUL等Spring Cloud生态中的网关产品本质上也是基于Spring WebFlux/MVC做扩展,所以我们只需要拦截interceptor或WebFilter即可

整体架构

image.png

工作项

  1. 在本次活动中,将实现以上所有JWT鉴权的能力
  2. 在本次活动中,将实现所有IP黑白名单相关的逻辑,根据请求的来源IP,目标IP,remoteIP来实现相关的鉴权逻辑
  3. 在本次活动中,将实现所有HTTP请求信息鉴权相关的逻辑,根据请求的HOST, PORT,METHOD, PATH来实现相关的鉴权逻辑
  4. 需要注意的是,用户身份鉴权需要首先实现mTLS,这一块工作量比较大,所以在这次活动中仅给出相关的类定义,具体的逻辑可以等到后面实现了mTLS后实现

参考资料

@123liuziming 123liuziming changed the title Spring Cloud Alibaba 对接ISTIO XDS实现鉴权功能方案 Spring Cloud Alibaba Istio XDS Auth System Design | Spring Cloud Alibaba 对接ISTIO XDS实现鉴权功能方案 Aug 12, 2022
@steverao steverao added the kind/discussion Mark as discussion issues/pr label Aug 12, 2022
Copy link

This issue has been open 30 days with no activity. This will be closed in 7 days.

@github-actions github-actions bot added the stale label Apr 17, 2024
Copy link

This issue has been automatically marked as stale because it hasn't had any recent activity.If you think this should still be open, or the problem still persists, just pop a reply in the comments and one of the maintainers will (try!) to follow up. Thank you for your interest and contribution to the Sping Cloud Alibaba Community.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants