Cloud SQLインスタンスのrootユーザーアクセス制限設定手順

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

この記事では、Cloud SQLインスタンスのrootユーザーに対するホストベースのアクセス制限について、リスクと対策を解説します。

ポリシーの説明

Cloud SQLインスタンスのrootユーザーは、データベースシステムにおける最高権限を持つ特権アカウントです。このアカウントに対して適切なアクセス制限を設定せずに、どこからでもアクセス可能な状態(0.0.0.0/0)にしておくことは、重大なセキュリティリスクとなります。

※ 併せてパブリックIPの無効化も行うようにしましょう。

ホストベースのアクセス制限(IPホワイトリスト)を実装することで、特定のIPアドレスやネットワークからのみrootユーザーでの接続を許可し、不正アクセスのリスクを大幅に低減できます。Google Cloudでは、Cloud SQLインスタンスレベルとユーザーレベルの両方でアクセス制御を設定できます。

修復方法

前提条件の確認

修復を行う前に、以下を確認してください:

  • 現在のrootユーザーからの接続元IPアドレス
  • アプリケーションやバックアップツールがrootユーザーを使用している場合、その接続元IPアドレス
  • 緊急時のアクセス経路(VPN、踏み台サーバーなど)

コンソールでの修復手順

  1. Google Cloud Consoleにアクセス
    • Cloud Consoleにログイン
    • ナビゲーションメニューから「SQL」を選択
  2. インスタンスレベルのアクセス制御設定(推奨)
    • 対象のCloud SQLインスタンスを選択
    • 「概要」タブから「編集」をクリック
    • 「接続」セクションまでスクロール
    • 「承認済みネットワーク」で「ネットワークを追加」をクリック
    • 信頼できるIPアドレス/CIDR範囲を追加
  3. ユーザーレベルのアクセス制御設定
    • 左側のメニューから「ユーザー」を選択
    • rootユーザーの行を見つけ、右端の「⋮」(その他の操作)メニューをクリック
    • 「編集」を選択
  4. ホスト制限を設定
    • 「ホスト名」セクションで「制限する」を選択
    • 許可するIPアドレスまたはCIDR範囲を入力
      • 例: 内部ネットワーク: 10.0.0.0/8
      • 例: 特定のサーバー: 192.168.1.100
    • 複数のIPアドレスを追加する場合は「+追加」をクリック
  5. 設定を保存
    • 「保存」ボタンをクリックして変更を適用
    • 変更が反映されるまで数秒待機
  6. 設定の確認
    • ユーザー一覧でrootユーザーの「ホスト」列に制限が表示されていることを確認
    • 「概要」タブで承認済みネットワークが正しく設定されていることを確認

Terraformでの修復手順

# Cloud SQLインスタンスの定義(セキュリティ強化版)
resource "google_sql_database_instance" "main" {
  name             = "secure-mysql-instance"
  database_version = "MYSQL_8_0"
  region           = "asia-northeast1"

  # 重要: 削除保護を有効化
  deletion_protection = true

  settings {
    tier = "db-n1-standard-2"

    # バックアップ設定
    backup_configuration {
      enabled                        = true
      start_time                     = "03:00"
      location                       = "asia-northeast1"
      point_in_time_recovery_enabled = true
      transaction_log_retention_days = 7
      backup_retention_settings {
        retained_backups = 30
        retention_unit   = "COUNT"
      }
    }

    # IPベースのアクセス制御(インスタンスレベル)
    ip_configuration {
      ipv4_enabled    = true
      require_ssl     = true  # SSL接続を強制

      # プライベートIPを使用する場合
      private_network = var.enable_private_ip ? google_compute_network.vpc[0].id : null

      # パブリックIPを使用する場合の承認済みネットワーク
      dynamic "authorized_networks" {
        for_each = var.authorized_networks
        content {
          name  = authorized_networks.value.name
          value = authorized_networks.value.cidr
        }
      }
    }

    # セキュリティ関連のデータベースフラグ
    database_flags {
      name  = "skip_name_resolve"
      value = "ON"
    }

    database_flags {
      name  = "local_infile"
      value = "OFF"  # LOCAL INFILEを無効化
    }

    # 監査ログの有効化
    database_flags {
      name  = "cloudsql_mysql_audit"
      value = "ON"
    }
  }
}

# rootユーザーの設定(ホスト制限付き)
# 注意: 本番環境ではrootユーザーの使用を最小限に抑える
resource "google_sql_user" "root_restricted" {
  name     = "root"
  instance = google_sql_database_instance.main.name

  # 特定のネットワークからのみ許可
  host     = var.root_allowed_host  # 例: "10.0.0.0/8"

  # パスワードはGoogle Secret Managerから取得
  password = data.google_secret_manager_secret_version.root_password.secret_data
}

