前回がCloudwatch AgentをPCに入れるという変化球だったのですが、
地に足を着ける時間として基本的なことをアウトプットしたくなったので書いてます。
今回やること
内容はRedmineを一旦AWSで構築した後で、
きちんとhttpsでのアクセスだったりRDSへ移行していく話です。
IaC化などはまた別途、勉強がてら育てます。
実施作業
ここからは実施作業について書いていきます。
IAMロールの作成
EC2に割り当てる用のIAMロールを作成します。
ポリシーAmazonSSMManagedInstanceCore
が割り当てられたロールを作成します。
理由は口述しますが、SSM Session Managerでの接続がしたいからです。
EC2デプロイ
RedmineのEC2をデプロイします。
EC2の起動画面からmarketplaceでRedmineを選択します。
バージョン 5.0.5-19-r30 on Debian 11
IAMロールは先ほど作成したものを使いましょう。
ユーザデータを以下の通りに記載しておくことで初回起動時にSSM Agentがインストールされ、
SSM Session ManagerからEC2へログインできます。
SSHポートを開ける必要がなく、SSH鍵の管理が不要になります。
Content-Type: multipart/mixed; boundary="==BOUNDARY=="
MIME-Version: 1.0
--==BOUNDARY==
Content-Type: text/x-shellscript; charset="us-ascii"
#!/bin/bash
echo "running userdata script"
# SSM Agent のインストール
curl "https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/debian_amd64/amazon-ssm-agent.deb" -o "amazon-ssm-agent.deb"
dpkg -i amazon-ssm-agent.deb
# SSM Agent の設定
echo "rebooting to start SSM Agent"
nohup sudo systemctl restart amazon-ssm-agent &
--==BOUNDARY==--
[ 59.621532] device-mapper: ioctl: 4.43.0-ioctl (2020-10-01) initialised: dm-devel@redhat.com
[ 59.308394] bitnami[587]: #########################################################################
[ 59.314250] bitnami[587]: # #
[ 59.320008] bitnami[587]: # Setting Bitnami application password to 'ここにパスワード' #
[ 59.324419] bitnami[587]: # (the default application username is 'user') #
[ 59.328632] bitnami[587]: # #
[ 59.333957] bitnami[587]: #########################################################################
ここで出てこない場合は後にSSM Session Managerでの接続を行って確認するのでご安心を
これでパブリックIPをブラウザから打鍵してユーザ名とパスワードを打てばまずは使えます。
という訳でEC2画面の接続をやってみると
新しいタブが開き、接続できました。
もし、先ほどRedmineのパスワードを取得できていない場合は下記のコマンドで取得できます。
sudo cat /var/log/syslog
Route53でドメイン取得
https通信に証明書取得などが必要で、ドメインなどが必要になるため作成します。
Route53画面からcloudcentric.comが空いてるか確認します。
ちなみに弊社はこれです
検索結果です。
(.ninjaって候補出ますね。。海外で人気なんでしょうか?)
選択したらチェックアウトに進みます。
完了するとRoute53のダッシュボートでドメインの登録が進行中というステータスになります。
リソースで表示されるのは先ほど選択したドメインです。
約1時間後
ACMの設定
AWS Certificate Managerの画面に遷移して証明書のリクエストをします。
完全修飾ドメイン名は*.取得したドメイン名
で記載します。
詳細はガイドを貼っておきます。
その他項目はデフォルトのままリクエストします。
DNSプロバイダによっては24時間ほどかかるそうです。
が、必要な作業がまだあります。
証明書にはCNAME名とCNAME値があると思います。
これをRoute53に登録し忘れて保留中の検証ステータスが進まなかったです。
なので、次のホストゾーン修正までは終えて明日に確認した方がいいかと思います。
また、CNAME名とCNAME値に関しては以下に記載があります。
https://docs.aws.amazon.com/ja_jp/acm/latest/userguide/dns-validation.html
Route53でホストゾーン修正
Route53にもう一度戻ります。
Route53の画面からホストゾーンを選択します。
ホストゾーンの作成で、取得したドメインを入力して作成します。
作成したホストゾーン内でレコードを作成します。
AレコードとCNAMEレコードの2つが追加されていることを確認
ここまで完了するとACMのDNS検証準備が終わっているので
一日放置するか、ELB設定を飛ばしてRDS移行を行うのどちらかです。
ELB設定
EC2の画面左にあるELBを作成します。
Application Load Balancerでないと証明書を使えないようなのでALBを使用します。
セキュリティグループはALB用に作成します。
セキュリティグループとリスナー、ターゲットグループのイメージはこちらです。
だれでもアクセスされるわけにはいかないので自分のGlobalIPを許可するようにしました。
ターゲットグループも作成します。
既にあるEC2を設定します。
リスナーは以下の設定ですが、DNS検証が終わっていないとこの証明書を選択できないのでご注意を。
1ruleとあるリンクに飛びます。
ルールを挿入します。
Route53で作成するELBのAレコードを記載します。
追加すると以下の状態になるかと思います。
これでHTTPホストヘッダーが特定の条件の時にEC2インスタンスへ、
その他の場合はHTTPステータスが503でエラーを返すような設定です。
RDSへの移行
現状、EC2内部のDBを使っているのでオートスケールができない状態です。
RDSへ移行してWeb層とDB層を分けようと思います。
やることはざっくり以下です。
- RDSをデプロイ
- IMAロールを修正
- EC2インスタンス内部にあるDB情報をファイルへエクスポートする
- RDSに接続してエクスポートしたファイルをインポートする
- EC2インスタンスへログインして
/opt/bitnami/redmine/config/database.yml
でDBの接続先を設定する
また、RDSのパスワードをSystemManagerで管理してパスワードを定期変更できるようにしたかったです。
が、環境変数を/opt/bitnami/redmine/config/database.yml
内で読み込むことがうまくできませんでした。
そのため、database.yml内にパスワードをべた書きしたままになってしまいました。。
RDSをデプロイ
まずはRDS画面の左側からサブネットグループを作成します。
RDSの配置先で使うのでプライベートサブネットを指定して作成します。
次にSSM Session ManagerでEC2インスタンスへに入ってDB情報を確認します。
root@(略):/usr/bin# mysql --version
mysql Ver 15.1 Distrib 10.11.4-MariaDB, for Linux (x86_64) using readline 5.1
root@(略):/usr/bin#
Ver 15.1 Distrib 10.11.4-MariaDB
とあるのでRDSはMariaDBでいきます。
作成時に下記にチェックを入れるとSecretManagerでパスワードが自動ローテーションできます。
前述の通り、環境変数に埋め込むことはできましたがdatabase.ymlで読み込むことができなかったため
現状はローテーションをオフにしています。
その他設定は大体以下で設定しました。
IMAロールを修正
RDSの設定でIAMDB認証を有効にしているのでEC2インスタンスプロファイルにアタッチしているIAMロールを変更します。
追加したポリシーはAmazonRDSFullAccess
とSecretsManagerReadWrite
とAWSKeyManagementServicePowerUser
にしました。
KMSが突然出てきたように感じますが、EC2からSecretManagerに格納されているパスワードを取得するなら必要です。
また、先に言っておくとSecretsManagerReadWrite
とAWSKeyManagementServicePowerUser
を実際に生かすに至ってないのでAmazonRDSFullAccess
だけよいです。
EC2インスタンス内部にあるDB情報をファイルへエクスポートする
SSM Session ManagerでEC2インスタンスへログインしてDB情報を外に出します。
その上でEC2インスタンスにあるDBのパスワードが必要です。
cat /opt/bitnami/redmine/config/database.yml | grep password
で取得します。
root@(略):/usr/bin# cat /opt/bitnami/redmine/config/database.yml | grep password
password: "EC2インスタンス内のDBパスワード"
password: ""
password: ""
# password: "postgres"
# password: jenkins
root@(略):/usr/bin#
ユーザもdatabase.ymlに記載あるのでそれを採用してDBの情報を取り出します。
root@(略):/usr/bin# mysqldump -u bn_redmine -p bitnami_redmine > redmine_bakup.sql
Enter password:
root@(略):/usr/bin# ls -l redmine*
-rw-r--r-- 1 root root 74466 Jun 11 09:08 redmine_bakup.sql
root@(略):/usr/bin#
これでDB情報の取得完了です。
RDSに接続してエクスポートしたファイルをインポートする
まずはEC2インスタンスからRDS接続確認します。
RDSへ接続するユーザとパスワードはSecretManagerに連携する設定で作成したのでそちらから確認できます。
その情報をもとに接続をしてredmineというDBを作ってみます。
(ここのDB名はRDSに付けた名前とは関係ないです)
root@(略):/usr/bin# mysql -u admin -p -h (RDSのエンドポイント)
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 70
Server version: 10.6.10-MariaDB-log managed by https://aws.amazon.com/rds/
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> CREATE DATABASE redmine;
Query OK, 1 row affected (0.003 sec)
MariaDB [(none)]> USE redmine
Database changed
MariaDB [redmine]> SHOW TABLES;
Empty set (0.001 sec)
MariaDB [redmine]> exit
Bye
root@(略):/usr/bin#
これでインポートしてみます。
root@(略):/usr/bin# mysql -u admin -p -h (RDSのエンドポイント) redmine < redmine_bakup.sql
Enter password:
root@(略):/usr/bin# echo $?
0
root@(略):/usr/bin#
DBに接続して確認してみます。
MariaDB [(none)]> USE redmine;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
MariaDB [redmine]> SHOW TABLES;
+---------------------------+
| Tables_in_redmine |
+---------------------------+
| ar_internal_metadata |
| attachments |
| auth_sources |
| boards |
| changes |
| changeset_parents |
| changesets |
| changesets_issues |
| comments |
| custom_field_enumerations |
| custom_fields |
| custom_fields_projects |
| custom_fields_roles |
| custom_fields_trackers |
| custom_values |
| documents |
| email_addresses |
| enabled_modules |
| enumerations |
| groups_users |
| import_items |
| imports |
| issue_categories |
| issue_relations |
| issue_statuses |
| issues |
| journal_details |
| journals |
| member_roles |
| members |
| messages |
| news |
| projects |
| projects_trackers |
| queries |
| queries_roles |
| repositories |
| roles |
| roles_managed_roles |
| schema_migrations |
| settings |
| time_entries |
| tokens |
| trackers |
| user_preferences |
| users |
| versions |
| watchers |
| wiki_content_versions |
| wiki_contents |
| wiki_pages |
| wiki_redirects |
| wikis |
| workflows |
+---------------------------+
54 rows in set (0.001 sec)
MariaDB [redmine]>
がっつりインポートしてそうですね!
EC2インスタンスのdatabase.ymlでDBの接続先を設定する
/opt/bitnami/redmine/config/database.yml
の中身を修正します。
直す部分を切り出すと以下です。
production:
database: redmine
host: (RDSのエンドポイント)
username: admin
password: "SecretManagerで格納したパスワード"
という訳でパスワードべた書きのままになっていますがRDS化もできました。
番外編
ここからはうまくいかなかった部分の話です。
やりたいことは以下です。
- SecretManagerでパスワードローテーションが走る
- EC2のユーザーデータで起動ごとにSecretManagerからパスワードを取得して環境変数として
/etc/environment
へ格納 - database.ymlの中で環境変数としてパスワードを呼び出す
実際に以下のユーザーデータを記載しました。
#!/bin/bash
の前に書いてある部分は再起動ごとにユーザデータを実行してもらうためのおまじないです。
Content-Type: multipart/mixed; boundary="//"
MIME-Version: 1.0
--//
Content-Type: text/cloud-config; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="cloud-config.txt"
#cloud-config
cloud_final_modules:
[scripts-user, always]
--//
Content-Type: text/x-shellscript; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="userdata.txt"
#!/bin/bash
sudo apt -y update ## jsonファイルをjqコマンドで成形するためにjqコマンドインストールを行う
sudo apt -y install jq ## jsonファイルをjqコマンドで成形するためにjqコマンドインストールを行う
rm -f /etc/environment ## environmentファイルを起動ごとに最新化したいのでいったん削除
touch /etc/environment ## environmentファイルのからファイル作成
chmod 744 /etc/environment ## environmentファイルの権限を元通りに
chown root:root /etc/environment ## environmentファイルの権限を元通りに
echo "export user="$(aws secretsmanager get-secret-value --secret-id '(SecretManagerのシークレットの値)' | jq .SecretString | jq fromjson | jq -r .username)"" >> /etc/environment ## SecretManagerから取得してそのまま環境変数設定ファイルに格納
aws secretsmanager get-secret-value --secret-id '(SecretManagerのシークレットの値)' | jq .SecretString | jq fromjson | jq -r .password ## SecretManagerからパスワードを取得(特殊文字があるので一旦取得だけ)
echo "export password=$pass" >> /etc/environment ## SecretManagerから取得したパスワードを環境変数設定ファイルに格納
source /etc/environment ## enviromentファイルを再読み込み
database.ymlは下記の要領で記載すると環境変数を読み込んでくれるとブログやChatGPTが教えてくれます。
が、色々試してもあまりうまくいきませんでした。
password: <%= ENV[`環境変数名`]>
また、下記を実行してもきちんと出力はされたので環境変数としての格納には問題なさそうです。
何が違うのか次回までに見つけたいです。。
echo $pass
以上です!