Skip to content

资源类型

流量管理

网关

信息

Gateway(gw):用于管理服务网格的入站(ingress)和出站(egress)流量。指定要进入或离开网格的流量。

bash
$ kubectl -n test apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: nginx-gateway
  namespace: test
spec:
  selector:
    istio: ingressgateway # 与istio-system中ingressgateway的pod的label匹配
  servers:
    - port:
        name: http
        number: 80
        protocol: HTTP
      hosts:
        - test/httpbin.example.com # 匹配指定namespace下的vs中的域名
    - port:
        name: https
        number: 443
        protocol: HTTPS
      hosts:
        - httpbin.example.com
      tls:
        mode: SIMPLE
        credentialName: httpbin-secret # 默认在istio-system下查找
EOF
  • 支持监听同个节点上相同的端口,但是需要通过不同的name来区分。
  • hosts参数除了支持域名,还支持IP、DNS、FQDN外,也支持通配符"*"
  • 如需监听HTTPS域名,需要配置TLS证书,默认在istio-system下查找保存证书信息的secret。
  • protocl支持HTTP|HTTPS|GRPC|GRPC-WEB|HTTP2|MONGO|TCP|TLS类型。更多

TLS类型

NameDescription
PASSTHROUGHIstio 不干预 TLS 握手过程,客户端和服务直接进行加密通信。
SIMPLE启用TLS但不需要对客户端进行身份验证。服务之间的通信是加密的,但不要求客户端提供证书。
MUTUAL双向TLS模式。客户端和服务之间的通信是加密的,且双方都要验证对方的身份,即客户端和服务都要提供证书。
AUTO_PASSTHROUGH自动选择透传或简单模式。Istio将根据客户端请求是否提供证书来动态选择透传或简单模式。
ISTIO_MUTUAL由istio生成和管理证书,不需要手动配置,其他与MUTUAL相同。
OPTIONAL_MUTUAL双向 TLS 模式,要求服务提供证书,但客户端可以选择是否提供证书。

虚拟服务

提示

VirtualService(vs):虚拟服务允许配置请求如何路由到特定的服务,每个虚拟服务包含一组按顺序评估的路由规则。与网关整合并配置流量规则能够控制出入流量。通过虚拟服务能处理特定ns下的所有服务,将单一虚拟服务映射到多个真实服务

bash
$ kubectl -n test apply -f - <<EOF 
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: nginx-virtual-service
spec:
  hosts: # 与绑定gateway下的hosts匹配才会生效
    - httpbin.example.com
  gateways:
    - nginx-gateway  # 用来匹配绑定的网关
  http:
    - match:
        - headers:
            end-user:
              exact: zhangsan # exact 精确匹配 请求头end-user=zhangsan才能匹配
      route:
        - destination:
            host: nginx-svc # 必须是真实存在的svc
            subset: v1 # 对应DestinationRule定义的subset
            port:
              number: 80
          weight: 50 # 50%流量访问v1
        - destination:
            host: nginx-svc
            subset: v2
            port:
              number: 80
          weight: 50
      headers:
        request:
          set:
            custom-header: helloworld # 请求到达pod前添加自定义header
          add:
            hello: world # 添加到指定头中,多值用逗号分割
          remove:
            - end-user # 请求到达pod前移除header
        response:
          set:
            end-user: helloworld # 设置响应头
          add:
            custom-header: custom-value # 添加到指定头中,多值用逗号分割  
    - match:
        - uri:
            exact: /hello # 匹配/hello
      rewrite: # 重写uri /hello -> /
        uri: /      
      route:
        - destination:
            host: nginx-svc
            subset: v2
            port:
              number: 80
      retries: # 重试三次,timeout 2s
        attempts: 3
        perTryTimeout: 2s
      timeout: 10s # 10s超时
    - match:
        - uri:
            exact: /
      fault: # 故障注入,一百个访问中有一个访问会出现5s的延时
        delay:
          percentage:
            value: 1 # 设置为100,就表示全部的请求都会5s延时
          fixedDelay: 5s
      route:
        - destination:
            host: nginx-svc
            subset: v2
            port:
              number: 80
EOF
  • 一个虚拟服务尽量只路由一个域名,避免多个虚拟服务文件路由多个相同域名出现未知的情况。按照文件字母排序,前者会被后者覆盖。
  • 路由规则按照从上到下的顺序选择,第一条规则具有最高优先级,不满足则依次向后匹配。建议最后一个规则作为默认规则,确保至少能匹配一条路由规则。
  • host属性如果使用短名称,默认会添加与vs相同的ns的域后缀,即nginx-svc => nginx-svc.test.svc.cluster.local
  • VirtualService支持对header的增删改操作超时和重试配置操作。
  • 故障注入是一种将错误引入系统以确保系统能够承受并从错误条件中恢复的测试方法。一个路由中,故障注入和超时重试不能同时配置
  • 通过vs的weight能够很好的实现金丝雀部署(让一小部分流量引入新版本来进行测试,若顺利,则可以增加百分比来逐步替换旧版本)。更多

