Initial commit
This commit is contained in:
438
references/tls-ssl-setup.md
Normal file
438
references/tls-ssl-setup.md
Normal file
@@ -0,0 +1,438 @@
|
||||
# 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)
|
||||
Reference in New Issue
Block a user