Skip to content

Commit d6fc834

Browse files
committed
feat(snowflake-driver): Ability to use encrypted private keys for auth
1 parent 3a2f4ac commit d6fc834

File tree

5 files changed

+16407
-2
lines changed

5 files changed

+16407
-2
lines changed

packages/cubejs-snowflake-driver/src/SnowflakeDriver.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
} from '@cubejs-backend/base-driver';
2323
import { formatToTimeZone } from 'date-fns-timezone';
2424
import fs from 'fs/promises';
25+
import crypto from 'crypto';
2526
import { HydrationMap, HydrationStream } from './HydrationStream';
2627

2728
const SUPPORTED_BUCKET_TYPES = ['s3', 'gcs', 'azure'];
@@ -245,8 +246,30 @@ export class SnowflakeDriver extends BaseDriver implements DriverInterface {
245246
assertDataSource('default');
246247

247248
let privateKey = getEnv('snowflakePrivateKey', { dataSource });
248-
if (privateKey && !privateKey.endsWith('\n')) {
249-
privateKey += '\n';
249+
250+
if (privateKey) {
251+
// If the private key is encrypted - we need to decrypt it before passing to
252+
// snowflake sdk.
253+
if (privateKey.includes('BEGIN ENCRYPTED PRIVATE KEY')) {
254+
const keyPasswd = getEnv('snowflakePrivateKeyPass', { dataSource });
255+
256+
if (!keyPasswd) {
257+
throw new Error(
258+
'Snowflake encrypted private key provided, but no passphrase was given.'
259+
);
260+
}
261+
262+
const privateKeyObject = crypto.createPrivateKey({
263+
key: privateKey,
264+
format: 'pem',
265+
passphrase: keyPasswd
266+
});
267+
268+
privateKey = privateKeyObject.export({
269+
format: 'pem',
270+
type: 'pkcs8'
271+
});
272+
}
250273
}
251274

252275
snowflake.configure({ logLevel: 'OFF' });
@@ -267,6 +290,7 @@ export class SnowflakeDriver extends BaseDriver implements DriverInterface {
267290
privateKeyPath: getEnv('snowflakePrivateKeyPath', { dataSource }),
268291
privateKeyPass: getEnv('snowflakePrivateKeyPass', { dataSource }),
269292
privateKey,
293+
...(privateKey ? { privateKey } : {}),
270294
exportBucket: this.getExportBucket(dataSource),
271295
resultPrefetch: 1,
272296
executionTimeout: getEnv('dbQueryTimeout', { dataSource }),

packages/cubejs-testing-drivers/fixtures/snowflake.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@
4040
"CUBEJS_DB_EXPORT_GCS_CREDENTIALS": "${DRIVERS_TESTS_CUBEJS_DB_EXPORT_GCS_CREDENTIALS}"
4141
}
4242
}
43+
},
44+
"encrypted-pk": {
45+
"cube": {
46+
"environment": {
47+
"CUBEJS_DB_SNOWFLAKE_AUTHENTICATOR": "SNOWFLAKE_JWT",
48+
"CUBEJS_DB_SNOWFLAKE_PRIVATE_KEY": "${DRIVERS_TESTS_CUBEJS_DB_SNOWFLAKE_PRIVATE_KEY}",
49+
"CUBEJS_DB_SNOWFLAKE_PRIVATE_KEY_PASS": "${DRIVERS_TESTS_CUBEJS_DB_SNOWFLAKE_PRIVATE_KEY_PASS}"
50+
}
51+
}
4352
}
4453
},
4554
"cube": {

packages/cubejs-testing-drivers/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"snowflake-driver": "yarn test-driver -i dist/test/snowflake-driver.test.js",
4545
"snowflake-core": "yarn test-driver -i dist/test/snowflake-core.test.js",
4646
"snowflake-full": "yarn test-driver -i dist/test/snowflake-full.test.js",
47+
"snowflake-encrypted-pk-full": "yarn test-driver -i dist/test/snowflake-encrypted-pk-full.test.js",
4748
"snowflake-export-bucket-s3-full": "yarn test-driver -i dist/test/snowflake-export-bucket-s3-full.test.js",
4849
"snowflake-export-bucket-azure-full": "yarn test-driver -i dist/test/snowflake-export-bucket-azure-full.test.js",
4950
"snowflake-export-bucket-azure-via-storage-integration-full": "yarn test-driver -i dist/test/snowflake-export-bucket-azure-via-storage-integration-full.test.js",

0 commit comments

Comments
 (0)