Azure Kubernetesで立ち上げたWordPressをHTTPS対応にする

#はじめに
前回の記事で作成したAzure Kubernetes Service(AKS)上のWordPressコンテナは、AKSの「LoadBalancer」を使ってhttpによる接続を検証しました。

前回の記事 : [Azure KubernetesとAzure Database for MySQLを使ってWordPress Containerを動かす](https://qiita.com/yotan/items/aa4b0285ebefc4d1e8fe)

今回はこのLoadBalancerを止めて、「nginx-ingress」を導入します。

誤解を恐れずにnginx-ingressの概要を書くと

- L7レベルのアプリケーションロードバランサ
- MS公式ドキュメントにも載っている他、Googleも推奨
- バックエンドの複数のサービスをURLでリダイレクト可能
- SSL証明書をnginx-ingressに投入することでバックエンドのサービスがhttpのみであっても、httpsによるサービス提供が可能

といったところでしょうか。

参考 : [Azure Kubernetes Service (AKS) での HTTPS イングレス](https://docs.microsoft.com/ja-jp/azure/aks/ingress?WT.mc_id=AZ-MVP-5002499)

#必要なもの
前回作成したAKS、Azure Database for MySQLの環境の他、今回は更に以下のものが必要です。

- 独自ドメイン (この記事では私の個人ドメイン "nya-n.net" を使用します)
- 独自ドメインを管理しているDNSサーバ (この記事ではAzure DNSを使用します)
- SSL証明書 (この記事では digicert から取得したワイルドカード証明書を使用します)


#手順

##nginx-ingressのインストール
AzureポータルからCloudshellで利用している場合にはhelmは既にインストール済みですので、今回はこちらを使います。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/137436/d1b52bf3-1e2c-d9fa-d446-e623e2b2d66c.png)

Cloudshellから以下のコマンドを入力してhelmの初期化と、nginx-ingressのインストールをします。
namespaceの指定はご自由に。

```sh
$ helm init
$ helm install stable/nginx-ingress --namespace default --set rbac.create=false
```

しばらくすると、Azure上にも新しいPublic IP Addressリソースが作成されて、nginx-ingressに割り当てられます。

以下のコマンドを入力して「altered-octopus-nginx-ingress-controller」に割り当てられたEXTERNAL-IPを控えておきます。
こちらのIPアドレスはこの後、ご自身のDNSサーバのレコード登録時に使用します。

```sh
$ kubectl get service -l app=nginx-ingress --namespace wordpress01
NAME                                            TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
altered-octopus-nginx-ingress-controller        LoadBalancer   10.0.14.213    XX.XX.XX.XX    80:30686/TCP,443:32533/TCP   1h
altered-octopus-nginx-ingress-default-backend   ClusterIP      10.0.216.180   <none>        80/TCP                     7m
```

##Azure DNSへのAレコード登録
先程作成されたEXTERNAL-IPをDNSサーバにAレコードとして登録します。

ちょっと画面が細かくて恐縮ですが、これで「wordpress.nya-n.net」で名前解決ができるようになりました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/137436/50cd6c2d-a36e-2a88-858f-40249ea19563.png)

お使いのNameserverがAzure DNSとは異なるものの場合にはそれぞれの設定方法でAレコードを登録します。

TTLは今回は検証用なので10分にしましたが、本番運用するのであればもっと長くていいと思います。

##SSL証明書ファイルの準備

