Secure SSH tunnels for PostgreSQL and Redshift connections through bastion hosts.
import { PostgresWarehouseClient } from '@lightdash/warehouses';
const client = new PostgresWarehouseClient({
type: 'postgres',
host: 'internal-db.local',
port: 5432,
user: 'dbuser',
password: 'dbpass',
dbname: 'warehouse',
schema: 'public',
sslmode: 'disable',
// SSH tunnel config
useSshTunnel: true,
sshTunnelHost: 'bastion.example.com',
sshTunnelPort: 22,
sshTunnelUser: 'sshuser',
sshTunnelPrivateKey: '-----BEGIN RSA PRIVATE KEY-----\n...',
});
await client.test(); // Tunnel created automatically| Warehouse | SSH Tunnel Support |
|---|---|
| PostgreSQL | ✓ |
| Redshift | ✓ |
| BigQuery | ✗ (uses API) |
| ClickHouse | ✗ |
| Databricks | ✗ (uses API) |
| Snowflake | ✗ (uses API) |
| Trino | ✗ (uses HTTP) |
import { SshTunnel } from '@lightdash/warehouses';
const tunnel = new SshTunnel(credentials);
const modifiedCreds = await tunnel.connect();
console.log('Tunnel port:', tunnel.localPort);
const client = new PostgresWarehouseClient(modifiedCreds);
await client.test();
await tunnel.disconnect();Original: Client -> internal-db.local:5432 (blocked)
With SSH: Client -> 127.0.0.1:random_port
-> [SSH Tunnel] -> bastion.example.com:22
-> internal-db.local:5432 (accessible){
useSshTunnel: true,
sshTunnelHost: 'bastion.example.com',
sshTunnelPort: 22, // Default: 22
sshTunnelUser: 'sshuser',
sshTunnelPrivateKey: '-----BEGIN RSA PRIVATE KEY-----\n...',
sshTunnelPublicKey: '...', // Optional, for reference
}Must be PEM format with newlines:
const privateKey = `-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA1234567890...
[multiple lines]
-----END RSA PRIVATE KEY-----`;Supported Key Types:
-----BEGIN RSA PRIVATE KEY----------BEGIN DSA PRIVATE KEY----------BEGIN EC PRIVATE KEY----------BEGIN OPENSSH PRIVATE KEY-----class SshTunnel<T extends CreateWarehouseCredentials> {
readonly originalCredentials: T;
overrideCredentials: T;
localPort: number | undefined;
constructor(credentials: T);
connect(): Promise<T>;
disconnect(): Promise<void>;
}try {
const tunnel = new SshTunnel(credentials);
const modifiedCreds = await tunnel.connect();
const client = new PostgresWarehouseClient(modifiedCreds);
await client.test();
} catch (error) {
console.error('SSH tunnel failed:', error.message);
} finally {
await tunnel.disconnect();
}Error: SSH tunnel connection timeoutSolutions: Check bastion hostname, port, firewall, network connectivity
Error: SSH authentication failedSolutions: Verify username, private key format, key matches public key on bastion
Error: Failed to establish port forwardSolutions: Verify database host:port reachable from bastion, check firewall rules
const pgTunnel = new SshTunnel(pgCredentials);
const rsTunnel = new SshTunnel(rsCredentials);
const pgCreds = await pgTunnel.connect();
const rsCreds = await rsTunnel.connect();
const pgClient = new PostgresWarehouseClient(pgCreds);
const rsClient = new RedshiftWarehouseClient(rsCreds);
// Use both clients...
await pgTunnel.disconnect();
await rsTunnel.disconnect();