【EC2】GitlabのインストールからSSL証明書の取得、リポジトリ移行までの手順

# はじめに

EC2で稼働しているgitlabを、別AWSアカウントのEC2に移行したいという要件がありました。

そこで、EC2にgitlabのインストールからセットアップ、gitリポジトリの移行までを備忘がてら手順を残します。

## やること
- 新gitlabインスタンスの立ち上げ
- 旧gitlabから新gitlabへのリポジトリ移行
- 新gitlabにローカル環境から接続（commit, pushなど）

---
【環境】
EC2 OS: `Amazon Linux2`
gitlab: `ver15.0`

# ■ インストールと初期設定
新しくEC2インスタンスを起動します。
今回は、AMIに`Amazon　Linux2`を使用しました。
（インスタンスタイプが小さすぎると処理しきれない可能性があります。今回は、`m5.large`で行います。）

今回だと、gitlabインスタンスはパブリックサブネット内に配置する要件なので、ElasticIPをアタッチします。

新しく起動したEC2に↓記事を参考にgitlabをインストールします。

https://qiita.com/Ajyarimochi/items/9dcaba108fb1bce3f019

```shell: git labインスタンス
$ sudo yum install -y gitlab-ee

完了しました！
```


```sh
#root権限で作業
$ sudo su
$ vi /etc/gitlab/gitlab.rb
~
external_url 'http://gitlabインスタンスのグローバルIPアドレス'
~
~

#gitを再起動
$ gitlab-ctl reconfigure
```
ブラウザで確認
なぜか、rootユーザー（管理者アカウント）のパスワード変更画面にならなかったので、ログインできず・・・

![スクリーンショット 2022-05-16 16.45.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669969/764d34a8-0f4f-6da1-52b1-251c887094d6.png)

↓記事を参考に管理者アカウントのパスワードを設定

https://qiita.com/crnls1985/items/4fb42d803b0685eff092


コンソールからパスワード設定後、ログインし無事スタート画面に来ました！

![スクリーンショット 2022-05-16 17.26.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669969/310dd3ba-ac42-b457-ef79-7a5d20169b45.png)


---
**※追記**
あとで知ったのですが、rootユーザーの初期パスワードは、インスタンス内のここに存在していた👀

```sh:/etc/gitlab/initial_root_password
Password: XXXXXXXXXXXXXXXXXXXXXXXXXXXX
```

# ■ ドメインの設定
## Route53にAレコード登録
Route53のホストゾーンに対するサブドメインとして、EC2インスタンスにアタッチしたEIPをルーティング先にした`Aレコード`を登録します。

## 名前解決の確認
登録したドメイン名がEC2インスタンスのEIPと名前解決できているか、`dig`コマンドまたは`nslookup`コマンドなどで確認します。

```sh
$ dig ドメイン名　 a
```

https://qiita.com/hypermkt/items/610b5042d290348a9dfa


# ■ SSL証明書の取得
## gitlabはnginxが内蔵されている

nginxのインストールから　`nginx ⇄ gitlab`間の通信が必要かと思ったのですが、調べてみると、
実は`gitlab`ではデフォルトで`nginx`がバンドルされているそうなので、このプロセスは不要でした・・・

https://yoshinorin.net/articles/2018/04/08/gitlab-with-nginx-reverse-proxy/


## Let's encryptでの取得
基本的には↓記事の手順どおり実行

https://webree.jp/article/letsencrypt-install/

↑記事内の`$ certbot certonly --webroot -w /var/www/html -d example.com -d www.example.com`の部分を↓のように変更して実行

`--webroot`や`--standalone`などは取得する方法によって変わります。

```sh
$ certbot certonly --standalone -d ドメイン名

=> could not bind tcp port 80 because it is already in use by another process on this system (such as a web server). please stop the program in question and then try again.
```
しかし、ポート80番は既に使われているから使えないよと言われてしまった。

https://free-ssl.jp/usage/#ExecClientSoftware

色々調査したところ、原因は、`gitlab.rb`の`external_url`が`http://ドメイン名`だったこと。
```ruby:/etc/gitlab/gitlab.rb
external_url "http://ドメイン名"
```
`sudo lsof -i :80`で使用している80番ポートを確認すると、なんかいろいろ起動している。
```sh
nginx   19178       root    7u  IPv4 117001      0t0  TCP *:http (LISTEN)
nginx   19179 gitlab-www    7u  IPv4 117001      0t0  TCP *:http (LISTEN)
nginx   19180 gitlab-www    7u  IPv4 117001      0t0  TCP *:http (LISTEN)
```