目标规则

提示

DestinationRule(dr):虚拟服务侧重的是如何将流量路由给定目标地址,而目标规则可以通过调整负载均衡模型、TLS 安全模式或熔断器设置来配置该目标的流量。

bash
$ kubectl -n test apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: nginx-destination-rule
spec:
  host: nginx-svc # 绑定真实的svc服务
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 100 # 最多100个请求,超过熔断
      http:
        http1MaxPendingRequests: 100
        http2MaxRequests: 100 # 最多100个请求,超过熔断,支持HTTP1.1&HTTP2
        maxRequestsPerConnection: 1 # 每个连接到后端的最大请求数,默认为0表示不限制,设置为1表示禁用keepalive
    loadBalancer:
      simple: RANDOM # 如果subset不设置负载均衡策略,那么使用此处的随机策略
  subsets:
    - name: v1
      labels:
        version: v1 # 匹配label为version=v1的pod
    - name: v2
      labels:
        version: v2
      trafficPolicy:
        loadBalancer:
          simple: LEAST_REQUEST # 请求负载最少的端点
EOF
  • dr中的host是集群中真实存在的svc服务,dr中的subset通过name与vs中的subset绑定,用于匹配符合指定标签的pod
  • dr可以设置熔断策略,针对一个服务中的单个host调用的限制(并发连接数量限制,主机调用失败限制等),使用熔断后会快速失败。更多

负载均衡策略

NameDescription
UNSPECIFIED在不显式指定策略时,将使用默认的策略。
RANDOM随机选择一个健康实例,不配置健康检查的前提下,RANDOM > ROUND_ROBIN
PASSTHROUGH把连接转发到调用者请求的原始IP地址,而不进行任何形式的负载平衡。此选项必须谨慎使用。
ROUND_ROBIN按照顺序将请求发送到每个可用的实例(更推荐LEAST_REQUEST)
LEAST_REQUEST将新的请求发送到当前请求数最少的服务实例 LEAST_REQUEST > ROUND_ROBIN
LEAST_CONN过期,使用LEAST_REQUEST代替

安全

istio安全功能提供了强大的身份、强大的策略、透明的 TLS 加密、 认证/授权/审计(AAA)工具来保护您的服务和数据。

身份

istio使用经典的service identity(服务身份)来确定一个请求源端的身份(人类用户,单个服务或一组服务)。istiod基于证书的方式为每个服务都提供身份标识,通过Envoy中的pilot-agent(istio-agent)进程实现。

istio工作架构图
  • istio-agent启动时创建私钥和CSR,将CSR和凭据发送到istiod(基于grpc接收证书签名请求)进行签名。
  • istiod CA验证CSR中携带的凭据,成功验证后签署CSR以生成证书。
  • 服务启动后,Envoy 通过 Secret 发现服务(SDS)API向同容器内的 istio-agent 发送证书和密钥请求。
  • istio-agentistiod发来的证书和密钥发送给Envoy。
  • istio-agent 监控工作负载证书的过期时间。上述过程会定期重复进行证书和密钥轮换。

认证

对等认证

提示

PeerAuthentication(pa):用于服务到服务的认证,以验证建立连接的客户端,istio默认提供了双向TLS(mTLS)解决方案。

bash
$ kubectl -n test apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: httpbin-peer-policy
spec:
  selector:
    matchLabels:
      app: httpbin # 符合label app=httpbin 的服务互相通信都使用mTLS
  mtls:
    mode: STRICT
EOF
  • 具有代理的服务间的所有流量即可启用双向TLS,无需做额外操作。启用mTLS后,会注入X-Forwarded-Client-Cert到后端的上游请求。

  • 对等认证通过selector去匹配服务,如果不指定,默认匹配命令空间下的所有服务。

  • 相同范围的多个策略和相同服务上多个策略默认采用旧的认证策略。

  • 双向TLS(mTLS)通信流程:

    • istio将出站流量从客户端重新路由到客户端的本地Envoy。
    • 客户端Envoy与服务器端Envoy开始双向TLS握手。在握手期间,客户端Envoy还做了安全命名检查,以验证服务器证书中显示的服务帐户是否被授权运行目标服务。
    • 客户端Envoy和服务器端Envoy建立了一个双向的TLS连接,istio将流量从客户端Envoy转发到服务器端Envoy。
    • 服务器端Envoy授权请求。如果获得授权,它将流量转发到通过本地TCP连接的后端服务。
  • 安全命名:将服务器身份映射到服务名称。身份A到服务名称B的映射表示"授权A运行服务B。控制平面将映射关系分发到所有服务。服务器身份被编码在证书中,客户端调用服务端时,会从服务端证书中提取身份,并检查此身份是否被允许运行对应的服务

