Skip to content

sslrootcert parameter for PostgreSQL connections with custom CA certificates #64

@krismcfarlin

Description

@krismcfarlin

Summary

When connecting to PostgreSQL databases that use self-signed or private CA certificates (such as DigitalOcean Managed Databases), Spin's allowed_outbound_hosts validation rejects connection strings that include SSL parameters like sslrootcert. This prevents Spin applications from connecting to these databases with proper TLS certificate verification.

Problem

I'm trying to connect a Spin application deployed on Fermyon Cloud to a DigitalOcean Managed PostgreSQL database. DigitalOcean uses a private CA to sign their database certificates, which means:

  1. Without specifying sslrootcert, TLS handshake fails:

    error performing TLS handshake: certificate verify failed (self-signed certificate in certificate chain)
    
  2. When I add sslrootcert to the connection string (URL format), the connection is rejected:

    address postgres://...?sslmode=verify-full&sslrootcert=/do-ca.crt is not permitted
    
  3. When I use the libpq key/value format, the entire connection string is treated as the "address" and rejected:

    address host=db.example.com port=25060 ... sslrootcert=/do-ca.crt is not permitted
    

Environment

  • Spin CLI: 3.5.1
  • spin-sdk (Rust): 5.1
  • Fermyon Cloud: latest
  • Database: DigitalOcean Managed PostgreSQL (uses private CA)

What I've Tried

  1. URL format with sslrootcert: Rejected because the / in the path breaks URL parsing for allowed_outbound_hosts validation

  2. URL format with percent-encoded path (sslrootcert=%2Fdo-ca.crt): Still rejected

  3. Key/value connection string format: The entire string is treated as the address rather than extracting the host for validation

  4. Mounting the CA certificate via files = ["do-ca.crt"]: File is mounted correctly, but can't use it in the connection string

  5. Various allowed_outbound_hosts patterns: Including postgres://*:*, explicit hostname with and without port

Proposed Solution

Based on documentation I found (possibly from an unreleased version), it appears the intended behavior is:

  1. For key/value connection strings: Parse the host= value and validate it against allowed_outbound_hosts separately, allowing other parameters like sslmode and sslrootcert to pass through to the driver

Example from documentation I found:

// allowed_outbound_hosts = ["postgres://db.example.com:5432"]
let db = Connection::open(
    "host=db.example.com port=5432 user=app dbname=appdb sslmode=verify-full sslrootcert=/ca.crt",
)?;

Impact

This limitation prevents Spin applications from connecting to:

  • DigitalOcean Managed Databases
  • AWS RDS with private CA certificates
  • Azure Database for PostgreSQL with private endpoints
  • Any PostgreSQL instance using self-signed or private CA certificates

These are common production database configurations, and the workaround of using sslmode=require (which skips certificate verification) is not secure as it leaves connections vulnerable to MITM attacks.

Workaround Attempts

  • sslmode=require still fails with certificate verification errors
  • Cannot use a database provider with publicly-trusted certificates for this project

Request

Please add support for:

  1. Parsing key/value PostgreSQL connection strings to extract the host for allowed_outbound_hosts validation
  2. Allowing SSL-related query parameters in URL-style connection strings without breaking the host validation

This would enable secure connections to PostgreSQL databases using private CA certificates, which is a common enterprise and cloud database configuration.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions