How to Call & Export Environment Variables in AWS Elastic Beanstalk

Read Time: 4 minutes

AWS How-To Guide

The AWS Elastic Beanstalk documentation does not list exactly how environment variables are exported (or just simply set for top level shell commands). Since we use variables for all kinds of things and we needed a definitive guide of how environment variables are used, I decided to create a how-to guide for calling and viewing environment variables in ebextension config files.

In this post we’ll dive into a number of different ways to call them and see how they show up under different circumstances:

Environment Variables in ebextension config files: How to call and export in Elastic Beanstalk

Lets take the following as our .ebextensions/00-variables.config file. This will be the basis for all of our tests:

option_settings:

  "aws:elasticbeanstalk:application:environment":
    envvar1: value1

commands and container_commands

echo output

The first test is to see how these two can be used in the commands and container_commands sections of an ebextensions config file:

commands:
a00_command_line_test:
command: “echo $envvar1 > /tmp/a00_command_line_test”

container_commands:
c00_command_line_test:
command: “echo $envvar1 > /tmp/c00_command_line_test”

Here are the results:

$ cat /tmp/a00_command_line_test

$ cat /tmp/c00_command_line_test
value1
The /tmp/a00_command_line_test file ends up being empty while 
the latter /tmp/c00_command_line_test file has the value1 value
in it as expected.
The envvar1 variable is not even seen when used in commands!
To force this you can use the env: option along 
with the command: option:
commands:
  a00_command_line_test:
    command: "echo $envvar1 > /tmp/a00_command_line_test"
    env:
      envvar1: 
        "Fn::GetOptionSetting":
          Namespace: "aws:elasticbeanstalk:application:environment"
          OptionName: envvar1


get-config
output

The next test I conducted is simply to use the get-config command included in all Elastic Beanstalk AMIs:

commands:
  a01_command_line_test:
    command: "/opt/elasticbeanstalk/bin/get-config environment 
-k envvar1 > /tmp/a01_command_line_test"

container_commands:
  c01_command_line_test:
    command: "/opt/elasticbeanstalk/bin/get-config environment 
-k envvar1 > /tmp/c01_command_line_test"

 

$ cat /tmp/a01_command_line_test
value1$

$ cat /tmp/c01_command_line_test
value1$

Both files have the variable in it, but there’s no newline. This is due to the echo command above natively adding a newline. I like this command in shell scripts like so:

somevar=$(/opt/elasticbeanstalk/bin/get-config environment -k envvar1)

files

The next tests I did were around the files directive. I created two files – a bash script and a python script. Each one tests the ability to:
1. Simply just call an environment variable when ran
2. Use the backtick + curly brace + Fn::GetOptionSetting command embedded in the file
3. Use the get-config command

files:
  "/tmp/00_file_test.sh":
    content: |
      #!/bin/sh
      env_method_1=$envvar1
      echo $env_method_1

      env_method_2=`{"Fn::GetOptionSetting": {"Namespace": 
"aws:elasticbeanstalk:application:environment", "OptionName": 
      "envvar1", "DefaultValue": "my_default_value"}}`
      echo $env_method_2

      env_method_3=$(/opt/elasticbeanstalk/bin/get-config 
environment -k envvar1)
      echo $env_method_3

    group: root
    mode: "000755"
    owner: root

  "/tmp/00_file_test.py":
    content: |
      #!/usr/bin/env python
      import os, subprocess
      try:
        env_method_1 = os.environ['envvar1']
        print(env_method_1)
      except:
        print("Failed to get env_method_1")

      try:
        env_method_2 = "`{"Fn::GetOptionSetting": {"Namespace": 