双向TLS策略
模式含义
PERMISSIVE工作负载接受双向 TLS 和纯文本流量。用来兼容没有sidecar的服务。
STRICT工作负载仅接收双向 TLS 流量。
DISABLE禁用双向 TLS。(不推荐)

请求认证

提示

RequestAuthentication(ra):用于终端用户的认证(服务间也支持),以验证附加到请求的凭证,默认支持JWT。也可以通过自定义实现的方式支持keycloak、OAuth 2等符合openid connect规范的协议。

bash
$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: RequestAuthentication
metadata:
  name: "jwt-example"
  namespace: istio-system
spec:
  selector:
    matchLabels:
      istio: ingressgateway #绑定istio的ingressgateway
  jwtRules:
  - issuer: "testing@secure.istio.io"
    jwksUri: "https://raw.githubusercontent.com/istio/istio/release-1.20/security/tools/jwt/samples/jwks.json"
EOF
  • 请求身份验证将在istio网关上启用JWT校验,issuer对应着jwt.claims[issuer]的值,jwksUri对应着公钥的jwks地址。
  • 不携带令牌(禁止此类请求由授权控制)、携带正确令牌的请求会被接收,携带错误令牌(issuer不匹配,令牌不合法等)的请求不会被接收。更多

授权

提示

授权(AuthorizationPolicy)策略对服务器端Envoy代理的入站流量实施访问控制。每个Envoy代理都运行一个授权引擎,该引擎在运行时授权请求。当请求到达代理时,授权引擎根据当前授权策略评估请求上下文, 并返回授权结果ALLOWDENY

授权匹配流程图

授权流程图

注意

授权的匹配流程遵循CUSTOM -> DENY -> ALLOW的顺序进行评估。

bash
$ kubectl -n test apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: httpbin
  namespace: test
spec:
  selector:
    matchLabels:
      app: httpbin # 关联的服务很重要,关联谁,就是对谁控制
  action: ALLOW
  rules:
    - from:
        - source:
            principals: ["cluster.local/ns/test/sa/sleep"] # 限制了必须是集群内的访问才可以,因为需要有sa账户
    - to:
        - operation:
            paths: ["/headers"]
            # notPaths: ["/headers"] # 访问除了headers外的
            methods: ["GET"]
      when:
        - key: destination.port
          values: ["80"]
EOF
  • port == 80 && source.sa = sleep && to.paths == /headers && to.methods == "GET"? ALLOW : DENY
  • from表示请求的来源,to表示请求的操作,when表示授权规则应用所需要的条件,when添加符合,规则会被应用,否则忽略。
  • 如果namespace设置的为根目录空间(默认istio-system),那么策略会适用于所有的命令空间。
  • 授权策略中大部分字段都支持值匹配模式,即前缀匹配(*.aaa.com)、后缀匹配(abc.*)、存在匹配(["*"]即字段必须存在)
  • 授权策略支持ALLOWDENYCUSTOM操作,按照CUSTOM -> DNEY -> ALLOW的顺序进行匹配。若不匹配最终会拒绝。
  • source字段下的principals、notProncipals、namespaces、notNamespaces要先开启mTLS才能生效。
allow-nothing
bash
$ kubectl -n test apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: allow-nothing
spec:
  action: ALLOW
EOF

该策略因为没有定义rules,所以从不匹配,最终都会拒绝。若有其他允许策略匹配,则允许访问,建议默认添加

deny-all
bash
$ kubectl -n test apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: deny-all
spec:
  action: DENY
  # rules 字段有一个空白规则,策略将始终匹配。
  rules:
  - {}
EOF

该拒绝策略默认匹配所有规则,即使存在允许策略,因为DENY优先ALLOW,所以还是会被拒绝。适合临时禁止所有访问

allow-all
yaml
$ kubectl -n test apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: allow-all
spec:
  action: ALLOW
  # 这将匹配所有内容。
  rules:
  - {}
EOF

匹配所有策略,允许所有服务的访问(前提是不存在custom和deny策略)。