Cloud SQLでSSL/TLS接続の必須化の手順

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

ポリシーの説明
Cloud SQLインスタンスとクライアント間の通信をSSL/TLSで暗号化することで、データベース通信の機密性と完全性を確保します。SSL/TLS接続が無効の場合、データベースとアプリケーション間で送受信されるデータ(SQLクエリ、認証情報、クエリ結果など)が平文で送信され、ネットワーク上で盗聴や改ざんのリスクにさらされます。
Cloud SQLはTLS 1.2以上をサポートし、古いプロトコル(SSL 3.0、TLS 1.0/1.1)は無効化されているため、安全な暗号化通信が保証されます。
リスク
SSL/TLS接続が無効化されている場合、攻撃者がネットワーク通信を傍受した際にSQLクエリや結果データを盗聴できたり、データベースのユーザー名とパスワードが平文で送信され、不正アクセスのリスクが高まります。
修復方法
コンソールでの修復手順
Google Cloud コンソールを使用して、Cloud SQLインスタンスのSSL/TLS接続を有効化します。
- Cloud SQLページへ移動
- ナビゲーションメニューから「SQL」を選択し、接続へ遷移する

- SSL設定の変更
- 対象のインスタンスを選定し、[セキュリティ]- [信頼できるクライアント証明書を必須にする]を選択する
- 対象のインスタンスを選定し、[セキュリティ]- [信頼できるクライアント証明書を必須にする]を選択する
- 承認済みネットワークの設定(推奨)
- 「承認済みネットワーク」セクションで、接続を許可するIPアドレスを追加
- 0.0.0.0/0(すべてのIP)は避け、特定のIPアドレスまたはCIDRブロックを指定
- SSL証明書の作成
- 「証明書」タブに移動
- 「新しいクライアント証明書を作成」をクリック
- 証明書に名前を付けて「作成」をクリック
- 生成された証明書(server-ca.pem、client-cert.pem、client-key.pem)をダウンロード
- 重要: ダウンロードした証明書は安全な場所に保管し、アクセス権限を適切に設定
- 注意: 証明書は作成時にのみダウンロード可能で、後から再取得はできません
- 推奨: Secret Managerやハードウェアセキュリティモジュール(HSM)での管理を検討
- 設定の保存
- 「保存」ボタンをクリックして変更を適用
- 数分で設定が反映されます(インスタンスの再起動は不要)
Terraformでの修復手順
Cloud SQLインスタンスのSSL/TLS接続を有効にするTerraformコードと、主要な修正ポイントを説明します。
# Cloud SQLインスタンスの設定
resource "google_sql_database_instance" "main" {
name = "secure-mysql-instance"
database_version = "MYSQL_8_0"
region = "asia-northeast1"
settings {
tier = "db-n1-standard-2"
# IPコンフィグレーション
ip_configuration {
ipv4_enabled = true
# SSL/TLS接続を必須にする(重要:falseにしないこと)
require_ssl = true
# SSLモードの暗号スイートを最新に保つ
# Cloud SQLは自動的に安全な暗号スイートを選択
# TLS 1.2以上が使用され、古いプロトコルは無効化されています
# 承認済みネットワーク(特定のIPからのみ接続を許可)
authorized_networks {
name = "office-network"
value = "203.0.113.0/24" # 実際のオフィスIPに置き換え
}
authorized_networks {
name = "app-server"
value = "198.51.100.10/32" # アプリケーションサーバーのIP
}
# プライベートIPの設定(推奨)
private_network = google_compute_network.private_network.id
}
# バックアップ設定
backup_configuration {
enabled = true
start_time = "02:00"
binary_log_enabled = true
transaction_log_retention_days = 7
}
# データベースフラグ(MySQL用のセキュリティ強化設定)
database_flags {
name = "skip_show_database"
value = "on"
}
database_flags {
name = "local_infile"
value = "off"
}
# PostgreSQL の場合は以下のフラグを使用
# database_flags {
# name = "cloudsql.enable_pgaudit"
# value = "on"
# }
# database_flags {
# name = "log_connections"
# value = "on"
# }
}
deletion_protection = true
}
# SSL証明書の作成
resource "google_sql_ssl_cert" "client_cert" {
common_name = "application-client"
instance = google_sql_database_instance.main.name
# ライフサイクル管理
lifecycle {
create_before_destroy = true
}
}
# 証明書の有効期限監視用メタデータ
resource "google_project_metadata_item" "ssl_cert_expiry" {
key = "cloudsql-ssl-cert-${google_sql_ssl_cert.client_cert.sha1_fingerprint}"
value = timestamp()
}
# プライベートVPC設定(推奨)
resource "google_compute_network" "private_network" {
name = "sql-private-network"
auto_create_subnetworks = false
}
resource "google_compute_global_address" "private_ip_address" {
name = "sql-private-ip"
purpose = "VPC_PEERING"
address_type = "INTERNAL"
prefix_length = 16
network = google_compute_network.private_network.id
}
resource "google_service_networking_connection" "private_vpc_connection" {
network = google_compute_network.private_network.id
service = "servicenetworking.googleapis.com"
reserved_peering_ranges = [google_compute_global_address.private_ip_address.name]
}
# アプリケーション用の接続情報を出力
output "connection_name" {
value = google_sql_database_instance.main.connection_name
description = "Instance connection name for application configuration"
}
output "private_ip_address" {
value = google_sql_database_instance.main.private_ip_address
description = "Private IP address for VPC internal access"
}
output "public_ip_address" {
value = google_sql_database_instance.main.public_ip_address
description = "Public IP address (use with SSL only)"
sensitive = true
}
output "server_ca_cert" {
value = google_sql_database_instance.main.server_ca_cert[0].cert
description = "Server CA certificate for SSL connection"
sensitive = true
}
output "client_cert" {
value = google_sql_ssl_cert.client_cert.cert
description = "Client certificate for SSL connection"
sensitive = true
}
output "client_key" {
value = google_sql_ssl_cert.client_cert.private_key
description = "Client private key for SSL connection"
sensitive = true
}
# 接続監視アラート
resource "google_monitoring_alert_policy" "ssl_connection_failures" {
display_name = "Cloud SQL SSL Connection Failures"
combiner = "OR"
conditions {
display_name = "SSL connection failures detected"
condition_threshold {
filter = <<-EOT
resource.type="cloudsql_database"
AND metric.type="cloudsql.googleapis.com/database/network/connections"
AND metric.label.is_ssl="false"
EOT
duration = "60s"
comparison = "COMPARISON_GT"
threshold_value = 0
aggregations {
alignment_period = "60s"
per_series_aligner = "ALIGN_RATE"
}
}
}
notification_channels = [google_monitoring_notification_channel.email.id]
documentation {
content = "Non-SSL connections detected to Cloud SQL instance. Investigate immediately."
}
}
# アプリケーション設定例(MySQL接続文字列)
locals {
mysql_connection_config = {
host = google_sql_database_instance.main.private_ip_address
port = 3306
database = "application_db"
ssl_mode = "VERIFY_IDENTITY" # 最も安全な設定
# ssl_mode の選択肢:
# - REQUIRED: SSL接続を必須とする(最低限)
# - VERIFY_CA: サーバー証明書の検証を行う(推奨)
# - VERIFY_IDENTITY: サーバー証明書とホスト名の検証を行う(最も安全)
ssl_ca = "/path/to/server-ca.pem"
ssl_cert = "/path/to/client-cert.pem"
ssl_key = "/path/to/client-key.pem"
}
}
ベストプラクティス
- 多層防御の実装
- SSL/TLS接続の必須化と併せて、プライベートIPアドレスの使用を検討
- Cloud SQL ProxyやIAM認証の併用を推奨
- VPCサービスコントロールによる境界セキュリティの実装
- 証明書管理
- クライアント証明書の定期的なローテーション(90日ごとを推奨)
- Secret ManagerやHashiCorp Vaultなどの証明書管理ツールの活用
- 証明書の有効期限監視とアラート設定
- 監査とコンプライアンス
- Cloud Auditログでの接続監視
- 非SSL接続試行の検出とアラート
- 定期的なセキュリティ評価の実施
最後に
この記事では、Cloud SQLインスタンスのSSL/TLS接続有効化手順について、リスクと対策を解説しました。
SSL/TLS接続の必須化は、データベース通信のセキュリティ確保の基本です。特にパブリックIPアドレスを使用する場合は必ず有効化し、可能な限りプライベートIPアドレスでの接続と組み合わせることを推奨します。
この問題の検出は弊社が提供するSecurifyのCSPM機能で簡単に検出及び管理する事が可能です。 運用が非常に楽に出来る製品になっていますので、ぜひ興味がある方はお問い合わせお待ちしております。 最後までお読みいただきありがとうございました。この記事が皆さんの役に立てば幸いです。