"aws:elasticbeanstalk:application:environment", "OptionName": 
"envvar1", "DefaultValue": "my_default_value"}}`"
        print(env_method_2)
      except:
        print("Failed to get env_method_2")

      try:
        env_method_3 = subprocess.check_output
(['/opt/elasticbeanstalk/bin/get-config', 
'environment', '-k', 'envvar1'])
        print(env_method_3)
      except:
        print("Failed to get env_method_3")

    group: root
    mode: "000755"
    owner: root
The result of the files directive are these files:
$ cat /tmp/00_file_test.sh
#!/bin/sh
env_method_1=$envvar1
echo $env_method_1

env_method_2=value1
echo $env_method_2

env_method_3=$
(/opt/elasticbeanstalk/bin/get-config environment 
-k envvar1)
echo $env_method_3

 

$ cat /tmp/00_file_test.py
#!/usr/bin/env python
import os, subprocess
try:
  env_method_1 = os.environ['envvar1']
  print(env_method_1)
except:
  print("Failed to get env_method_1")

try:
  env_method_2 = "value1"
  print(env_method_2)
except:
  print("Failed to get env_method_2")

try:
  env_method_3 = subprocess.check_output
(['/opt/elasticbeanstalk/bin/get-config', 'environment',
 '-k', 'envvar1'])
  print(env_method_3)
except:
  print("Failed to get env_method_3")

It is very important to notice how this affects scripts
In the second test on both the shell script and the python script, the variable is already embedded into the script! You can run either script at any time under any user and it’ll always have the right variable there. The variable is ‘set’ when the file is created (at deploy time) rather than evaluating the variable when it is ran.

If the environment variable changes and this file is not updated (say it is removed from the ebextentions config file but still called by another script/program), it will then have the wrong variable in it.

The other two tests (env_method_1 and env_method_3) still gather the environment variable when they’re ran. Lets run them under commands and container_commands and check out the results:

commands:
  a20_files_test:
    command: /tmp/00_file_test.sh > /tmp/a20_files_test
  a21_files_test:
    command: python /tmp/00_file_test.py > /tmp/a21_files_test

container_commands:
  c20_files_test:
    command: /tmp/00_file_test.sh > /tmp/c20_files_test
  c21_files_test:
    command: python /tmp/00_file_test.py > /tmp/c21_files_test

 

$ cat /tmp/a20_files_test

value1
value1

$ cat /tmp/a21_files_test
Failed to get env_method_1
value1
value1

$ cat /tmp/c20_files_test
value1
value1
value1

$ cat /tmp/c21_files_test
value1
value1
value1

As we can see from these results, the commands doesnt seem to see the $envvar1 variable in env_method_1 of either script. Otherwise, all scripts pick up all other variables.

Next, I’ll run these as standard ec2-user via ssh:

$ /tmp/00_file_test.sh
value1
value1
Permission denied @ rb_sysopen - 
/opt/elasticbeanstalk/deploy/configuration/containerconfiguration

$ python /tmp/00_file_test.py
value1
value1
Permission denied @ rb_sysopen - 
/opt/elasticbeanstalk/deploy/configuration/containerconfiguration

As you can see, sudo is required for the get-config command. Lets try that:

$ sudo /tmp/00_file_test.sh

value1
value1

$ sudo python /tmp/00_file_test.py
Failed to get env_method_1
value1
value1

Running them as root (via sudo) yields effectively the same results as running under commands. However, if we run them under the webserver user (via the actual webserver):

$ cat /var/app/current/index.php
<?php
echo `/tmp/00_file_test.sh`;
?>
$ curl localhost
value1
value1

$ 

 

$ cat /var/app/current/index.php
<?php
echo `/usr/bin/python /tmp/00_file_test.py`;
?>
$ curl localhost
value1
value1
Failed to get env_method_3
$

As you can see, the webserver has the environment variables set but the get-config command is still limited to the root user, therefore it fails.

All done!

Hopefully the above experiments shed some light on how environment variables are used in Elastic Beanstalk. I see all tools as having their place and I believe each one of the methods above have appropriate use cases it’ll be up to you to determine which method(s) you want to use and in which situations.

Happy scripting and be sure to contact us if you need any help with Elastic Beanstalk.

Hidden layer

Share on linkedin
Share on twitter
Share on facebook
Share on email

Onica Insights

Stay up to date with the latest perspectives, tips, and news directly to your inbox.

Explore More Cloud Insights from Onica

Blogs

The latest perspectives on navigating an ever-changing cloud landscape

Case Studies

Explore how our customers are driving cloud innovation in their industries

Videos

Watch an on-demand library of cloud tutorials, tips and tricks

Publications

Learn how to succeed in the cloud with deep-dives into pressing cloud topics

Subscribe to Onica Insights