Inject Rails encrypted credentials in CI/CD for public repositories
- rails
- ci/cd
- environment variables
Rails offers a convenient feature called encrypted credentials, which helps in keeping sensitive data safe from prying eyes. One reason behind it is that environment variables are not completely safe and can potentially leak which would compromise your application’s security. With encrypted credentials, there is only one environment variable left: the RAILS_MASTER_KEY
that decrypts the credentials. If only the RAILS_MASTER_KEY
leaks, then the attacker can’t do anything with it because the attacker has no access encrypted credentials file (config/credentials.yml.enc
). If, however, other environment variables like for example AWS_ACCESS_KEY_ID
and AWS_SECRET_ACCESS_KEY
leak, then the attacker can make use of it right away with no additional requirements.
If your code is not public, then this approach is fine. Every developer has a copy of the encrypted credentials on disk and the ones who are allowed to adjust them have the Rails master key. However, if your source code is public, simply committing the config/credentials.yml.enc
file can be risky, as anyone can potentially access it. In this scenario, it’s necessary to find an alternative solution. An alternative to this approach is to not commit the config/credentials.yml.enc
file but to inject it in CI/CD just before you deploy or build your Docker image. If you deploy to fly.io for example it’s enough to create this file from an environment variable in CI/CD. The Github Actions workflow could look like this:
name: Fly Deploy
# Only trigger, when the CI workflow succeeded
on:
workflow_run:
workflows: ["CI"]
types: [completed]
branches: [main]
jobs:
deploy:
name: Deploy app
runs-on: ubuntu-latest
environment: main
steps:
- uses: actions/checkout@v3
- name: Create credentials file and remove it from .gitignore
env:
CREDENTIALS_BASE64: ${{ secrets.CREDENTIALS_BASE64 }}
run: |
echo $CREDENTIALS_BASE64 | base64 -d > config/credentials.yml.enc
sed -i '/config\/credentials.yml.enc/d' .gitignore
- uses: superfly/flyctl-actions/setup-flyctl@master
- name: Deploy to fly.io
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
run: flyctl deploy --remote-only
You will get the content for CREDENTIALS_BASE64
with the following command in your Rails root directory:
cat config/credentials.yml.enc | base64 | pbcopy
And you can set it directly via the Github CLI with this command:
cat config/credentials.yml.enc | base64 | xargs gh secret set CREDENTIALS_BASE64 --body
NOTE: base64 encoding the
credentials.yml.enc
file is probably not necessary because the file itself is already base64 encoded. But it also doesn’t do any harm.