ローカルからEC2の踏み台サーバーを経由してRDSデータベースにアクセスするために、IAMベースの認証とAWS Systems Manager(SSM)を使ってパスワードレスにする仕組みをCDKで作ったので、やり方を残しておきます。
まず、従来のアプローチ(SSHとパスワード)の問題点について。通常、ユーザーはSSH経由でEC2インスタンスにアクセスします。これにはキーペアの管理が必要です。これには2つのデメリットがあります。
- 運用コスト:EC2管理者がユーザーの公開キーをインスタンスに追加する必要がある
- セキュリティ:秘密キーを安全に保管する必要がある
また、データベースアクセスに関しては、パスワード認証の場合チーム間で共有する際にセキュリティリスクとなります。
SSMとIAM認証
仕組み
- EC2アクセス:AWS Systems Manager (SSM) により、SSHやキーペアなしでEC2インスタンスに接続できます。ユーザーはIAMロールを通じて認証を行います。
- RDSアクセス:IAMデータベース認証により、パスワードが不要になります。ユーザーは認証情報を保存する代わりにAWS IAMロールを通じて認証を行います。
以下の図は全体のアーキテクチャを示しています。
- ローカルPCからのユーザーアクセス
- ユーザーはAWS Systems Manager (SSM) を通じて認証し、安全なシェルアクセスを取得します。
- EC2(バスティオン)インスタンス
- RDSデータベースにアクセスするための中間サーバーとして機能します。
- RDSのIAM認証
- CloudWatchによるログとモニタリング
実装
システムの大部分はCDKを使用して実装し、一部はAWSコンソールとデータベースで個別に設定します。
SSMを使用したEC2のセットアップ
Step1. EC2インスタンス用の新しいインスタンスプロファイルIAMロールを作成し、SSMとCloudWatchへのアクセスを設定
インスタンスプロファイルはEC2インスタンスがSSMとCloudWatchサービスにアクセスするために使用されます
// ... スタック内 const ec2BastionRole = new iam.Role(this, "EC2BastionRole", { assumedBy: new iam.ServicePrincipal("ec2.amazonaws.com"), // EC2をプリンシパルとして設定 description: "Role for EC2 bastion instances", }); // ロールにポリシーをアタッチ(必要な場合) ec2BastionRole.addManagedPolicy( iam.ManagedPolicy.fromAwsManagedPolicyName( "AmazonSSMManagedInstanceCore", ), ); // アクセスログの保存用にCloudWatchLogsFullAccessをアタッチ ec2BastionRole.addManagedPolicy( iam.ManagedPolicy.fromAwsManagedPolicyName("CloudWatchLogsFullAccess"), ); // インスタンスプロファイルを作成し、ロールを関連付け const instanceProfile = new iam.CfnInstanceProfile( this, "InstanceProfile", { roles: [ec2BastionRole.roleName], instanceProfileName: "EC2BastionInstanceProfile", }, );
Step2: EC2インスタンスにインスタンスプロファイルを設定
... ec2Instance.instance.iamInstanceProfile = instanceProfile.ref;
Step3: SSMセッション用のロググループを作成
監査目的でEC2サーバーへのアクセスを記録するために、CloudWatchでロググループを定義する必要があります。
// CloudWatchロググループを作成 const logGroup = new logs.LogGroup(this, "SSMSessionLogGroup", { logGroupName: "/ssm/ec2/session", retention: logs.RetentionDays.ONE_WEEK, // 7日間の保持期間 });
このスタックをデプロイします:cdk deploy
Step4: SSMログの設定
ロググループが作成できたので、SSMでログを有効にします。AWSコンソールから手動で設定する必要があります。
AWS Systems Manager
を開き、左側のパネルからSession Manager
を選択します。次にCloudWatch logging
にチェックを入れ、作成したロググループ(/ssm/ec2/session
)を入力します。
Step5. ローカルPCにSSMプラグインをセットアップ
SSMを使用するには、AWS Cliの追加プラグインが必要です。以下のガイドに従ってください:
- Windows https://docs.aws.amazon.com/systems-manager/latest/userguide/install-plugin-windows.html
- Mac OS https://docs.aws.amazon.com/systems-manager/latest/userguide/install-plugin-macos-overview.html
これで準備完了です!サーバーにアクセスするには、EC2コンソールページでインスタンスIDを探し、以下のコマンドを使用します:
aws ssm start-session --target {instanceId} --profile={your profile} --region=us-west-2
補足:
- EC2インスタンスをプライベートサブネット内に作成することで、EC2サーバーへのアクセスをセキュアにできます
const ec2Instance = new ec2.Instance(this, "BastionInstance", { instanceType: ec2.InstanceType.of( ec2.InstanceClass.T3, ec2.InstanceSize.MICRO, ), // インスタンスタイプ machineImage: ec2.MachineImage.latestAmazonLinux2023(), // 最新のAmazon Linux AMI vpc, // インスタンスをVPCにアタッチ vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, // プライベートサブネットを使用 role: ec2BastionRole, // インスタンスにロールを割り当て });
IAM認証を使用したRDSの設定
次に、RDSのIAM認証を設定します。
Step1. EC2からPostgresにアクセスするためのネットワークポートを開放
データベースのセキュリティグループにインバウンドルールを追加します。Postgresの標準ポートである5432を開放します:
// 接続用セキュリティグループ const dbsg = new ec2.SecurityGroup(this, "DatabaseSecurityGroup", { vpc: vpc, description: id + "Database", securityGroupName: id + "Database", }); dbsg.addIngressRule( ec2.Peer.anyIpv4(), ec2.Port.tcp(5432), "allow Postgres access from Bastion Server", );
Step2. IAM認証を有効化
iamAuthentication
フラグでIAM認証を有効化します:
const rdsInstance = new rds.DatabaseInstance(this, "PgDatabase", { // その他の設定 ... iamAuthentication: true, // IAM認証を有効化 });
Step3. インスタンスプロファイルIAMロールにDBアクセスポリシーを追加
IAMを使用してDBに接続するためのポリシーを設定します:
ec2BastionRole.addToPolicy( new iam.PolicyStatement({ actions: ["rds-db:connect"], resources: [ `arn:aws:rds-db:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:dbuser:${rdsInstance.instanceResourceId}/db_user`, ], }), ); rdsInstance.grantConnect(ec2BastionRole);
ACCOUNT_ID
の後のdbuser
は固定値です。instanceResourceId
の後のdb_user
はDB内のユーザー名で、aws_user
など任意の値に設定できます。
リソースの詳細な説明については、https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.IAMPolicy.html を参照してください。
Step4. デプロイ
cdk deploy
を実行して更新を適用します
Step5. DBとテーブルアクセスの設定
マスター認証情報(管理者ロール)を使用してデータベースに接続します。次に、IAMロールに対応するデータベースユーザーを作成します。作成したものと完全に一致する必要があります。PostgreSQLの場合:
CREATE USER db_user; GRANT rds_iam TO db_user;
次に、既存のテーブルがある場合、それらへのアクセス権を付与する必要があります。例えば、public
スキーマにテーブルがある場合:
GRANT USAGE ON SCHEMA public TO db_user; GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO db_user;
将来作成されるテーブルにも権限を適用する場合は、デフォルトの権限も変更します:
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO db_user;
Step5. db_user
としてDBにアクセス
SSMを使用して踏み台サーバーにssm-user
としてアクセスした後、以下のコマンドを実行します:
sh-5.2$ export RDSHOST="{your db instance name}.rds.amazonaws.com" sh-5.2$ export PGPASSWORD="$(aws rds generate-db-auth-token --hostname $RDSHOST --port 5432 --region us-west-2 --username db_user)" sh-5.2$ psql "host=$RDSHOST port=5432 dbname=postgres user=db_user password=$PGPASSWORD"
こちらが最終的なアウトプットです。