How to use aws-s3 provider with a kubernetes "service" account

System Information
  • Strapi Version: 4.07
  • Operating System: MacOs 11.6
  • Database: postgres:12.0-alpine
  • Node Version: v14.18.3
  • NPM Version: 6.14.15
  • Yarn Version: N/A

Hey everyone,

I am having a lot of hassle setting up the @strapi/provider-upload-aws-s3 to successfully add images to S3. I have my strapi app successfully running inside a kubernetes pod. My issue is that I am not permitted by my company to add AWS credentials to my app (and the aws-s3 provider via env variables) and instead must use a kubernetes “service account”

More details on service accounts here - Configure Service Accounts for Pods | Kubernetes

I cannot find anything in the docs that outlines how to avail of the AWS_WEB_IDENTITY_TOKEN_FILE that is made available via the service account. I have confirmed that the token does indeed exist. The closest thing I can find that looks like a solution to my problem is found in this old issue - Cannot use AWS_ROLE_ARN and AWS_WEB_IDENTITY_TOKEN_FILE for S3 Credentials · Issue #10473 · strapi/strapi · GitHub

So this is how my config/plugins.js file looks:

var AWS = require('aws-sdk');

module.exports = ({ env }) => ({
  upload: {
    config: {
      provider: 'aws-s3',
      providerOptions: {
        credentials: new AWS.TokenFileWebIdentityCredentials(),
        region: env('AWS_REGION'),
        params: {
          Bucket: env('AWS_BUCKET'),
        },
      },
    }
  },
});

Here is my package.json:

{
  "name": "lima-strapi",
  "private": true,
  "version": "0.1.0",
  "description": "A Strapi application",
  "scripts": {
    "develop": "strapi develop",
    "start": "strapi start",
    "build": "strapi build",
    "strapi": "strapi"
  },
  "devDependencies": {
    "knex": "^1.0.4",
    "pg": "^8.7.3"
  },
  "dependencies": {
    "@strapi/plugin-i18n": "4.0.7",
    "@strapi/plugin-users-permissions": "4.0.7",
    "@strapi/provider-upload-aws-s3": "^4.1.8",
    "@strapi/strapi": "4.0.7"
  },
  "author": {
    "name": "A Strapi developer"
  },
  "strapi": {
    "uuid": "76b7b260-6a9d-4af0-9cda-aba3f1ab0665"
  },
  "engines": {
    "node": ">=12.x.x <=16.x.x",
    "npm": ">=6.0.0"
  },
  "license": "MIT"
}

When I try to add an image I get the following error in the strapi logs:

[2022-04-20 21:11:43.632] error: Missing credentials in config, if using AWS_CONFIG_FILE, set AWS_SDK_LOAD_CONFIG=1
CredentialsError: Missing credentials in config, if using AWS_CONFIG_FILE, set AWS_SDK_LOAD_CONFIG=1
    at Request.extractError (/app/node_modules/aws-sdk/lib/protocol/query.js:50:29)
    at Request.callListeners (/app/node_modules/aws-sdk/lib/sequential_executor.js:106:20)
    at Request.emit (/app/node_modules/aws-sdk/lib/sequential_executor.js:78:10)
    at Request.emit (/app/node_modules/aws-sdk/lib/request.js:688:14)
    at Request.transition (/app/node_modules/aws-sdk/lib/request.js:22:10)
    at AcceptorStateMachine.runTo (/app/node_modules/aws-sdk/lib/state_machine.js:14:12)
    at /app/node_modules/aws-sdk/lib/state_machine.js:26:10
    at Request.<anonymous> (/app/node_modules/aws-sdk/lib/request.js:38:9)
    at Request.<anonymous> (/app/node_modules/aws-sdk/lib/request.js:690:12)
    at Request.callListeners (/app/node_modules/aws-sdk/lib/sequential_executor.js:116:18)
    at Request.emit (/app/node_modules/aws-sdk/lib/sequential_executor.js:78:10)
    at Request.emit (/app/node_modules/aws-sdk/lib/request.js:688:14)
    at Request.transition (/app/node_modules/aws-sdk/lib/request.js:22:10)
    at AcceptorStateMachine.runTo (/app/node_modules/aws-sdk/lib/state_machine.js:14:12)
    at /app/node_modules/aws-sdk/lib/state_machine.js:26:10
    at Request.<anonymous> (/app/node_modules/aws-sdk/lib/request.js:38:9)

