439 lines
10 KiB
Markdown
439 lines
10 KiB
Markdown
# TLS/SSL Setup Guide
|
|
|
|
Complete guide to configuring SSL/TLS certificates with Hyperdrive.
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
**Hyperdrive requires TLS/SSL** for all database connections.
|
|
|
|
**Supported Configurations**:
|
|
1. **Basic TLS** (`require` mode) - Default, validates certificates via WebPKI
|
|
2. **Server Certificates** (`verify-ca`, `verify-full`) - Verify server's CA certificate
|
|
3. **Client Certificates** (mTLS) - Authenticate Hyperdrive to database
|
|
|
|
---
|
|
|
|
## SSL Modes
|
|
|
|
### 1. require (Default)
|
|
|
|
**What it does**:
|
|
- Enforces TLS encryption
|
|
- Validates server certificate using WebPKI (standard browser certificate authorities)
|
|
- No additional certificate configuration needed
|
|
|
|
**When to use**:
|
|
- Most cloud databases (AWS RDS, Google Cloud SQL, Azure, Neon, Supabase)
|
|
- Standard SSL/TLS setup
|
|
- Default choice for most applications
|
|
|
|
**Example**:
|
|
```bash
|
|
npx wrangler hyperdrive create my-db \
|
|
--connection-string="postgres://user:password@host:5432/database"
|
|
|
|
# SSL mode is "require" by default
|
|
```
|
|
|
|
**No configuration needed** - this is automatic.
|
|
|
|
---
|
|
|
|
### 2. verify-ca
|
|
|
|
**What it does**:
|
|
- Verifies server certificate is signed by expected Certificate Authority (CA)
|
|
- Prevents man-in-the-middle attacks
|
|
- Requires uploading CA certificate to Hyperdrive
|
|
|
|
**When to use**:
|
|
- Enhanced security requirements
|
|
- Self-signed certificates
|
|
- Private/internal certificate authorities
|
|
|
|
**Setup**:
|
|
|
|
**Step 1: Upload CA certificate**:
|
|
```bash
|
|
npx wrangler cert upload certificate-authority \
|
|
--ca-cert /path/to/root-ca.pem \
|
|
--name my-ca-cert
|
|
```
|
|
|
|
**Output**:
|
|
```
|
|
✅ Uploaded CA Certificate my-ca-cert
|
|
ID: ca-12345678-1234-1234-1234-123456789012
|
|
```
|
|
|
|
**Step 2: Create Hyperdrive with CA**:
|
|
```bash
|
|
npx wrangler hyperdrive create my-db \
|
|
--connection-string="postgres://user:password@host:5432/database" \
|
|
--ca-certificate-id ca-12345678-1234-1234-1234-123456789012 \
|
|
--sslmode verify-ca
|
|
```
|
|
|
|
---
|
|
|
|
### 3. verify-full
|
|
|
|
**What it does**:
|
|
- Everything from `verify-ca`, PLUS
|
|
- Verifies database hostname matches Subject Alternative Name (SAN) in certificate
|
|
|
|
**When to use**:
|
|
- Maximum security requirements
|
|
- Preventing hostname spoofing
|
|
- Compliance requirements (PCI-DSS, HIPAA)
|
|
|
|
**Setup** (same as verify-ca, but use `--sslmode verify-full`):
|
|
```bash
|
|
npx wrangler hyperdrive create my-db \
|
|
--connection-string="postgres://user:password@host:5432/database" \
|
|
--ca-certificate-id ca-12345678-1234-1234-1234-123456789012 \
|
|
--sslmode verify-full
|
|
```
|
|
|
|
---
|
|
|
|
## Certificate Requirements
|
|
|
|
### CA Certificate Format
|
|
|
|
**Must be**:
|
|
- PEM format (`.pem` file)
|
|
- Root CA or Intermediate CA certificate
|
|
- **Region-specific** (not global bundle with multiple CAs)
|
|
|
|
**Example CA Certificate** (root-ca.pem):
|
|
```
|
|
-----BEGIN CERTIFICATE-----
|
|
MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
|
|
...
|
|
-----END CERTIFICATE-----
|
|
```
|
|
|
|
**Get CA Certificate**:
|
|
|
|
**AWS RDS**:
|
|
```bash
|
|
wget https://truststore.pki.rds.amazonaws.com/us-east-1/us-east-1-bundle.pem
|
|
# Use region-specific bundle (NOT global bundle)
|
|
```
|
|
|
|
**Google Cloud SQL**:
|
|
```bash
|
|
# Download from Cloud SQL instance details page
|
|
# Instance → Connections → Server CA certificate
|
|
```
|
|
|
|
**Azure Database**:
|
|
```bash
|
|
wget https://www.digicert.com/CACerts/BaltimoreCyberTrustRoot.crt.pem
|
|
```
|
|
|
|
---
|
|
|
|
## Client Certificates (mTLS)
|
|
|
|
### Overview
|
|
|
|
**What is mTLS?**
|
|
- Mutual TLS: Both client and server authenticate each other
|
|
- Hyperdrive provides client certificate to database
|
|
- Database verifies certificate before allowing connection
|
|
|
|
**When to use**:
|
|
- Database requires client certificate authentication
|
|
- Enhanced security beyond username/password
|
|
- Compliance requirements
|
|
|
|
---
|
|
|
|
### Setup
|
|
|
|
**Step 1: Generate Client Certificate** (if needed):
|
|
```bash
|
|
# Generate private key
|
|
openssl genrsa -out client-key.pem 2048
|
|
|
|
# Generate certificate signing request (CSR)
|
|
openssl req -new -key client-key.pem -out client.csr
|
|
|
|
# Get certificate from your CA (or self-sign for testing)
|
|
openssl x509 -req -in client.csr -CA root-ca.pem -CAkey root-ca-key.pem \
|
|
-CAcreateserial -out client-cert.pem -days 365
|
|
```
|
|
|
|
**Step 2: Upload Client Certificate to Hyperdrive**:
|
|
```bash
|
|
npx wrangler cert upload mtls-certificate \
|
|
--cert /path/to/client-cert.pem \
|
|
--key /path/to/client-key.pem \
|
|
--name my-client-cert
|
|
```
|
|
|
|
**Output**:
|
|
```
|
|
✅ Uploaded client certificate my-client-cert
|
|
ID: mtls-87654321-4321-4321-4321-210987654321
|
|
```
|
|
|
|
**Step 3: Create Hyperdrive with Client Certificate**:
|
|
```bash
|
|
npx wrangler hyperdrive create my-db \
|
|
--connection-string="postgres://user:password@host:5432/database" \
|
|
--mtls-certificate-id mtls-87654321-4321-4321-4321-210987654321
|
|
```
|
|
|
|
**Optionally combine with server certificates**:
|
|
```bash
|
|
npx wrangler hyperdrive create my-db \
|
|
--connection-string="postgres://..." \
|
|
--ca-certificate-id ca-12345678-1234-1234-1234-123456789012 \
|
|
--mtls-certificate-id mtls-87654321-4321-4321-4321-210987654321 \
|
|
--sslmode verify-full
|
|
```
|
|
|
|
---
|
|
|
|
## Complete Setup Examples
|
|
|
|
### Example 1: AWS RDS with verify-full
|
|
|
|
```bash
|
|
# 1. Download AWS RDS CA certificate (region-specific)
|
|
wget https://truststore.pki.rds.amazonaws.com/us-east-1/us-east-1-bundle.pem
|
|
|
|
# 2. Upload CA certificate
|
|
npx wrangler cert upload certificate-authority \
|
|
--ca-cert us-east-1-bundle.pem \
|
|
--name aws-rds-us-east-1-ca
|
|
|
|
# Output: ID = ca-abc123...
|
|
|
|
# 3. Create Hyperdrive
|
|
npx wrangler hyperdrive create aws-rds-db \
|
|
--connection-string="postgres://admin:password@mydb.abc123.us-east-1.rds.amazonaws.com:5432/postgres" \
|
|
--ca-certificate-id ca-abc123... \
|
|
--sslmode verify-full
|
|
```
|
|
|
|
---
|
|
|
|
### Example 2: Self-Hosted with mTLS
|
|
|
|
```bash
|
|
# 1. Upload server CA certificate
|
|
npx wrangler cert upload certificate-authority \
|
|
--ca-cert /path/to/server-ca.pem \
|
|
--name my-server-ca
|
|
|
|
# Output: ID = ca-server123...
|
|
|
|
# 2. Upload client certificate
|
|
npx wrangler cert upload mtls-certificate \
|
|
--cert /path/to/client-cert.pem \
|
|
--key /path/to/client-key.pem \
|
|
--name my-client-cert
|
|
|
|
# Output: ID = mtls-client456...
|
|
|
|
# 3. Create Hyperdrive with both
|
|
npx wrangler hyperdrive create secure-db \
|
|
--connection-string="postgres://user:password@secure-db.example.com:5432/mydb" \
|
|
--ca-certificate-id ca-server123... \
|
|
--mtls-certificate-id mtls-client456... \
|
|
--sslmode verify-full
|
|
```
|
|
|
|
---
|
|
|
|
### Example 3: Basic SSL (Default)
|
|
|
|
```bash
|
|
# Most cloud databases (AWS, GCP, Azure, Neon, Supabase)
|
|
# No certificate configuration needed
|
|
npx wrangler hyperdrive create my-db \
|
|
--connection-string="postgres://user:password@host:5432/database"
|
|
|
|
# SSL mode "require" is automatic
|
|
```
|
|
|
|
---
|
|
|
|
## Database Configuration
|
|
|
|
### PostgreSQL SSL Setup
|
|
|
|
**postgresql.conf**:
|
|
```conf
|
|
ssl = on
|
|
ssl_cert_file = 'server.crt'
|
|
ssl_key_file = 'server.key'
|
|
ssl_ca_file = 'root.crt' # For client certificate verification
|
|
|
|
# Optional: Require SSL
|
|
ssl_min_protocol_version = 'TLSv1.2'
|
|
```
|
|
|
|
**pg_hba.conf** (require SSL):
|
|
```conf
|
|
# TYPE DATABASE USER ADDRESS METHOD
|
|
hostssl all all 0.0.0.0/0 md5
|
|
|
|
# Or require client certificates
|
|
hostssl all all 0.0.0.0/0 cert
|
|
```
|
|
|
|
**Restart PostgreSQL**:
|
|
```bash
|
|
sudo systemctl restart postgresql
|
|
```
|
|
|
|
---
|
|
|
|
### MySQL SSL Setup
|
|
|
|
**my.cnf** or **my.ini**:
|
|
```conf
|
|
[mysqld]
|
|
require_secure_transport = ON
|
|
ssl-ca = /path/to/ca-cert.pem
|
|
ssl-cert = /path/to/server-cert.pem
|
|
ssl-key = /path/to/server-key.pem
|
|
```
|
|
|
|
**Require client certificates** (MySQL user):
|
|
```sql
|
|
CREATE USER 'hyperdrive'@'%' IDENTIFIED BY 'password' REQUIRE X509;
|
|
GRANT ALL PRIVILEGES ON mydb.* TO 'hyperdrive'@'%';
|
|
FLUSH PRIVILEGES;
|
|
```
|
|
|
|
**Restart MySQL**:
|
|
```bash
|
|
sudo systemctl restart mysql
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Error: "TLS not supported by the database"
|
|
|
|
**Cause**: Database doesn't have SSL/TLS enabled.
|
|
|
|
**Solution**:
|
|
1. Enable SSL in database configuration
|
|
2. Restart database
|
|
3. Verify SSL enabled: `SHOW ssl;` (MySQL) or `SHOW ssl;` (PostgreSQL)
|
|
|
|
**PostgreSQL verification**:
|
|
```sql
|
|
SHOW ssl;
|
|
-- Should return "on"
|
|
```
|
|
|
|
**MySQL verification**:
|
|
```sql
|
|
SHOW VARIABLES LIKE 'have_ssl';
|
|
-- Should return "YES"
|
|
```
|
|
|
|
---
|
|
|
|
### Error: "TLS handshake failed: cert validation failed"
|
|
|
|
**Cause**: Server certificate not signed by expected CA.
|
|
|
|
**Solutions**:
|
|
1. Verify correct CA certificate uploaded
|
|
2. Check CA certificate is for correct region (AWS RDS)
|
|
3. Ensure CA certificate format is PEM
|
|
4. Verify connection string hostname matches certificate SAN (verify-full mode)
|
|
|
|
---
|
|
|
|
### Error: "Server return error and closed connection"
|
|
|
|
**Cause**: Database requires client certificate, but none provided.
|
|
|
|
**Solution**: Upload client certificate and configure Hyperdrive with mTLS:
|
|
```bash
|
|
npx wrangler cert upload mtls-certificate \
|
|
--cert client-cert.pem \
|
|
--key client-key.pem \
|
|
--name my-cert
|
|
|
|
npx wrangler hyperdrive create my-db \
|
|
--connection-string="..." \
|
|
--mtls-certificate-id <id>
|
|
```
|
|
|
|
---
|
|
|
|
### Error: "Certificate has expired"
|
|
|
|
**Cause**: Server certificate or client certificate expired.
|
|
|
|
**Solutions**:
|
|
1. Renew certificate from certificate authority
|
|
2. Upload new certificate to Hyperdrive
|
|
3. Update Hyperdrive configuration
|
|
|
|
---
|
|
|
|
## Local Development
|
|
|
|
### SSL in Local Development
|
|
|
|
**Option 1: Disable SSL for local database** (NOT recommended):
|
|
```bash
|
|
# Local PostgreSQL without SSL
|
|
export CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE="postgres://user:password@localhost:5432/db?sslmode=disable"
|
|
```
|
|
|
|
**Option 2: Use Tunnel for local database** (Recommended):
|
|
```bash
|
|
# Use Cloudflare Tunnel to local database (keeps SSL)
|
|
cloudflared tunnel create local-db
|
|
cloudflared tunnel run local-db
|
|
|
|
# Hyperdrive connects via tunnel with SSL
|
|
```
|
|
|
|
**Option 3: Self-signed certificates for local dev**:
|
|
```bash
|
|
# Generate self-signed cert
|
|
openssl req -new -x509 -days 365 -nodes -out server.crt -keyout server.key
|
|
|
|
# Configure local PostgreSQL to use it
|
|
# Then use verify-ca mode with local CA
|
|
```
|
|
|
|
---
|
|
|
|
## Best Practices
|
|
|
|
1. **Use default `require` mode** unless you have specific security requirements
|
|
2. **Use verify-full for production** if handling sensitive data
|
|
3. **Store certificates securely** - don't commit to git
|
|
4. **Rotate certificates regularly** - before expiration
|
|
5. **Test certificate setup** in staging before production
|
|
6. **Use region-specific CA bundles** (AWS RDS) not global bundles
|
|
7. **Document certificate IDs** in project README
|
|
8. **Monitor certificate expiration** (set calendar reminders)
|
|
|
|
---
|
|
|
|
## References
|
|
|
|
- [Hyperdrive TLS/SSL Docs](https://developers.cloudflare.com/hyperdrive/configuration/tls-ssl-certificates-for-hyperdrive/)
|
|
- [PostgreSQL SSL Docs](https://www.postgresql.org/docs/current/ssl-tcp.html)
|
|
- [MySQL SSL Docs](https://dev.mysql.com/doc/refman/8.0/en/using-encrypted-connections.html)
|
|
- [AWS RDS SSL Certificates](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL.html)
|