■ECR+ECS+Codeシリーズで自動デプロイ: RDSに接続する
■Cloud9を作成
RDSにユーザやテーブルを作成するため、Cloud9を作成しておく
(運用はコンテナなので、作業用にFargateやEC2を作成する…が、一時的に必要になるだけなのでCloud9を使う)
Name: Test
Description: (空欄のまま)
Environment type: New EC2 instance
Instance type: t2.micro (1 GiB RAM + 1 vCPU)
Platform: Amazon Linux 2 (recommended)
Cost-saving setting: After 30 minutes (default) ※再検証時は項目が無かったので未設定
IAM role: AWSServiceRoleForAWSCloud9 ※再検証時は項目が無かったので未設定
Network (VPC): Container ※コンテナ用のVPCを選択
Subnet: Container-Public-A ※外部からアクセスできる(Publicな)サブネットを選択
Cloud9のEC2には、以下のセキュリティグループが自動で割り当てられていた
(EC2インスタンスの一覧から確認できる。このセキュリティグループは後から使用する)
sg-04b8e304c2064b14d
Environments一覧の「Cloud9 IDE」列の「Open」から接続できる
「Welcome」タブなどが開くが、「bash」タブからコマンドを入力できることを確認する
■パラメータグループの作成
パラメータグループファミリー: mariadb10.6
グループ名: container-test
説明: for Container-Test
以下のとおりパラメータを設定する
character_set_client: utf8mb4
character_set_connection: utf8mb4
character_set_database: utf8mb4
character_set_results: utf8mb4
character_set_server: utf8mb4
init_connect: SET SESSION time_zone = CASE WHEN POSITION('rdsadmin@' IN CURRENT_USER()) = 1 THEN 'UTC' ELSE 'Asia/Tokyo' END;
■RDSの作成
データベース作成方法を選択: 標準作成
エンジンのオプション: MariaDB
バージョン: MariaDB 10.6.10
テンプレート: 開発/テスト
DBインスタンス識別子: container-test
マスターユーザー名: admin
マスターパスワード: qazwsxedc
DBインスタンスクラス: バースト可能クラス(t クラスを含む)
db.t3.micro
ストレージタイプ: 汎用(SSD)
ストレージ割り当て: 20GiB
ストレージの自動スケーリング: (チェックを外す)
マルチAZ配置: なし
コンピューティングリソース: EC2コンピューティングリソースに接続 ※「EC2コンピューティングリソースに接続しない」だと、後からセキュリティグループを調整してもCloud9から接続できなかった。また検証したい
EC2インスタンス: (上の手順で作成してCloud9のEC2インスタンスを選択する)
Virtual Private Cloud: (初めから選択済みになっている)※「EC2コンピューティングリソースに接続」にすると、VPCを選択できない?選択したEC2に合わせて適切に設定される?
DBサブネットグループ: 自動セットアップ(初めから選択済みになっている)
既存のVPCセキュリティグループ:(変更せずだが、「rds-ec2-1」が自動的に追加される)
最初のデータベース名: container
DBパラメータグループ: container-test
オプショングループ: default:mariadb-10-6
以下のセキュリティグループが作成&割り当てられていた
ec2-rds-1 ... Cloud9に割り当てられていた
rds-ec2-1 ... RDSに割り当てられていた
■RDSへの接続を許可
Cloud9からは、以下のようにして接続できる(mysqlはデフォルトでインストール済みだった)
パスワードを入力しても、いつまで経っても結果が返ってこない場合、セキュリティグループの設定が正しいか確認する
$ mysql --version
mysql Ver 15.1 Distrib 10.2.38-MariaDB, for Linux (x86_64) using EditLine wrapper
$ mysql -h container-test.xxxxx.ap-northeast-1.rds.amazonaws.com -u admin -p
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 8
Server version: 10.6.10-MariaDB 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)]> SELECT VERSION();
+-----------------+
| VERSION() |
+-----------------+
| 10.6.10-MariaDB |
+-----------------+
1 row in set (0.00 sec)
AWS Cloud9 環境を作成してAmazon Aurora Serverless MySQL データベースに接続する | DevelopersIO
https://dev.classmethod.jp/articles/amazon-aurora-serverlessmysql-cloud9/
■RDSに作業ユーザを作成
> CREATE USER webmaster IDENTIFIED BY 'qazwsxedc';
> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, EVENT ON container.* TO webmaster;
> FLUSH PRIVILEGES;
> QUIT;
■RDSへの作業ユーザでの接続を確認&テーブルを作成
$ mysql -h container-test.xxxxx.ap-northeast-1.rds.amazonaws.com -u webmaster -p
Enter password:
> CREATE TABLE test_table(
> id INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID',
> text VARCHAR(255) NOT NULL COMMENT 'テキスト',
> PRIMARY KEY(id)
> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT 'テスト';
> INSERT INTO test_table(text) VALUES('Test1');
> INSERT INTO test_table(text) VALUES('Test2');
> SELECT * FROM test_table;
+----+-------+
| id | text |
+----+-------+
| 1 | Test1 |
| 2 | Test2 |
+----+-------+
2 rows in set (0.00 sec)
■Secrets ManagerにRDSへの接続情報を登録
※環境変数や taskdef.json 内に、直接機密情報を記載しなくていいようにする
Secrets Manager → 新しいシークレットを保存する
シークレットのタイプを選択
シークレットのタイプ: Amazon RDS データベースの認証情報
ユーザー名: (RDS上に作成したユーザー)
パスワード: (RDS上に作成したパスワード)
暗号化キー: aws/secretmanager (初回は「DefaultEncryptionKey」を選択するといい)
データベース: (RDS上に作成したデータベース)
「次」ボタンをクリック
シークレットを設定
シークレットの名前: dev/container-test/Mysql
「次」ボタンをクリック
ローテーションを設定 - オプション
自動ローテーション: OFF
「次」ボタンをクリック
レビュー
「保存」ボタンをクリック
■ポリシーの作成
※ECSからSecrets Managerの情報を取得するためのポリシーを作成する
セキュリティ認証情報 → ポリシー → ポリシーの作成
「JSON」タブに以下を入力する
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "GetSecretForECS",
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue"
],
"Resource": [
"*"
]
}
]
}
「次のステップ:タグ」をクリック
そのまま「次のステップ:確認」をクリック
ポリシーの作成画面になるので以下を入力
名前: Container-Test-GettingSecretForECS
説明: Policy to get Secret for ECS
「ポリシーの作成」をクリック
なお、上記のコードは書籍のサポートページ掲載されている
sbcntr-resources/secrets_policy.json at main - uma-arai/sbcntr-resources - GitHub
https://github.com/uma-arai/sbcntr-resources/blob/main/iam/secrets_policy.json
■タスク実行ロールの作成
※ECSがタスクを実行するときのロールを作成する
※ロール ecsTaskExecutionRole を作成済みの場合、この手順は飛ばす
セキュリティ認証情報 → ロール → ロールを作成
信頼されたエンティティを選択
信頼されたエンティティタイプ: AWSのサービス
ユースケース
他のAWSのサービスのユースケース:
Elastic Container Service → Elastic Container Service Task を選択
「次へ」ボタンをクリック
許可を追加
「AmazonECSTaskExecutionRolePolicy」を検索してチェックを入れる
「次へ」ボタンをクリック
名前、確認、および作成
ロール名: ecsTaskExecutionRole
「ロールを作成」ボタンをクリック
Amazon ECS タスク実行IAM ロール - Amazon Elastic Container Service
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task_execution_IAM_role.html#creat...
ECSのタスクロールとタスク実行ロールの違い - karakaram-blog
https://www.karakaram.com/difference-between-ecs-task-role-and-task-execution-role/
■タスク実行ロールにアクセス権限を付与
※ECSがタスクを実行するとき、Secrets Managerの情報を取得できるように権限を付与する
セキュリティ認証情報 → ロール
上の手順で作成した ecsTaskExecutionRole を選択
「許可を追加 → ポリシーをアタッチ」をクリック
上の手順中で作成した Container-Test-GettingSecretForECS にチェックを入れ、「ポリシーのアタッチ」ボタンをクリック
■Secrets Managerの情報を読み込ませるためにタスクを更新
Elastic Container Service → Amazon ECS → タスク定義
「Container-Test-Task」にチェックを入れて「新しいリビジョンの作成」をクリック
(以下、前回タスクを作成した時の内容をベースに入力する)
もともと追加されている「ecr_php81_apache」に対し、必要な箇所を調整
今回は「環境変数」にある「環境変数を追加」をクリックし、以下のように入力する
キー 値のタイプ 値
RDS_HOST ValueFrom arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:dev/container-test/Mysql-bcmXxP:host::
RDS_DBNAME ValueFrom arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:dev/container-test/Mysql-bcmXxP:dbname::
RDS_USERNAME ValueFrom arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:dev/container-test/Mysql-bcmXxP:username::
RDS_PASSWORD ValueFrom arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:dev/container-test/Mysql-bcmXxP:password::
上記で更新すると、各値がコンテナに渡されるようになる
デプロイすると、phpinfo() の「Environment」に以下が現れた
RDS_HOST: container-test.xxxxx.ap-northeast-1.rds.amazonaws.com
RDS_DBNAME: container
RDS_USERNAME: (RDS上に作成したユーザー)
RDS_PASSWORD: (RDS上に作成したパスワード)
環境変数にはarnの値が表示されて、実際のパスワードを得るにはSDKなどで独自に処理が必要なのかと思いきや、普通に環境変数へ展開された
これだと環境変数に普通に接続情報を書くのと変わらないような
…と思ったが、taskdef.json に直接接続情報を書くと「リポジトリ内に機密情報を含めている」状態になるので、それを避けるための措置か
phpinfo() の内容は絶対に流出させてはならない(もともと流出させるべきでは無い内容だが)
以下などを参考に、本番環境では phpinfo() を使用できないようにするなどしておくべきか
php.iniで危険な関数を無効化する | 晴耕雨読
https://tex2e.github.io/blog/php/set-disable-functions
■PHPプログラムからの接続確認
Dockerfileを調整し、PHPからMySQLへ接続するための命令を追加インストールする
具体的には、ecr_php81_apache\docker\php\Dockerfile を以下のように修正する(「pdo_mysql」と「mysqli」を追加している)
RUN docker-php-ext-install gd mbstring intl zip
↓
RUN docker-php-ext-install gd pdo_mysql mysqli mbstring intl zip
デプロイして、PHPからMySQLへ接続する命令を書いたページへアクセスすると、データベースに接続できた
具体的なコードは以下のとおり
<?php
try {
$pdo = new PDO(
'mysql:dbname=' . $_ENV['RDS_DBNAME'] . ';host=' . $_ENV['RDS_HOST'],
$_ENV['RDS_USERNAME'],
$_ENV['RDS_PASSWORD']
);
$stmt = $pdo->query('SELECT NOW() AS now;');
$data = $stmt->fetch(PDO::FETCH_ASSOC);
echo "<p>" . $data['now'] . "</p>\n";
$pdo = null;
} catch (PDOException $e) {
exit($e->getMessage());
}
■トラブル: PHPプログラムのページからRDSへアクセスしようとすると「504 Gateway Time-out」と表示された
WebサーバのコンテナからRDSにアクセスできるように、
RDSに割り当てているセキュリティグループの設定を調整する