1. Istio 身份标识

身份是任何安全基础设施的基本概念。在工作负载到工作负载的通信开始时,双方必须交换凭据及其身份信息,以实现相互身份验证的目的。

Istio标识模型使用一流的服务标识来确定请求源的标识。此模型允许极大的灵活性和粒度,以便将服务标识表示为一个人工用户、单个工作负载或一组工作负载。在没有服务标识的平台上,Istio可以使用可以对工作负载实例进行分组的其他标识,例如服务名称。

下面的列表显服务标识,可以用于不同的平台

  • Kubernetes: Kubernetes service account

  • GKE/GCE: GCP service account

  • AWS: AWS IAM user/role account

  • On-premises (non-Kubernetes): user account, custom service account, service name, Istio service account, or GCP service account. The custom service account refers to the existing service account just like the identities that the customer’s Identity Directory manages.

2. 认证

Istio提供两种类型的认证:

  • peer authentication: 常常用服务到服务的认证来校验客户端的连接。 Istio提供了双向的TLS针对透明的认证作为全栈的解决方案,在开启此功能时不需要在代码层面做出改变。这个解决方案是:

    • 针对每个服务附加了强有力的身份标识代表它的角色, 去和集群和云进行交互。
    • 服务到服务间的通信是安全的。
    • 提供了个key管理系统去自动的证书生成、分布、自转。
  • Request authentication: 针对终端用户去校验关联到请求的证书。 Istio使用JSON Web Token(JWT)去开启请求级别的认证校验和使用自定义的认证提供者来或者OpenID 连接的供应者。

    • ORY Hydra
    • Keycloak
    • AuthO
    • Firebase Auth
    • Google Auth

在所有的案例中,Istio通过自定义的Kubernetes API在istio config store存储认证策略。Istiod针对每个代理保持它们是最新的。此外,Istio支持在许可模式下的身份验证,以帮助您理解策略更改如何在实施之前影响您的安全状态。

2.1 双向TLS认证

Istio通过客户端和服务器端PEPs实现服务到服务的通信,这些PEPs实现为envoy代理。当一个工作负载使用相互TLS身份验证向另一个工作负载发送请求时,请求处理如下:

  1. Istio从一个客户端到本地sidecar Envoy的客户端重新路由外部流量。

  2. 客户端的Envoy开如和服务器端的Envoy开始双向的TLS握手。在握手期间,客户端Envoy还执行安全命名检查,以验证服务器证书中提供的服务帐户是否被授权运行目标服务。

  3. 客户端envoy和服务器端envoy建立一个相互的TLS连接,并将通信从客户端envoy转发到服务器端envoy。

  4. 授权之后,服务器端envoy通过本地TCP连接将通信转发到服务器服务。

2.2 允许模式

Istio mutual TLS有一个允许模式,它允许一个服务同时接受纯文本流量和相互TLS流量。这个特性极大地改进了相互的TLS使用体验。

许多与非Istio服务器通信的非Istio客户端会给希望在启用相互TLS的情况下将该服务器迁移到Istio的操作人员带来问题。通常,操作员不能同时为所有客户端安装Istio sidecar,或者甚至没有权限在某些客户端上安装Istio sidecar。即使在服务器上安装了Istio sidecar,操作员也不能在不破坏现有通信的情况下启用相互TLS。

在启用许可模式后,服务器同时接受纯文本和相互的TLS通信。该模式为进入的流量提供了更大的灵活性。服务器安装的Istio sidecar立即接受相互的TLS流量,而不会破坏现有的明文流量。因此,操作员可以逐渐安装和配置客户端的Istio sidecars来发送相互的TLS流量。一旦客户端配置完成,操作员就可以将服务器配置为只有TLS模式。

2.3 认证策略

本节提供有关Istio身份验证策略如何工作的更多细节。正如您将在体系结构部分中所记得的,身份验证策略适用于服务接收到的请求。要在相互的TLS中指定客户端身份验证规则,需要在DestinationRule中指定TLSSettings。

与其他Istio配置一样,可以在.yaml文件中指定身份验证策略。使用kubectl部署策略。下面的示例身份验证策略指定使用app传输工作负载的身份验证:reviews标签必须使用相互TLS:

  1. apiVersion: "security.istio.io/v1beta1"
  2. kind: "PeerAuthentication"
  3. metadata:
  4. name: "example-peer-policy"
  5. namespace: "foo"
  6. spec:
  7. selector:
  8. matchLabels:
  9. app: reviews
  10. mtls:
  11. mode: STRICT

2.4 选择字段

对等和请求身份验证策略使用选择器字段指定策略应用到的工作负载的标签。下面的示例显示了一个策略的选择器字段,该策略应用于带有app的工作负载:product-page label:

  1. selector:
  2. matchLabels:
  3. app: product-page

