Istio的mTLS认证

一、理解mTLS
TLS在web端使用的非常广泛,针对传输的内容进行加密,能够有效的防止中间人攻击。双向TLS(Two way TLS/Mutual TLS,简称mTLS)的主要使用场景是在B2B和Server-toServer的场景中,以支持服务与服务之间的身份认证与授权。
在这里插入图片描述

在这里插入图片描述
mTLS主要负责服务与服务之间传输层面的认证,具体实现在sidecar中,在具体进行请求时,讲经历如下过程:
1)客户端发出的请求将被发送到客户端sidecar
2)客户端sidecar与服务端sidecar开始mTLS握手,在握手的同时,客户端sidecar讲进行secure naming check的额外操作,对服务端中的server identity(存储在证书中的SAN)进行检查,以确保其能够运行服务,该操作能够防止一些常见HTTP/TCP的流量劫持攻击。
3)在完成身份认证以及授权之后,客户端和服务端开始建立连接进行通信
在这里插入图片描述
Istio提供如下几种mTLS身份认证模式,在不同的场景下进行使用:
1)PERMISSIVE:同时支持密文传输和明文传输,则不管是在Istio管理下的Pod还是在Istio管理外的Pod,相互之间的通信畅通无阻。PERMISSIVE模式的主要用途是在用户迁移的过程中,服务与服务之间也仍然能够通信,例如部分workload并未注入sidecar。对于刚接触Istio的人来说是非常友好的,官方也建议在完成迁移之后调整为STRICT模式
2)STRICT:workload只支持密文传输
3)DISABLE:关闭Mutual TLS,从安全的角度而言,官方不建议在没有其他安全措施的情况下使用该模式
4)UNSET:具体的策略将从父级配置中继承(命名空间或网络层面),如果父级没有进行相应的配置,则使用PERMISSIVE模式。
在这里插入图片描述

二、配置TLS
1)查看curl是否支持LibreSSL

➜  ~ curl --version | grep LibreSSL
curl 7.64.1 (x86_64-apple-darwin20.0) libcurl/7.64.1 (SecureTransport) LibreSSL/2.8.3 zlib/1.2.11 nghttp2/1.41.0

2)生成证书和密钥

➜  ~ openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout example.com.key -out example.com.crt
Generating a 2048 bit RSA private key
............................................................................................................................................................+++
..............+++
writing new private key to 'example.com.key'
-----
➜  ~ ls -lh example.com.crt 
-rw-r--r--  1 jyy  staff   1.0K  8 14 15:41 example.com.crt
➜  ~ ls -lh example.com.key 
-rw-r--r--  1 jyy  staff   1.7K  8 14 15:41 example.com.key
➜  ~ openssl req -out httpbin.example.com.csr -newkey rsa:2048 -nodes -keyout httpbin.example.com.key -subj "/CN=httpbin.example.com/O=httpbin organization"
Generating a 2048 bit RSA private key
...........................................+++
........+++
writing new private key to 'httpbin.example.com.key'
-----
➜  ~ 
➜  ~ ls -lh httpbin.example.com.key 
-rw-r--r--  1 jyy  staff   1.7K  8 14 15:43 httpbin.example.com.key
➜  ~ ls -lh httpbin.example.com.csr 
-rw-r--r--  1 jyy  staff   948B  8 14 15:43 httpbin.example.com.csr
➜  ~ openssl x509 -req -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in httpbin.example.com.csr -out httpbin.example.com.crt
Signature ok
subject=/CN=httpbin.example.com/O=httpbin organization
Getting CA Private Key

➜  ~ ls -l httpbin.example.com.crt 
-rw-r--r--  1 jyy  staff  1054  8 14 15:43 httpbin.example.com.crt

3)创建httpbin服务的Deployment和Service、Gateway

➜  ~ cat httpbin-service.yaml      
apiVersion: v1
kind: Service
metadata:
  name: httpbin
  labels:
    app: httpbin
spec:
  ports:
  - name: http
    port: 8000
  selector:
    app: httpbin
➜  ~ kubectl apply -f httpbin-service.yaml 
service/httpbin configured
➜  ~ cat httpbin-deployment.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin
spec:
  replicas: 1
  selector: 
    matchLabels:
      app: httpbin
      version: v1
  template:
    metadata:
      labels:
        app: httpbin
        version: v1
    spec:
      containers:
      - image: docker.io/citizenstig/httpbin
        imagePullPolicy: IfNotPresent
        name: httpbin
        ports:
        - containerPort: 8000
➜  ~  kubectl apply -f httpbin-deployment.yaml 
deployment.apps/httpbin configured

4)创建证书secret

➜  ~  kubectl create  -n istio-system secret generic httpbin-credential --from-file=key=httpbin.example.com.key --from-file=cert=httpbin.example.com.crt
secret/httpbin-credential created
➜  ~ kubectl describe secret httpbin-credential -n istio-system
Name:         httpbin-credential
Namespace:    istio-system
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
cert:  1054 bytes
key:   1704 bytes

