Istio 安全管理
· 阅读需 15 分钟
主要涉及
- 配置 TLS 网关
- mTLS
- 设置访问策略
- 认证
制作环境

# 初始化环境
kubectl get svc
#svc1
#vm2-svc
kubectl delete svc svc1
kubectl expose --name=svc1 pod pod1 --port=80
kubectl expose --name=svc2 pod pod2 --port=80
mkdir chap5 && cd chap5
cp ../chap4/mygw1.yaml ../chap4/vs.yaml ../chap4/vs2.yaml ./
cat mygw1.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: mygw
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80
name: http-1
protocol: HTTP
hosts:
- "*.yuan.cc"
cat vs.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: myvs
spec:
hosts:
- "aa.yuan.cc"
gateways:
- mygw
http:
- route:
- destination:
host: svc1
# 创建 vs
kubectl apply -f vs.yaml
mv vs2.yaml vs3.yaml
cat vs3.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: myvs3
spec:
hosts:
- "vm.yuan.cc"
gateways:
- mygw
http:
- route:
- destination:
host: vm2-svc
# 创建 vs3
kubectl apply -f vs3.yaml
cp vs.yaml vs2.yaml
cat vs2.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: myvs2
spec:
hosts:
- "bb.yuan.cc"
gateways:
- mygw
http:
- route:
- destination:
host: svc2
# 创建 vs2
kubectl apply -f vs2.yaml
客户端服务器修改hosts
vim /etc/hosts
192.168.26.230 aa.yuan.cc aa
192.168.26.230 bb.yuan.cc bb
192.168.26.230 vm.yuan.cc vm
# 测试连通
curl aa.yuan.cc #111
curl bb.yuan.cc #222
curl vm.yuan.cc #hello vm vm
为了安全性,我们更建议使用 https 访问
https ---- http + TLS (传输层加密) 在 SSL 被放弃使用后转向 TLS
- 有效的提升安全性
- 有效提升网站权重(百度/谷歌)
- 有效解决流量劫持
启用 TLS 网关
对于istio 来说,所有需要的密钥都需要放入特定的目录中
# 生成密钥对(自签发)
mkdir -p /etc/istio/ingressgateway-certs/
# 有效期为 365天,rsa算法,私钥为.key ,公钥为.crt(公钥就是证书)
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"
# 注意 :一定要放在/etc/istio/ingressgateway-certs/里
# 创建tls类型的secret
kubectl create secret tls istio-ingressgateway-certs --key /etc/istio/ingressgateway-certs/mykey.key --cert /etc/istio/ingressgateway- certs/mycrt.crt -n istio-system
# 注意:密钥名必须是 istio-ingressgateway-certs
# 创建 secret 的目录,是让isgressgateway知道有这个证书和私钥
cp mygw1.yaml mygw1-tls.yaml
vim mygw1-tls.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: mygw
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
#- port:
# number: 80
# name: http-1
# protocol: HTTP
# hosts:
# - "*.yuan.cc"
- port:
number: 443
name: https
protocol: HTTPS
hosts:
- "aa.yuan.cc"
tls:
mode: SIMPLE #简单的单项认证(客户端单项的认证服务器端)
serverCertificate: /etc/istio/ingressgateway-certs/mycrt.crt
privateKey: /etc/istio/ingressgateway-certs/mykey.key
# 客户端访问测试
curl -kv https://aa.yuan.cc
#curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to aa.yuan.cc:443
#查看istio-ingressgateway日志
kubectl get pods -n istio-system
kubectl logs istio-ingressgateway-8f747d485-g3h35 -n istio-system
#/etc/istio/ingressgateway-certs/mycrt.crt: no such file or directory
kubectl get depoly istio-ingressgateway -o yaml -n istio-system
kubectl get secrets -n istio-system
#进入容器查看
kubectl exec -it istio-ingressgateway-8f747d485-g3h35 -n istio-system -- bash
ls /etc/istio/ingressgateway-certs
# tls.crt tls.key
# 修改 mygw1-tls.yaml
vim mygw1-tls.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: mygw
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
#- port:
# number: 80
# name: http-1
# protocol: HTTP
# hosts:
# - "*.yuan.cc"
- port:
number: 443
name: https
protocol: HTTPS
hosts:
- "aa.yuan.cc"
tls:
mode: SIMPLE
#serverCertificate: /etc/istio/ingressgateway-certs/mycrt.crt
#privateKey: /etc/istio/ingressgateway-certs/mykey.key
serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
privateKey: /etc/istio/ingressgateway-certs/tls.key
# 重载 mygw1-tls.yaml
kubectl apply -f mygw1-tls.yaml
#客户端测试
curl -kv https://aa.yuan.cc # 访问通过,但是访问http是访问不通的,如果需要访问需要放行80端口,如果需要跳转需要加上 tls:httpsRedirect:
--------------------------------------------
# http 跳转 https
# 修改 mygw1-tls.yaml
vim mygw1-tls.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: mygw
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80 #放行 80 端口
name: http-1
protocol: HTTP
hosts:
- "aa.yuan.cc" #当然此处的hosts和下面的hosts也可以使用通配符,但是一般不同的三级域名会有自己的证书,不太建议这么做,比如写成 "*.yuan.cc"
tls:
httpsRedirect: true #跳转 https
- port:
number: 443
name: https
protocol: HTTPS
hosts:
- "aa.yuan.cc"
tls:
mode: SIMPLE
#serverCertificate: /etc/istio/ingressgateway-certs/mycrt.crt
#privateKey: /etc/istio/ingressgateway-certs/mykey.key
serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
privateKey: /etc/istio/ingressgateway-certs/tls.key
基于虚拟主机做 TLS
kubectl get secrets -n istio-system
kubectl delete secrts istio-ingressgateway-certs -n istio-system
# 生成证书
ls /etc/istio/ingressgateway-certs
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/istio/ingressgateway- certs/mykey22.key -out /etc/istio/ingressgateway-certs/mycrt22.crt -subj "/CN=mytest22/O=my-test22"
# 生成是generic类型的证书,不是tls证书
kubectl create secret generic istio-ingressgateway-certs \
--from-file=/etc/istio/ingressgateway-certs/mycrt.crt \
--from-file=/etc/istio/ingressgateway-certs/mykey.key \
--from-file /etc/istio/ingressgateway-certs/mycrt22.crt \
--from-file /etc/istio/ingressgateway-certs/mykey22.key -n istio-system
# 做 TLS 类型的证书的话,他只支持给一个站点提供服务
#编辑 mygw1-tls.yaml
vim mygw1-tls.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: mygw
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80
name: http-1
protocol: HTTP
hosts:
- "aa.yuan.cc"
tls:
httpsRedirect: true #跳转 https
- port:
number: 443
name: https-2
protocol: HTTPS
hosts:
- "aa.yuan.cc"
tls:
mode: SIMPLE
serverCertificate: /etc/istio/ingressgateway-certs/mycrt.crt
privateKey: /etc/istio/ingressgateway-certs/mykey.key
- port:
number: 443
name: https
protocol: HTTPS
hosts:
- "bb.yuan.cc"
tls:
mode: SIMPLE
serverCertificate: /etc/istio/ingressgateway-certs/mycrt22.crt
privateKey: /etc/istio/ingressgateway-certs/mykey22.key
# 重载 mygw-tls
kubectl apply -f mygw-tls.yaml
# 客户端测试
curl -kv https://aa.yuan.cc #可以访问
curl -kv https://bb.yuan.cc #可以访问
# 查看 gateway 证书验证
kubectl get pods -n istio-system
kubectl exec -it istio-ingressgateway-8f568d595-8cvl8 -n istio-system -- bash
ls /etc/istio/ingressgateway-certs/
# mycrt.crt mycrt22.crt mykey.key mykey22.key
cert-manager 概念及使用
使用 cert-manager 来管理证书
通过 let encrypt 去帮助我们申请证书 (免费,但只有90天有效期,需要续期)
帮助文档:
mkdir cert-m && cd cert-m
#创建 cert-manager
wget https://github.com/cert-manager/cert-manager/releases/download/v0.16.0/cert-manager.yaml
kubectl apply -f cert-manager.yaml #如果拉不到镜像,可以对对应的镜像 save 再 load 回来
kubectl get crd | grep cert
# 查看官网手册
cert-manager.io/docs/configuration/acme/dns01
# 修改DNS
# --- 登入阿里云,对域名的 DNS 服务器改为 dara.ns.cloudflare.com 和 rob.ns.cloudflare.com
# 登入 cloudflare,使用 cloudflare DNS
https://dash.cloudflare.com/
1、添加站点
2、选择 0 美元免费版
# 生成token , 添加API令牌
dash.cloudflare.com/profile/api-tokens
#创建自定义令牌 参考 cert-manager.io/docs/configuration/acme/dns01/cloudflare
创建完令牌后会给出一段令牌,需要及时保存
#创建 Secret, 编辑 mydnssecret
vim mydnssecret.yaml
apiVersion: v1
kind: Secret
metadata:
name: cloudflare-api-token-secret
type: Opaque
stringData:
api-token: <API Token> #将令牌复制到此处
#创建 secret
kubectl get ns
kubectl apply -f mydnssecret.yaml -n cert-manager
#创建 clusterissuer
kubectl get clusterissuer
# No resources found
vim ciss.yaml
apiVersion: cert-manager.io/v1alpha2
kind: ClusterIssuer
metadata:
name: letsencrypt-dns01 #用dns来审核,会比http审核的方式会方便一下
spec:
acme:
privateKeySecretRef:
name: letsencrypt-dns01
server: https://acme-v02.api.letsencrypt.org/directory #通过此站点访问
solvers:
- dns01:
cloudflare:
email: my-cloudflare-acc@example.com
apiTokenSecretRef:
key: api-token #此处value即为secret的stringData所对应的api-token,名字保持一致
name: cloudflare-api-token-secret #和secret的name保持一致
#启动
kubectl apply -f ciss.yaml
kubectl get clusterissuer
#letsencrypt-dns01 True
# 开始申请证书
kubectl get certificate
# www-ck8s-com True www-ck8s-com-tls
kubectl get secrets www-ck8s-com-tls -o yaml #可以看到证书的相关信息
kubectl get secrets www-ck8s-com-tls -o jsonpath='{.data.tls\.crt}' | base64 -d > mycertx.crt
kubectl get secrets www-ck8s-com-tls -o jsonpath='{.data.tls\.key}' | base64 -d > mycertx.key
cp mycertx.crt mycertx.key /etc/istio/ingressgateway-certs/
# 删除原来的 tls 证书
kubectl delete secrets istio-ingressgateway-certs -n istio-system
# 生成证书
kubectl create secret generic istio-ingressgateway-certs --from-file=/etc/istio/ingressgateway-certs/mycertx.crt --from-file=/etc/istio/ingressgateway-certs/mykeyx.key -n istio-system
vim vs.yaml
spec:
hosts:
- "www.ck8s.com"
vim mygw1-tls.yaml
servers:
- port:
number: 80
name: http-1
protocol: HTTP
hosts:
- "www.ck8s.com"
tls:
httpsRedirect: true #跳转 https
- port:
number: 443
name: https-2
protocol: HTTPS
hosts:
- "www.ck8s.com"
tls:
mode: SIMPLE
serverCertificate: /etc/istio/ingressgateway-certs/mycertx.crt
privateKey: /etc/istio/ingressgateway-certs/mykeyx.key
kubectl apply -f vs.yaml
kubectl apply -f mygw1-tls.yaml
# 内网测试机 本机修改 hosts 文件 192.168.26.230 www.ck8s.com www
浏览器访问 www.ck8s.com ,显示https 并且没有显示警告不安全
# 将 vs hosts 恢复为之前的