如果没有为选择器字段提供值,则Istio会将策略匹配到策略存储范围内的所有工作负载。因此,选择器字段可以帮助您指定策略的范围:

  • 网络范围策略:为根命名空间指定的策略,没有或带有空选择器字段。

  • 名称空间范围策略:为非根名称空间指定的策略,没有或带有空选择器字段。

  • 指定的工作流策略:在常规命名空间中定义的策略,具有非空的选择器字段。

对于选择器字段,对等和请求身份验证策略遵循相同的层次结构原则,但是Istio以略微不同的方式组合和应用它们。

每个名称空间只能有一个网格范围的对等身份验证策略,每个名称空间只能有一个名称空间范围的对等身份验证策略。当您为同一个网格或名称空间配置多个网格或名称空间范围的对等身份验证策略时,Istio将忽略较新的策略。当多个特定于工作负载的对等身份验证策略匹配时,Istio将选择最老的策略。

对于Istio,对等和请求身份验证策略遵循相同的层次结构原则,使用以下顺序为每个工作负载应用最窄匹配策略:

  • 指定的工作流

  • 指定的名称空间

  • 网络范围

Istio可以组合所有匹配的请求身份验证策略,就像它们来自单个请求身份验证策略一样。因此,在一个网格或名称空间中可以有多个网格级或名称空间级策略。但是,避免使用多个网格范围或名称空间范围的请求身份验证策略仍然是一个很好的实践。

2.5 对等认证

对等身份验证策略指定目标工作负载上的相互TLS模式。支持以下模式:

  • 允许: 工作负载同时接受相互的TLS和纯文本流量。当没有sidecar的工作负载无法使用相互TLS时,这种模式在迁移期间非常有用。使用sidecar注入迁移工作负载之后,应该将模式切换到STRICT。

  • 严格: 工作流仅接受双向的TLS流量

  • 关闭: 双向TLS被禁用。从安全角度看,除非您提供自己的安全解决方案,否则不应该使用此模式。

当模式未设置时,父范围的模式将被继承。具有未设置模式的网格级对等身份验证策略默认使用许可模式。

下面的对等认证策略请求在名称空间foo中使用双向TLS认证策略。

  1. apiVersion: "security.istio.io/v1beta1"
  2. kind: "PeerAuthentication"
  3. metadata:
  4. name: "example-policy"
  5. namespace: "foo"
  6. spec:
  7. mtls:
  8. mode: STRICT

使用特定于工作负载的对等身份验证策略,您可以为不同的端口指定不同的相互TLS模式。您只能使用工作负载为端口范围的相互TLS配置声明的端口。下面的示例禁用了应用程序在端口80上的相互TLS:example-app 工作负载,并对所有其他端口使用名称空间范围的对等身份验证策略的相互TLS设置:

  1. apiVersion: "security.istio.io/v1beta1"
  2. kind: "PeerAuthentication"
  3. metadata:
  4. name: "example-workload-policy"
  5. namespace: "foo"
  6. spec:
  7. selector:
  8. matchLabels:
  9. app: example-app
  10. portLevelMtls:
  11. 80:
  12. mode: DISABLE

上面的对等身份验证策略之所以有效,是因为下面的服务配置将来自example-app工作负载的请求绑定到example-service的80端口:

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: example-service
  5. namespace: foo
  6. spec:
  7. ports:
  8. - name: http
  9. port: 8000
  10. protocol: TCP
  11. targetPort: 80
  12. selector:
  13. app: example-app

3. 授权

Istio的授权特性为网格中的工作负载提供了网格、名称空间和工作负载范围的访问控制。这种程度的控制提供了以下好处:

  • 工作流到工作流和终端用户到工作流的授权

  • 一个简单的API: 它包含一个单一的授权策略CRD, 这可以简单的使用和维护。

  • 灵活的语义: 在istio属性中,操作员可以自定义条件,和使用DENY和ALLOW动作。

  • 高性能:Istio的授权在Envoy中天生强制性的。

  • 高兼容性: 支持gRPC,HTTP,HTTPS和HTTP2

3.1 授权的策略

去配置一个授权策略,你创建一个自定义资源的授权策略。一个授权策略包含一个选择器,一个运作和一系列的规则。

  • selector字段指定了策略的目标

  • action字段指定了允许还是拒绝

  • rules指定了什么时候触发动作

  • rules中的from字段指定了请求的源

  • rules中的to字段指定了请求的操作

  • when字段指定了应用规则的条件

