@@ -1174,3 +1174,134 @@ func TestDialerChecksSubjectAlternativeNameAndFails(t *testing.T) {
11741174 t .Fatal ("want error containing `tls: failed to verify certificate`. Got: " , err )
11751175 }
11761176}
1177+
1178+ func TestDialerRefreshesAfterRotateClientCA (t * testing.T ) {
1179+ inst := mock .NewFakeCSQLInstanceWithSan (
1180+ "my-project" , "my-region" , "my-instance" , []string {"db.example.com" },
1181+ mock .WithDNS ("db.example.com" ),
1182+ mock .WithServerCAMode ("GOOGLE_MANAGED_CAS_CA" ),
1183+ )
1184+
1185+ d := setupDialer (t , setupConfig {
1186+ skipServer : true ,
1187+ testInstance : inst ,
1188+ reqs : []* mock.Request {
1189+ mock .InstanceGetSuccess (inst , 2 ),
1190+ mock .CreateEphemeralSuccess (inst , 2 ),
1191+ },
1192+ dialerOptions : []Option {
1193+ WithTokenSource (mock.EmptyTokenSource {}),
1194+ WithDebugLogger (& dialerTestLogger {t : t }),
1195+ //WithLazyRefresh(),
1196+ // Note: this succeeds with lazy refresh, but fails with lazy.
1197+ // because dialer.ForceRefresh does not block connections while the
1198+ // refresh is in progress.
1199+ },
1200+ })
1201+ cancel1 := mock .StartServerProxy (t , inst )
1202+ t .Log ("First attempt..." )
1203+ testSuccessfulDial (
1204+ context .Background (), t , d ,
1205+ "my-project:my-region:my-instance" ,
1206+ )
1207+ t .Log ("First attempt OK. Resetting client cert." )
1208+
1209+ // Close the server
1210+ cancel1 ()
1211+
1212+ mock .RotateClientCA (inst )
1213+
1214+ // Start the server with new certificates
1215+ cancel2 := mock .StartServerProxy (t , inst )
1216+ defer cancel2 ()
1217+
1218+ // Dial a second time. We expect no error on dial, but TLS error on read.
1219+ t .Log ("Second attempt should fail..." )
1220+ conn , err := d .Dial (context .Background (), "my-project:my-region:my-instance" )
1221+ if err != nil {
1222+ t .Fatal ("Should be no certificate error after, got " , err )
1223+ }
1224+
1225+ // Expect an error on read. This should trigger the dialer to refresh.
1226+ _ , err = io .ReadAll (conn )
1227+ if err != nil {
1228+ t .Log ("Got error on read as expected." , err )
1229+ } else {
1230+ t .Fatal ("Want read error, got no error" )
1231+ }
1232+ t .Log ("Second attempt done" )
1233+
1234+ // Dial again. This should complete after the refresh.
1235+ t .Log ("Third attempt..." )
1236+ testSuccessfulDial (
1237+ context .Background (), t , d ,
1238+ "my-project:my-region:my-instance" ,
1239+ )
1240+ t .Log ("Third attempt OK." )
1241+ }
1242+
1243+ func TestDialerRefreshesAfterRotateServerCA (t * testing.T ) {
1244+ inst := mock .NewFakeCSQLInstanceWithSan (
1245+ "my-project" , "my-region" , "my-instance" , []string {"db.example.com" },
1246+ mock .WithDNS ("db.example.com" ),
1247+ mock .WithServerCAMode ("GOOGLE_MANAGED_CAS_CA" ),
1248+ )
1249+
1250+ d := setupDialer (t , setupConfig {
1251+ skipServer : true ,
1252+ testInstance : inst ,
1253+ reqs : []* mock.Request {
1254+ mock .InstanceGetSuccess (inst , 2 ),
1255+ mock .CreateEphemeralSuccess (inst , 2 ),
1256+ },
1257+ dialerOptions : []Option {
1258+ WithTokenSource (mock.EmptyTokenSource {}),
1259+ WithDebugLogger (& dialerTestLogger {t : t }),
1260+ WithLazyRefresh (),
1261+ // Note: this succeeds with lazy refresh, but fails with lazy.
1262+ // because dialer.ForceRefresh does not block connections while the
1263+ // refresh is in progress.
1264+ },
1265+ })
1266+ cancel1 := mock .StartServerProxy (t , inst )
1267+ t .Log ("First attempt..." )
1268+ testSuccessfulDial (
1269+ context .Background (), t , d ,
1270+ "my-project:my-region:my-instance" ,
1271+ )
1272+ t .Log ("First attempt OK. Resetting client cert." )
1273+
1274+ // Close the server
1275+ cancel1 ()
1276+
1277+ mock .RotateCA (inst )
1278+
1279+ // Start the server with new certificates
1280+ cancel2 := mock .StartServerProxy (t , inst )
1281+ defer cancel2 ()
1282+
1283+ // Dial a second time. We expect no error on dial, but TLS error on read.
1284+ t .Log ("Second attempt should fail..." )
1285+ _ , err := d .Dial (context .Background (), "my-project:my-region:my-instance" )
1286+ if err != nil {
1287+ t .Log ("Got error on dial as expected." , err )
1288+ } else {
1289+ t .Fatal ("Want dial error, got no error" )
1290+ }
1291+
1292+ // Dial again. This should occur after the refresh has completed.
1293+ t .Log ("Third attempt..." )
1294+ testSuccessfulDial (
1295+ context .Background (), t , d ,
1296+ "my-project:my-region:my-instance" ,
1297+ )
1298+ t .Log ("Third attempt OK." )
1299+ }
1300+
1301+ type dialerTestLogger struct {
1302+ t * testing.T
1303+ }
1304+
1305+ func (l * dialerTestLogger ) Debugf (f string , args ... interface {}) {
1306+ l .t .Logf (f , args ... )
1307+ }
0 commit comments