-
Notifications
You must be signed in to change notification settings - Fork 119
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Support CAS server certificate authority to validate instance connections. #2060
Conversation
core/src/main/java/com/google/cloud/sql/core/DefaultConnectionInfoRepository.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe we want to update the PSC check now that dnsName can be for CAS-based instances as well as PSC just like Go did: https://github.com/GoogleCloudPlatform/cloud-sql-go-connector/pull/850/files#diff-5097a430f11cfd2c79c874367e2f96cf048d9e47112b01f7650d961d8a677ff8R104
Not sure where exactly in the Java code base this would be, maybe here?
Line 282 in e13fa46
ipAddrs.put(IpType.PSC, instanceMetadata.getDnsName()); |
InstanceMetadata( | ||
Map<IpType, String> ipAddrs, | ||
List<Certificate> instanceCaCertificates, | ||
boolean casManagedCertificate, | ||
String dnsName) { | ||
this.ipAddrs = ipAddrs; | ||
this.instanceCaCertificates = instanceCaCertificates; | ||
this.casManagedCertificate = casManagedCertificate; | ||
this.dnsName = dnsName; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we really need two constructors for InstanceMetadata
? seems like we should be able to just use one...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. I consolidated this to 1 constructor.
408d64e
to
668aa58
Compare
Java has this requirement covered without needing additional code:
The Java connector calls SSLSocket.connect() at Connector.java:118 with either the instance IP or the PSC domain name. When the instance is a CAS instance, the TLS context will be configured to use the built-in logic to check certificate trust. When SSLSocket.connect() is called with the PSC domain name, the built-in TLS logic will check the certificate's SAN records as expected. |
668aa58
to
8de81ea
Compare
return delegate; | ||
} | ||
|
||
// Otherwise, Use a custom trust manager factory that checks the CN against the instance name | ||
InstanceCheckingTrustManagerFactory tmf = | ||
new InstanceCheckingTrustManagerFactory(instanceName, delegate); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like the dnsName
is not actually used to verify the server identity? Can we enhance this part and pass in the dnsName
to verify it? I think we can use getSubjectAlternativeNames() to get the SAN fields. Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should not need to explicitly program the TrustManagerFactory to check the subjectAlternateName records, that behavior should be built in. I will add some unit tests with correct and incorrect server certificates to demonstrate this behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 we need to actually check the dnsName against the SAN fields
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. I also moved some of the code from this into 2 other PRs for clarity.
- chore(refactor): Add CAS related fields to the InstanceMetadata. #2067
- (this one) feat: Support CAS server certificate authority to validate instance connections
- test: Add integration test for public IP instance with CAS enabled. #2066
0ef54c0
to
689b27f
Compare
26e21b7
to
fe76396
Compare
} | ||
throw new CertificateException( | ||
"Server certificate does not contain expected name '" | ||
+ instanceMetadata.getInstanceName() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use instanceMetadata.getDnsName()
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
|
||
for (List item : sanAsn1Field) { | ||
Integer type = (Integer) item.get(0); | ||
if (type == 0 || type == 2) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add a comment here for the 0 and 2? I assume that 0
is the otherName
and 2
is the dNSName
according to the RFC 5280.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are correct. I added a comment to clarify.
SSLParameters sslParams = new SSLParameters(); | ||
socket.setSSLParameters(sslParams); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you add a comment in the code here explaining this new piece?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed. This was unnecessary.
@@ -367,7 +374,7 @@ private Certificate fetchEphemeralCertificate( | |||
// Parse the certificate from the response. | |||
Certificate ephemeralCertificate; | |||
try { | |||
ephemeralCertificate = createCertificate(response.getEphemeralCert().getCert()); | |||
ephemeralCertificate = createCertificate(response.getEphemeralCert().getCert()).get(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add a comment in the code about which cert .get(0)
is gettiing...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
// If this is CAS-managed, then use the HTTPS algorithm to check the subjectAlternateNames | ||
// against the certificate. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we not also be doing this for PSC? It also has the DNS name as a SAN entry...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, this is wrong. I'm removing it. It won't work because unlike Go we cannot override the hostname passed to Socket.connect().
I built custom hostname verification logic in InstanceCheckingTrustManager
.
The built-in HTTPS hostname verification algorithm won't work because the connector cannot override the hostname when Socket.connect(addr)
is called with an IP Address.
* checks that the Subject CN field contains the Cloud SQL instance ID. | ||
* does custom hostname checking in accordance with these rules: | ||
* | ||
* <p>If an instanceMetadata.casEnabled Check that the subjectAlternativeNames in the server |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: this sentence seems off to me, reads a bit funny...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. I fixed it.
fe76396
to
55d227f
Compare
a9815d8
to
12de4d4
Compare
647e946
to
f2fefc0
Compare
87a8a3f
to
096f8e7
Compare
096f8e7
to
4ee3acc
Compare
core/src/main/java/com/google/cloud/sql/core/InstanceCheckingTrustManger.java
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM ✅
f2fefc0
to
15e9584
Compare
For Cloud SQL instances with CAS enabled, the connector will use the certificate chain of trust reported by the
SQL Admin API to validate the instance connection.