下面的案例演示了一个授权的策略,它允许两个源: cluster.local/ns/default/sa/sleep服务帐户和dev名称空间,去访问在foo名称空间中带有app: httpbinversion: v1标签的app。 当请求含 有有效的JWT token时执行。

  1. apiVersion: security.istio.io/v1beta1
  2. kind: AuthorizationPolicy
  3. metadata:
  4. name: httpbin
  5. namespace: foo
  6. spec:
  7. selector:
  8. matchLabels:
  9. app: httpbin
  10. version: v1
  11. action: ALLOW
  12. rules:
  13. - from:
  14. - source:
  15. principals: ["cluster.local/ns/default/sa/sleep"]
  16. - source:
  17. namespaces: ["dev"]
  18. to:
  19. - operation:
  20. methods: ["GET"]
  21. when:
  22. - key: request.auth.claims[iss]
  23. values: ["https://accounts.google.com"]

下面案例展示了一个假如源不是foo名称空间的请求的话,直接拒绝的案例

  1. apiVersion: security.istio.io/v1beta1
  2. kind: AuthorizationPolicy
  3. metadata:
  4. name: httpbin-deny
  5. namespace: foo
  6. spec:
  7. selector:
  8. matchLabels:
  9. app: httpbin
  10. version: v1
  11. action: DENY
  12. rules:
  13. - from:
  14. - source:
  15. notNamespaces: ["foo"]

拒绝策略的优先级大于允许策略的。

3.2 策略的目标

可以指定策略的范围或目标,由metadata/namespace字段和可选selector字段确定。策略应用于metadata/namespace字段tell中的名称空间。如果将其值设置为根名称空间,则策略将应用于网格中的所有名称空间。根名称空间的值是可配置的,默认值是istio -system。如果设置为任何其他名称空间,则策略仅适用于指定的名称空间。

你可以使用selector字段更进一步的限制策略应用于指定的工作流。 selector使用标签去选择目标工作流。selector包含一个{key: value} 对, key是标签的名称,假如没有设置。 这个授权策略将会应用于授权策略所在的所有名称空间。

比如,allow-red策略允许"GET""HEAD"访问在默认名称空间中带有app:products的工作流。

  1. apiVersion: security.istio.io/v1beta1
  2. kind: AuthorizationPolicy
  3. metadata:
  4. name: allow-read
  5. namespace: default
  6. spec:
  7. selector:
  8. matchLabels:
  9. app: products
  10. action: ALLOW
  11. rules:
  12. - to:
  13. - operation:
  14. methods: ["GET", "HEAD"]

3.3 值的匹配

在授权策略中大多数字段支持所有的下列匹配架构:

  • 精确匹配:精确匹配字符

  • 前辍匹配: 一个字符后紧跟着"*"字符,比如"test.abc.*"匹配"test.abc.com", "test.abc.com.cn","test.abc.org"

  • 后辍匹配: 一个以"*"开头的字符,比如"*.abc.com"匹配"eng.abc.com","test.eng.abc.com"

  • 存在的匹配:*往往用于指定任何事情,但不是空。 也就是说必须有一个字段存在, 使用fieldnaem: ["*"].这和不指定字段是有很大的区别的,不指定字段代表着匹配所有,包容空。

也有几个例外,比如,下面的几个字段仅支持精确匹配:

  • when范围下的key字段

  • source范围下的ipBlocks.

  • to 范围下的ports字段。

下面案例策略允许 访问/test/*为前辍的或*/info为后辍的路径。

  1. apiVersion: security.istio.io/v1beta1
  2. kind: AuthorizationPolicy
  3. metadata:
  4. name: tester
  5. namespace: default
  6. spec:
  7. selector:
  8. matchLabels:
  9. app: products
  10. action: ALLOW
  11. rules:
  12. - to:
  13. - operation:
  14. paths: ["/test/*", "*/info"]

3.4 排除匹配

匹配像when字段中的notValues这样的负条件,可以在source字段中使用notIpBlocks,在To字段中使用notPorts, Istio支持排除匹配。下面的示例需要一个有效的请求主体,如果请求路径不是/healthz,则该主体派生自JWT身份验证。因此,该策略从JWT身份验证中排除了对/healthz路径的请求:

  1. apiVersion: security.istio.io/v1beta1
  2. kind: AuthorizationPolicy
  3. metadata:
  4. name: disable-jwt-for-healthz
  5. namespace: default
  6. spec:
  7. selector:
  8. matchLabels:
  9. app: products
  10. action: ALLOW
  11. rules:
  12. - to:
  13. - operation:
  14. notPaths: ["/healthz"]
  15. from:
  16. - source:
  17. requestPrincipals: ["*"]

