概述
Istio 为运行于不可信环境内的服务网格提供了无须代码侵入的安全加固能力。微服务改造之后,在流量、监控等基本业务目标之外,安全问题也要引起重视。
原本在单体应用内通过进程内访问控制框架完成的任务,被分散到各个微服中;在容器集群中还可能出现不同命名空间及不同业务域的互访问题。
Istio中也提供了无侵入的安全解决方案,能够提供网格内部、网格和边缘之间的安全通信和访问控制能力。
- Citadel 提供证书和认证管理功能;
- Sidecar 建立加密通道,为其代理的应用进行协议升级,为客户端和服务端之间提供基于 mTLS 的加密通信;
- Pilot 负责传播加密身份和认证策略。
实战
测试默认访问
# http http://httpbin:8000/get
HTTP/1.1 200 OK
access-control-allow-credentials: true
access-control-allow-origin: *
content-length: 423
content-type: application/json
date: Wed, 15 Jul 2020 07:19:59 GMT
server: envoy
x-envoy-upstream-service-time: 343
{
"args": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Content-Length": "0",
"Host": "httpbin:8000",
"User-Agent": "HTTPie/2.1.0",
"X-B3-Parentspanid": "18d852cdd8dd75f1",
"X-B3-Sampled": "0",
"X-B3-Spanid": "b15acfa72373229e",
"X-B3-Traceid": "f3146b46ba6fc96f18d852cdd8dd75f1"
},
"origin": "127.0.0.1",
"url": "http://httpbin:8000/get"
}
启用 mTLS
apiVersion: "authentication.istio.io/v1alpha1"
kind: "MeshPolicy"
metadata:
name: "default"
spec:
peers:
- mtls: {}
测试默认访问
http http://httpbin:8000/get
HTTP/1.1 503 Service Unavailable
content-length: 57
content-type: text/plain
date: Wed, 15 Jul 2020 07:32:51 GMT
server: envoy
upstream connect error or disconnect/reset before headers
所有的服务端 Sidecar 都只接受 mTLS 客户端的接人,客户端 DestinationRule 对象来显式声明这个接人要求:
apiVersion: "networking.istio.io/v1alpha3"
kind: "DestinationRule"
metadata:
name: "httpbin"
spec:
host: "httpbin.default.svc.cluster.local"
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
接入dr客户端测试结果:
http http://httpbin:8000/get
HTTP/1.1 200 OK
access-control-allow-credentials: true
access-control-allow-origin: *
content-length: 708
content-type: application/json
date: Wed, 15 Jul 2020 08:28:36 GMT
server: envoy
x-envoy-upstream-service-time: 37
{
"args": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Content-Length": "0",
"Host": "httpbin:8000",
"User-Agent": "HTTPie/2.1.0",
"X-B3-Parentspanid": "4ac341b2375f5855",
"X-B3-Sampled": "0",
"X-B3-Spanid": "ed42d2b48f4873b0",
"X-B3-Traceid": "e7f321984fc7b4524ac341b2375f5855",
"X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/27a89b94b77f459e81a6010905c33a1e-book2mesh/sa/default;Hash=0861af59ac9db940e67ed01281692b0862568ba08368dd7381ca9f89e532053c;Subject=\"\";URI=spiffe://cluster.local/ns/27a89b94b77f459e81a6010905c33a1e-book2mesh/sa/default"
},
"origin": "127.0.0.1",
"url": "http://httpbin:8000/get"
}
设置 RBAC
为所有default 命名空间中的服务都启动 RBAC 策略:
apiVersion: "rbac.istio.io/v1alpha1"
kind: RbacConfig
metadata:
name: default
spec:
mode: "ON_WITH_INCLUSION"
inclusion:
namespaces: ["default"]
再次启动测试:
HTTP/1.1 403 Forbidden
content-length: 19
content-type: text/plain
date: Wed, 15 Jul 2020 08:55:57 GMT
server: envoy
x-envoy-upstream-service-time: 25
RBAC: access denied
RBAC 启动之 后,在默认情况下,所有服务的调用都会被拒绝。
一般来 说, RBAC 系统中的授权过程都是通过以下几步进行设置的:
-( 1)在系统中定义原子粒度的权限;
-( 2)将一个或者多个权限组合为角色
-( 3)将角色和用户进行绑定 ,从而让用 户具备绑定的角色所 拥有的权限
设置service role:
定义service-viewer 角色,在 rules 字段中进行授权,允许该角色使用 GET 方法访问所有服务。
apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRole
metadata:
name: service-viewer
spec:
rules:
- services:
- "*"
methods:
- "GET"
将上面的角色绑到所有 default 命名空间的ServiceAccount 上:
apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRoleBinding
metadata:
name: bind-service-viewer
spec:
subjects:
- properties:
source.namespace: "default"
roleRef:
kind: ServiceRole
name: "service-viewer"
subject 用了一个属性限制来指定绑定目标:所有来自 default 命名空间的调用者的用 户都被绑定 service viewer 这个角色上。
测试结果:
http http://httpbin:8000/ip
HTTP/1.1 200 OK
access-control-allow-credentials: true
access-control-allow-origin: *
content-length: 28
content-type: application/json
date: Wed, 15 Jul 2020 09:45:14 GMT
server: envoy
x-envoy-upstream-service-time: 6
{
"origin": "127.0.0.1"
}
测试有没有授权的 POST 方法:
http -f POST http http://httpbin:8000/post name=vincent
HTTP/1.1 404 Not Found
connection: close
content-length: 0
date: Wed, 15 Jul 2020 09:47:43 GMT
server: envoy