AWS ECS経由でRDSに簡単接続のためのセキュアなポートフォワーディングCLIツールを作ってみた

# AWS ECS経由でRDSに簡単接続のためのセキュアなポートフォワーディングCLIツールを作ってみた

## はじめに

AWS環境でRDSにアクセスしたいとき、セキュリティを考慮すると直接インターネット経由でアクセスするのは推奨されません。通常は踏み台サーバーを使ったり、VPN接続を設定したりしますが、設定が複雑だったり管理が大変だったりします。

そこで、**AWS ECS**と**SSM Session Manager**を使って、セキュアで簡単にRDSに接続できるCLIツールを作ってみました！

## このツールの特徴

- ✅ **インタラクティブな操作**: 使いやすいzoxideスタイルの検索付きCLI
- ✅ **セキュア**: AWS SSM Session Managerを使用した暗号化通信
- ✅ **簡単設定**: 複雑な設定ファイル不要
- ✅ **自動取得**: ECSクラスター・タスク・RDSインスタンスを自動で取得
- ✅ **TypeScript製**: 型安全で保守性の高いコード

## 仕組み

```text
[ローカルPC] → [SSM Session Manager] → [ECSタスク] → [RDS]
     ↑                                               ↑
localhost:8888                                プライベートサブネット
```

このツールは以下の仕組みで動作します：

1. AWS SSM Session Managerでセキュアな接続を確立
2. 指定したECSタスクを踏み台として使用
3. ローカルポートからRDSへのポートフォワーディングを実行

## 📊 なぜこのツールを作ったのか

### 従来の方法の課題

1. **踏み台サーバー管理**: EC2インスタンスの管理・監視が必要
2. **VPN設定の複雑さ**: Client VPNの設定・維持コスト
3. **セキュリティリスク**: SSH鍵管理・セキュリティパッチ適用
4. **操作の煩雑さ**: 毎回コマンドを手動入力する手間

### このツールで解決できること

1. **管理不要**: ECSタスクを踏み台として利用（既存リソース活用）
2. **簡単操作**: 対話的UIで誰でも簡単に使用可能
3. **セキュア**: SSM Session Managerによる暗号化通信
4. **コスト効率**: 追加インフラ不要

## 🚀 インストールと使用方法

### 前提条件

- AWS CLI設定済み
- Session Manager Plugin
- Node.js (v18以上)

```bash
# AWS CLI (macOS)
brew install awscli
aws configure

# Session Manager Plugin (macOS)
brew install session-manager-plugin
```

### 実行

```bash
# npmから直接実行
npx ecs-pf connect
```

## 🎮 実際の使用例

```bash
$ npx ecs-pf connect

🚀 AWS ECS経由RDS接続ツールを開始します...
📋 AWS設定を確認しています...
🌍 利用可能なAWSリージョンを取得しています...

💡 zoxide-style: リストは入力に応じてフィルタされます (↑↓で選択, Enterで確定)

? 🌍 AWSリージョンを検索・選択: ap-northeast-1
✅ リージョン: ap-northeast-1

🔍 ECSクラスターを取得しています...
? 🔍 ECSクラスターを検索・選択: production-cluster

🔍 ECSタスクを取得しています...
? 🔍 ECSタスクを検索・選択: web-service: 12345678...

🔍 RDSインスタンスを取得しています...
? 🔍 RDSインスタンスを検索・選択: production-db (postgres) - xxx.rds.amazonaws.com:5432

? RDSポート番号を入力 (postgres): 5432
? ローカルポート番号を入力: 8888

🚀 ポートフォワーディングセッションを開始します...
選択されたタスク: ecs:production-cluster_123456789

実行コマンド:
aws ssm start-session --target ecs:production-cluster_123456789 --parameters {"host":["xxx.rds.amazonaws.com"],"portNumber":["5432"],"localPortNumber":["8888"]} --document-name AWS-StartPortForwardingSessionToRemoteHost

🎯 localhost:8888 でRDS接続が利用可能になります
セッションを終了するには Ctrl+C を押してください
```

