【備忘録】GKEをhttps化する(GoogleマネージドSSL証明書)

# 経緯

[こちら](https://qiita.com/kwbt/items/4eed650a7037ca6373c1) の記事を参考に cert-manager で [Let's Encrypt](https://letsencrypt.org/) の証明書を自動更新する環境を整えようとしたがうまくいかなかったので、GoogleのマネージドSSL証明書を試してみた。
GoogleのマネージドSSL証明書もLet's Encryptなので、試すだけならお手軽だった。

## (蛇足) cert-managerの書法

この記事を書いている地点で、公式ドキュメントに記されているバージョンはv0.15.0
https://cert-manager.io/docs/installation/kubernetes/#installing-with-regular-manifests

過去のバージョンとはyamlの書式がかなり異なっているのでハマった。
また証明書取得部分の挙動も変わっているらしい。([参考](https://github.com/jetstack/cert-manager/issues/1343))
詳しい方、教えていただけると嬉しいです。

# GoogleマネージドSSL証明書の有効化

[公式のドキュメント](https://cloud.google.com/kubernetes-engine/docs/how-to/managed-certs?hl=ja)

公式が丁寧なので基本的にこの通りで問題無いが、ハマりどころだけメモ

### 前提

* Deployment + Service でデプロイできている
    * Service の type は "NodePort" または "LoadBalancer" を指定
* 静的IPを用意する
    * VPCネットワーク → 外部IPアドレス
    * タイプはグローバル (リージョンではダメ)
* ドメインを取得しておく
    * 筆者は [ここ( freenom.com )](https://my.freenom.com/) でテスト用を取得
* Cloud DNS などでAレコードに取得した静的IPを設定しておく

## ManagedCertificateリソースの作成

```managedCertificate.yml

apiVersion: networking.gke.io/v1beta2
kind: ManagedCertificate
metadata:
  name: certificate-name # ManagedCertificateリソース名を指定
spec:
  domains:
    - domain-name1 # 取得したドメイン名を指定
    - domain-name2
```

## Ingressリソースの作成

```ingress.yml

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: ingress-name # Ingress名を指定
    annotations:
      kubernetes.io/ingress.global-static-ip-name: address-name # 用意した静的IPの名前を指定(IPアドレス自体では無い)
      networking.gke.io/managed-certificates: certificate-name # ManagedCertificate で指定した ManagedCertificateリソース名 を指定
spec:
  backend:
    serviceName: service-name # Serviceリソース(本記事では省略)で指定したリソース名を指定
    servicePort: service-port # Serviceリソースの portで指定したポート(targetPortでは無い)
```

## 各リソースを適応

```bash

kubectl apply -f xxxxxxxx.yaml
```

kustomizeで管理すると楽

```kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - deployment.yml
  - ingress.yml
  - service.yml
  - managedCertificate.yml
secretGenerator:
  - name: xxx
    files:
      - xxxxx
    envs:
      - xxxxx
generatorOptions:
  disableNameSuffixHash: true
```

CIに組み込むなどで適応

```bash

# Github Actionsの場合
curl -o kustomize --location https://github.com/kubernetes-sigs/kustomize/releases/download/v3.1.0/kustomize_3.1.0_linux_amd64
chmod u+x ./kustomize

gcloud container clusters get-credentials $GKE_CLUSTER --zone $GKE_ZONE --project $GKE_PROJECT
./kustomize edit set image app-image=$REGISTRY_HOSTNAME/$GKE_PROJECT/$IMAGE:${GITHUB_SHA} # タグをデプロイ毎に変更
./kustomize build . | kubectl apply -f -
```

##注意点

* 証明書がプロビジョニングされるまで**15分ほど**掛かる場合がある
* Ingressのセットアップにもそれなりに時間が掛かる

急いで変にいじる前にとりあえず待つべし

# Ingressでhttpsのアクセスを強制する

Ingressにアノテーションを追記

```yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress
  annotations:
    kubernetes.io/ingress.allow-http: "false" # httpsのみ許可
    ...
```

## 注意点

### 先にhttp許可でデプロイした後に上記設定(httpsのみ)を追加でデプロイし直した場合

**Ingressに下記のアラートが出て、httpアクセスが許可されたままになる** ([参考](https://github.com/kubernetes-retired/contrib/issues/1517))
```invalid ingress frontend configuration, please check your usage of the 'kubernetes.io/ingress.allow-http' annotation.```

一度Ingressを削除した後に再デプロイするのが手っ取り早い。

#参考

https://cloud.google.com/kubernetes-engine/docs/how-to/managed-certs?hl=ja
https://github.com/kubernetes-retired/contrib/issues/1517
https://qiita.com/kwbt/items/4eed650a7037ca6373c1