Cloud SQL MySQLインスタンスの管理者ユーザーにおけるパスワード設定について

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

この記事では、Cloud SQL MySQLインスタンスの管理者ユーザーのパスワード設定について、リスクと対策を解説します。

ポリシーの説明

Cloud SQL MySQLインスタンスの管理者ユーザー(root)にパスワードを設定し、不正アクセスを防止します。

Cloud SQL MySQLインスタンスを作成する際、デフォルトではrootユーザーにパスワードが設定されない場合があります。これにより、誰でも管理者権限でデータベースに接続できる状態となり、深刻なセキュリティリスクを招きます。管理者ユーザーには必ず強力なパスワードを設定し、適切なアクセス制御を実施することが重要です。

修復方法

コンソールでの修復手順

Google Cloud コンソールを使用して、Cloud SQL MySQLインスタンスのrootユーザーにパスワードを設定します。

  1. Google Cloud Consoleにログインし、SQLページに移動します。
  1. 対象のCloud SQL MySQLインスタンスを選択します。
  2. 左側のメニューからユーザーを選択します。
  3. rootユーザーを見つけて、その行の右端にあるその他の操作(3点メニュー)をクリックします。
  4. パスワードを変更を選択します。
  5. 新しいパスワードを入力します:
    • 最低16文字以上の長さ
    • 大文字・小文字・数字・特殊文字を含む
    • 推測しにくい複雑なパスワード
  6. 保存をクリックして変更を適用します。

Terraformでの修復手順

Cloud SQL MySQLインスタンスで管理者パスワードを設定するTerraformコードと、主要な修正ポイントを説明します。

# -------------------- ① ランダムパスワードの生成 --------------------
resource "random_password" "mysql_root_password" {
  length           = 20
  special          = true
  override_special = "!#$%&*()-_=+[]{}<>:?"
  min_lower        = 2
  min_upper        = 2
  min_numeric      = 2
  min_special      = 2
}

# -------------------- ② Secret Managerでの保存 --------------------
resource "google_secret_manager_secret" "mysql_root_password" {
  secret_id = "mysql-root-password-${var.environment}"

  replication {
    automatic = true
  }
}

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

# -------------------- ③ Cloud SQLインスタンス --------------------
resource "google_sql_database_instance" "mysql" {
  name             = "mysql-instance-${var.environment}"
  database_version = "MYSQL_8_0"
  region           = var.region

  # rootパスワードの設定
  root_password = random_password.mysql_root_password.result

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

    # --- IPアクセス制御 ---
    ip_configuration {
      ipv4_enabled = true

      # 必要最小限のIPアドレスのみ許可
      authorized_networks {
        name  = "office-network"
        value = var.office_ip_cidr
      }

      # SSL接続を強制
      require_ssl = true
    }

    # --- セキュリティ強化設定 ---
    database_flags {
      name  = "require_secure_transport"
      value = "on"
    }

    database_flags {
      name  = "skip-grant-tables"
      value = "off"  # 認証をバイパスしない
    }

    database_flags {
      name  = "local_infile"
      value = "off"
    }

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

    # --- 監査ログ設定 ---
    insights_config {
      query_insights_enabled  = true
      query_string_length     = 1024
      record_application_tags = true
    }
  }

  deletion_protection = true
}

# -------------------- ④ アプリケーション用ユーザーの作成 --------------------
resource "random_password" "app_user_password" {
  length           = 16
  special          = true
  override_special = "!#$%&*()-_=+[]{}<>:?"
}

resource "google_sql_user" "app_user" {
  name     = "app_user"
  instance = google_sql_database_instance.mysql.name
  password = random_password.app_user_password.result

  # rootユーザーと異なり、限定的な権限を付与
}

# -------------------- ⑤ データベースの作成 --------------------
resource "google_sql_database" "app_database" {
  name     = "application_db"
  instance = google_sql_database_instance.mysql.name
  charset  = "utf8mb4"
}

# -------------------- ⑥ IAMロールの設定 --------------------
resource "google_project_iam_member" "sql_client" {
  project = var.project_id
  role    = "roles/cloudsql.client"
  member  = "serviceAccount:${var.app_service_account_email}"
}

# -------------------- ⑦ 変数定義 --------------------
variable "environment" {
  description = "Environment name (dev/staging/prod)"
  type        = string
}

variable "region" {
  description = "The GCP region for resources"
  type        = string
  default     = "asia-northeast1"
}

variable "project_id" {
  description = "GCP Project ID"
  type        = string
}

variable "office_ip_cidr" {
  description = "Office network IP CIDR for authorized access"
  type        = string
}

variable "app_service_account_email" {
  description = "Application service account email"
  type        = string
}

# -------------------- ⑧ 出力 --------------------
output "instance_connection_name" {
  value       = google_sql_database_instance.mysql.connection_name
  description = "The connection name of the Cloud SQL instance"
}

output "root_password_secret_id" {
  value       = google_secret_manager_secret.mysql_root_password.id
  description = "The Secret Manager secret ID for root password"
}

output "app_user_password" {
  value       = random_password.app_user_password.result
  sensitive   = true
  description = "The password for app_user (store this securely)"
}

 

主要な修正ポイント

  1. root_password: インスタンス作成時に必ずrootパスワードを設定
  2. random_password: 強力なランダムパスワードを自動生成
  3. google_secret_manager_secret: パスワードをSecret Managerで安全に管理
  4. require_secure_transport: SSL/TLS接続を強制
  5. skip-grant-tables = off: 認証バイパスを無効化

重要な注意事項

  • 既存インスタンスの場合: すでに作成されたインスタンスにはroot_passwordパラメータは使用できません。gcloud CLIまたはコンソールでパスワードを設定してください
  • パスワードポリシーの適用: MySQL 8.0の場合、デフォルトでvalidate_passwordプラグインが有効になっています

最後に

この記事では、Cloud SQL MySQLインスタンスの管理者ユーザーパスワード設定について、リスクと対策を解説しました。

パスワードなしの管理者アカウントは、データベースセキュリティにおける最も重大な脆弱性の一つです。本記事で紹介した手順により、強力なパスワードを設定し、適切なアクセス制御を実装することで、データベースへの不正アクセスを防止できます。

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

参考情報

Google Cloud公式ドキュメント

MySQL公式ドキュメント

この記事をシェアする

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

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

料金プランを詳しく見る