electric-sql / electric

Sync little subsets of your Postgres data into local apps and services.
https://electric-sql.com
Apache License 2.0
6.2k stars 146 forks source link

fix(electric): Update SSL logic after upgrading to OTP 27.0 #1396

Closed alco closed 3 months ago

alco commented 3 months ago

When we upgraded the sync service to OTP 27.0, we missed the changed default from verify_none to verify_peer in SSL connections.

We now explicitly set verify to verify_none because it's currently the only way to ensure encrypted connections work even when a faulty certificate chain is presented by the PG host. This behaviour matches that of psql <DATABASE_URL>?sslmode=require.

Here's an example of connecting to DigitalOcean's Managed PostgreSQL to illustrate the point:

$ psql 'postgresql://...?sslmode=require'
Null display is "∅".
Output format is aligned.
Expanded display is used automatically.
Line style is unicode.
Border style is 1.
psql (16.1, server 16.3)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)
Type "help" for help.

[db-postgresql-do-user-13160360-0] doadmin:defaultdb=> \q
$ psql 'postgresql://...?sslmode=verify-full'
psql: error: connection to server at "***.db.ondigitalocean.com" (167.99.250.38), port 25060 failed: root certificate file "/home/alco/.postgresql/root.crt" does not exist
Either provide the file, use the system's trusted roots with sslrootcert=system, or change sslmode to disable server certificate verification.

$ psql 'sslrootcert=system sslmode=verify-full host=***.db.ondigitalocean.com ...'
psql: error: connection to server at "***.db.ondigitalocean.com" (167.99.250.38), port 25060 failed: SSL error: certificate verify failed
$ openssl s_client -starttls postgres -showcerts -connect ***.db.ondigitalocean.com:25060 -CApath /etc/ssl/certs/
[...]
SSL handshake has read 3990 bytes and written 885 bytes
Verification error: self-signed certificate in certificate chain

Fix #1395.

linear[bot] commented 3 months ago

VAX-1987 Sync service 12.0.1 fails to connect to the database with {:case_clause, :undefined} error

alco commented 3 months ago

Found another issue with DO's managed Postgres while testing this fix:

14:56:49.189 pid=<0.3377.0> [error] GenServer #PID<0.3377.0> terminating
** (stop) exited in: :options.incompatible({:verify, :verify_peer}, {:cacerts, :undefined})
    ** (EXIT) :ssl_negotiation_failed
Last message (from #PID<0.3370.0>): {:command, :epgsql_cmd_connect, %{...}}
▓ ┌────────────────────┐
▓ │  CONNECTION ERROR  │
▓ ┕━━━━━━━━━━━━━━━━━━━━┙
▓ 
▓ Failed to initialize Postgres state:
▓   {:error, {:ssl_negotiation_failed, {:options, :incompatible, [verify: :verify_peer, cacerts: :undefined]}}}
▓ 
▓ Double-check the value of DATABASE_URL and make sure your database
▓ is running and can be reached using the connection URL in DATABASE_URL.
14:56:49.190 pid=<0.3370.0> origin=postgres_1 [error] Initialization of Postgres state failed with reason: {:error, {:ssl_negotiation_failed, {:options, :incompatible, [verify: :verify_peer, cacerts: :undefined]}}}.