目录

  • 1. Istio Security概览
  • 2. Istio 身份
  • 2.1 Istio身份的具体示例
  • 2.2 Istio workload身份的承载物 - X.509证书
  • 3. 认证Authentication
  • 3.1 认证策略 Authentication policies
  • 3.1.1 PeerAuthentication
  • 3.1.2 RequestAuthentication
  • 3.1.3 认证通过后输出的principal
  • 4. 授权Authorization
  • 4.1 授权策略 Authorization policies
  • 5. 总结
  • 6. 后续 TODO


1. Istio Security概览

Istio Security可整体概括为下图:

istio trafficPolicy配置 istio destination_security


Istio安全保护工具:

  • 身份(strong identity)
  • 策略(powerful policy):包括认证策略、授权策略
  • 传输加密(TLS encryption)
  • AAA(authentication, authrorization, audit):认证、授权、审计

Istio Security目标:

  • Security by default
  • Defense in depth
  • Zero-trust network

Istio Security整体架构

istio trafficPolicy配置 istio destination_oauth_02


核心组件:

  • CA(证书权威机构Certificate Authority):负责密钥key和证书cert管理
  • Configuration API server(Authen policies, Author policies, Secure naming information):负责向proxies分发策略
  • PEPs(Policy Enforcement Points,例如sidecar, perimeter proxies):接收安全策略并执行相关安全策略(通讯加密)
  • Envoy proxy extensions: manage telemetry and auditing

2. Istio 身份

身份是任何安全框架的基础,后续的认证、授权都是在身份的基础上进行的,
我们做应用开发时,身份可以表示具体的用户、企业、设备、服务等等。

2.1 Istio身份的具体示例

