GitLabでLet's Encryptを使ってSSLを設定しょうとしたら盛大にハマったのでメモ。
目次
環境
- OS: Amazon Linux 2
- gitLab-ee: 13.5.3
一般的にはgitlab-ceを使うほうが多いんでしょうが、GitLabの公式の以下の説明より、gitlab-eeを使っても問題ないと判断しました。
GitLab EEの有料の機能を使用可能にするためには、ライセンスを購入する必要があります。 もしもライセンスが未登録のGitLab EEを使用している場合は、MITライセンスの無料の機能だけを使用していることになります。
つまり、GitLab EEをインストールしてライセンスを未登録のまま使用することと、GitLab CEをインストールして使用することに表面的な違いはありません。
ハマったところ
流れだけ。
- そもそもHTTPでいいのではないか?というところなのだけど、container registryをHTTPで使う場合、docker側でinsecure_registryとして設定する必要があってめんどくさい。まあ時代はHTTPSということで。
- GitLab自体がLet's Encrypt対応しているので設定変えるだけでいけるはず・・・が、なぜかうまく行かない。
ということで、手動でLet's Encryptの設定を行います。
GitLabにLet's Encryptを導入する記事を見ていると、だいたいnginxに以下のようなcustom設定を追加するものが多い。
nginx['custom_gitlab_server_config'] = "location ^~ /.well-known { root /var/letsencrypt; }"
もしくは、カスタムなnginxの設定ファイルをincludeする。
nginx['custom_nginx_config'] = "include /etc/gitlab/custom_nginx_config.conf;"
includeする設定はこういうの。
server { listen 80; server_name _; access_log /var/log/gitlab/nginx/access.log; error_log /var/log/gitlab/nginx/error.log; location / { return 404; } location /.well-known { alias /var/letsencrypt/.well-known; } }
やり方は違うけど、/var/letsencryptをHTTPで公開して、certbotのHTTPアクセスチェックを回避するっていうやり方ですね。
設定を追加してgitlab-ctl reconfigure
して、certbotで証明書を取得します。(ドメインはサンプル)
# certbot certonly --webroot --webroot-path=/var/letsencrypt -d gitlab.example.com
で失敗する。
Saving debug log to /var/log/letsencrypt/letsencrypt.log Plugins selected: Authenticator webroot, Installer None Obtaining a new certificate Performing the following challenges: http-01 challenge for gitlab.example.com Using the webroot path /var/letsencrypt for all unmatched domains. Waiting for verification... Challenge failed for domain gitlab.example.com http-01 challenge for gitlab.example.com Cleaning up challenges Some challenges have failed. IMPORTANT NOTES: - The following errors were reported by the server: Domain: gitlab.example.com Type: unauthorized Detail: Invalid response from http://gitlab.example.com/.well-known/acme-challenge/XXXX-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX [XXX.XXX.XXX.XXX]: "<html>\r\n<head><title>404 Not Found</title></head>\r\n<body>\r\n<center><h1>404 Not Found</h1></center>\r\n<hr><center>nginx</center>\r\n" To fix these errors, please make sure that your domain name was entered correctly and the DNS A/AAAA record(s) for that domain contain(s) the right IP address.
どうもHTTPチェック用のパスにアクセスができてないみたいです。
gitlab-nginxのエラーログを見てみます。
2020/11/08 05:42:02 [error] 9467#0: *24 open() "/var/opt/gitlab/nginx/www/.well-known/acme-challenge/...." failed (2: No such file or directory), ...
どうも違うパスを見ているみたいです。
gitlabが生成するnginxの設定ファイルを見てみましょう。まず、custom_gitlab_server_configを追加した場合は、/var/opt/gitlab/nginx/conf/gitlab-http.confに追加されます。
server { listen *:443 ssl http2; (snip) location ^~ /.well-known { root /var/letsencrypt; } }
む、HTTPSの設定に追加されていますね・・・・そして上にあるHTTPの設定を見ると別のLet's Encrypt用の設定が見えます。(ちなみにこれ以外のhttpアクセスはhttpsにリダイレクトされてます)
server { listen *:80; (snip) location /.well-known { root /var/opt/gitlab/nginx/www/; (snip)
ここ違うパスを見ていますね。この設定、GitLabのLet's encrypt対応による設定じゃないかな。おそらく、external_urlにhttpsを指定するとこの設定が自動的に入るのだと思います。external_urlの設定はインストール時に行っていました。
sudo EXTERNAL_URL="${GITLAB_URL}" yum install -y gitlab-e
ということで、結論から言うと、certbotの証明書取得はこうすればOKです。
# certbot certonly --webroot --webroot-path= /var/opt/gitlab/nginx/www -d gitlab.example.com
うまくいきました。これで証明書が/etc/letsencrypt以下に置かれます。
aving debug log to /var/log/letsencrypt/letsencrypt.log Plugins selected: Authenticator webroot, Installer None Obtaining a new certificate Performing the following challenges: http-01 challenge forgitlab.example.com Using the webroot path /var/opt/gitlab/nginx/www for all unmatched domains. Waiting for verification... Cleaning up challenges Subscribe to the EFF mailing list (email: xxxxxx@example.com). IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/gitlab.example.com/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/gitlab.example.com/privkey.pem Your cert will expire on 2021-02-06. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew *all* of your certificates, run "certbot renew" - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le
ちなみに、custom_nginx_configの方はというと、/var/opt/gitlab/nginx/conf/nginx.confに追加されます。
http { (snip) include /var/opt/gitlab/nginx/conf/gitlab-http.conf; include /var/opt/gitlab/nginx/conf/gitlab-registry.conf; include /var/opt/gitlab/nginx/conf/nginx-status.conf; include /etc/gitlab/custom_nginx_config.conf; }
さきほどのgitlab-http.confもincludeされているのがわかりますね。つまり、Let's Encrypt用のパス公開設定が2重になってしまうということですね。nginxあまり触ってないのでわからないですが、同じserver設定がある場合は、前勝ちになる、ということなのでしょうか。
うまく行ったのでregistry用にも証明書を発行して、
certbot certonly --webroot --webroot-path=/var/opt/gitlab/nginx/www -d registry.example.com
/etc/gitlab/gitlab.rbにregistry_external_urlを有効化。このときにGitLabのLet's Encrypt integrationを無効化(reconfigureで有効になってしまい再度証明書取得プロセスが走ってしまう)、各証明書はcertbotで生成したものを指すようにします。
letsencrypt['enable'] = false nginx['ssl_certificate'] = "/etc/letsencrypt/live/gitlab.example.com/fullchain.pem" nginx['ssl_certificate_key'] = "/etc/letsencrypt/live/egistry.example.com/privkey.pem" registry_external_url "https://regstry.example.com" registry_nginx['ssl_certificate'] = "/etc/letsencrypt/live/gitlab.example.com/fullchain.pem" registry_nginx['ssl_certificate_key'] = "/etc/letsencrypt/live/registry.example.com/privkey.pem"
$ gitlab-ctl reconfigure
これでOKです。
まとめ
これ以外にもPackerで作ったGitLabのAMIである程度gitlabの設定も入れていたのでAMI作り直したり、失敗しすぎてLet's Encryptのレート制限に引っかかったりもしてたので、ハマりにハマりました・・・
GitLabのnginx設定ファイルの構成とかもちょっとわかったので良かったですが、GitLab側のLet's Encrypt Integration、やっぱりよくわかりません。certbotで一度生成成功すると、reconfigureでエラーも出なくなるので、卵・鶏の話のような気もします。更新時のこととかを考えるとちょっと怖くて使えないですね。まあそういうケースでは有償の証明書を使うべきだと思いますが。