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_BUCKETCREDENTIALS_KEYEB_IAM_ROLE
Alter the above file to replace
BUCKET_NAMEwith{{ settings.CREDENTIALS_BUCKET }}PATH/TO/CREDENTIALSwith{{ settings.CREDENTIALS_KEY }}my.elasticbeanstalk.iam.roleto{{ 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:ListBucketVersionss3:GetObjectVersions3:ListBuckets3: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.