mTLS认证 PeerAuthentication
mTLS (mutual TLS,双向TLS): 让客户端和服务器端通信的时候都必须进行TLS认证
默认情况下,在网格内部 默认启用了mTLS 了。
PERMISSIVE:工作负载接受双向 TLS 和纯文本流量。
当没有 Sidecar 的工作负载无法使用双向 TLS 时,此模式适合用在迁移过程。
通过使用 sidecar 注入迁移工作负载后,应该将模式切换为 STRICT。
STRICT:工作负载仅接受双向 TLS 通信。
### 测试没有添加 mTLS
# 编辑 vs yaml
vim vs.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: myvs
spec:
hosts:
- "aa.yuan.cc"
- "svc1" #添加
gateways:
- mygw
http:
- route:
- destination:
host: svc1
# 重载 vs yaml
kubectl apply -f vs.yaml
kubectl get pods -n default # 没有被注入的pod
#podx 1/1 Running
kubectl exec -it podx -n default -- bash
curl svc1.ns1 #返回111,代表网格之外现在也可以被访问
111
--------------------------------------------------------
### 测试添加 mTLS,如果没有在网格里的 pod 是不能访问的
vim mtls1.yaml
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
spec:
mtls:
mode: STRICT #仅接受双向 TLS 通信
# 创建 mtls
kubectl get PeerAuthentication
# No resources found in ns1 namespace
kubectl apply -f mtls1.yaml
#网格外 pod 测试
kubectl exec -it podx -n default -- bash
curl svc1.ns1 #访问不通的
# curl: (56) Recv failure: COnnection reset by peer
# istio 对 podx 进行注入,加入网格内在进行测试
kubectl delete pod podx -n default
istioctl kube-inject -f podx.yaml | kubectl apply -f - -n default
kubectl get pods -n default
#podx 2/2 Running
kubectl exec -it podx -n default -- bash
curl svc1.ns1 #访问的通了,返回111
# 111
单pod设置mTLS
#把网格内的 podx 去除
kubectl delete pod podx -n default
kubectl apply -f podx.yaml -n default
kubectl exec -it podx -n default -- bash
curl svc1.ns1
#curl: (56) Recv failure: Connection reset by peer
#创建namespace ns2,给 ns2 添加 istio 标签
kubectl create ns ns2
kubectl get ns --show-labels
#ns1 istio-injection=enabled.kubernetes.io/metadata.name=ns1
#ns2 kubernetes.io/metadata.name=ns2
kubectl label ns ns2 istio-injection=enabled
# 创建 ns2 内的 podx,svc2 ,让 default 中的 podx 访问测试
kubectl apply -f podx.yaml -n ns2
kubectl get pods -n ns2
#podx 2/2 Running
kubectl expose --name=svc2 pod podx --port=80 -n ns2
#default podx进行测试
kubectl exec -it podx -n default -- bash
curl svc2.ns2 #返回 nginx 页面,访问连通
#清理下环境
kubectl delete pod podx -n ns2
kubectl delete svc svc2 -n ns2
------------------------------------------------------------
# 修改 mtls,针对单 pod 设置 mTLS
vim mtls1.yaml
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
spec:
selector:
matchLabels:
run: pod1 #只应用与 pod1 上,与 pod1 通信时必须通过 mTLS
mtls:
mode: STRICT #仅接受双向 TLS 通信
# 修改 mtls,针对单 pod 设置 mTLS,放行某端口,对某端口可以不建立 mTLS
vim mtls1.yaml
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
spec:
selector:
matchLabels:
run: pod1 #只应用与 pod1 上,与 pod1 通信时必须建立 mTLS
mtls:
mode: STRICT #或者此处可以改为PERMISSIVE
portLevelMtls:
80:
mode: DISABLE # 和端口80通信可以不需要 mTLS