【Istio】TLS / Authentication / Authorizationまとめ

# TLS設定

### TLS Secretを用いたHTTPS設定

```Gateway_https.yml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: my-gateway
  namespace: default
spec:
  selector:
    istio: ingressgateway　 # default istio gateway proxy
  servers:
  - port:
      number: 80  # HTTP用
      name: http
      protocol: HTTP
    hosts:
    - uk.bookinfo.com  # DNSホスト（HTTP用）
  - port:
      number: 443  # HTTPS用
      name: https
      protocol: HTTPS
    hosts:
    - "bookinfo-namespace/*.bookinfo.com"  # HTTPS ポート443用DNS
    tls:
      mode: SIMPLE  # SIMPLE or MUTUAL
      credentialName: bookinfo-secret  # TLS証明書
```

### SNI（複数ホストへのTLS）設定

```Gateway_https-sni.yml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: my-gateway
  namespace: default
spec:
  selector:
    istio: ingressgateway　 # default istio gateway proxy
  servers:
  - port:
      number: 80  # HTTP用
      name: http
      protocol: HTTP
    hosts:
    - uk.bookinfo.com  # DNSホスト（HTTP用）
  - port:
      number: 443  # HTTPS用
      name: https
      protocol: HTTPS
    hosts:
    - "bookinfo-namespace/*.bookinfo.com"  # HTTPS ポート443用DNS
    tls:
      mode: SIMPLE  # SIMPLE or MUTUAL
      credentialName: bookinfo-secret  # TLS証明書
  - port:
      number: 443  # SNI用HTTPSポート443
      name: https-sni
      protocol: HTTPS
    hosts:
    - "bookinfo-namespace/*.bookinfo-to-sni.com"  # DNS（SNI用）
    tls:
      mode: SIMPLE  # SIMPLE or MUTUAL
      credentialName: bookinfo-secret-to-sni # TLS証明書（SNI用）
```

### SNI用ホストをVirtualServiceに追加

```virtual_service_sni.yml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: bookinfo-rule
  namespace: default
spec:
  hosts:
  - "bookinfo-namespace/*.bookinfo.com"  # HTTPS（メイン用）
  - "bookinfo-namespace/*.bookinfo-to-sni.com"  # HTTPS（SNI用）
  gateways:
  - default/my-gateway
  http:
  - match:
    - uri:
        prefix: /reviews/
    route:
    - destination:
        port:
          number: 80  # serviceポート
        host: reviews.prod.svc.cluster.local
```

### PeerAuthentication（Namespace限定）

```PeerAuthentication_namespace.yml
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: default  # 相互TLSトラフィックのみ許容　相互TLSのためdefaultはブロック
spec:
  mtls:
    mode: STRICT
```

### PeerAuthentication（Workload限定）

```PeerAuthentication_workload.yml
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: default  # 相互TLSトラフィックのみ許容　
spec:
  selector:
    matchLabels:
      run: httpbin  # ラベル（httpbin）がついているpodに限定される
  mtls:
    mode: STRICT
```

```destinationrule_mutual_tls.yaml
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: httpbin
spec:
  host: httpbin.default  # ホスト
  trafficPolicy:
    tls: 
      mode: ISTIO_MUTUAL  # 相互TLSのみ許可する
```

### HTTPからHTTPSへのリダイレクト

```gateway_https_redirect.yml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: my-gateway
  namespace: some-config-namespace
spec:
  selector:
    app: my-gateway-controller
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - uk.bookinfo.com  # HTTPホスト
    tls:
      httpsRedirect: true  # HTTPからHTTPSへリダイレクト
```

### curl pod作成

```
$ kubectl run curl \
      --restart Never \
      --image curlimages/curl \
      -n <namespace名> \
      --dry-run -o yaml \
      -- /bin/sh -c "sleep infinity" > curl_pod.yaml
```

### httpbin pod作成

```
$ kubectl run httpbin \
      --restart Never \
      -n <namespace名> \
      --image docker.io/kennethreitz/httpbin
```

### httpbin pod公開

```
kubectl expose pod httpbin --port 80 -n <namespace名>
```

### curl実行

```
$ kubectl exec -it curl -n <curl podのnamespace名> sh
$ curl httpbin.<httpbinのnamespace名>/headers -v
```

### JWT認証

```jwt_authentication.yml
apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
  name: "jwt-example"
  namespace: istio-system  # Istioのroot namespaceに適用する
spec:
  selector:
    matchLabels:
      app: ingressgateway  # IngressGatewayに適用
  jwtRules:  # JWT必須化
  - issuer: "testing@secure.istio.io"
    jwksUri: "https://raw.githubusercontent.com/istio/istio/release-1.10/security/tools/jwt/samples/jwks.json"
```