接続が確立されたら、別のターミナルでデータベースに接続できます：

```bash
# TablePlusや DBeaver などのGUIツールでも接続可能


# PostgreSQLの場合
psql -h localhost -p 8888 -U myuser -d mydatabase

# MySQLの場合
mysql -h localhost -P 8888 -u myuser -p mydatabase

```

## 🛠️ 技術詳細

### 使用している技術スタック

- **言語**: TypeScript + Node.js (ESModules)
- **AWS SDK**: @aws-sdk/client-*シリーズ
- **CLI**: Commander.js
- **対話UI**: Inquirer.js + Fuse.js (あいまい検索)
- **ビルドツール**: TypeScript Compiler
- **リンター/フォーマッター**: Biome

### 主要な実装ポイント

#### 1. zoxideスタイルの検索機能

```typescript
const selectedCluster = await search({
  message: "🔍 Search and select ECS cluster:",
  source: async (input) => {
    return await searchClusters(clusters, input || "");
  },
  pageSize: 12,
}) as ECSCluster;
```

Fuse.jsを使って、リアルタイムでファジー検索ができる使いやすいUIを実装しました。

#### 2. AWS SDK v3の活用

```typescript
const ecsClient = new ECSClient({ region });
const clusters = await ecsClient.send(new ListClustersCommand({}));
```

最新のAWS SDK v3を使用して、モジュラーで効率的なAWS APIの呼び出しを実現。

#### 3. エラーハンドリングと再試行機能

```typescript
export async function connectToRDS(): Promise<void> {
  let retryCount = 0;
  const maxRetries = 3;

  while (retryCount <= maxRetries) {
    try {
      await connectToRDSInternal();
      return;
    } catch (error) {
      retryCount++;
      displayFriendlyError(error);

      if (retryCount <= maxRetries) {
        const shouldRetry = await askRetry();
        if (!shouldRetry) return;
      }
    }
  }
}
```

## 🔧 必要なAWS権限

このツールを使用するには、以下のIAM権限が必要です：

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ecs:ListClusters",
        "ecs:ListServices",
        "ecs:ListTasks",
        "ecs:DescribeTasks",
        "rds:DescribeDBInstances",
        "ssm:StartSession",
        "ec2:DescribeRegions"
      ],
      "Resource": "*"
    }
  ]
}
```

## 🔒 セキュリティの考慮点

### 1. セキュアな通信

- SSM Session Managerによる暗号化通信
- インターネットゲートウェイ不要
- セキュリティグループでの厳密なアクセス制御

### 2. 最小権限の原則

- 必要最小限のIAM権限のみ要求
- 一時的な接続（セッション終了で自動切断）

### 3. 監査ログ

- AWS CloudTrailでセッション開始/終了を記録
- Session Managerによる接続ログ

## 🚧 今後の改善予定

- [ ] **引数対応**: コマンドライン引数での接続先指定
- [ ] **設定ファイル対応**: よく使う接続先の保存機能

## 🌟 まとめ

AWS ECS経由でRDSに接続するCLIツール「ecs-pf」を紹介しました。

このツールの特徴：

- **セキュア**: SSM Session Managerによる暗号化通信
- **簡単**: 対話的UIで直感的な操作
- **効率的**: 既存のECSタスクを踏み台として活用
- **保守性**: TypeScriptによる型安全なコード

開発者の皆さん、ぜひ試してみてください！

```bash
npx ecs-pf connect
```

## 🔗 リンク

- [GitHub Repository](https://github.com/yuyakinjo/aws-portfoward)
- [npm Package](https://www.npmjs.com/package/ecs-pf)

## 🏷️ タグ

AWS ECS RDS CLI TypeScript ポートフォワーディング SSM セキュリティ DevOps