私は[digicert](https://www.digicert.com/)からワイルドカード証明書を取得しました。
SSL証明書の取得手順は各社異なりますので本記事では割愛します。

手元には以下のファイルがあります。

- private.key (パスワード暗号化された RSA PRIVATE KEY)
- server.csr (署名リクエスト CERTIFICATE REQUEST)
- star_nya-n_net.cer (digicertから送られてきたサーバー証明書 PKCS7)

private.keyは手元で作成時にパスワード設定を行いましたが、AKSのSecretに登録する際にはそのパスワードを外さないといけません。

不本意ですが、以下のコマンドでパスワードを外したprivate_unenc.keyを作成します。

```sh
$ openssl rsa -in server.key -out unencryred.key
Enter pass phrase for server.key:********
writing RSA key
```

また、digicertから送られてきたcerファイルはPKCS7形式で、申請したドメインの証明書の他、中間証明書などが含まれていて、このままではAKSのSecretに登録はできますが、nginx-ingressから認識してもらえません。

digicertのサイトではWindows PCを使った変換方法が書かれています。

[証明書の形式変換方法（PKCS#7→X.509）](https://knowledge.digicert.com/ja/jp/solution/SO22890.html)

もしopensslしか使えなければ、以下のコマンドでX.509に変換できます。

```sh
openssl pkcs7 -in star_nya-n_net.cer -print_certs > for-nginx-ingress.cer
```

出力されたファイルには中間証明書がまだ含まれていますので、「CN=」の内容を確認して自分のドメインの証明書(通常一番先頭のブロック)の「-----BEGIN CERTIFICATE-----」から「-----END CERTIFICATE-----」の部分を残して後の行は削除します。

最後にAKS上のSecretに登録して完了です。

```sh
$ kubectl apply secret tls tls-cert --key unencryred.key --cert for-nginx-ingress.cer
$ kubectl get secret
NAME                                        TYPE                                  DATA      AGE
altered-octopus-nginx-ingress-token-vtj4j   kubernetes.io/service-account-token   3         2h
default-token-75gbb                         kubernetes.io/service-account-token   3         2h
tls-cert                                    kubernetes.io/tls                     2         2h
wp-secrets                                  Opaque                                1         2h
```

##WordPressサービス登録
前回の記事ではWordPressはLoadBalancer経由でしたが、今回はnginx-ingressの配下にぶら下げるため、Serviceとして登録しておきます。

yamlで書いてもいいのですが、以下のコマンドでサクッとサービスを作成します。

```sh
$ kubectl expose deployment wordpress --type NodePort
```

これでnginx-ingressからwordpressが参照できるようになりました。

##nginx-ingressの登録
先程作成したのはnginx-ingressのコントローラー部分となるため、最後にwordpressをnginx-ingressの配下に設定します。

以下のyamlファイルを準備します。

```yaml:wp-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: wordpress-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  tls:
  - hosts:
    - wordpress.nya-n.net (ここは適宜変更)
    secretName: tls-cert
  rules:
  - host: wordpress.nya-n.net (ここは適宜変更)
    http:
      paths:
      - path: /
        backend:
          serviceName: wordpress
          servicePort: 80
```

最後に以下のコマンドで適用します。

```sh
$ kubectl apply -f wp-ingress.yaml
$ kubectl get ingress
NAME                HOSTS                 ADDRESS   PORTS     AGE
wordpress-ingress   wordpress.nya-n.net             80, 443   1h
```

実際にnginx-ingressに新しい設定が追加されるまで、5分程度かかるみたいです。

## WordPress側の変更
前回作成したLoadBalancer経由でhttpでアクセスして、「Really Simple SSL」プラグインをインストールします。
(WordPress側の操作方法は割愛)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/137436/5560f5d0-ceb4-f87e-ba92-20be5237cc1e.png)

[設定] → [一般] のWordPressアドレス(URL)とサイトアドレス(URL)を変更します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/137436/12cf6180-e7f8-6afc-1254-ff777408962c.png)

無事httpsによる接続が行えて、証明書もdigicertのものが設定されていることが確認できました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/137436/d7c62f12-7194-d41f-ffa7-15ab36063812.png)

##LoadBalancerの削除
別にこのまま残しておいても良いとは思いますが、前回の記事で作成したLoadBalancerはもう不要となりますので削除します。

```sh
$ kubectl get service
NAME                                            TYPE           CLUSTER-IP     EXTERNAL-IP                           PORT(S)                      AGE
altered-octopus-nginx-ingress-controller        LoadBalancer   10.0.14.213    XX.XX.XX.XX                            80:30686/TCP,443:32533/TCP   2h
altered-octopus-nginx-ingress-default-backend   ClusterIP      10.0.216.180   <none>                                80/TCP                       2h
azure-mysql                                     ExternalName   <none>         ktkr-mysql.mysql.database.azure.com   <none>                       2h
wordpress                                       NodePort       10.0.201.181   <none>                                80:31464/TCP                 2h
wp-external-lb                                  LoadBalancer   10.0.9.190     XX.XX.XX.XX                           80:30611/TCP                 2h

$ kubectl delete service wp-external-lb
service "wp-external-lb" deleted
```

#おわりに
前回の記事で作成したWordPressは、pod ⇔ MySQLの間はAzureのサービスエンドポイントを使って仮想ネットワーク内で安全に通信をする構成を取りました。

前回の記事 : [Azure KubernetesとAzure Database for MySQLを使ってWordPress Containerを動かす](https://qiita.com/yotan/items/aa4b0285ebefc4d1e8fe)

今回は更に外部との通信にhttpsを強制することで、よりセキュアなサービス構成が作れたと思います。(WordPress自身の脆弱性については別のオハナシ)