kun432's blog

Alexaなどスマートスピーカーの話題中心に、Voiceflowの日本語情報を発信してます。たまにAWSやkubernetesなど。

〜スマートスピーカーやVoiceflowの記事は右メニューのカテゴリからどうぞ。〜

GitLabでLet's Encryptを使う

f:id:kun432:20201108151742p:plain

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をインストールして使用することに表面的な違いはありません。

www.gitlab.jp

ハマったところ

流れだけ。

  • そもそも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でエラーも出なくなるので、卵・鶏の話のような気もします。更新時のこととかを考えるとちょっと怖くて使えないですね。まあそういうケースでは有償の証明書を使うべきだと思いますが。