diff --git a/libraries/object-persistor/src/S3Persistor.js b/libraries/object-persistor/src/S3Persistor.js index 048cff6564..f69e884e84 100644 --- a/libraries/object-persistor/src/S3Persistor.js +++ b/libraries/object-persistor/src/S3Persistor.js @@ -14,12 +14,7 @@ const { pipeline, PassThrough } = require('stream') const fs = require('fs') const S3 = require('aws-sdk/clients/s3') const { URL } = require('url') -const { - WriteError, - ReadError, - NotFoundError, - SettingsError, -} = require('./Errors') +const { WriteError, ReadError, NotFoundError } = require('./Errors') module.exports = class S3Persistor extends AbstractPersistor { constructor(settings = {}) { @@ -336,23 +331,11 @@ module.exports = class S3Persistor extends AbstractPersistor { } _getClientForBucket(bucket, clientOptions) { - if (this.settings.bucketCreds && this.settings.bucketCreds[bucket]) { - return new S3( - this._buildClientOptions( - this.settings.bucketCreds[bucket], - clientOptions - ) + return new S3( + this._buildClientOptions( + this.settings.bucketCreds?.[bucket], + clientOptions ) - } - - // no specific credentials for the bucket - if (this.settings.key) { - return new S3(this._buildClientOptions(null, clientOptions)) - } - - throw new SettingsError( - 'no bucket-specific or default credentials provided', - { bucket } ) } @@ -364,11 +347,14 @@ module.exports = class S3Persistor extends AbstractPersistor { accessKeyId: bucketCredentials.auth_key, secretAccessKey: bucketCredentials.auth_secret, } - } else { + } else if (this.settings.key) { options.credentials = { accessKeyId: this.settings.key, secretAccessKey: this.settings.secret, } + } else { + // Use the default credentials provider (process.env -> SSP -> ini -> IAM) + // Docs: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/CredentialProviderChain.html#defaultProviders-property } if (this.settings.endpoint) { diff --git a/libraries/object-persistor/test/unit/S3PersistorTests.js b/libraries/object-persistor/test/unit/S3PersistorTests.js index c374d873d7..7866247f23 100644 --- a/libraries/object-persistor/test/unit/S3PersistorTests.js +++ b/libraries/object-persistor/test/unit/S3PersistorTests.js @@ -281,14 +281,16 @@ describe('S3PersistorTests', function () { expect(S3.firstCall).to.have.been.calledWith(alternativeS3Credentials) expect(S3.secondCall).to.have.been.calledWith(defaultS3Credentials) }) + }) - it('throws an error if there are no credentials for the bucket', async function () { + describe('without hard-coded credentials', function () { + it('uses the default provider chain', async function () { delete settings.key delete settings.secret - await expect( - S3Persistor.getObjectStream('anotherBucket', key) - ).to.eventually.be.rejected.and.be.an.instanceOf(Errors.SettingsError) + await S3Persistor.getObjectStream(bucket, key) + expect(S3).to.have.been.calledOnce + expect(S3.args[0].credentials).to.not.exist }) }) diff --git a/services/filestore/config/settings.defaults.js b/services/filestore/config/settings.defaults.js index cc97974c32..47eb94c4fb 100644 --- a/services/filestore/config/settings.defaults.js +++ b/services/filestore/config/settings.defaults.js @@ -62,19 +62,16 @@ const settings = { signedUrlExpiryInMs: parseInt(process.env.LINK_EXPIRY_TIMEOUT || 60000), }, - s3: - process.env.AWS_ACCESS_KEY_ID || process.env.S3_BUCKET_CREDENTIALS - ? { - key: process.env.AWS_ACCESS_KEY_ID, - secret: process.env.AWS_SECRET_ACCESS_KEY, - endpoint: process.env.AWS_S3_ENDPOINT, - pathStyle: process.env.AWS_S3_PATH_STYLE, - partSize: process.env.AWS_S3_PARTSIZE || 100 * 1024 * 1024, - bucketCreds: process.env.S3_BUCKET_CREDENTIALS - ? JSON.parse(process.env.S3_BUCKET_CREDENTIALS) - : undefined, - } + s3: { + key: process.env.AWS_ACCESS_KEY_ID, + secret: process.env.AWS_SECRET_ACCESS_KEY, + endpoint: process.env.AWS_S3_ENDPOINT, + pathStyle: process.env.AWS_S3_PATH_STYLE, + partSize: process.env.AWS_S3_PARTSIZE || 100 * 1024 * 1024, + bucketCreds: process.env.S3_BUCKET_CREDENTIALS + ? JSON.parse(process.env.S3_BUCKET_CREDENTIALS) : undefined, + }, // GCS should be configured by the service account on the kubernetes pod. See GOOGLE_APPLICATION_CREDENTIALS, // which will be picked up automatically. diff --git a/services/filestore/test/acceptance/js/TestConfig.js b/services/filestore/test/acceptance/js/TestConfig.js index 260cd6e2d4..d8c6d30a94 100644 --- a/services/filestore/test/acceptance/js/TestConfig.js +++ b/services/filestore/test/acceptance/js/TestConfig.js @@ -11,6 +11,14 @@ function s3Config() { } } +function s3ConfigDefaultProviderCredentials() { + return { + endpoint: process.env.AWS_S3_ENDPOINT, + pathStyle: true, + partSize: 100 * 1024 * 1024, + } +} + function s3Stores() { return { user_files: process.env.AWS_S3_USER_FILES_BUCKET_NAME, @@ -65,6 +73,11 @@ module.exports = { s3: s3Config(), stores: s3Stores(), }, + S3PersistorDefaultProviderCredentials: { + backend: 's3', + s3: s3ConfigDefaultProviderCredentials(), + stores: s3Stores(), + }, GcsPersistor: { backend: 'gcs', gcs: gcsConfig(),