Brian Hanson

Separate Asset Configs in Craft CMS

In our case, we have a situation where the production environment is run in containers powered by AWS (not managed by me, so I'm not 100% sure what's happening behind the scenes). Our assets are powered by S3, but the environment requires us to leave the "Access Key ID" and "Secret Access Key" fields blank in production to take advantage of functionality allowing role assumption.

This led to a fun problem. In order for the rule assumption to work, the field has to be blank. Putting in an environment variable isn't enough. Craft will store that environment variable as a string (to be evaluated later) which means the plugin won't try to assume roles.

This problem left me stumped for awhile. I posted in the Craft Discord, and on the plugin repo but basically resigned myself to having one environment broken.

Until Brad saved me.

He suggested a multi-environment config. I suspected this would work, but unfortunately they were deprecated. Thankfully, the people at Craft are good people and put a knowledge base article link into the deprecation exception.

With that article, I was able to solve my issue. Below is the final code I put into a custom module's init method.

if (in_array(Craft::$app->env, ['dev', 'odc-stage'])) {
    Craft::$container->set(Volume::class, function($container, $params, $config) {
        if (empty($config['id'])) {
            return new Volume($config);

        return new Volume(array_merge($config, [
            'keyId' => '$S3_ACCESS_KEY_ID',
            'secret' => '$S3_SECRET_ACCESS_KEY'

With this in place, when Craft is running in the dev or odc-stage environment, our S3 bucket will be used and in production the fields will be blank, the role assumed, and everyone happy.