証明書の取得ができない!!
問題文
概要
k8sクラスターにcert-managerをインストールしhttp01認証で証明書を発行するissuerを設定した。
その上でhost
のnginxのpodを展開するDeploymentと、それを公開するService、Ingressを記述した/home/user/manifests/web.yaml
を作成しapplyした。
しかし、なぜか証明書が発行されない。その理由と解決方法を報告してほしい。
トポロジを以下の図で示す。
前提条件
- cert-managerで取得する証明書は自己署名証明書を使用している
host
やcert-manager
など必要なものにはルートCA証明書をインストール済み
host
のuser
ユーザーでkubectl
コマンドが利用できるhost
の/home/user/manifests
に今回applyしたmanifestが保存されているcert-manager.yaml
ingress-controller.yaml
root-ca.yaml
は変更しないことweb.yaml
の再展開(kubectl delete
,kubectl apply
など)可
acme-server
には、追加でDNSサーバーが稼働しており以下のレコードが設定されている
IN NS ictsc.test.
IN A 192.168.20.125
ca IN A 192.168.20.125
www IN A 192.168.20.1
lb
にはkeepalivedがインストールされている。- 変更しないこと
初期状態
host
でcurl -L www.ictsc.test
を実行したとき以下のようなエラーになる
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.haxx.se/docs/sslcerts.html
curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
host
でkubectl get cert
を実行したときwww-ictsc-test-tls
のREADYがFalse
になっている
終了状態
host
でcurl -L www.ictsc.test
を実行したときにnginxの初期ページが表示される- 証明書が設定されている
host
でkubectl get cert
を実行したときにwww-ictsc-test-tls
のREADYがTrue
になっている
接続情報
lb
とhost
のみSSHログインできる。
VM名 | ホスト名 | ユーザ | パスワード |
---|---|---|---|
lb | 192.168.20.1 | user | ictsc2020 |
host | 192.168.20.20 | user | ictsc2020 |
acme-server | 192.168.20.125 | ||
k8s-master | 192.168.20.129 | ||
k8s-worker1 | 192.168.20.130 | ||
k8s-worker2 | 192.168.20.131 |
解説
原因
cert-managerはhttp01認証を行うときにacme challengeが行えるかセルフチェックを行います。その際、www.ictsc.test
つまり192.168.20.1
宛てにGETリクエストを行いますが、このリクエストの戻りのパケットがnginxのPODから直接cert-managerのPODに送られてしまいます。
その時の送信元アドレスが、リクエストの送信時の宛先と異なるためセルフチェックのリクエストは失敗してしまい証明書の取得が行われませんでした。
以下のようにセルフチェックが失敗していることを確認できます。
user@host:~$ kubectl describe challenges.acme.cert-manager.io
Name: www-ictsc-test-tls-dhksj-696946275-1037365539
Namespace: default
Labels: <none>
Annotations: <none>
API Version: acme.cert-manager.io/v1
Kind: Challenge
...
省略
...
Status:
Presented: true
Processing: true
Reason: Waiting for HTTP-01 challenge propagation: failed to perform self check GET request 'http://www.ictsc.test/.well-known/acme-challenge/c4mi9je6PJ87H9ulTtAPOu1xSjXEyDo9': Get "http://www.ictsc.test/.well-known/acme-challenge/c4mi9je6PJ87H9ulTtAPOu1xSjXEyDo9": dial tcp 192.168.20.1:80: connect: connection timed out
State: pending
...
省略
...
解決策
解決策としては以下のことが考えられます。
- LBにhaproxyやnginxなどのリバースプロキシを用いる
- LBにヘアピンNATの設定を行う
今回は、keepalivedを変更できないのでヘアピンNATの設定を行います。
/etc/sysctl.conf
に以下の設定を追記し更新します。
$ sudo vim /etc/sysctl.conf
net.ipv4.vs.conntrack=1 # 最終行に追記
$ sudo sysctl -p
iptablesで内部からの通信をMASQUERADEする設定を行い永続化します。
$ sudo iptables -t nat -A POSTROUTING -s 192.168.20.128/25 -m ipvs --vaddr 192.168.20.1/32 -j MASQUERADE
$ sudo netfilter-persistent save
/home/user/manifests/web.yaml
をapplyし直すとkubectl get cert
でREADYがTrue
になることを確認できます。
またcurl -L www.ictsc.test
で正常にnginxのページが表示されます。
user@host:~/manifests$ kubectl delete -f web.yaml
deployment.apps "web" deleted
service "web" deleted
Warning: extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
ingress.extensions "a-web" deleted
user@host:~/manifests$ kubectl apply -f web.yaml
deployment.apps/web created
service/web created
Warning: extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
ingress.extensions/a-web created
user@host:~/manifests$ kubectl get cert
NAME READY SECRET AGE
www-ictsc-test-tls True www-ictsc-test-tls 35s
user@host:~/manifests$ curl -L www.ictsc.test
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
採点基準
- 理由が説明できている 20%
- 解決方法が記述されておりその解決方法で解決が可能 80%
さいごに
問題を解いていただきありがとうございました。
また上記のような想定解法での解答はなく、以下のような解答を頂きました。DNATの解法は、想定はしていたのですがCoreDNSは完全に想定しなかったので、確かにそういう方法もあるのかと思いました。(self checkとは?という感じではありますが、問題の終了条件を満たせるので満点としました。)
- CoreDNSのレコードを変更しingress controllerのPODのIPアドレスを名前解決するようにする
- lbでk8sのいずれかのノードにDNATをする