0

I am currently struggling to persist environment variables through my DevOps deployment pipeline to Azure App Service.

I am deploying a Django app on Azure App Service with Docker containers and Azure's Container Registry. The containers are built on Azure DevOps and pushed to the registry via a release pipeline. I need to keep a few environment variables secret since the app will connect to our Azure Cosmos DB, and I'm doing so by using a tokenized .env file. The variables are kept secret and added to my '.env-prod' file with pipeline variables and the Replace Tokens DevOps task during the build.

Here is what my '.env-prod' file looks like:

PRODUCTION_KEY=#{{PRODUCTION_KEY}}#
AZURE_DB=#{{AZURE_DB}}#
AZURE_CONNECT=#{{AZURE_CONNECT}}#
...

The tokens are getting properly replaced during the build on DevOps, and the build executes without errors to push containers to our Azure container registry.

Now the problem arises when I launch the app on App Service via the docker compose script also used to build the containers. Here is the backend-service in my compose file which builds and runs the Django app:

backend-service:
  env_file: backend_folder/.env-prod
  build: backend_folder
  # Container registry name in Azure
  image: **.azurecr.io/**:0.1.1
  volumes:
    - static:/app/static
  command: gunicorn django_proj.wsgi:application --chdir django_proj --bind 0.0.0.0:8001
  expose:
    - 8001

The static files are created via the CMD python manage.py collectstatic --no-input command in my Docker file. There is also an nginx and a frontend service to serve our website, but they do not reference the .env file.

When I launch my App Service, the variables seem not to be loaded to the backend service when starting the app. I've also added the same variables to my Application Settings in the App Service, but I'm still encountering errors that indicate to me the variables were not set.

Here is a snapshot from my container log stream which describes the error:

2021-06-02 INFO - Container logs from backend-service = 2021-06-02 [2021-06-02] [INFO] Starting gunicorn 20.1.0 2021-06-02 [2021-06-02] [INFO] Listening at: http://0.0.0.0:8001 (1) 2021-06-02T2 [2021-06-02] [6] [ERROR] Exception in worker process 2021-06-02 Traceback (most recent call last):

...

2021-06-02 File "/app/django_proj/settings.py", line 116, in <module>

2021-06-02 connect(os.environ['AZURE_DB'], host=os.environ['AZURE_CONNECT'])

...

2021-06-02 pymongo.errors.InvalidURI: Invalid URI scheme: URI must begin with 'mongodb://' or 'mongodb+srv://'

It seems like my AZURE_CONNECT variable is not being set in our running App Service backend container.

  1. How can I securely persist the secret environment variables in my compose script so they are present during both my build step in Azure DevOps and the run step in the Azure App Service?
  2. Is there another way to serve the static files via gunicorn so the environment variables are only referenced during the build step and not when launching the App Service?

Here is the closest related question I found to my issue, but we differ in that we are using multiple environment variables on Azure App Service and not Heroku. Also, I have no issues running the site on my local machine if I use my private .env file without tokens.

Flumenque
  • 45
  • 6
  • 1
    If `AZURE_CONNECT` weren't set at all, then you'd get a KeyError, yes? Seems like it is set to _something_. Print the value in a debug message. – John Gordon Jun 02 '21 at 22:51
  • You had the right intuition. Strangely enough, the variable seems to be set but not done properly. When I log the value, I see "Settings.py: My secret variable value for AZURE_CONNECT is: 'mongodb://***'", but I still receive the error "pymongo.errors.InvalidURI: Invalid URI scheme: URI must begin with 'mongodb://' or 'mongodb+srv://'". I'll be looking into why this variable is perhaps not formatted correctly. – Flumenque Jun 03 '21 at 18:49
  • 1
    Are the single quotes actually part of the value? – John Gordon Jun 03 '21 at 19:03
  • I should not have added the single quotes. Removing these quotes made for a successful deployment and the environment variable was properly loaded in my instance. Thank you for your help! I'll summarize and make the question answered. – Flumenque Jun 08 '21 at 15:24

1 Answers1

0

Thanks to Josh Gordon for the help, I learned that I should not have formatted the Azure App Service application settings with quotes--the raw text is loaded in the environment as a string and does not need anticipatory quotes.

In my question, I was also looking for a way to persist environment variables through the pipeline. I suppose this could be done by setting same variables in both the pipeline and the application settings of the app service, but I was also able to avoid the use of environment variables in my deployment pipeline by replacing the line in my Dockerfile from

RUN python manage.py collectstatic --no-input

to

CMD python manage.py collectstatic --no-input

Now the build and push step does not require the loaded environment variables, and I'm properly loading the environment variables in the App Service. Thanks again, Josh.

Flumenque
  • 45
  • 6