Skip to content

Conversation

@itowlson
Copy link
Collaborator

Partially fixes fermyon/feedback#64 - this handles the custom root certs side, but not the sslmode=verify-full part.

Credit and thanks to @kate-goldenring for figuring out a test case.

How to specify custom roots

In this PR, trusted roots certificates are referenced in the runtime config file:

[postgres]
root_certificates = ["postgres-ssl/ca.crt"]

Things to consider:

  • This leaves no trace in the manifest that an application might require custom certificates: deployment tools therefore have no way of knowing that they need to also prepare custom certs. (Although this is probably reasonable. The deployment environment will likely connect to a different Postgres host, which may or may not require a custom CA when accessed from the deployment environment.)

  • This makes it clear that the custom certificates will only be when making Postgres connections. But this seems potentially weird: if I trust these CAs, why would I not trust them for all my network traffic? But I am not sure how to set this up. Sockets have some existing runtime-config network config stuff but it's not clear to me whether that applies to Postgres (e.g. I don't think the Postgres library allows for client certificates) and if so how to re-use it. But very open to feedback on this: it feels like trust is trust and would be good not to have that partitioned by API.

Testing

I don't currently have a good way to test this. Kate wrote an excellent and convenient manual test case, which I've committed as part of this draft, but really we'd want a Docker-based test to run as part of integration. The existing PG tests are done via conformance-test, but that doesn't seem like a natural home for this (not to mention I'd prefer not to have to deal with the circularity problem again), and yet I'm hazy on how to write PG tests outside of conformance-test. So... open to advice/suggestions on this.

@fibonacci1729 fibonacci1729 moved this to Triage Needed in Spin Triage Dec 15, 2025
@fibonacci1729 fibonacci1729 moved this from Triage Needed to In Progress in Spin Triage Dec 15, 2025
@kate-goldenring
Copy link
Contributor

Thank you for putting this together @itowlson! Is there a reason why we cannot use the existing client_tls runtime config? Is it too weird validating the associated host in this scenario?

@lann
Copy link
Collaborator

lann commented Dec 15, 2025

It should be possible to use the existing client TLS runtime config but it would require either a) adding support for native-tls there or b) switching from postgres-native-tls to postgres-rustls.

For b) I think the rough approach would be something like:

  1. In OutboundPgFactor::prepare get a handle to the OutboundNetworkingFactor's ComponentTlsClientConfigs:

    let outbound_networking = ctx.instance_builder::<OutboundNetworkingFactor>()?;

    let component_tls_configs = outbound_networking.component_tls_configs();

  2. Pass that through in InstanceState (as already done with OutboundAllowedHosts) and then at the point where you need TLS config call get_client_config to get TlsClientConfig:

    Some(self.component_tls_configs.get_client_config(host).clone())

  3. Trade your TlsClientConfig for a TlsConnector, something like:

     let tls_connector = tokio_rustls::TlsConnector::from(tls_client_config.inner().clone())
  4. Then it should be similar to this PR, except with postgres-rustls instead: https://docs.rs/postgres_rustls/latest/postgres_rustls/struct.TlsConnector.html

I think a) would be similar but the runtime config parsing would need to be reworked a bit to allow conversion to either rustls or native-tls config.

@itowlson
Copy link
Collaborator Author

The trouble with using the TLS configs from the outbound networking factor is that they are component specific and available at instance state level, but Postgres uses an app-level connection pool. I guess we could make it pool per component - technically it feels a bit naughty for one component's InstanceState to bleed through to another's but in this case it would be benign. I am not sure how much faff would be involved, but probably not an excessive amount. (We could even make it pool per instance but that obviates a lot of the value of pooling.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

sslrootcert parameter for PostgreSQL connections with custom CA certificates

3 participants