12

I have a continuous integration which takes rails app and package it as a docker image.

As one of the steps of this packaging process, I want to do asset precompilation.

I was doing this on Rails 5.1. I had to provide some dummy SECRET_KEY_BASE to let it go through.

SECRET_KEY_BASE=1 RAILS_ENV=production rails assets:precompile

I am moving to Rails 5.2 now and want to start using credentials. I am trying following command:

RAILS_ENV=production rails assets:precompile

If I don't RAILS_MASTER_KEY then it will show me an error:

Missing encryption key to decrypt file with. Ask your team for your master key and write it to /home/config/master.key or put it in the ENV['RAILS_MASTER_KEY'].

If I provide dummy (incorrect) RAILS_MASTER_KEY, it will complain that it can't decode credentials.

I don't want to give a real RAILS_MASTER_KEY to CI.

As result, the question is. How to compile asset without it or what are the workarounds?

Victor Ronin
  • 22,758
  • 18
  • 92
  • 184

4 Answers4

2

I'm not seeing a solution either. Another way would be to continue to set config/environments/production.rb to have the line:

config.require_master_key = false

and continue to use your SECRET_KEY_BASE=1 rails assets:precompile

I haven't found a better way. At least this way seems better than maintaining a fake master key.

nicb
  • 191
  • 2
  • 10
1

My solution to this (Rails 6+) is to have separate credential files for each env (test, development, production).

I provide the decryption key for the test environment via RAILS_MASTER_KEY=xxx to my CI when running tests. And to precompile assets with RAILS_ENV=production I just copy my test credentials YML file over top of the production credentials. The asset step can then decrypt the credentials just using the test environment key.

echo "Using 'test' environment credentials for precompiling"
cp ./config/credentials/test.yml.enc ./config/credentials/production.yml.enc

echo "Compiling assets"
RAILS_ENV=production bundle exec rake assets:precompile
Alex Dunae
  • 1,290
  • 3
  • 17
  • 28
0

I created a fake credentials.yml.enc and RAILS_MASTER_KEY associated with it and I use them when I precompile asset.

Victor Ronin
  • 22,758
  • 18
  • 92
  • 184
  • 1
    So this worked to precompile assets? How did you manage to pass over error of decoding credentails – Edvin May 09 '18 at 23:27
  • Yes. It worked. And pretty much I did what I wrote in the answer. I created another credentials file (fake one) with known RAILS_MASTER_KEY which I wasn't afraid to share. I configured CI to use this RAILS_MASTER_KEY and I was temporary replacing real credential.yml.enc with fake one. – Victor Ronin May 10 '18 at 05:54
0

We can easy solve the issue in Docker 1.13 and higher (assuming your CI is also running in a Docker container) by passing the master.key to the CI container using the docker secrets. Note that this works only in docker swarm, but also a single docker container can act as a docker swarm node. To change a single node (for example, on your local development system) to a swarm node use the init command and follow the instructions:

docker swarm init

https://docs.docker.com/engine/reference/commandline/swarm_init/

Then in your docker-compose.yml of your CI container declare the master.key as docker secret and target it to the right position in the container:

version: '3.4'

services:
  my_service:

    ...  

    secrets:
    - source: master_key
      target: /my_root/config/master.key
      uid: '1000'
      gid: '1000'
      mode: 0440

    ...  

    security_opt:
    - no-new-privileges

    ...  

secrets:
  master_key:
    file: config/master.key

https://docs.docker.com/compose/compose-file/

As you can see, we can also assign dedicated access rights to the master.key in the container and protect it from privilege escalation. For further explanations to docker swarm visit:

https://docs.docker.com/engine/swarm/secrets/#how-docker-manages-secrets

Why should this be the preferred solution to the issue? Your secret master.key is no longer stored in the CI Docker container, but secure kept in the encrypted Raft log of the Docker Swarm infrastructure, and you do not have to make any acrobatic contortions with faked keys.

BTW, I use this approach to protect my domain-specific expertise in public Docker containers: Using the target parameter, each docker secret can carry generic strings or binary content up to 500 kb in size, especially pieces of code that contain sensitive knowledge.

SkatEddy
  • 494
  • 1
  • 3
  • 7