Any advice would be greatly appreciated.

Thanks.

I am also facing the same issue, were you able to resolve this ?
I am not getting an error as well, looks like the config is not getting picked up at all

Added `var AWS = require(‘aws-sdk’);

module.exports = {
upload: {
provider: ‘aws-s3’,
providerOptions: {
credentials: new AWS.TokenFileWebIdentityCredentials(),
region: ‘ap-south-1’,
params: {
Bucket: ‘surgicare-assets-dev’,
},
},
},
};
`

in plugins.js

You can use the code below but server build has to be done when container starts up

const AWS = require(‘aws-sdk’);
const fs = require(‘fs’);
const sts = new AWS.STS();

const role = sts.assumeRoleWithWebIdentity({
RoleArn: process.env.AWS_ROLE_ARN,
RoleSessionName: “strapi”,
WebIdentityToken: fs.readFileSync(process.env.AWS_WEB_IDENTITY_TOKEN_FILE, “utf8”)
});

module.exports = ({ env }) => ({
upload: {
config: {
provider: ‘aws-s3’,
providerOptions: {
credentials: role.Credentials,
region: env(‘AWS_REGION’),
params: {
Bucket: env(‘S3_BUCKET_NAME’),
},
},
actionOptions: {
upload: {},
uploadStream: {},
delete: {},
},
},
},
});

Helloo

Tried this but strapi application is not running after that.

Error: Could not load js config file /Users/mintoak/Desktop/explore-now-cms/config/plugins.js: The "path" argument must be of type string or an instance of Buffer or URL. Received undefined
    at loadJsFile (/Users/mintoak/Desktop/explore-now-cms/node_modules/@strapi/strapi/lib/core/app-configuration/load-config-file.js:18:11)
    at loadFile (/Users/mintoak/Desktop/explore-now-cms/node_modules/@strapi/strapi/lib/core/app-configuration/load-config-file.js:35:14)
    at /Users/mintoak/Desktop/explore-now-cms/node_modules/@strapi/strapi/lib/core/app-configuration/config-loader.js:18:18
    at Array.reduce (<anonymous>)
    at module.exports (/Users/mintoak/Desktop/explore-now-cms/node_modules/@strapi/strapi/lib/core/app-configuration/config-loader.js:15:6)
    at module.exports (/Users/mintoak/Desktop/explore-now-cms/node_modules/@strapi/strapi/lib/core/app-configuration/index.js:55:38)
    at primaryProcess (/Users/mintoak/Desktop/explore-now-cms/node_modules/@strapi/strapi/lib/commands/actions/develop/action.js:54:18)
    at module.exports (/Users/mintoak/Desktop/explore-now-cms/node_modules/@strapi/strapi/lib/commands/actions/develop/action.js:30:14)

My plugins.js

 var AWS = require('aws-sdk')
    const fs = require("fs");
    const sts = new AWS.STS();

    const role = sts.assumeRoleWithWebIdentity({
        RoleArn: process.env.AWS_ROLE_ARN,
        RoleSessionName: "strapi",
        WebIdentityToken: fs.readFileSync(process.env.AWS_WEB_IDENTITY_TOKEN_FILE, "utf8")
    });
    
    module.exports = ({ env }) => ({
        upload: {
          config: {
            provider: 'aws-s3',
            providerOptions: {
              credentials: role.Credentials,
              region: 'region',
              params: {
                Bucket: 'mybucket',
              },
            },
            actionOptions: {
              upload: {},
              uploadStream: {},
              delete: {},
            },
          },
        },
  });