AWS Elastic Beanstalk makes it easy to get a simple application from development into a public web server. If you use a linked RDS instance for storage, the service even handles the population of the database credentials on your application instance by loading them in the environment. If you want to include additional credentials as environment variables, you can do it, but they are unfortunately readable as plain text in the Elastic Beanstalk console. Instead, I've taken to importing a credentials.py
file which gets loaded on my instances via encrypted S3 as part of the deploy script.
credentials.py
Create your credentials.py
file for the environments you'll be deploying to. Upload them to S3 making sure to enable server-side encryption. Protect the bucket these are stored in. Treat it just like part of a settings.py
file.
MY_SECRET_PASSWORD = 'five golDen chickens'
(Jeez, that's not really my password. Whatever.)
Import credentials
In the top of my base.py
, which is loaded in each of my tier-sepcific config files, I include:
from config.settings.credentials import * #noqa
Including #noqa
ensures that
flake8
won't register an error, since we really do want to import everything in this case. I include a default config/settings/credentials.py
that sets dummy variables to enable my tests to pass, or reads those from the environment. That file is overwritten during deployment and copied into place via an .ebextensions
file.
.ebextensions
The following code is an .ebextensions
file with the settings needed to get credentials.py
installed into your Django application on each deploy. Depending where your credentials files are stored, you'll want to change config/settings/
to lineup with your directory structure. container_commands
run from the root of your app:
commands:
01_mkdirs:
test: '[ ! -d /var/makeconf ]'
command: 'mkdir -p /var/makeconf'
02_set_perms:
command: 'chown -R wsgi:wsgi /var/makeconf'
container_commands:
01_move_credentials:
command: 'mv /var/makeconf/credentials.py config/settings/'
files:
'/var/makeconf/credentials.py':
owner: wsgi
group: wsgi
mode: '000400'
source: https://s3.amazonaws.com/BUCKET_NAME/PATH/TO/CREDENTIALS
authentication: S3Access
Resources:
AWSEBAutoScalingGroup:
Metadata:
AWS::CloudFormation::Authentication:
S3Access:
type: S3
roleName: my.elastic.beanstalk.iam.role
buckets: BUCKET_NAME
django-makeconf
You're likely going to want a different credentials.py
file for each tier, and so I recommend using a tool like django-makeconf to build your .ebextensions
for each tier. It could be as simple as specifying the following variables in your tier-based Django config files:
CREDENTIALS_BUCKET
CREDENTIALS_KEY
EB_IAM_ROLE
Alter the above file to replace
BUCKET_NAME
with{{ settings.CREDENTIALS_BUCKET }}
PATH/TO/CREDENTIALS
with{{ settings.CREDENTIALS_KEY }}
my.elasticbeanstalk.iam.role
to{{ settings.EB_IAM_ROLE }}
Once those pieces are in place, put that file at YOUR_APP_NAME/templates/credentials.config.tmpl
and set MAKECONF_MAP
to something like:
{'.ebextensions/01_credentials.config': 'credentials.config.tmpl'}
Then run python manage.py makeconf
with the correct config file for each tier during each deploy build. e.g. for QA, you'd run the following command to build your .ebextensions
file:
DJANGO_SETTINGS_MODULE=config.settings.qa python manage.py makeconf
IAM role
You're going to need an IAM role with permissions to the buckets you're storing your credentials.py files in. You'll need the following properties on the buckets you're using:
s3:ListBucketVersions
s3:GetObjectVersion
s3:ListBucket
s3:GetObject
And you'll want to allow s3:ListAllMyBucket
for all resources.
Deploy
Make sure you include the .ebextensions
file you just created in the zipfile you're senging to Elastic Beanstalk, and then it's rock & roll.