はじめに
EC2 Instance Connect Endpoint(EIC Endpoint)使っていますか? 無料で踏み台ホストを撲滅できる画期的なサービスです。
これをCDKで簡単に作成できるようになったので、そのご紹介です。
ネタバレ
EC2への管理通信はもちろんのこと、RDS(Aurora)への管理通信も確立できます。 めちゃめちゃ便利だと思うので、ぜひお試しください。
下準備
EIC Endpointは公式L2コンストラクトが存在しませんが、コミュニティ主導でのConstruct libraryであるopen-constructsにL2が存在しています。 そこで、CDKプロジェクトをセットアップし、open-constructsをインストールして使っていきます。
npx cdk init --language=typescript
npm install @open-constructs/aws-cdk
ユースケース
EC2 instanceへの管理通信
プライベートサブネットにEC2インスタンスを設置し、SSHでの管理通信をEIC Endpoint経由で実行してみます。
CDKでの実装例
export class TempCdkProjectStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); // NATGWやIGWも不要です。適宜削除してください。 const vpc = new ec2.Vpc(this, 'VPC') // EC2 instance const insntance = new ec2.Instance(this, 'Instance', { vpc, instanceType: ec2.InstanceType.of(ec2.InstanceClass.T2, ec2.InstanceSize.MICRO), machineImage: new ec2.AmazonLinuxImage({ generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2023, }) }); // EIC EndpointのL2コンストラクト const eicEndpoint = new ocf.aws_ec2.InstanceConnectEndpoint(this, 'InstanceConnectEndpoint', { vpc, }); // EIC Endpoint -> EC2 InstanceへのSecurity Groupの穴あけ eicEndpoint.connections.allowTo(insntance, ec2.Port.tcp(22)); // Instance IDを出力 new cdk.CfnOutput(this, 'InstanceId', { value: insntance.instanceId, }); } }
接続方法
上記CDKコードをデプロイ後、以下のコマンドを実行します。 instance idはcdk deploy時に出力されたものに修正してください。
$ aws ec2-instance-connect ssh --instance-id i-12345example --connection-type eice The authenticity of host '10.0.0.1 (<no hostip for proxy command>)' can't be established. ED25519 key fingerprint is SHA256:abcdefg. This key is not known by any other names. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added '10.0.0.1' (ED25519) to the list of known hosts. , #_ ~\_ ####_ Amazon Linux 2023 ~~ \_#####\ ~~ \###| ~~ \#/ ___ https://aws.amazon.com/linux/amazon-linux-2023 ~~ V~' '-> ~~~ / ~~._. _/ _/ _/ _/m/' [ec2-user@ip-10-0-0-1 ~]$
さっくり繋がりました!最高ですね。
RDS(Aurora)への管理通信
続いて、プライベートサブネットにAurora(mysql)を設置し、EIC Endpoint経由で管理通信を行ってみます。 mysqlのデフォルトポートは3306なのでEIC Endpointは非対応ですが、DBがlistenするポートを3389に変える荒業で切り抜けてみたいと思います。
CDKでの実装例
export class TempCdkProjectStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); const vpc = new ec2.Vpc(this, 'VPC') // Aurora cluster const auroraCluster = new rds.DatabaseCluster(this, 'Aurora', { engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_3_06_0, }), // 【重要】EIC Endpointでアクセスするため、ポートを3389に変更 port: 3389, // パスワードハードコーディングの駄目な例です。本番ではrds.Credentials.fromGeneratedSecret('hogeuser')などを使ってください credentials: rds.Credentials.fromPassword('admin', cdk.SecretValue.unsafePlainText('testPass')), vpc, writer: rds.ClusterInstance.serverlessV2('writer'), }); const eicEndpoint = new ocf.aws_ec2.InstanceConnectEndpoint(this, 'InstanceConnectEndpoint', { vpc, }); // EIC Endpoint -> Aurora Cluster へのSecurity Groupの穴あけ eicEndpoint.connections.allowTo(auroraCluster, ec2.Port.tcp(3389)); // DB Endpoint (プライベートIPの取得に用います) new cdk.CfnOutput(this, 'AuroraEndpoint', { value: auroraCluster.clusterEndpoint.hostname, }); new cdk.CfnOutput(this, 'EicEndpointId', { value: eicEndpoint.instanceConnectEndpointId, }); } }
接続方法
まず、DBのプライベートIPを取得します。パブリックDNSサーバ上での名前解決で問題ありません。
$ nslookup hogehoge.cluster-cvekcubvryhp.ap-northeast-1.rds.amazonaws.com Server: 8.8.8.8 Address: 8.8.8.8#53 Non-authoritative answer: hogehoge.cluster-cvekcubvryhp.ap-northeast-1.rds.amazonaws.com canonical name = hogehoge.cluster-cvekcubvryhp.ap-northeast-1.rds.amazonaws.com. Name: hogehoge.cluster-cvekcubvryhp.ap-northeast-1.rds.amazonaws.com Address: 10.0.198.63 // こちら
続いて、SSHトンネルを張ります。以下の通り、パラメータを指定してください。
パラメータ名 | value |
---|---|
--private-ip-address | DBのプライベートIP |
--instance-connect-endpoint-id | EIC EndpointのID |
--local-port | ローカルでlistenするポート (何でもOK) |
--remote-port | DBサーバがlistenするポート(3389) |
$ aws ec2-instance-connect open-tunnel --instance-connect-endpoint-id eice-hogehoge --private-ip-address 10.0.198.63 --local-port 3306 --remote-port 3389 Listening for connections on port 3306.
無事にトンネルが張れました!上記のコマンドは動かしたまま、適当なDBクライアントツールでlocalhost:3306に接続してみましょう。
今回はSequel Aceで接続してみます。クレデンシャルはCDKで指定したusername:admin, pass: testPassです。
いけました〜!最高ですね。
これはSession Managerではできないので、大きな差別化ポイントだと思います。
使用上の注意
EIC Endpoint経由でのアクセス時の権限
ユーザに特定の権限が必要です。正確な情報は公式ドキュメントを参照してください。
これを活用することで、特定のユーザにのみアクセス権限を与えることができます。IAMのお陰で認可管理もラクラクですね!
DBアクセスはEIC Endpointのユースケースに含まれていますか?
わかりません。多分グレーゾーンです。
当初EIC Endpointのサービスリリース時には全portが開放されていましたが、すぐに22, 3389以外closeされてしまいました。したがって、AWS的には大人しくSSH, RDPでだけ使ってほしいのだと思っています。
現状、EIC Endpointはあくまでポート番号だけ(L4レイヤだけ)で通信の許可/拒否を判定しています。 更にL7レイヤのペイロードまで深堀って許可/拒否の判定は流石にしないと思うのですが、、そもそも技術的にはできるのでしょうか...??詳しい人教えて下さい...
ということで、動きはしますが、自己責任でお願いいたします。
その他のVPCリソースへのアクセスもできますか?
VPC内のプライベートIPとポート番号さえ決まればイケルはずです。
最後に
実はこのL2コンストラクトは私がPRを作成しました!
open-constructsにはまだ2つしかL2が無いので、コントリビュートチャンスが無限に眠っています。 皆様もぜひチャレンジください〜!