Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: strip monotonic clock reading in cert check
In Go, when two time.Time objects have a monotonic clock value, calls to time.After will use the monotonic readings to compare the two values. However, when the CPU goes to sleep and later awakes, the monotonic clock will stop on some systems. As a result, the time comparison will produce inaccurate results. See the Go documentation on time for a discussion of the details: https://pkg.go.dev/time#hdr-Monotonic_Clocks. In an earlier commit [1], we added code to ensure the ephemeral certificate was not expired. If it was, we blocked the connection attempt on a certificate refresh. This solved one bug where a laptop went to sleep, later awoke, and was unable to connect given the existing certificate had expired. However, the change in #686 fixed this bug, but only for clients connecting with built-in authentication. [1] #686 When the Go Connector is configured to use built-in authentication, it compares the ephemeral certificate's expiration (a time.Time object produced from JSON deserialization and therefore lacking a monotonic clock reading) with time.Now(). Because only one of the two time values has a monotonic reading (i.e. time.Now()), the wall clock time is used to compare the two vales and calls to time.After produce valid results. When the Go Connector is configured to use auto IAM authentication, it updates the certificate's expiration to be the earlier of the certificate's expiration or the OAuth2 token's expiration. In the majority of cases, the OAuth2 token will expire earlier and so its expiration will be set to the certificate's expiration. Further, the OAuth2 token's expiration is a time.Time value *with* a monotonic clock reading. As a result, calls to time.After will be using time values that both have a monotonic clock reading, and so are susceptible to producing the wrong result when a machine has been asleep for some time. For example, with debug logging enabled in the Proxy, we observed the following logs after suspending the VM running the Proxy for more than an hour, resuming the VM, and then attempting to connect: Accepted connection from 127.0.0.1:56782 Now = 2024-03-10T04:34:37Z, Current cert expiration = 2024-03-10T00:38:48Z Cert is valid = true Dialing <INSTANCE_IP_ADDR> connection aborted - error reading from instance: remote error: tls: bad certificate Even though the cert expiration is clearly before "now," the Go Connector incorrectly concludes the certificate is still valid. This is on account of the erroneous monotonic clock value in time.Now that is then used in calls to time.After. This commit resolves this last bug by stripping the monotonic clock value from both times before doing the comparison. In addition to time.Round(0), time.UTC() will also strip the monotonic reading. This commit uses time.UTC(). Past, related issues: GoogleCloudPlatform/cloud-sql-proxy#1788 GoogleCloudPlatform/cloud-sql-proxy#1199 #402
- Loading branch information