I am trying to connect to a PostgreSQL database instance in Google Cloud (with a private IP connection) using the SQL Connector library in Go. However, I am encountering the following error:
ERROR Failed to dial instance {"error": "failed to get instance: Refresh error: failed to get instance metadata (connection name = \"<connection-string>\"): Get \"https://sqladmin.googleapis.com/sql/v1beta4/projects/\/instances/postgres/connectSettings?alt=json&prettyPrint=false\": compute: Received 403 `Unable to generate access token; IAM returned 403 Forbidden: Permission 'iam.serviceAccounts.getAccessToken' denied on resource (or it may not exist).
This error could be caused by a missing IAM policy binding on the target IAM service account.
For more information, refer to the Workload Identity documentation:
Environment Details:
Google Cloud: PostgreSQL instance with private IP connection enabled
Service Account Permissions:
- Cloud SQL Admin
- Cloud SQL Client
- Compute Network Admin
- Project IAM Admin
- Service Account Admin
- Service Account Token Creator
- Storage Admin
- Workload Identity User
Go Environment: Running the code in a VM instance that is part of the GKE cluster in the same VPC.
Here’s the relevant portion of my Go code:
func connectDB() error {
user := "postgres"
password := "password"
connectionName := "connectionName"
sslmode := "require"
dbName := "databaseName"
config, err := pgx.ParseConfig(connStr)
if err != nil {
return err
}
opts := append([]cloudsqlconn.Option{},
cloudsqlconn.WithDefaultDialOptions(cloudsqlconn.WithPrivateIP()),
)
d, err := cloudsqlconn.NewDialer(context.Background(), opts...)
if err != nil {
return err
}
config.DialFunc = func(ctx context.Context, network, instance string) (net.Conn, error) {
log.FromContext(ctx).Info(fmt.Sprintf("Dialing instance: %s", instance))
conn, err := d.Dial(ctx, connectionName)
if err != nil {
log.FromContext(ctx).Error(err, "Failed to dial instance")
}
return conn, err
}
dbURI := stdlib.RegisterConnConfig(config)
dbPool, err := sql.Open("pgx", dbURI)
if err != nil {
return err
}
err = dbPool.Ping()
if err != nil {
return err
}
return nil
}
Troubleshooting Attempts:
Verified that the database instance has a private IP and is reachable within the same VPC. Checked and ensured that the service account has the following permissions: Cloud SQL Admin Cloud SQL Client Service Account Token Creator Workload Identity User, among others. Ensured that the Go application is running inside a VM that has access to the private VPC.
Service Account Token Creatorrole instead of the Workload Identity service account.