`/etc/gitlab/gitlab.rb`に↓の内容を追記。gitを再起動してあげると・・・

```ruby:/etc/gitlab/gitlab.rb
external_url "https://ドメイン名"
#letsencrypt['enable'] = true    #GitLab 10.5 and 10.6 require this option
nginx['redirect_http_to_https'] = true
nginx['redirect_http_to_https_port'] = 80
# ↓証明書の位置を設定（※これを設定しないと、更新の際に設定した証明書を見に行ってくれない）
nginx['ssl_certificate'] = "/etc/letsencrypt/live/[ドメイン名]/fullchain.pem"
nginx['ssl_certificate_key'] = "/etc/letsencrypt/live/[ドメイン名]/privkey.pem"
```

```sh
#gitの再起動
$ gitlab-ctl reconfigure
```
無事、`htts://ドメイン名`でアクセスできた！！🙌

一応、これで証明書の取得と、`https`化の設定は終わりです。

が、しかし・・・

これだと、証明書更新の際に、
**インスタンスを起動し80番ポートを常時開放した上で、webサーバを停止しておく必要がある** など、セキュリティ的に何かと都合が悪いので、`DNS-01チャレンジ`というRoute53を使用した方法に切り替えて再度、取得し更新まで実装しました。

## Let's Encryptのログ確認
` /var/log/letsencrypt/letsencrypt.log`

## Route53を使用したDNS-01チャレンジでSSL証明書を取得し直す

```sh
#すでにある証明書無効・削除
$ certbot revoke --cert-path /etc/letsencrypt/live/ドメイン名/fullchain.pem

#再度取得
$ certbot certonly --manual \
--server https://acme-v02.api.letsencrypt.org/directory \
--preferred-challenges dns \
-d  ドメイン名 \
-m 登録するメールアドレス \
--agree-tos \
--manual-public-ip-logging-ok
```

https://ssilab.co.jp/blog/tech-blog/tech-blog-child/lets-encrypt_wildcard

## cronでの自動更新

証明書の更新は、root権限でないとできないので、rootユーザーのcronに以下を設定。

letsencryptの有効期限は3ヶ月。

`--force-renewal`をオプションで指定すると期限が来なくても強制的に取得することができる。

```sh:crontab
#毎月1日のAM10:00にLet's encryptのSSL証明書を更新
#* * * * * の意味は、左から、[分 時 日 月 曜日]
00 10 1 * * certbot renew --force-renewal --dns-route53 --post-hook "gitlab-ctl restart"
```

## 自動更新の確認
### EC2にRoute53を操作するIAMロールをアタッチ
1. 以下のjson内容を持つカスタム管理ポリシーを任意の名前で作成
2. 作成したポリシーをIAMロールに追加
3. gitlabインスタンスに、このIAMロールをアタッチ

これをしないと、EC2からRoute53へのドメインの問い合わせができないです。

```json:SSLCertificateUpdatePolicy

{
    "Version": "2012-10-17",
    "Id": "certbot-dns-route53 sample policy",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "route53:ListHostedZones",
                "route53:GetChange"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "route53:ChangeResourceRecordSets"
            ],
            "Resource": [
                "arn:aws:route53:::hostedzone/ホストゾーンID"
            ]
        }
    ]
}
```

### 証明書の有効期限確認
`/etc/letsencrypt/live/ドメイン名`に`fullcain.pem`が存在します。

↓コマンド実行結果の`notAfter`が設定されている証明書の有効期限となっています

```sh
$ sudo openssl x509 -in /etc/letsencrypt/live/ドメイン名/fullchain.pem -noout -dates

=> 
notBefore=May 17 04:00:58 2022 GMT
notAfter=Aug 15 04:00:57 2022 GMT
```

### 証明書更新テスト
証明書更新コマンドに、`--dry-run`オプションをつけてあげると、実際には更新されず更新できるかどうかのテストをしてくれます。

```sh
$ certbot renew --force-renewal --dry-run --dns-route53 --post-hook "gitlab-ctl restart"

#dns-route53プラグインなるものをインストールしてくれと言われる
=> 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/ドメイン名
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Failed to renew certificate ドメイン名 with error: The requested dns-route53 plugin does not appear to be installed
```

