'How do I use an env file with GitHub Actions?
I have multiple environments (dev, qa, prod) and I'm using .env files to store secrets etc... Now I'm switching to GitHub Actions, and I want to use my .env files and declare them into the env
section of the github actions yml.
But from what I've seen so far, it seems that I can not set a file path and I have to manually re-declare all variables.
How should I proceed as best practice?
Solution 1:[1]
a quick solution here could be having a step to manually create the .env
file before you need it.
- name: 'Create env file'
run: |
touch .env
echo API_ENDPOINT="https://xxx.execute-api.us-west-2.amazonaws.com" >> .env
echo API_KEY=${{ secrets.API_KEY }} >> .env
cat .env
Solution 2:[2]
The easiest way to do this is to create the .env file as a github secret and then create the .env file in your action.
So step 1 is to create the .env files as a secret in github as a base64 encoded string:openssl base64 -A -in qa.env -out qa.txt
orcat qa.env | base64 -w 0 > qa.txt
Then in you action, you can do something like
- name: Do Something with env files
env:
QA_ENV_FILE: ${{ secrets.QA_ENV_FILE }}
PROD_ENV_FILE: ${{ secrets.PROD_ENV_FILE }}
run: |
[ "$YOUR_ENVIRONMENT" = qa ] && echo $QA_ENV_FILE | base64 --decode > .env
[ "$YOUR_ENVIRONMENT" = prod ] && echo $PROD_ENV_FILE | base64 --decode > .env
There are a number of ways for determining $YOUR_ENVIRONMENT
but usually this can be extracted from the GITHUB_REF
object. You applications should be able to read from the .env files as needed.
Solution 3:[3]
I see 3 pretty simple ways to engage your .env
file variables in the GitHub Actions workflow. They differ based on whether you store the file in your repository (the worst practice) or keep it out of it (the best practice).
You keep your file in the repository:
- There are some ready-made actions that allow to read the
.env
variables (e.g. Dotenv Action,Simple Dotenv).
- There are some ready-made actions that allow to read the
(simple, manual, annoying when update
.env
variables) You keep your file out of your repository:You manually copy the content of the respective
.env
files (say.env.stage
,.env.production
) into the respective GitHub Actions secret variables (sayWEBSITE_ENV_STAGE
,WEBSITE_ENV_PRODUCTION
).Then at your GitHub Actions workflow script create the
.env
file from the desired variable like thisecho "${{secrets.WEBSITE_ENV_STAGE }}" > .env
and use it in the workflow.
(a bit more involved though prepare it once, then change your
.env
variables at the local machine, then sync these at GitHub with one click) As in item 2 above, the file is out of the repository.- Now you use the GitHub Actions API to create or update the secrets. On your local machine in the
dev
environment you write the NodeJS script that calls the API endpoint and write the.env
files to the desired GitHub Actions secret variable (say as above intoWEBSITE_ENV_STAGE
or to both stage and production variables at once);
- Now you use the GitHub Actions API to create or update the secrets. On your local machine in the
This is pretty wide choice of ways to engage the .env
files's variables in the workflow. Use any matching your preference and circumstances.
Solution 4:[4]
Edit: You were using Circleci Contexts, so with that you had a set of secrets of each env. I know they are working to bring secrets to org level, and maybe team level... there is no info if they will create sort of contexts like we have in CCI.
I have thought on adding the env as prefix of the secret name like STAGE_GITHUB_KEY or INTEGRATION_GITHUB_KEY using ${env}_GITHUB_KEY on the yml as a workaround for now... What do you think?
--- Original answer: If I understand you well, you already have the dotenv files stored somewhere and you want to inject all those secrets into the steps, without having to manually add them to github secrets and do the mapping in each workflow you migrate... right?
There is an action made by someone that reads a dotenv file and put its values into ouputs, so you can use them linked in further steps. Here is the link: https://github.com/marketplace/actions/dotenv-action
Whatever is present in the .env file will be converted into an output variable. For example .env file with content:
VERSION=1.0
AUTHOR=Mickey Mouse
You do:
id: dotenv
uses: ./.github/actions/dotenv-action
Then later you can refer to the alpine version like this ${{ steps.dotenv.outputs.version }}
Solution 5:[5]
You can also use a dedicated github action
from github-marketplace to create .env
files.
Example usage:
name: Create envfile
on: [push]
jobs:
create-envfile:
runs-on: ubuntu-18.04
steps:
- name: Make envfile
uses: SpicyPizza/create-envfile@v1
with:
envkey_DEBUG: false
envkey_SOME_API_KEY: "123456abcdef"
envkey_SECRET_KEY: ${{ secrets.SECRET_KEY }}
file_name: .env
Depending on your values defined for secrets in github repo, this will create a .env
file like below:
DEBUG: false
SOME_API_KEY: "123456abcdef"
SECRET_KEY: password123
More info: https://github.com/marketplace/actions/create-env-file
Solution 6:[6]
Another alternative is to use the Environments feature from github. Although that isn't available on private repos in the free plan. You could have scoped variables, at repository, profile/organization level and environment. The configuration variables closer to the repository takes precedence over the others.
Solution 7:[7]
I tried using the accepted solution but GitHub actions was complaining about the shell commands. I kept getting this error: line 3: unexpected EOF while looking for matching ``'
Instead of referencing the secrets directly in the shell script, I had to pass them in separately.
- name: Create env file
run: |
touch .env
echo POSTGRES_USER=${POSTGRES_USER} > .env
echo POSTGRES_PASSWORD=${POSTGRES_PASSWORD} > .env
cat .env
env:
POSTGRES_USER: ${{ secrets.POSTGRES_USER }}
POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
Solution 8:[8]
I was having the same issue. What I wanted was to upload a .env file to my server instead of defining the env variables in my Github repo. Since I was not tracking my .env file so every time my workflow ran the .env file got deleted. So what I did was :
- Added the
.env
file in the project root directory in my server. - Added
clean: false
underwith
key in myactions/checkout@v2
in my workflow
eg:
jobs:
build:
runs-on: self-hosted
strategy:
matrix:
node-version: [14.x]
- uses: actions/checkout@v2
with:
clean: 'false'
This prevents git from deleting untracked files like .env. For more info see: actions/checkout
Solution 9:[9]
One more approach would be doing something as described in https://docs.github.com/en/actions/security-guides/encrypted-secrets#limits-for-secrets
So basically treating your .env
file as a "large secret". In this case, the encrypted .env
file is kept commited in your repo, which should be fine. Then in your action have a step to decrypt the .env
file.
This removes the overhead of having to create each individual secret inside your .env
as a Github secret. The only Github secret to maintain in this case, is one for the encryption password. If you have multiple .env
files such as qa.env
, prod.env
, etc... I would strongly suggest using a different encryption password for each, and then store each encryption passwords as an "environment secret" in Github instead of "repo secret" (if using Github environments is your thing. See https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment).
If you don't want to commit the (encrypted) .env
file in you repo, then I would go with the base64 approach described in https://stackoverflow.com/a/64452700/1806782 (which is simmilar to what's in https://docs.github.com/en/actions/security-guides/encrypted-secrets#storing-base64-binary-blobs-as-secrets) and then create a new Github secret to host the encoded contents.
For those like me with aversion to manual repetitive tasks, Github secret creation can these days easily be scripted with the Github CLI tool. See
https://cli.github.com/manual/gh_secret_set . It also supports 'batch' creation of secrets from env files (see the -f
, --env-file
flags)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Dan Barclay |
Solution 2 | secure12 |
Solution 3 | |
Solution 4 | |
Solution 5 | ankur512512 |
Solution 6 | user3746240 |
Solution 7 | sgonzalez |
Solution 8 | |
Solution 9 |