RDSデータベースとクラスターのデフォルトポートの変更について

このブログシリーズ 「クラウドセキュリティ 実践集」 では、一般的なセキュリティ課題を取り上げ、「なぜ危険なのか?」 というリスクの解説から、 「どうやって直すのか?」 という具体的な修復手順(コンソール、AWS CLI、Terraformなど)まで、分かりやすく解説します。

この記事では、RDSデータベースとクラスターのデフォルトポート使用について、リスクと対策を解説します。

ポリシーの説明

RDSデータベースインスタンスやクラスターをデフォルトポート(MySQL/MariaDB: 3306、PostgreSQL: 5432、SQL Server: 1433、Oracle: 1521、Aurora MySQL: 3306、Aurora PostgreSQL: 5432)で運用することは、セキュリティ上の重大な脆弱性を生み出します。

デフォルトポートは世界中の攻撃者に広く知られており、自動化されたスキャニングツールやボットネットがこれらのポートを継続的に監視し、攻撃可能なデータベースを探しています。特に、パブリッククラウド環境では、セキュリティグループの設定ミスにより、意図せずインターネットに公開されるリスクがあります。

カスタムポートの使用は「多層防御(Defense in Depth)」戦略の重要な要素であり、「Security through Obscurity」だけに依存するものではありませんが、他のセキュリティ対策と組み合わせることで、データベースへの不正アクセスのリスクを大幅に低減できます。

修復手順

AWS Management Consoleでの修復手順

RDSインスタンスのポート変更

  1. AWS Management Consoleにログイン
    • RDSダッシュボードに移動
  2. 対象のDBインスタンスを選択
    • データベース一覧から変更対象を選択
    • 「変更」ボタンをクリック
  3. 接続とセキュリティの設定
    • 「追加設定」セクションを展開
    • 「データベースポート」フィールドでカスタムポート番号を入力
    • 推奨ポート範囲:
      • ユーザーポート: 1024-49151(IANA登録済みポートを避ける)
      • 動的/プライベートポート: 49152-65535(推奨)
    • 避けるべきポート: 8080, 8443, 9000番台(一般的なアプリケーションポート)
  4. 変更の適用タイミングを選択
    • 「すぐに適用」または「次のメンテナンスウィンドウ中に適用」を選択
    • 本番環境では計画的なメンテナンスウィンドウでの適用を推奨
    • 注意: ポート変更にはデータベースの再起動が必要(ダウンタイム: 約1-3分)
  5. セキュリティグループの更新
    • 関連するセキュリティグループを編集
    • インバウンドルールを新しいポート番号に更新
    • 古いポートのルールを削除

Aurora クラスターのポート変更

  1. クラスターの変更
    • RDSコンソールでAuroraクラスターを選択
    • 「変更」をクリック
  2. ポート設定の変更
    • 「ネットワークとセキュリティ」セクションで新しいポート番号を入力
    • クラスター内の全インスタンスに適用される

AWS CLIでの修復手順

# 1. 現在の設定確認
aws rds describe-db-instances \
  --db-instance-identifier <db-instance-id> \
  --query 'DBInstances[0].[DBInstanceIdentifier,Endpoint.Port,DBInstanceStatus]' \
  --output table

# 2. RDSインスタンスのポート変更(即時適用)
aws rds modify-db-instance \
  --db-instance-identifier <db-instance-id> \
  --db-port-number 23306 \
  --apply-immediately

# またはメンテナンスウィンドウで適用
aws rds modify-db-instance \
  --db-instance-identifier <db-instance-id> \
  --db-port-number 23306 \
  --no-apply-immediately

# 3. Aurora クラスターのポート変更
aws rds modify-db-cluster \
  --db-cluster-identifier <cluster-id> \
  --port 25432 \
  --apply-immediately

# クラスターインスタンスの確認
aws rds describe-db-clusters \
  --db-cluster-identifier <cluster-id> \
  --query 'DBClusters[0].DBClusterMembers[*].DBInstanceIdentifier' \
  --output table

