Skip to content

Commit 6c4f20e

Browse files
authored
feat: add support for MySQL Auto IAM AuthN (#309)
1 parent eec019f commit 6c4f20e

File tree

4 files changed

+55
-13
lines changed

4 files changed

+55
-13
lines changed

.github/workflows/tests.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ jobs:
7979
with:
8080
secrets: |-
8181
MYSQL_CONNECTION_NAME:${{ secrets.GOOGLE_CLOUD_PROJECT }}/MYSQL_CONNECTION_NAME
82+
MYSQL_IAM_CONNECTION_NAME:${{ secrets.GOOGLE_CLOUD_PROJECT }}/MYSQL_IAM_CONNECTION_NAME
8283
MYSQL_USER:${{ secrets.GOOGLE_CLOUD_PROJECT }}/MYSQL_USER
84+
MYSQL_USER_IAM:${{ secrets.GOOGLE_CLOUD_PROJECT }}/MYSQL_USER_IAM_GO
8385
MYSQL_PASS:${{ secrets.GOOGLE_CLOUD_PROJECT }}/MYSQL_PASS
8486
MYSQL_DB:${{ secrets.GOOGLE_CLOUD_PROJECT }}/MYSQL_DB
8587
POSTGRES_CONNECTION_NAME:${{ secrets.GOOGLE_CLOUD_PROJECT }}/POSTGRES_CONNECTION_NAME
@@ -95,11 +97,12 @@ jobs:
9597
- name: Run tests
9698
env:
9799
MYSQL_CONNECTION_NAME: '${{ steps.secrets.outputs.MYSQL_CONNECTION_NAME }}'
100+
MYSQL_IAM_CONNECTION_NAME: '${{ steps.secrets.outputs.MYSQL_IAM_CONNECTION_NAME }}'
98101
MYSQL_USER: '${{ steps.secrets.outputs.MYSQL_USER }}'
102+
MYSQL_USER_IAM: '${{ steps.secrets.outputs.MYSQL_USER_IAM }}'
99103
MYSQL_PASS: '${{ steps.secrets.outputs.MYSQL_PASS }}'
100104
MYSQL_DB: '${{ steps.secrets.outputs.MYSQL_DB }}'
101105
POSTGRES_CONNECTION_NAME: '${{ steps.secrets.outputs.POSTGRES_CONNECTION_NAME }}'
102-
POSTGRES_IAM_CONNECTION_NAME: '${{ steps.secrets.outputs.POSTGRES_IAM_CONNECTION_NAME }}'
103106
POSTGRES_USER: '${{ steps.secrets.outputs.POSTGRES_USER }}'
104107
POSTGRES_USER_IAM: '${{ steps.secrets.outputs.POSTGRES_USER_IAM }}'
105108
POSTGRES_PASS: '${{ steps.secrets.outputs.POSTGRES_PASS }}'

dialer_test.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -255,11 +255,6 @@ func TestIAMAuthNErrors(t *testing.T) {
255255
version string
256256
opts Option
257257
}{
258-
{
259-
desc: "when the database engine is MySQL",
260-
version: "MYSQL",
261-
opts: WithIAMAuthN(),
262-
},
263258
{
264259
desc: "when the database engine is SQL Server",
265260
version: "SQLSERVER",

e2e_mysql_test.go

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,24 @@ import (
2121
"testing"
2222
"time"
2323

24+
"cloud.google.com/go/cloudsqlconn"
2425
"cloud.google.com/go/cloudsqlconn/mysql/mysql"
2526
)
2627

2728
var (
28-
mysqlConnName = os.Getenv("MYSQL_CONNECTION_NAME") // "Cloud SQL MySQL instance connection name, in the form of 'project:region:instance'.
29-
mysqlUser = os.Getenv("MYSQL_USER") // Name of database user.
30-
mysqlPass = os.Getenv("MYSQL_PASS") // Password for the database user; be careful when entering a password on the command line (it may go into your terminal's history).
31-
mysqlDb = os.Getenv("MYSQL_DB") // Name of the database to connect to.
29+
// "Cloud SQL MySQL instance connection name, in the form of 'project:region:instance'.
30+
mysqlConnName = os.Getenv("MYSQL_CONNECTION_NAME")
31+
// "Cloud SQL MySQL instance connection name, in the form of 'project:region:instance'.
32+
mysqlIAMConnName = os.Getenv("MYSQL_IAM_CONNECTION_NAME")
33+
// Name of database user.
34+
mysqlUser = os.Getenv("MYSQL_USER")
35+
// Name of database IAM user.
36+
mysqlIAMUser = os.Getenv("MYSQL_USER_IAM")
37+
// Password for the database user; be careful when entering a password on
38+
// the command line (it may go into your terminal's history).
39+
mysqlPass = os.Getenv("MYSQL_PASS")
40+
// Name of the database to connect to.
41+
mysqlDB = os.Getenv("MYSQL_DB")
3242
)
3343

3444
func requireMySQLVars(t *testing.T) {
@@ -39,7 +49,7 @@ func requireMySQLVars(t *testing.T) {
3949
t.Fatal("'MYSQL_USER' env var not set")
4050
case mysqlPass:
4151
t.Fatal("'MYSQL_PASS' env var not set")
42-
case mysqlDb:
52+
case mysqlDB:
4353
t.Fatal("'MYSQL_DB' env var not set")
4454
}
4555
}
@@ -55,15 +65,47 @@ func TestMySQLDriver(t *testing.T) {
5565
}
5666
t.Log(now)
5767
}
58-
cleanup, err := mysql.RegisterDriver("cloudsql-mysql")
68+
cleanup, err := mysql.RegisterDriver(
69+
"cloudsql-mysql",
70+
cloudsqlconn.WithAdminAPIEndpoint(os.Getenv("ADMIN_API_ENDPOINT")),
71+
cloudsqlconn.WithQuotaProject(os.Getenv("QUOTA_PROJECT")),
72+
)
5973
if err != nil {
6074
t.Fatalf("failed to register driver: %v", err)
6175
}
6276
defer cleanup()
6377
db, err := sql.Open(
6478
"mysql",
6579
fmt.Sprintf("%s:%s@cloudsql-mysql(%s)/%s?parseTime=true",
66-
mysqlUser, mysqlPass, mysqlConnName, mysqlDb),
80+
mysqlUser, mysqlPass, mysqlConnName, mysqlDB),
81+
)
82+
if err != nil {
83+
t.Fatalf("sql.Open want err = nil, got = %v", err)
84+
}
85+
defer db.Close()
86+
testConn(db)
87+
}
88+
89+
func TestMySQLDriverIAMAuthN(t *testing.T) {
90+
if testing.Short() {
91+
t.Skip("skipping MySQL integration tests")
92+
}
93+
testConn := func(db *sql.DB) {
94+
var now time.Time
95+
if err := db.QueryRow("SELECT NOW()").Scan(&now); err != nil {
96+
t.Fatalf("QueryRow failed: %v", err)
97+
}
98+
t.Log(now)
99+
}
100+
cleanup, err := mysql.RegisterDriver("cloudsql-mysql-iam", cloudsqlconn.WithIAMAuthN())
101+
if err != nil {
102+
t.Fatalf("failed to register driver: %v", err)
103+
}
104+
defer cleanup()
105+
db, err := sql.Open(
106+
"mysql",
107+
fmt.Sprintf("%s:empty@cloudsql-mysql-iam(%s)/%s?parseTime=true",
108+
mysqlIAMUser, mysqlIAMConnName, mysqlDB),
67109
)
68110
if err != nil {
69111
t.Fatalf("sql.Open want err = nil, got = %v", err)

internal/cloudsql/refresh.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,8 @@ func supportsAutoIAMAuthN(version string) error {
391391
switch {
392392
case strings.HasPrefix(version, "POSTGRES"):
393393
return nil
394+
case strings.HasPrefix(version, "MYSQL"):
395+
return nil
394396
default:
395397
return fmt.Errorf("%s does not support Auto IAM DB Authentication", version)
396398
}

0 commit comments

Comments
 (0)