1. 简介

mTLS (mutual TLS,双向TLS): 让客户端和服务器端通信的时候都必须进行TLS认证
默认情况下,在网格内部默认启用了mTLS了。

2. 启用tls网关

2.1 创建私钥

1
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/istio/ingressgateway-certs/mykey.key -out /etc/istio/ingressgateway-certs/mycrt.crt -subj "/CN=mytest/O=my-test"

2.2 创建secret

1
kubectl create secret generic istio-ingressgateway-certs --from-file /etc/istio/ingressgateway-certs/mykey.key --from-file /etc/istio/ingressgateway-certs/mycrt.crt -n istio-system

2.3 创建gateway

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: mygw
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "aa.rhce.cc"
- "bb.rhce.cc"
- "demoapp.rhce.cc"
tls:
httpsRedirect: true
- port:
number: 443
name: https
protocol: HTTPS
hosts:
- "aa.rhce.cc"
tls:
mode: SIMPLE
serverCertificate: /etc/istio/ingressgateway-certs/mycrt.crt
privateKey: /etc/istio/ingressgateway-certs/mykey.key

3. PeerAuthentication

用于设置别人在和网格里的pod进行通信的时候,是否要求mTLS

3.1 默认策略

1
2
3
4
5
6
7
8
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
spec:
mtls:
#mode: PERMISSIVE
mode: STRICT

PERMISSIVE:工作负载接受双向TLS和纯文本流量,当没有Sidecar的工作负载无法使用双向TLS时,此模式适合用在迁移过程。
通过使用sidecar注入迁移工作负载后,应该将模式切换为STRICT。
STRICT:工作负载仅接受双向TLS通信。

3.2 选择性策略

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
spec:
selector:
matchLabels:
run: pod1
mtls:
mode: STRICT
portLevelMtls:
80:
mode: DISABLE

4. 授权管理AuthorizationPolicy

设置的是允许哪些客户端允许过来访问,功能类似k8s networkpolicy

拒绝优先级 > 允许优先

4.1 默认拒绝

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

这里就拒绝掉了所有的,虽然这里没有指定是允许还是拒绝,但是是拒绝的意思。
默认是拒绝的意思,且优先级最低

4.2 允许访问pod1

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-pod1
namespace: ns1
spec:
selector:
matchLabels:
run: pod1
action: ALLOW
rules:
- {}

一旦设置了允许,那么没有允许的也会被拒绝。这种写了action: DENY,然后在rules里写了{},则是拒绝所有的,这种优先级最高,其他的allow都不会在生效

4.3 基于名称空间过滤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-pod1
namespace: ns1
spec:
selector:
matchLabels:
run: pod2
action: ALLOW
rules:
- from:
- source:
namespaces:
- ns2

4.4 基于sa过滤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-pod1
namespace: ns1
spec:
selector:
matchLabels:
run: pod2
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/ns1/sa/default"]

4.5 基于IP地址过滤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-pod1
namespace: ns1
spec:
selector:
matchLabels:
run: pod2
action: ALLOW
rules:
- from:
- source:
ipBlocks:
- "0.0.0.0/0"

ipBlocks: 允许的IP通信
notIpBlocks: 拒绝的ip

4.6 基于头部信息过滤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-pod1
namespace: ns1
spec:
selector:
matchLabels:
run: pod2
action: ALLOW
rules:
- from:
- source:
remoteIpBlocks:
- "192.168.26.23"

remoteIpBlocks: 允许的IP通信
notRemoteIpBlocks: 拒绝的ip

只有指定了X-Forwarded-For头部信息才可以访问

4.7 限制请求方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-pod1
namespace: ns1
spec:
selector:
matchLabels:
run: pod2
action: ALLOW
rules:
- to:
- operation:
methods: ["GET"]
hosts:
- "svc2"
paths:
- /demo1/*

4.8 when语句

when和from这些是或的关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-pod1
namespace: ns1
spec:
selector:
matchLabels:
run: pod2
action: ALLOW
rules:
- when:
- key: request.headers[test]
values:
- "test"

4.9 JWT过滤

JWT全称: Json Web Token
本质就是类似用户名和密码,客户端访问的时候,必须要提供这些token信息,不然访问不了。
这个token有固定的格式,采用JWK/JWKs格式的。
JWK: Json Web Key
JWKs :JWK set

4.9.1 生成token

生成公钥和私钥

1
2
openssl genrsa -out key.pem 2048
openssl rsa -in key.pem -pubout -out pub.pem

生成JWKs信息

1
2
3
4
yum install boost-python36.x86_64 python3-pip.noarch
pip3 install --upgrade pip
pip3 install jwt
pip3 install ipython jwcr

脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/python3
#-*- coding: UTF-8 -*-
from jwcrypto.jwk import JWK
from pathlib import Path
private_key = Path("key.pem
").read_bytes()
jwk = JWK.from_pem(private_key)
# 导出公钥 RSA Public Key
public_key = jwk.public().export_to_pem()
print(public_key)
print("="*30)
# 导出 JWK
jwk_bytes = jwk.public().export()
print(jwk_bytes)

或在线生成 https://8gwifi.org/jwkconvertfunctions.jsp

4.9.2 创建ra

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: "security.istio.io/v1beta1"
kind: "RequestAuthentication"
metadata:
name: "productpage"
spec:
selector:
matchLabels:
run: pod1
jwtRules:
- issuer: "testing@secure.istio.io"
jwks: |
{ "keys":
[
{
"e":"AQAB",
"kid":"85d3c3fe-5c86-4482-a165-9b66dc3773c3",
"kty":"RSA",
"n":"ucu4hlGJFdEw4rLW1hmVCa_sHcAyKrHnBxtFYGUVVLvUBAGZ1pgU2YOmtTDoN5rrew_4-511U1q4IYmWKiwNjt-4-JLR7auTH8L_GIcpUh8LO77i8btsbExV7hduHc1ewiOI8fgTUQ4sADiLb-_hnZTYaAJTpNOVZKcyIakNo7rNTXFzaArKVp88GMZMIq6f9R2f-Sd-Hh70aMzwUFAA3bpWxRQYdYrQschKnBceVLNKXtXjQA0MZnb-dq6sjiVmkp0a20GBs8-ib-mIZROkM8Mno9mu4DXZVu0GLJRUwU_puwMZ6hQqB8ucsS0l2xMJtc_2uL05f-Vd5V9JLAdzJw"
}
]
}

4.9.3 创建AuthorizationPolicy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-pod1
namespace: ns1
spec:
selector:
matchLabels:
run: pod2
action: ALLOW
rules:
- from:
- source:
requestPrincipals: ["testing@secure.istio.io/testing@secure.istio.io"]