# 無制限のrootユーザー(%)が存在しないことを確認するnullリソース
resource "null_resource" "remove_unrestricted_root" {
  provisioner "local-exec" {
    command = <<-EOT
      # 無制限のrootユーザーが存在する場合は削除
      if gcloud sql users list --instance=${google_sql_database_instance.main.name} | grep -q "root.*%"; then
        gcloud sql users delete root --host='%' --instance=${google_sql_database_instance.main.name} --quiet
      fi
    EOT
  }

  depends_on = [google_sql_database_instance.main]
}

# アプリケーション用の最小権限ユーザー(推奨)
resource "google_sql_user" "app_user" {
  name     = "application"
  instance = google_sql_database_instance.main.name
  host     = var.app_allowed_host  # 例: "10.1.0.0/16"
  password = data.google_secret_manager_secret_version.app_password.secret_data
}

# 読み取り専用ユーザー
resource "google_sql_user" "readonly_user" {
  name     = "readonly"
  instance = google_sql_database_instance.main.name
  host     = var.monitoring_allowed_host
  password = data.google_secret_manager_secret_version.readonly_password.secret_data
}

# データベースの作成
resource "google_sql_database" "app_db" {
  name     = "application_db"
  instance = google_sql_database_instance.main.name
  charset  = "utf8mb4"
  collation = "utf8mb4_unicode_ci"
}

# Secret Managerでパスワードを管理
resource "google_secret_manager_secret" "root_password" {
  secret_id = "cloudsql-root-password"

  replication {
    automatic = true
  }
}

resource "google_secret_manager_secret_version" "root_password" {
  secret      = google_secret_manager_secret.root_password.id
  secret_data = random_password.root.result
}

resource "random_password" "root" {
  length  = 32
  special = true
  override_special = "!#$%&*()-_=+[]{}<>:?"
}

# 変数定義
variable "authorized_networks" {
  description = "List of authorized networks for Cloud SQL instance"
  type = list(object({
    name = string
    cidr = string
  }))
  default = [
    {
      name = "office-network"
      cidr = "203.0.113.0/24"
    },
    {
      name = "vpn-gateway"
      cidr = "198.51.100.50/32"
    }
  ]
}

variable "root_allowed_host" {
  description = "Allowed host pattern for root user"
  type        = string
  default     = "10.0.0.0/8"  # 内部ネットワークのみ
}

variable "app_allowed_host" {
  description = "Allowed host pattern for application user"
  type        = string
  default     = "10.1.0.0/16"  # アプリケーションサブネット
}

variable "enable_private_ip" {
  description = "Enable private IP for Cloud SQL instance"
  type        = bool
  default     = true
}

# 出力値
output "instance_connection_name" {
  value       = google_sql_database_instance.main.connection_name
  description = "Instance connection name for Cloud SQL Proxy"
}

output "instance_ip_address" {
  value       = google_sql_database_instance.main.ip_address
  description = "The IPv4 address assigned"
}

 

その他ベストプラクティスについて

  1. 最小権限の原則
    • rootユーザーの使用を最小限に抑え、アプリケーション用の専用ユーザーを作成
    • 各ユーザーには必要最小限の権限のみを付与
  2. 多層防御
    • インスタンスレベルの承認済みネットワーク設定
    • ユーザーレベルのホスト制限
    • SSL/TLS接続の強制
    • Cloud SQL Proxyの使用
  3. 定期的な監査
    • 定期的にユーザーとそのホスト制限を確認
    • 不要なユーザーやアクセス許可を削除
    • 接続ログを監視して異常なアクセスを検出
  4. パスワード管理
    • Google Secret Managerを使用してパスワードを安全に管理
    • 定期的なパスワードローテーション
    • 強力なパスワードポリシーの実施

まとめ

Cloud SQLインスタンスのrootユーザーに対するホストベースのアクセス制限は、データベースセキュリティの基本的かつ重要な対策です。この記事で紹介した手順により、rootユーザーへの不正アクセスリスクを大幅に低減できます。

さらに、Cloud SQL Proxy、プライベートIP、IAM認証などの追加のセキュリティ機能を組み合わせることで、より堅牢なデータベースセキュリティを実現できます。定期的な監査とモニタリングを実施し、継続的にセキュリティ態勢を改善していくことが重要です。

この問題の検出は弊社が提供するSecurifyのCSPM機能で簡単に検出及び管理する事が可能です。 運用が非常に楽に出来る製品になっていますので、ぜひ興味がある方はお問い合わせお待ちしております。

最後までお読みいただきありがとうございました。この記事が皆さんの役に立てば幸いです。

参考情報

 

この記事をシェアする

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

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

料金プランを詳しく見る