# 4. セキュリティグループの更新
# 新しいポートのルール追加(特定のセキュリティグループからのみ許可)
aws ec2 authorize-security-group-ingress \
  --group-id <security-group-id> \
  --protocol tcp \
  --port 23306 \
  --source-group <source-security-group-id> \
  --group-owner <account-id>

# IPアドレスベースの場合(VPN経由など)
aws ec2 authorize-security-group-ingress \
  --group-id <security-group-id> \
  --protocol tcp \
  --port 23306 \
  --cidr 10.0.0.0/8 \
  --description "Database access from internal network"

# 古いポートのルール削除(確認後)
aws ec2 revoke-security-group-ingress \
  --group-id <security-group-id> \
  --protocol tcp \
  --port 3306 \
  --source-group <source-security-group-id>

# 5. 変更の確認
aws rds describe-db-instances \
  --db-instance-identifier <db-instance-id> \
  --query 'DBInstances[0].PendingModifiedValues'

# 6. 接続テスト(各データベースエンジン別)
# MySQL/MariaDB
mysql -h <endpoint> -P 23306 -u <username> -p

# PostgreSQL
psql -h <endpoint> -p 25432 -U <username> -d <database>

# SQL Server
sqlcmd -S <endpoint>,21433 -U <username> -P <password>

# Oracle
sqlplus <username>/<password>@<endpoint>:21521/<service_name>

 

Terraformでの修復手順

# カスタムポートを使用したRDSインスタンス
resource "aws_db_instance" "database" {
  identifier             = var.db_instance_identifier
  allocated_storage      = var.allocated_storage
  storage_type          = "gp3"
  engine                = "mysql"
  engine_version        = "8.0.35"
  instance_class        = var.instance_class
  db_name               = var.database_name
  username              = var.master_username
  password              = var.master_password

  # カスタムポートの設定(本番環境推奨値)
  port                  = var.db_port != null ? var.db_port : 23306

  # セキュリティ設定
  vpc_security_group_ids = [aws_security_group.rds.id]
  db_subnet_group_name   = aws_db_subnet_group.database.name

  # バックアップ設定
  backup_retention_period = 30
  backup_window          = "03:00-04:00"
  maintenance_window     = "sun:04:00-sun:05:00"

  # 暗号化設定
  storage_encrypted      = true
  kms_key_id            = aws_kms_key.rds.arn

  # 監査設定
  enabled_cloudwatch_logs_exports = ["error", "general", "slowquery"]

  # その他の設定
  deletion_protection    = true
  skip_final_snapshot   = false
  final_snapshot_identifier = "${var.db_instance_identifier}-final-snapshot-${formatdate("YYYY-MM-DD-hhmm", timestamp())}"

  tags = merge(
    var.common_tags,
    {
      Name = var.db_instance_identifier
      Port = "Custom"
    }
  )
}

# Aurora クラスターの設定
resource "aws_rds_cluster" "aurora" {
  cluster_identifier     = var.cluster_identifier
  engine                = "aurora-mysql"
  engine_version        = "8.0.mysql_aurora.3.04.0"
  database_name         = var.database_name
  master_username       = var.master_username
  master_password       = var.master_password

  # カスタムポートの設定(Auroraクラスター)
  port                  = var.aurora_port != null ? var.aurora_port : 25432

  # ネットワーク設定
  db_subnet_group_name  = aws_db_subnet_group.aurora.name
  vpc_security_group_ids = [aws_security_group.aurora.id]

  # バックアップ設定
  backup_retention_period = 35
  preferred_backup_window = "03:00-04:00"
  preferred_maintenance_window = "sun:04:00-sun:05:00"

  # 暗号化設定
  storage_encrypted     = true
  kms_key_id           = aws_kms_key.aurora.arn

  # 監査とログ設定
  enabled_cloudwatch_logs_exports = ["audit", "error", "general", "slowquery"]

  # 削除保護
  deletion_protection   = true
  skip_final_snapshot  = false
  final_snapshot_identifier = "${var.cluster_identifier}-final-${formatdate("YYYY-MM-DD-hhmm", timestamp())}"

  tags = var.common_tags
}