下面的示例拒绝对没有请求主体的请求的/admin路径的请求:

  1. apiVersion: security.istio.io/v1beta1
  2. kind: AuthorizationPolicy
  3. metadata:
  4. name: enable-jwt-for-admin
  5. namespace: default
  6. spec:
  7. selector:
  8. matchLabels:
  9. app: products
  10. action: DENY
  11. rules:
  12. - to:
  13. - operation:
  14. paths: ["/admin"]
  15. from:
  16. - source:
  17. notRequestPrincipals: ["*"]

3.5 允许所有和默认拒绝所有的授权策略

下面案例展示了一个简单的允许所有授权策略,允许在默认的名称空间所有的访问到所有的工作流。

  1. apiVersion: security.istio.io/v1beta1
  2. kind: AuthorizationPolicy
  3. metadata:
  4. name: allow-all
  5. namespace: default
  6. spec:
  7. action: ALLOW
  8. rules:
  9. - {}

下面的案例展现了一个策略,它不允许任何访问在admin名称空间的所有工作流。

  1. apiVersion: security.istio.io/v1beta1
  2. kind: AuthorizationPolicy
  3. metadata:
  4. name: deny-all
  5. namespace: admin
  6. spec:
  7. {}

3.6 自定义条件

可以使用when去指定附加条件,比如,下面的AuthorizationPolicy 定义了包含一个条件。比如,下面的AuthorizationPolicy定义包含了一个条件,request.headers[version]为”v1”或者”v2”.

  1. apiVersion: security.istio.io/v1beta1
  2. kind: AuthorizationPolicy
  3. metadata:
  4. name: httpbin
  5. namespace: foo
  6. spec:
  7. selector:
  8. matchLabels:
  9. app: httpbin
  10. version: v1
  11. action: ALLOW
  12. rules:
  13. - from:
  14. - source:
  15. principals: ["cluster.local/ns/default/sa/sleep"]
  16. to:
  17. - operation:
  18. methods: ["GET"]
  19. when:
  20. - key: request.headers[version]
  21. values: ["v1", "v2"]

3.7 认证和非认证的标识

如果您希望将工作负载公开为可访问的,则需要将source部分保留为空。例如,这允许来自所有(通过身份验证和未经身份验证)用户和工作负载的源

  1. apiVersion: security.istio.io/v1beta1
  2. kind: AuthorizationPolicy
  3. metadata:
  4. name: httpbin
  5. namespace: foo
  6. spec:
  7. selector:
  8. matchLabels:
  9. app: httpbin
  10. version: v1
  11. action: ALLOW
  12. rules:
  13. - to:
  14. - operation:
  15. methods: ["GET", "POST"]

仅允许认证的用户,设置principals*代替,比如

  1. apiVersion: security.istio.io/v1beta1
  2. kind: AuthorizationPolicy
  3. metadata:
  4. name: httpbin
  5. namespace: foo
  6. spec:
  7. selector:
  8. matchLabels:
  9. app: httpbin
  10. version: v1
  11. action: ALLOW
  12. rules:
  13. - from:
  14. - source:
  15. principals: ["*"]
  16. to:
  17. - operation:
  18. methods: ["GET", "POST"]

3.8 在文本TCP协议上使用Istio授权

Istio授权支持使用任何普通TCP协议(如MongoDB)的工作负载。在本例中,您将使用与配置HTTP工作负载相同的方式配置授权策略。不同之处在于某些字段和条件只适用于HTTP工作负载。这些字段包括

  • 授权策略对象的source章节中的request_principals 字段。

  • 授权策略对象的operation章节的hosts,methods,paths字段。

假设你有一个MongoDB服务,使用的端口27017, 下面的案例配置一个授权策略,仅允许在istio网格的bookinfo-ratings-v2服务去访问MongoDB工作流。

  1. apiVersion: "security.istio.io/v1beta1"
  2. kind: AuthorizationPolicy
  3. metadata:
  4. name: mongodb-policy
  5. namespace: default
  6. spec:
  7. selector:
  8. matchLabels:
  9. app: mongodb
  10. action: ALLOW
  11. rules:
  12. - from:
  13. - source:
  14. principals: ["cluster.local/ns/default/sa/bookinfo-ratings-v2"]
  15. to:
  16. - operation:
  17. ports: ["27017"]

3.9 依靠于双向的TLS

Istio使用双向的TLS去从客户端到服务器间安全的传输一些信息。 在授权策略中使用任何下列字段之前,双向TLS必须开启。

  • source部分的principals字段

  • source部分的namespaces字段

  • source.principals自定义条件

  • source.namespace 自定义条件

  • connection.sni 自定义条件

假如你不在授权策略中使用上面所说的字段,那么可以不用开启双向TLS.