ここが結構ハマりました。`certbot-dns-route53`をインストールしようと`pip`や`apt`, `snap`など色々試しましたが、なかなかうまくいかず・・・😖

結局は、`snap`ではなく`yum`から再度`cerbot`を入れ直すことで解決しました。

### `certbot-dns-route53`のインストール
```sh
$ amazon-linux-extras install -y epel
$ sudo yum install certbot
$ sudo yum install python2-certbot-dns-route53

#certbotプラグイン一覧を確認
$ certbot pulgins
=> 
#これがあればOK
* dns-route53
Description: Obtain certificates using a DNS TXT record (if you are using AWS
Route53 for DNS).
Interfaces: IAuthenticator, IPlugin
Entry point: dns-route53 =
certbot_dns_route53._internal.dns_route53:Authenticator
~~
```

再度更新テストを実行すると成功！
```sh
$ certbot renew --force-renewal --dry-run --dns-route53 --post-hook "gitlab-ctl restart"
```


## Lambda✖︎EventBridgeで証明書更新時にインスタンスの起動設定
今回のgitlabインスタンスの運用として、基本は停止状態で必要なときのみ立ち上げるスタンスだったので、cron実行されるタイミングでgitlabインスタンスが立ちあがっておく必要がある。

そこで、LambdaとEventBridgeで毎月1日にインスタンスを立ち上げる関数を作成し、cronが実行できる状態にしておく。


https://it-jog.com/khow/serv/renewletsencrypt


# ■ Gitlabリポジトリの移行
## 新規リポジトリ作成
新gitlab上で、リポジトリを作成しておきます。

`--mirror`オプションで旧リポジトリをローカルに取り込みます。リモート先を変更し、pushします。

**(※注意）`--mirror`でとってきたリポジトリは、dokcer.gitみたいになっており、そのリポジトリ内ではgitコマンドを使用できない**

```sh
mkdir gitlab_dir
cd gitlab_dir
git clone --mirror 旧gitlabのリポジトリ(git@git~~~~~/XX.git)

#remote先を確認
git remote -v
git remote set-url origin 新gitlabのリポジトリ(git@~~~~~/XX.git)
#remote先が変更されていることを確認
git remote -v
git push --mirror origin master
```
https://one-it-thing.com/1506/

https://qiita.com/morishu/items/182b5ac66550f92dc173

## GitlabにSSH接続
基本的には、↓記事の通りにやれば問題ないかと思います。

https://qiita.com/kyamawaki/items/07fb3332cf3c2f47728a

`/.ssh/config`に追記する情報として以下のように設定します。

`User`の部分は自分のgitlabアカウント作成時に設定した`@移行`になります。

```config:/Users/ユーザー名/.ssh/config
Host ホスト
  #gitlabの @移行の名前
  User ユーザー名
  Port 22
  HostName ホスト
  TCPKeepAlive yes
  identitiesonly yes
  IdentityFile ~/.ssh/鍵.pub
```


# 参考
- DNS
  - [Let's Encrypt DNS-01 challenge はいいぞ](https://blog.grasys.io/post/noriko/letsencrypt-dns-01-challenge/)
  - [The requested dns-route53 plugin does not appear to be installed](https://community.letsencrypt.org/t/the-requested-dns-route53-plugin-does-not-appear-to-be-installed/99428/9)
- Gitlab
    - [git pull で「fatal: This operation must be run in a work tree」となる](https://teratail.com/questions/109664)
    - [git push origin masterができない！master → mainに変更](https://qiita.com/zooootech/items/edf7e1955e9b6d9d832a)
    - [Amazon Linux上にインストールしたGitLab CEにLet's Encryptを適用する方法](https://qiita.com/morisuke/items/a772fc45242e418bf40b#:~:text=%E5%90%8C%E3%81%98%E3%81%8FAWS%E3%81%AE%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3%E3%82%B0%E3%83%AB%E3%83%BC%E3%83%97%E3%83%AC%E3%83%99%E3%83%AB%E3%81%A7%E3%82%8280%E7%95%AA%E3%83%9D%E3%83%BC%E3%83%88%E3%82%92%E6%BD%B0%E3%81%97%E3%81%A6%E3%81%97%E3%81%BE%E3%81%A3%E3%81%A6%E3%82%88%E3%81%84%E3%80%82)
    - [gitlabのSSL化公式](https://docs.gitlab.com/omnibus/settings/ssl/)