こんにちは。Kaneyasuです。
今回は、Amazon EC2上のGitLab Self Managedを自己署名証明書でHTTPS化する手順をまとめてみました。
なお、本手順は開発用を想定したCN(Common Name)のみを使用した簡易的な方法を書いています。Chrome等の最新ブラウザでは、SAN(Subject Alternative Name)が含まれていない証明書に対してNET::ERR_CERT_COMMON_NAME_INVALIDエラーを表示する場合があります。本番環境や確実な動作が必要な場合は、SANを含む証明書の作成を推奨します。
はじめに
本記事では、EC2上で稼働しているGitLabを自己署名証明書を使用してHTTPS化する手順と、その背景にある証明書の仕組みについて解説します。
本記事は個人ブログレベルの内容であり、実際の運用に際しては公式ドキュメントやセキュリティベストプラクティスを参照してください。
SSL証明書における基本的な用語の説明
SSL証明書における署名とは
証明書の「署名」とは、証明書の内容が改ざんされていないことを証明するデジタル署名のことです。
署名の仕組み
デジタル署名は、「署名の作成」と「署名の検証」の2つのプロセスから構成されます。
署名の作成プロセス(サーバー側)
SSL証明書における署名は、サーバー管理者が証明書を発行する際に行います。
本記事では openssl x509 コマンド実行時に自己署名を行っています。
署名の検証プロセス(ブラウザ側)
作成した署名付き証明書は、ブラウザがHTTPS接続を確立する際に検証されます。
検証作業はブラウザが自動的に行います。
CA署名と自己署名の違い
本記事では、自己署名証明書を使用していますが、通常のSSL証明書は信頼された認証局(CA)によって署名されています。
認証局(CA)による署名と自己署名の主な違いは以下の通りです。
| 項目 | CA署名証明書 | 自己署名証明書 |
|---|---|---|
| 署名者 | 信頼された認証局(CA) | 自分自身 |
| ブラウザの信頼 | 自動的に信頼される | 警告が表示される |
| 用途 | 本番環境 | 開発・テスト環境 |
| コスト | 有料(または無料でLet's Encrypt) | 無料 |
| 発行速度 | ドメイン検証が必要 | 即座に発行可能 |
証明書における秘密鍵と公開鍵とは
SSL/TLS証明書では、公開鍵暗号方式を使用しています。これは、ペアとなる2つの鍵(秘密鍵と公開鍵)を使った暗号化方式です。
秘密鍵(Private Key)
- ファイル名: 通常
.keyという拡張子 - 保管場所: サーバー側のみ(絶対に外部に漏らしてはいけない)
- 役割:
- 暗号化されたデータを復号する
- デジタル署名を作成する(証明書の署名)
- クライアントから送信された暗号化データを復号する
公開鍵(Public Key)
- ファイル形式: 公開鍵は証明書ファイル(
.crtや.pem)の中に含まれています- 注:
.crtファイルは公開鍵そのものではなく、公開鍵を含む証明書です
- 注:
- 保管場所: 証明書として配布され、誰でも取得可能
- 役割:
- データを暗号化する(秘密鍵でのみ復号可能)
- デジタル署名を検証する
- 配布: クライアント(ブラウザ)に送信される
公開鍵暗号方式の動作原理
わざわざ2つの鍵を使う理由は、万が一公開鍵が第三者に知られても、秘密鍵が漏れない限り安全性が保たれるためです。
実際のHTTPS通信での使われ方
実際のHTTPS通信では、公開鍵暗号方式と共通鍵暗号方式を組み合わせて使用します。
- 公開鍵暗号は処理が重いため、最初の鍵交換にのみ使用
- 実際のデータ通信は、共通鍵暗号(AESなど)で高速に処理
- これを「ハイブリッド暗号方式」と呼びます
<注意事項>
-
CN(Common Name)とSAN(Subject Alternative Name)について
本手順ではCNのみを設定していますが、Chrome等の最新ブラウザではSANの記載がない証明書に対してNET::ERR_CERT_COMMON_NAME_INVALIDというエラーを表示する場合があります。本手順は簡易化のためCNのみを使用していますが、本番環境ではSANを含む証明書の使用を推奨します。 -
鍵交換方式について
上記の図ではRSA鍵交換(共通鍵を公開鍵で暗号化して送信)を示していますが、現在のTLS 1.3およびTLS 1.2では、前方秘匿性(PFS: Perfect Forward Secrecy)を確保するため、Diffie-Hellman鍵交換(ECDHEなど)が主流です。本図は概念理解のための簡略化した説明です。
自己署名証明書とは
自己署名証明書(Self-Signed Certificate)は、外部の認証局(CA)に署名を依頼せず、自分自身で署名した証明書です。
通常の証明書との違い
通常の証明書(CA署名)
自己署名証明書
EC2上のGitLab Self Managedを自己署名証明書でHTTPS化する手順
前置きが非常に長くなりましたが、ここからは実際にEC2上のGitLab Self Managedを自己署名証明書でHTTPS化する手順を解説します。
なお、冒頭で述べた通り、本手順はCN(Common Name)のみを使用した簡易的な方法です。
本手順で実現するHTTPS接続の流れ
環境構成
本手順は、以下の環境を前提としています:
- 本手順はEC2単独構成を想定としています
- ALB/CloudFrontを使用する場合は、AWS Certificate Manager(ACM)で証明書を管理することを推奨します
- 本手順はEC2インスタンス単体でHTTPSを終端する場合に適用してください
- EC2 に GitLab Enterprise Edition をインストール済みであることを前提としています
- GitLab EE のインストール手順については、公式ドキュメントを参照してください
- セキュリティグループで、HTTPS(ポート443)へのインバウンドアクセスが許可されていること
- EC2にElastic IPが割り当てられていること
- 本手順の各種コマンドは、Session Manager経由でEC2インスタンスに接続して実行することを想定しています
手順の全体像
手順1: SSL証明書の作成
1.1 SSL証明書ディレクトリの作成と移動
# SSL証明書ディレクトリを作成(存在しない場合)
sudo mkdir -p /etc/gitlab/ssl
sudo chmod 755 /etc/gitlab/ssl
# SSL証明書ディレクトリに移動
cd /etc/gitlab/ssl
# ホスト名を変数に設定(実際のEC2のパブリックDNSに置き換えてください)
HOSTNAME="EC2のパブリックDNS"
- GitLabは
/etc/gitlab/sslディレクトリ内の証明書を自動的に読み込みます
1.2 暗号化された秘密鍵の生成
# AES128で暗号化された2048ビットの秘密鍵を生成
sudo openssl genrsa -aes128 -out ${HOSTNAME}.key 2048
-
openssl genrsa: RSA秘密鍵を生成するコマンド -
-aes128: AES128アルゴリズムで秘密鍵自体を暗号化(パスフレーズで保護) -
-out ${HOSTNAME}.key: 出力ファイル名を指定 -
2048: 鍵長2048ビット(推奨される最低限の強度) - パスフレーズは秘密鍵の盗難リスクを軽減するための追加のセキュリティ層です
コマンド実行後、パスフレーズの入力を求められます:
Enter PEM pass phrase: [安全なパスワードを設定]
Verifying - Enter PEM pass phrase: [再度同じパスワードを入力]
1.3 証明書署名要求(CSR)の作成
# CSRを作成
sudo openssl req -new -key ${HOSTNAME}.key -out ${HOSTNAME}.csr
- CSR(Certificate Signing Request)は証明書発行のための申請書です
- 通常はCAに送信しますが、自己署名証明書の場合は自分で署名します
コマンド実行後、以下の情報を入力します。
Common Name(CN)は必ずサーバーのホスト名と一致させる必要があります(ブラウザが検証します)。
今回は、EC2のパブリックDNS名を使用します。
Enter pass phrase for [HOSTNAME].key: [1.2で設定したパスフレーズを入力]
Country Name (2 letter code) []:JP # 国コード
State or Province Name (full name) []:Tokyo # 都道府県
Locality Name (eg, city) []:Chiyoda # 市区町村
Organization Name (eg, company) []:Your Company Name # 組織名
Organizational Unit Name (eg, section) []:IT Department # 部署名
Common Name (eg, YOUR name) []:[HOSTNAME] # サーバーのホスト名
Email Address []:admin@example.com # メールアドレス
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []: # 空でOK
An optional company name []: # 空でOK
1.4 自己署名証明書の作成
# 自己署名証明書を作成(有効期限: 100年)
sudo openssl x509 -in ${HOSTNAME}.csr -out ${HOSTNAME}.crt -req -signkey ${HOSTNAME}.key -days 36500
-
openssl x509: X.509形式の証明書を操作するコマンド -
-req: 入力がCSRであることを指定 -
-signkey: 自分の秘密鍵で署名(自己署名) -
-days 36500: 有効期限を約100年に設定(開発環境用)- 長すぎる有効期限は本番環境では推奨されません。証明書の漏えい時のリスクが長期間継続し、定期的な更新による安全性向上の機会を失います。本番環境では1年以内(365日以下)の有効期限を推奨します。本手順は開発・テスト環境での利便性を優先した設定です。
コマンド実行後、再度パスフレーズの入力を求められます:
Enter pass phrase for [HOSTNAME].key: [1.2で設定したパスフレーズを入力]
ここまでのコマンドで、合計3つのファイルが生成されます:
-
.keyファイル: 秘密鍵(サーバー側で厳重に管理) -
.csrファイル: 証明書署名要求(通常はCAに提出するが、本手順では自己署名証明書を作成するためにローカルでopenssl x509コマンドの入力として使用) -
.crtファイル: 自己署名証明書(クライアントに送信される)、公開鍵と証明書情報(CN、有効期限など)を含む
1.5 パスフレーズなしの秘密鍵の作成
GitLabが自動起動する際、パスフレーズ入力を求められると起動できません。
そのため、パスフレーズを除去した秘密鍵を作成します。
暗号化された元の鍵は .encrypted という名前でバックアップします。
# 元の秘密鍵をバックアップ
sudo mv ${HOSTNAME}.key ${HOSTNAME}.key.encrypted
# パスフレーズなしの秘密鍵を作成
sudo openssl rsa -in ${HOSTNAME}.key.encrypted -out ${HOSTNAME}.key
ここでも、コマンド実行後にパスフレーズの入力を求められます:
Enter pass phrase for [HOSTNAME].key.encrypted: [1.2で設定したパスフレーズを入力]
1.6 パスフレーズなしの秘密鍵にファイル権限を設定
パスフレーズなしの秘密鍵は、ファイルシステムの権限管理のみで保護されます。
そのため、次の手順でファイル権限を厳格に設定します。
# 秘密鍵のパーミッションを設定(所有者のみ読み書き可能)
sudo chmod 600 ${HOSTNAME}.key
sudo chmod 600 ${HOSTNAME}.key.encrypted
# 証明書のパーミッションを設定(所有者のみ書き込み可能、全員読み取り可能)
sudo chmod 644 ${HOSTNAME}.crt
# オーナーをrootに設定
sudo chown root:root ${HOSTNAME}.*
-
600: 所有者(root)のみ読み書き可能、他のユーザーはアクセス不可 -
644: 所有者は読み書き可能、その他は読み取りのみ可能 - 秘密鍵は最も重要なファイルなので、最も厳格な権限設定を行います
手順2: GitLabの設定変更
# GitLab設定ファイルを編集
sudo vi /etc/gitlab/gitlab.rb
/etc/gitlab/gitlab.rbを開き、以下の設定を追加または変更します。
GitLabは /etc/gitlab/ssl/ 内の [external_urlのホスト名].key と [external_urlのホスト名].crt を自動的に使用します。
letsencrypt['enable'] = false を設定して、Let's Encryptの自動証明書取得機能を無効化し、自動で証明書が上書きされないようにします。
# HTTPからHTTPSに変更(EC2のパブリックDNS名を使用)
external_url 'https://EC2のパブリックDNS名'
# Let's Encryptの自動設定を無効化(自己署名証明書を使用するため)
letsencrypt['enable'] = false
external_urlをhttps://に設定すると、GitLabは通常HTTP(ポート80)を待ち受けません。HTTPアクセスを自動的にHTTPSにリダイレクトしたい場合は、nginx['redirect_http_to_https'] = trueを明示的に設定する必要があります。
手順3: GitLabの再設定と再起動
# GitLabの設定を再読み込みして適用
sudo gitlab-ctl reconfigure
# GitLabを再起動
sudo gitlab-ctl restart
reconfigureは、GitLabの設定ファイルを読み込み、必要なサービスの設定を自動的に更新します。
restartは、GitLabの全サービスを再起動して新しい設定を反映させます。
再設定には数分かかる場合があります。
手順4: 動作確認
ブラウザでHTTPS接続を確認します:
https://EC2のパブリックDNS
参考リンク
本記事は以下の記事を参考にしています。
情報の共有ありがとうございます。