如何通过服务账号结合pymysql/mysql.connector跨VPC连接CloudSQL
跨VPC通过Nginx代理使用服务账号访问CloudSQL MySQL的解决方案
前置准备
授权服务账号
- 在Google Cloud IAM中,给目标服务账号添加
Cloud SQL Client角色(或更精细的Cloud SQL Instance User权限)。 - 在CloudSQL实例的IAM权限页面,将该服务账号添加为成员,分配
Cloud SQL Client角色。 - 在MySQL实例内部创建对应服务账号用户:
CREATE USER 'your-service-account@your-project.iam.gserviceaccount.com' IDENTIFIED WITH mysql_clear_password; GRANT ALL PRIVILEGES ON your_database.* TO 'your-service-account@your-project.iam.gserviceaccount.com'; FLUSH PRIVILEGES;
注意用户必须是完整的服务账号邮箱格式。
- 在Google Cloud IAM中,给目标服务账号添加
确保Nginx代理配置正确
- 代理需正确转发3306端口的TCP流量,且不篡改数据包内容(令牌需明文传递)。示例Nginx TCP代理配置:
stream { server { listen 3306; proxy_pass cloudsql-instance-ip:3306; } }
- 代理需正确转发3306端口的TCP流量,且不篡改数据包内容(令牌需明文传递)。示例Nginx TCP代理配置:
修复mysql.connector的认证插件错误
错误Authentication plugin 'mysql_clear_password' cannot be loaded是因为未指定认证插件,且未请求正确的CloudSQL权限范围。修改代码如下:
import google.auth import google.auth.transport.requests import mysql.connector from mysql.connector import Error # 指定CloudSQL所需的权限范围 SCOPES = ['https://www.googleapis.com/auth/sqlservice.admin'] creds, project = google.auth.default(scopes=SCOPES) auth_req = google.auth.transport.requests.Request() creds.refresh(auth_req) try: connection = mysql.connector.connect( host=YOUR_NGINX_PROXY_HOST, database=YOUR_DB_NAME, user=YOUR_SERVICE_ACCOUNT_EMAIL, # 完整服务账号邮箱 password=creds.token, auth_plugin='mysql_clear_password', # 启用明文密码认证插件 ssl_ca='path/to/server-ca.pem' # 若CloudSQL强制SSL,需添加此证书(从控制台下载) ) if connection.is_connected(): print(f"Connected to MySQL Server version {connection.get_server_info()}") cur = connection.cursor() cur.execute("SELECT now()") print(f"Query result: {cur.fetchall()}") except Error as e: print(f"Connection error: {e}") finally: if 'connection' in locals() and connection.is_connected(): cur.close() connection.close() print("Connection closed")
修复pymysql的权限错误
错误Access denied通常是因为未指定认证插件、权限范围不正确或SSL配置缺失。修改代码如下:
import pymysql import google.auth import google.auth.transport.requests from pymysql.constants import CLIENT SCOPES = ['https://www.googleapis.com/auth/sqlservice.admin'] creds, project = google.auth.default(scopes=SCOPES) auth_req = google.auth.transport.requests.Request() creds.refresh(auth_req) try: conn = pymysql.connect( host=YOUR_NGINX_PROXY_HOST, user=YOUR_SERVICE_ACCOUNT_EMAIL, passwd=creds.token, port=3306, database=YOUR_DB_NAME, auth_plugin='mysql_clear_password', ssl={'ca': 'path/to/server-ca.pem'}, # SSL证书配置 client_flag=CLIENT.SSL # 启用SSL连接 ) cur = conn.cursor() cur.execute("SELECT now()") print(f"Query result: {cur.fetchall()}") except Exception as e: print(f"Connection failed: {e}") finally: if 'conn' in locals() and conn.open: cur.close() conn.close() print("Connection closed")
关键注意事项
- 令牌范围:必须请求
sqlservice.admin或cloud-platform范围,否则令牌无法用于CloudSQL认证。 - SSL要求:CloudSQL默认强制SSL连接,需从控制台下载
server-ca.pem并在连接中配置。 - 服务账号环境:本地运行时需设置
GOOGLE_APPLICATION_CREDENTIALS环境变量指向服务账号密钥文件;GCP托管环境(如GKE、GCE)可直接使用默认服务账号。
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

