diff --git a/packages/cubejs-backend-shared/src/env.ts b/packages/cubejs-backend-shared/src/env.ts index 3d85a197b7add..6bee25489a2bc 100644 --- a/packages/cubejs-backend-shared/src/env.ts +++ b/packages/cubejs-backend-shared/src/env.ts @@ -1613,6 +1613,16 @@ const variables: Record any> = { ] ), + duckdbS3UseCredentialChain: ({ + dataSource + }: { + dataSource: string, + }) => ( + process.env[ + keyByDataSource('CUBEJS_DB_DUCKDB_S3_USE_CREDENTIAL_CHAIN', dataSource) + ] + ), + /** * Presto catalog. */ diff --git a/packages/cubejs-duckdb-driver/src/DuckDBDriver.ts b/packages/cubejs-duckdb-driver/src/DuckDBDriver.ts index 9eeba91b27ac1..4e392337ff222 100644 --- a/packages/cubejs-duckdb-driver/src/DuckDBDriver.ts +++ b/packages/cubejs-duckdb-driver/src/DuckDBDriver.ts @@ -20,6 +20,7 @@ export type DuckDBDriverConfiguration = { dataSource?: string, initSql?: string, schema?: string, + duckdbS3UseCredentialChain?: boolean, }; type InitPromise = { @@ -145,7 +146,7 @@ export class DuckDBDriver extends BaseDriver implements DriverInterface { value: getEnv('duckdbS3SessionToken', this.config), } ]; - + for (const { key, value } of configuration) { if (value) { try { @@ -159,6 +160,17 @@ export class DuckDBDriver extends BaseDriver implements DriverInterface { } } } + const useCredentialChain = getEnv('duckdbS3UseCredentialChain', this.config); + if (useCredentialChain === 'true' || useCredentialChain === true) { + try { + await execAsync('CREATE SECRET (TYPE S3, PROVIDER \'CREDENTIAL_CHAIN\')'); + } catch (e) { + if (this.logger) { + console.error('DuckDB - error on creating S3 credential chain secret', { e }); + } + throw e; + } + } if (this.config.initSql) { try { diff --git a/packages/cubejs-duckdb-driver/test/DuckDBDriver.test.ts b/packages/cubejs-duckdb-driver/test/DuckDBDriver.test.ts index b31bfc17af272..17f8244b7b049 100644 --- a/packages/cubejs-duckdb-driver/test/DuckDBDriver.test.ts +++ b/packages/cubejs-duckdb-driver/test/DuckDBDriver.test.ts @@ -73,4 +73,23 @@ describe('DuckDBDriver', () => { { id: '3', created: '2020-03-03T03:03:03.333Z', created_date: '2020-03-03T00:00:00.000Z', price: '300' } ]); }); + + test('should execute CREATE SECRET when duckdbS3UseCredentialChain is set', async () => { + process.env.duckdbS3UseCredentialChain = 'true'; + + // Create a new driver instance to pick up the environment variable + const driverWithCredentialChain = new DuckDBDriver({}); + + // Mock the execAsync method to spy on it + const execAsyncSpy = jest.spyOn((driverWithCredentialChain as any), 'execAsync'); + + await driverWithCredentialChain.testConnection(); + + expect(execAsyncSpy).toHaveBeenCalledWith(`CREATE SECRET (TYPE S3, PROVIDER 'CREDENTIAL_CHAIN')`); + + // Clean up + delete process.env.duckdbS3UseCredentialChain; + execAsyncSpy.mockRestore(); + await driverWithCredentialChain.release(); + }); });