# セキュリティグループの設定
resource "aws_security_group" "rds" {
  name_prefix = "${var.environment}-rds-sg"
  description = "Security group for RDS instance with custom port"
  vpc_id      = var.vpc_id

  # カスタムポートでのアクセス許可(動的設定)
  ingress {
    description     = "Database access from application layer on custom port"
    from_port       = var.db_port
    to_port         = var.db_port
    protocol        = "tcp"
    security_groups = [aws_security_group.app.id]
  }

  # タグでポート情報を管理(セキュリティ上、値は隠蔽)
  tags = merge(
    var.common_tags,
    {
      Name = "${var.environment}-rds-sg"
      CustomPort = "Enabled"
    }
  )

  # アウトバウンドルール
  egress {
    description = "Allow all outbound traffic"
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = merge(
    var.common_tags,
    {
      Name = "${var.environment}-rds-sg"
    }
  )

  lifecycle {
    create_before_destroy = true
  }
}

# ポート番号の変数定義(セキュリティ強化版)
variable "db_port" {
  description = "Custom port for database connection"
  type        = number
  default     = null  # 意図的にデフォルト値を設定しない
  sensitive   = true  # ポート番号をログに出力しない

  validation {
    condition = var.db_port == null || (
      var.db_port >= 49152 &&
      var.db_port <= 65535 &&
      !contains([3306, 5432, 1433, 1521, 3389, 22, 23, 25, 80, 443, 8080, 8443], var.db_port)
    )
    error_message = "Database port must be between 49152-65535 (dynamic/private range) and not a commonly used port."
  }
}

# 環境別設定の例(ランダム化を含む)
resource "random_integer" "db_port" {
  min = 49152
  max = 65535
  keepers = {
    # インスタンスIDが変わった場合のみポートを再生成
    instance_id = var.db_instance_identifier
  }
}

locals {
  # 環境ごとに異なるポートレンジを使用
  port_mapping = {
    production = {
      mysql      = 50000 + random_integer.db_port.result % 1000
      postgresql = 51000 + random_integer.db_port.result % 1000
      sqlserver  = 52000 + random_integer.db_port.result % 1000
      oracle     = 53000 + random_integer.db_port.result % 1000
    }
    staging = {
      mysql      = 54000 + random_integer.db_port.result % 1000
      postgresql = 55000 + random_integer.db_port.result % 1000
      sqlserver  = 56000 + random_integer.db_port.result % 1000
      oracle     = 57000 + random_integer.db_port.result % 1000
    }
    development = {
      mysql      = 58000 + random_integer.db_port.result % 1000
      postgresql = 59000 + random_integer.db_port.result % 1000
      sqlserver  = 60000 + random_integer.db_port.result % 1000
      oracle     = 61000 + random_integer.db_port.result % 1000
    }
  }

  # 選択されたポートをSecrets Managerに保存
  db_config = {
    engine   = var.db_engine
    port     = local.port_mapping[var.environment][var.db_engine]
    endpoint = aws_db_instance.database.endpoint
  }
}

 

最後に

この記事では、RDSデータベースとクラスターのデフォルトポート使用について、リスクと対策を解説しました。

この問題の検出は弊社が提供するSecurifyのCSPM機能で簡単に検出及び管理する事が可能です。 運用が非常に楽に出来る製品になっていますので、ぜひ興味がある方はお問い合わせお待ちしております。 最後までお読みいただきありがとうございました。この記事が皆さんの役に立てば幸いです。

参考情報

この記事をシェアする

クラウドセキュリティ対策実践集一覧へ戻る

貴社の利用状況に合わせた見積もりを作成します。

料金プランを詳しく見る