Istio使用了一个更广泛的service identity的概念,service identity可以代表:

  • 一个人类用户 对应Istio RequestAuthentication JWT认证,
    在Istio中对应属性:request.auth.principal={iss}/{sub},
    即通过JWT令牌标识一个用户
  • 单独的workload 对应Istio PeerAuthentication mTls验证,mTls证书中编码了workload身份,
    K8s service account标识一个workload,
    在Istio中对应属性:source.principal=cluster.local/ns/{namespace}/sa/{serviceAccountName}
  • 一组workloads 可以理解为一个K8s service account对应多个workload,
    又或者如形式:cluster.local/ns/default/sa/*
  • 自定义的用户账户、服务账户、服务名称、Istio service account …

2.2 Istio workload身份的承载物 - X.509证书

Istio中每个workload都有一个身份,这个身份是通过X.509证书来进行表示的
(即每个workload都有一套由istiod CA签发的证书,而证书中编码了当前worload的身份信息),
在Istio中workload的身份是由K8s Service account来进行表示的
格式:cluster.local/ns/{namespace}/sa/{serviceAccountName}

具体证书流转流程如下:

  • Istio agent(存在于sidecar 容器中的 pilot-agent 进程)负责生成key+csr
  • Istio agent 请求Istiod CA生成证书(grpc服务)
  • Istiod CA验证csr请求,生成并返回证书给Istio agent
  • workload启动完成后,Istio agent通过Envoy secret discovery service (SDS)向Envory发送key+cert
  • Istio agent监控cert过期时间并重复发起上述流程(即cert过期后会自动向Istiod CA续签证书 )

3. 认证Authentication

Isito提供两种认证类型:

  • Peer Authentication - 服务(工作负载)间的认证(service-to-service)
    Istio通过envoy间的双向TLS(mutual TLS)来实现服务间的认证通信加密
    同时client需要对server端证书cert中的service account进行安全命名(Secure Naming)检查 注:Istio使用的mTLS版本 >= TLSv1_2版本
  • Request Authentication - 终端用户(end-user)的请求(单个request)认证
    Istio启用请求级别的JWT验证,且支持集成自定义认证服务器(Authentication provider、OIDC provider),如:Keycloak, Auth0, Google Auth, ORY hydra等。
    注:需要应用Application自己去获取、添加JWT到请求request中

安全命名(Secure Naming)
Server IdentitiesService Name的映射,
K8s Service AccountK8s Service的映射,
Secure Naming Check即用于client检查server端cert中的service account是否被授权运行server端服务,
可用于防止DNS spoofing, BGP/route hijacking, ARP spoofing等。
注:对于非HTTP/HTTPS流量,安全命名不能保护其免于 DNS 欺骗

例如:

Server Identity

Service Name

说明

A

B

A被授权运行服务B

3.1 认证策略 Authentication policies

所有的的认证策略都是作用在Server服务端,即:

  • 为Server服务端指定Client客户端的认证策略
  • 由Server服务端对Client客户端执行认证

之前提到过Istio认证分为2种认证类型,2种认证类型即对应各自同名的认证策略配置如下表:

认证类型

认证策略配置

说明

Peer Authentication

PeerAuthentication

- 服务(工作负载)间的认证(service-to-service)

- Istio通过envoy间的双向TLS(mutual TLS)来实现服务间的认证通信加密- 同时client需要对server端证书cert中的service account进行安全命名(Secure Naming)检查

Request Authentication

RequestAuthentication

- 终端用户(end-user)的请求(单个request)认证

- Istio启用请求级别的JWT验证- 且支持集成自定义认证服务器(Authentication provider、OIDC provider)

- 需要应用Application自己去获取、添加JWT到请求request中

认证策略的作用范围:

  • Mesh-wide policy - 网格范围
    定义在root命名空间(即istio-system)下的策略,且没有selector或空selector,则对整个网格内的workload都生效
  • Namespace-wide policy - 命名空间范围
    定义在非root命名空间下,且没有selector或空selector,则对该命名空间下的workload都生效
  • workload-specific policy - 特定workload
    定义在非root命名空间下,且selector不为空,则对该命名空间下selector选中的workload生效

3.1.1 PeerAuthentication

PeerAuthentication主要用来给目标workload(或特定port)指定mutual TLS模式,

具体mtls.mode如下:

  • PERMISSIVE(宽容模式,默认)
    同时支持明文、mtls流量
  • STRICT(严格)
    仅支持mtls流量
  • DISABLE(禁用)
    禁用mtls,即仅支持明文传输

注:

  • PeerAuthentication mtls 用于配置指定workload对应sidecar需要接受的mTLS流量类型
  • DestinationRule tls 用于配置客户端workload对应的siedecar需要向指定服务端workload sidecar 发送的TLS流量类型
    若PeerAuthentication开启mtls.mode:STRICT模式,
    则DestinationRule需开启trafficPolicy.tls.mode: ISTIO_MUTUAL
    (DestinationRule默认不配置则Istio网格内服务默认开启ISTIO_MUTUAL)。
    PeerAuthentication和DestinationRule具体差别参见:
    https://preliminary.istio.io/latest//docs/ops/configuration/traffic-management/tls-configuration/#sidecars

PeerAuthentication具体示例如下:

# 假设在命名空间foo下存在服务exmaple-service,服务提供8000端口,对应容器80端口
# 对应K8s service定义如下:
apiVersion: v1
kind: Service
metadata:
  name: example-service
  namespace: foo
spec:
  ports:
  - name: http
    port: 8000
    protocol: TCP
    targetPort: 80
  selector:
    app: example-app


# 需求1:命名空间foo下的所有服务都需要开启mTls模式(即双向TLS认证)
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: "example-policy"
  namespace: "foo"
spec:
  # selector不存在
  # 则对命名空间foo下的所有workload均生效
  # 设置mtls.mode为STRICT,则开启mtls(仅接收mtls流量)
  mtls:
    mode: STRICT

      
# 需求2:命名空间foo下的服务example-service的80端口禁用mTls模式(即支持明文传输)
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: "example-workload-policy"
  namespace: "foo"
spec:
  # 通过selector指定label选择特定的workload
  selector:
     matchLabels:
       app: example-app
  # 端口级别的mTls模式设置
  portLevelMtls:
    # 指定workload的目标端口80的mtls模式为禁用
    80:
      mode: DISABLE

TODO: 多个规则合并、优先级

3.1.2 RequestAuthentication

RequestAuthentication主要用来设置对目标worload发起request请求的JWT验证,

即对JWT中标识的终端用户(end-user)的请求(request)认证。

istio trafficPolicy配置 istio destination_oauth_03

RequestAuthentication整体配置结构如下:

  • namespace 策略生效的命名空间
  • selector -> matchLables 指定策略作用的目标workload
  • jwtRules jwt验证规则的配置
  • issuer jwt的发布者
  • audiences 受众,即jwt的接受者
  • jwksUri | jwks jwks(公钥),即用来验证jwt签名的公钥,jwksUri和jwks二选一
  • fromHeaders jwt在请求头的位置
  • name header名称
  • prefix token前缀,如"Bearer "
  • fromParams jwt在query参数中的参数名称
  • outputPayloadToHeader 指定jwt验证通过后的payload传递给哪个请求header
  • forwardOriginalToken 是否保留原始token,默认false

jwtRules概括起来分为如下几类配置:

  • jwt token的位置(jwtRules.fromHeaders, jwtRules.fromParams)
  • jwt.payload等相关属性(jwtRules.issuer, jwtRules.audiences)、request
  • jwt公钥,即JWKS(JSON Web Key Set),用来验证jwt的签名(jwtRules.jwksUri, jwtRules.jwks)
  • 是否保留jwt(jwtRules.outputPayloadToHeader, jwtRules.forwardOriginalToken)

RequestAuthentication配置示例

apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
  name: httpbin
  namespace: foo
spec:
  # worload的label选择器
  selector:
    matchLabels:
      app: httpbin
  # jwt验证规则
  jwtRules:
    # jwt的发布者
  - issuer: "issuer-foo"
    # 受众,即jwt的接受者
    audiences:
	- bookstore_android.apps.example.com
  	  bookstore_web.apps.example.com
    # jwks(公钥)uri发现地址,即用来验证jwt签名的公钥
    jwksUri: https://example.com/.well-known/jwks.json
    # jwks(此属性与jwksUri需二选一)
    jwks: "jwks json"
  	# jwt在请求头的位置
  	fromHeaders:
  	- name: x-jwt-assertion
  	  prefix: "Bearer "
    # jwt在query参数中的参数名称
    fromParams:
    - "my_token"
    # 指定jwt验证通过后的payload传递给哪个请求header
    # 传递格式:base64_encoded(jwt_payload_in_JSON)
    outputPayloadToHeader: payload_header
    # 是否保留原始token(若保留则继续传递token到upstream请求),默认false
    forwardOriginalToken: false

注:

  • jwt验证通过,则正常接受请求
  • jwt验证失败,则拒绝请求
  • jwt为空,默认接受请求(需通过设置Authoriation policies来拒绝不带token的请求)
  • 支持多个不同位置的jwt token,
  • 但仅支持一个有效的token(多个有效的token会导致输出的principal不确定)

3.1.3 认证通过后输出的principal

认证(Authentication Policies)通过后,Istio会将各自的认证策略中抽取到的身份信息传递给Istio 身份属性,可供后续授权策略(AuthorizationPolies)使用

认证策略

抽取出的身份属性

(Istio属性)

授权策略

AuthorizationPolicy

说明

PeerAuthentication

source.principal

rules.from.principals

workload的身份,需开启mTls获取

格式:cluster.local/ns/{namespace}/sa/{serviceAccountName}

示例:cluster.local/ns/default/sa/productPage

RequestAuthentication

request.auth.principal

rules.from.requestPrinciplas

用户身份,即 jwt令牌(认证通过)中提取的身份,

格式:{issuer}/{subject}

示例: issuer.example.com/subject-admin

4. 授权Authorization

Isito默认开启对网格内的workload的访问控制,
由server端的Envoy代理(根据AuthorizationPolicy配置)对inbound流量执行access control,
Istio授权(Authorization)提供如下特性:

  • workload-to-workload, end-user-to-workload的访问控制
  • 提供简单、唯一的授权策略配置:AuthorizationPolicy
  • 兼容多协议:gRPC, HTTP, HTTPS, HTTP/2, TCP

Istio根据action类型( CUSTOM | DENY | ALLOW)分层验证AuthorizationPolicy,

即依次验证:CUSTOM -> DENY -> ALLOW,具体授权策略优先级如下图:

istio trafficPolicy配置 istio destination_security_04


注:目标workload的操作没有设置AuthorizationPolicy,则表示没有限制,放行所有对目标workload的请求

4.1 授权策略 Authorization policies

Istio提供唯一的授权策略配置:AuthorizationPolicy,其整体结构如下:

  • namespace 策略生效的命名空间(即目标workload所属的namespace)
  • selector -> matchLables 指定策略作用的目标workload
  • actions: CUSTOM | DENY | ALLOW 是否允许请求
  • rules 指定触发action的条件(即满足rules定义的请求,则执行action)
  • from -> source[] 指定请求来源(source满足的条件),为空则表示全部来源
    pincipals(workload身份)、requestPrincipals(用户身份)、namespaces、ipBlocks、remoteIpBlocks及相应not属性
  • to -> operation[] 指定请求的操作(request满足的条件),为空则表示所有操作
    hosts、ports、methods、paths及相应not属性
  • when 指定额外的附件条件(key对应Istio属性)
  • key -> values[] | notValues[] request.headers[header_name]、
    request.auth.[principal | audiences | presenter | claims[claimName] ]、
    source.[ip | namespace | principal ]、remote.ip、
    destination.[ip | port]、 connection.sni

AuthorizationPolicy配置概括起来就是:
允许(或拒绝) 来源workload 或 用户目标workload进行什么操作,并且需要满足什么条件

具体配置示例:

# 作用目标:               workload(namespace=foo, label(app=httpbin, version=v1))
# 动作action:            允许访问ALLOW
# 来源rules.from.source: principals=="cluster.local/ns/default/sa/sleep" or namepsace=="dev"
# 操作rules.to.operation:method=="GET"
# 条件rules.when:        request.auth.claims[iss]=="https://accounts.google.com"
# 即[仅允许][cluster.local/ns/default/sa/sleep身份(PeerAuthentication mTls验证通过)、或者dev命名空间]的workload访问[httpbin:v1服务的GET请求]
# 且[用户RequestAuthentication JWT验证通过、且jwt.claims[iss]=="https://accounts.google.com"]
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: httpbin
 namespace: foo
spec:
 selector:
   matchLabels:
     app: httpbin
     version: v1
 action: ALLOW
 rules:
 - from:
   - source:
   	   # 指定来源workload身份
   	   # principals: ["*"]则表示需要PeerAuthentication mtls验证通过
       principals: ["cluster.local/ns/default/sa/sleep"]
   - source:
       # 指定来源namespace
       namespaces: ["dev"]
   to:
   - operation:
       # 执行GET请求
       methods: ["GET"]
   when:
     # 指定用户jwt需验证通过,且iss为指定值
   - key: request.auth.claims[iss]
     values: ["https://accounts.google.com"]


# [拒绝][不属于foo命名空间的服务]访问[httpbin:v1服务]
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: httpbin-deny
 namespace: foo
spec:
 selector:
   matchLabels:
     app: httpbin
     version: v1
 action: DENY
 rules:
 - from:
   - source:
       # 不是来自于foo命名空间
       notNamespaces: ["foo"]

# 访问非/healthz的请求,均需要JWT验证通过,
# 而访问/healthz的请求,可无需JWT验证(即请求未携带JWT令牌、或者携带的JWT令牌为空)
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: disable-jwt-for-healthz
  namespace: default
spec:
  selector:
    matchLabels:
      app: products
  action: ALLOW
  rules:
  - to:
    - operation:
        # 访问除了/healthz以外的path
        notPaths: ["/healthz"]
    from:
    - source:
        # 需要RequestAuthentication JWT验证通过
        requestPrincipals: ["*"]

5. 总结

记得刚接触Istio时,就看过Istio官网上关于Istio/Concepts/Security 这一章节,当时看的不是很懂,后来陆续接触了

  • Oauth2
  • Spring Security
  • Spring Security Oauth
  • RBAC
  • OIDC
  • CAS
  • SSO, SLO
  • IDasS

最近回过头来再看Istio Security,渐渐读懂了Istio Security想要做什么了。

可以对比Spring Security,Spring Security是Java语言在Spring平台的安全管理框架,
通过编码集成用户登录认证、用户鉴权等操作,
后续出现了Oauth, OIDC后,我们可以搭建统一认证服务器AS(Authorization server), OP(OpenID Provider),
如Keycloak、IdentityServer、又或者购买IDaaS,
然后通过Spring Security Oauth框架编码、配置集成Client端、Resource server端,
在Client端我们通过Spring Security框架注册了认证中心,由认证中心完成统一的登录认证并颁发token,
而在Resource server端由Spring Security框架帮我们完了JWT认证,
而具体的鉴权(Authorization、Access control)操作(API path、数据权限、菜单、按钮)还是需要我们通过编码来完成。

Istio Security是站在更高层次(Service mesh)看问题,
Istio不关心具体服务使用的是什么编程语言(Java、Python、Go…)、什么安全框架(Spring Security、Shiro…),
它以不侵入代码的形式(Sidecar Envoy),
站在通信协议(HTTP、HTTPS、gRPC、TCP)、安全协议(Oauth2、OIDC)层面看问题,
通过Istio自定义的Yaml配置(PeerAuthentication、RequestAuthentication、AuthorizationPolicy)来实现一定程度的认证、授权配置。

目前简单来看Istio可以替代部分传统安全框架(基于编码开发)的功能:

传统方式

Istio方式

说明

Spring Security Oauth - Resource Server

RequestAuthentication

JWT验证(iss, aud…)

编码方式mTLS证书配置

容器、中间件trustStore配置

PeerAuthentication

应用间(workload间)的mTls认证

编码方式的鉴权

AuthorizationPolicy

workload-to-workload

end-user-to-workload

Istio除了支持传统的用户鉴权,

还支持Mesh内workload间的访问控制,

Istio鉴权粒度有限:workloads、hosts、paths、methods、ports

Spring Security Oauth - Client

AuthorizationPolicy

(action.CUSTOM + provider)

Istio实验特性

Istio支持集成外部认证中心

编码获取、添加JWT到请求中


Istio安全框架也需要应用本身自己负责获取、添加JWT到请求中

开发、搭建统一认证服务器


Istio安全框架不提供统一认证中心,需要应用平台自己搭建统一认证中心

6. 后续 TODO

  • 安全命名(Secure Naming)
  • Istio集成外部认证中心:External Authorization
  • Istio Security与Spring Security对比