5)创建挂载了证书的gateway

cat httpbin-gateway.yaml                       
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: mygateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 443
      name: https
      protocol: HTTPS
    tls:
      mode: SIMPLE
      credentialName: httpbin-credential
    hosts:
    - httpbin.example.com
➜  ~  kubectl apply -f httpbin-gateway.yaml    
gateway.networking.istio.io/mygateway created

6)创建虚拟服务

➜  ~  cat httpbin-vs.yaml 
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata: 
  name: httpbin
spec: 
  hosts:
  - "httpbin.example.com"
  gateways:
  - mygateway
  http:
  - match:
    - uri:
        prefix: /status
    - uri:
        prefix: /delay
    route:
    - destination:
        port:
          number: 8000
        host: httpbin
➜  ~  kubectl apply -f httpbin-vs.yaml      
virtualservice.networking.istio.io/httpbin created

7)访问测试

➜  ~  curl -v -HHost:httpbin.example.com --resolve httpbin.example.com:443:127.0.0.1 --cacert example.com.crt https://httpbin.example.com:443/status/418
* Added httpbin.example.com:443:127.0.0.1 to DNS cache
* Hostname httpbin.example.com was found in DNS cache
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to httpbin.example.com (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: example.com.crt
  CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=httpbin.example.com; O=httpbin organization
*  start date: Jun 29 01:48:32 2021 GMT
*  expire date: Jun 29 01:48:32 2022 GMT
*  common name: httpbin.example.com (matched)
*  issuer: O=example Inc.; CN=example.com
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x7fe86c00c800)
> GET /status/418 HTTP/2
> Host:httpbin.example.com
> User-Agent: curl/7.64.1
> Accept: */*
> 
* Connection state changed (MAX_CONCURRENT_STREAMS == 2147483647)!
< HTTP/2 418 
< server: istio-envoy
< date: Sat, 14 Aug 2021 07:52:11 GMT
< access-control-allow-credentials: true
< x-more-info: http://tools.ietf.org/html/rfc2324
< access-control-allow-origin: *
< content-length: 135
< x-envoy-upstream-service-time: 104
< 

    -=[ teapot ]=-

       _...._
     .'  _ _ `.
    | ."` ^ `". _,
    \_;`"---"`|//
      |       ;/
      \_     _/
        `"""`
* Connection #0 to host httpbin.example.com left intact
* Closing connection 0

三、配置mTLS
1)创建testauth名称空间,并创建sleep服务

➜  ~  kubectl create ns testauth 
namespace/testauth created
➜  ~  kubectl apply -f ../../samples/sleep/sleep.yaml -n testauth            
serviceaccount/sleep created
service/sleep created
deployment.apps/sleep created
➜  ~  kubectl get pods -n testauth 
NAME                     READY   STATUS    RESTARTS   AGE
sleep-557747455f-47zh7   1/1     Running   0          21s
➜  ~  kubectl exec -it sleep-557747455f-47zh7 -n testauth -c sleep -- curl http://httpbin.default:8000/ip 
{
  "origin": "127.0.0.6"
}

2)添加对等认证策略

➜  ~  cat peerauth.yaml  
apiVersion: "security.istio.io/v1beta1"
kind: "PeerAuthentication"
metadata:
  name: "default"
  namespace: "default"
spec:
  mtls:
    mode: PERMISSIVE

➜  ~  kubectl apply -f peerauth.yaml                                                                     
peerauthentication.security.istio.io/default created
➜  ~ kubectl exec -it sleep-557747455f-47zh7 -n testauth -c sleep -- curl http://httpbin.default:8000/ip
{
  "origin": "127.0.0.6"
}
➜  ~  cat peerauth-strict.yaml                                                                           
apiVersion: "security.istio.io/v1beta1"
kind: "PeerAuthentication"
metadata:
  name: "default"
  namespace: "default"
spec:
  mtls:
    mode: STRICT 
➜  ~  kubectl exec -it sleep-557747455f-47zh7 -n testauth -c sleep -- curl http://httpbin.default:8000/ip
{
  "origin": "127.0.0.6"
}

3)添加注入功能,并再次访问测试

➜  ~  kubectl apply -f <(/Users/jyy/istio-1.10.1/bin/istioctl kube-inject -f ../../samples/sleep/sleep.yaml) -n testauth 
serviceaccount/sleep unchanged
service/sleep unchanged
deployment.apps/sleep configured

➜  ~  kubectl exec -it sleep-557747455f-47zh7 -n testauth -c sleep -- curl http://httpbin.default:8000/ip
{
  "origin": "127.0.0.6"
}

4)上面的实验仅仅是针对的default名称空间的认证策略,针对全局的需要执行以下文件

➜  ~  cat peerauth-strict-global.yaml 
apiVersion: "security.istio.io/v1beta1"
kind: "PeerAuthentication"
metadata:
  name: "default"
spec:
  mtls:
    mode: STRICT 

版权声明:本文为Micky_Yang原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。