```jwt_authorization_policy.yml
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: require-jwt
  namespace: istio-system  # Istioのroot namespaceに適用する
spec:
  selector:
    matchLabels:
      app: ingressgateway  # IngressGatewayに適用
  action: ALLOW
  rules:
  - from:
    - source:  # principalsがある場合、JWT有効（valid）
       requestPrincipals: ["testing@secure.istio.io/testing@secure.istio.io"]
```

### JWT認証（HTTP PATH限定）

```jwt_authorization_policy_http_path.yml
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: jwt_path
  namespace: istio-system  # Istioのroot namespaceに適用する
spec:
  selector:
    matchLabels:
      app: ingressgateway  # IngressGatewayに適用
  action: ALLOW
  rules:
  - from:
    - source:  # principalsがある場合、JWT有効（valid）
       requestPrincipals: ["testing@secure.istio.io/testing@secure.istio.io"]
    to:
      - operation:
          paths: ["/headers"]  # headersへのアクセスは、JWT認証必須
　　　　　　hosts: ["test.sni.com"]  # test.sni.com/headersへのアクセスはJWT認証必須
```

### HTTP header Attributeを用いたJWT認証

```jwt_authorization_policy_http_header.yml
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: jwt_path
  namespace: istio-system  # Istioのroot namespaceに適用する
spec:
  selector:
    matchLabels:
      app: ingressgateway  # IngressGatewayに適用
  action: ALLOW
  rules:
  - from:
    - source:  # principalsがある場合、JWT有効（valid）
       requestPrincipals: ["testing@secure.istio.io/testing@secure.istio.io"]
    to:
      - operation:
          paths: ["/headers"]  # headersへのアクセスは、JWT認証必須
　　　　　　hosts: ["test.sni.com"]  # test.sni.com/headersへのアクセスはJWT認証必須
    when:
    - key: request.headers[x-token]
      values: ["admin"]  # headerのX-tokenがadminである必要あり
```

### 特定のIPアドレスに対して、JWT認証を有効化する

```jwt_authorization_policy_ip.yml
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: jwt_path
  namespace: istio-system  # Istioのroot namespaceに適用する
spec:
  selector:
    matchLabels:
      app: ingressgateway  # IngressGatewayに適用
  action: ALLOW
  rules:
  - from:
    - source:
       ipBlocks: ["XX.XXX.X.XX"]  # 指定したIPアドレスのみ、アクセス許可
```


### ServiceEntry

```service_entry.yml
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: external-svc-https
spec:
  hosts:
  - api.dropboxapi.com  # ServiceEntryに関連付けられているホスト
  location: MESH_EXTERNAL  # サービスを「メッシュの外部と見なす」か、「メッシュの一部と見なす」か
  ports:
  - number: 443
    name: https
    protocol: TLS
  resolution: DNS  # 必須項目
```

### タイムアウト設定

```virtualservice_timeout.yml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews-route
spec:
  hosts:
  - reviews.prod.svc.cluster.local # k8sのService名（virtualservice.ymlと同じ）
  - mesh  # Gatewayに限らず、それぞれのEnvoy Proxyにもルールを適用する
  http:
  - timeout: 1s  # 1秒以内にreturnしない場合、HTTPエラーコードが表示される
  - route:
    - destination:
        host: reviews.prod.svc.cluster.local # k8sのService名（virtualservice.ymlと同じ）
        subset: v1 # podにつけたlabel（負荷分散用）
      weight: 25
    - destination:
        host: reviews.prod.svc.cluster.local # k8sのService名（virtualservice.ymlと同じ）
        subset: v2　
      weight: 75
```

### ServiceEntry HTTPS有効化

```service_entry_https.yml
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: external-svc-https
spec:
  hosts:
  - www.google.com  # ServiceEntryに関連付けられているホスト
  location: MESH_EXTERNAL  # サービスを「メッシュの外部と見なす」か、「メッシュの一部と見なす」か
  ports:
  - number: 80
    name: http-port
    protocol: HTTP
  - number: 443
    name: https-port-for-tls-origination
    protocol: HTTPS
  resolution: DNS  # 必須項目
```

```service_entry_destination_rule.yml
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: google-com
spec:
  host: www.google.com
  subsets:
  - name: tls-origination
    trafficPolicy:
      loadBalancer:  # round robin / random / least connectionの3択
        simple: ROUND_ROBIN
      portLevelSettings:
      - port:
          number: 443
        tls:
          mode: SIMPLE  # SIMPLE or MUTUAL
```

```service_entry_virtual_service.yml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: google.com
spec:
  hosts:
  - "*.google.com"
  http:
  - match:
    - port: 80
  - route:
    - destination:
        host: www.google.com  # ServiceEntryとDestinationRuleと関連付け
        subset: tls-origination  # DestinationRuleで定義
        port:
          number: 443
```




# 参考文献
 - [米シリコンバレーDevOps監修！Istio Service Mesh ハンズオン+Kubernetes AWS EKS](https://www.udemy.com/course/istio-service-mesh-kubernetes-aws-eks-2020-handson/)
 - [Istio Documentation](https://istio.io/latest/docs/)