Istio v1.12 が HTTP/3 をサポートしはじめていた件

Istio v1.12から、HTTP/3対応を実験的にはじめていました。
https://istio.io/latest/news/releases/1.12.x/announcing-1.12/change-notes/

# Istioとは

Istioは最も有名なサービスメッシュです。
サービスメッシュとは、マイクロサービス間の通信状況を確認したり、アクセスコントロールしたりするツールです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534839/9244d053-5c65-d9ea-76aa-9c07aab7d584.png)
引用元：https://istio.io/latest/about/service-mesh/

上図の通り、IstioはEnvoyプロキシを用いて通信を行います。また、制御できるプロトコルは、HTTP/1.1、 HTTP/2、TCP、gRPCと様々なものがあります。

# HTTP/3とは

HTTP/3とは、QUICと呼ばれる新たなトランスポートプロトコルを用いた通信方式です。
QUICはUDPベースでストリーム多重化、暗号化トランスポートを行うプロトコルです。QUICのおかげで、HTTP/3はHTTP/2よりもはやく通信できます。またQUICを採用したことで、HTTP/3は必ず通信を暗号化するようになりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534839/124157b8-3c8d-3e5c-1710-3b35ccaa5859.png)

なお、QUICは標準化団体IETF（Internete Engineering Task Force）の[RFC 9000](https://www.rfc-editor.org/info/rfc9000)にて公開されました。

# IstioでHTTP/3を使う
Istio v1.12では、ゲートウェイでのHTTP/3サポートをα版として提供しはじめており、[公式のデモ](https://github.com/istio/istio/tree/master/samples/httpbin)を用いて挙動確認が可能です。

### 1.Istio設定準備

IstioOperatorの設定をyamlファイルで作成し、それを反映させます。

（注：Kubernetesはロードバランサーにて複数のポートが定義された場合、デフォルトでは同じプロトコルしか使えません。
そのため、異なるプロトコルを使用できるように、Kubernetesの設定にてMixedProtocolLBServiceを事前に有効にする必要があります。）


```n:IstioOperatorの設定（istio-operator.yaml）
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  name: install
spec:
  hub: localhost:5000
  tag: master
  components:
    ingressGateways:
    - name: istio-ingressgateway
      enabled: true
      k8s:
        service:
          ports:
          - name: status-port
            port: 15021
            targetPort: 15021
          # HTTPSと HTTP/3は同じポート番号を指定する必要あり
          # （443/TCPが公開される場合は、443/UDPも公開）
          - name: https
            port: 443
            targetPort: 8443
          - name: http3
            port: 443
            targetPort: 8443
            protocol: UDP
  values:
    pilot:
      # QUICをIstioで使えるようにするために、Istioの設定`PILOT_ENABLE_QUIC_LISTENERS`をtrueにする
      env:
        PILOT_ENABLE_QUIC_LISTENERS: true
```

```
$ istioctl apply -f istio-operator.yaml -y
```

### 2.デモアプリ準備

まず、namespaceとして`httpbin`を作成し、labelとして`istio-injection`を設定します。

```
$ kubectl create namespace httpbin
$ kubectl label namespace httpbin istio-injection=enabled
```

次に、デモアプリをデプロイします。

```
$ kubectl -n httpbin apply -f samples/httpbin/httpbin.yaml
```

その後、IngressのためのTLS certificates設定をします。このとき設定は`httpbin.cnf`に記載します。

```n:certificateの設定（httpbin.cnf）
[req]
default_bits       = 2048
prompt             = no
distinguished_name = req_distinguished_name
req_extensions     = san_reqext

[ req_distinguished_name ]
countryName         = IN
stateOrProvinceName = KA
organizationName    = QuicCorp

[ san_reqext ]
subjectAltName      = @alt_names

[alt_names]
DNS.0   = httpbin.quic-corp.com
```

```
// CA、server certificatesの作成
$ openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:4096 -subj "/C=IN/ST=KA/O=QuicCorp" -keyout quiccorp-ca.key -out quiccorp-ca.crt
$ openssl req -out httpbin.csr -newkey rsa:2048 -nodes -keyout httpbin.key -config httpbin.cnf
$ openssl x509 -req -days 365 -CA quiccorp-ca.crt -CAkey quiccorp-ca.key -set_serial 0 -in httpbin.csr -out httpbin.crt -extfile httpbin.cnf -extensions san_reqex
//Secretの作成
$ kubectl -n istio-system create secret tls httpbin-cred --key=httpbin.key --cert=httpbin.crt
```

### 3.HTTP/2、HTTP/3(over QUIC)の両方でアクセスできるように設定

まず、サービスを公開するためのゲートウェイの設定をyamlファイルで作成します。

```n:Gatewayの設定（gateway-config.yaml）
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: httpbin-gateway
spec:
  selector:
    app: istio-ingressgateway
    istio: ingressgateway
  servers:
  - port:
      number: 443
      name: https
      protocol: HTTPS
    hosts:
    - httpbin.quic-corp.com
    tls:
      mode: SIMPLE
      credentialName: httpbin-cred
```

```
$ kubectl -n istio-system apply -f gateway-config.yaml
```

つぎに、ルーティングのためにVirtualServiceの設定をyamlファイルで作成します。

```n:VirtualServiceの設定（virtualservice-config.yaml）
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: httpbin-route
spec:
  hosts:
  - httpbin.quic-corp.com
  gateways:
  - httpbin-gateway
  http:
  - name: httpbin-default-route
    route:
    - destination:
        host: httpbin.httpbin.svc.cluster.local
        port: 
          number: 8000
```

```
$ kubectl -n istio-system apply -f virtualservice-config.yaml
```

正しく適用できていれば、指定したポートに対して2つのリスナーが作成されます。

### 4.テスト

HTTP/3トラフィックをテストするためには、[HTTP/3をサポートしているcurl](https://github.com/curl/curl/blob/master/docs/HTTP3.md)を利用する必要があります。

```
$ curl --http3 --resolve httpbin.quic-corp.com:443:$INGRESS_IP https://httpbin.quic-corp.com/headers
* Added httpbin.quic-corp.com:443:172.XX.XX.XX to DNS cache
* Hostname httpbin.quic-corp.com was found in DNS cache
*   Trying 172.XX.XX.XX:443...
* Connect socket 5 over QUIC to 172.XX.XX.XX:443
* Sent QUIC client Initial, ALPN: h3,h3-29,h3-28,h3-27
* Connected to httpbin.quic-corp.com () port 443 (#0)
* h3 [:method: GET]
* h3 [:path: /headers]
* h3 [:scheme: https]
* h3 [:authority: httpbin.quic-corp.com]
* h3 [user-agent: curl/7.78.0-DEV]
* h3 [accept: */*]
* Using HTTP/3 Stream ID: 0 (easy handle 0xa64260)
> GET /headers HTTP/3
> Host: httpbin.quic-corp.com
> user-agent: curl
> accept: */*
> 
< HTTP/3 200
< server: istio-envoy
< date: Wed, dd MM yyyy hh:mm:ss GMT
< content-type: application/json
< content-length: 642
< access-control-allow-origin: *
< access-control-allow-credentials: true
< x-envoy-upstream-service-time: 2
< alt-svc: h3=":443"; ma=86400
< 
{
  "headers": {
    "Accept": "*/*", 
    "Host": "httpbin.quic-corp.com", 
    "Transfer-Encoding": "chunked", 
    "User-Agent": "curl", 
    "X-B3-Parentspanid": "XXXXXXXXXXXXXX", 
    "X-B3-Sampled": "0", 
    "X-B3-Spanid": "XXXXXXXXXXXXXX", 
    "X-B3-Traceid": "XXXXXXXXXXXXXXXXXXXXXX", 
    "X-Envoy-Attempt-Count": "1", 
    "X-Envoy-Internal": "true", 
    "X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/httpbin/sa/httpbin;Hash=XXXXXXXXXXXXXX;Subject=\"\";URI=spiffe://cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"
  }
}
```


# 参考情報

- https://istio.io/latest/
- https://istio.io/latest/news/releases/1.12.x/announcing-1.12/
- https://github.com/istio/istio
- https://datatracker.ietf.org/doc/draft-ietf-quic-http/
- https://http3-explained.haxx.se/ja/
- https://quicwg.org/