This repository contains code and documentation for configuring infrastructure managed by the NYC Planning Labs team. The parts that get modified most frequently:
playbooks/
: Ansible playbooks to configure DigitalOcean Droplets. Explanations of the playbooks below.roles/internal/
: Custom Ansible roles for code shared across playbooksrequirements.yml
: List of third-party Ansible roles, which get installed toroles/external/
.circleci/config.yml
: Configuration for continuous integration/deployment with CircleCI
- DigitalOcean dashboard (restricted)
- Security/devops planning board
-
Install dependencies.
-
Python 3
-
NOTE: You may need to install certificates to avoid an SSL error:
sudo /Applications/Python\ 3.6/Install\ Certificates.command
-
-
-
Install Ansible and its dependencies.
pipenv install pipenv run ansible-galaxy install -p roles/external -r requirements.yml
To run against a live server:
-
Do the one-time credential setup.
-
Create a DigitalOcean token with read access.
-
Save your token to a
digital_ocean.ini
configuration file.[digital_ocean] api_token=TOKEN
-
-
Enable the virtualenv.
pipenv shell
-
Set the Digital Ocean environment variable. This is required because Digital Ocean modules can't read from the
digital_ocean.ini
file.export $(./digital_ocean.py --env)
-
Run one of the playbooks. You will use
root
as theUSER
on the first run and your GitHub username on subsequent runs, asroot
access gets removed.
Any of these can be done as a "dry run" by adding --check
to the end of the command.
Examples:
-
Test connectivity to the Droplets tagged with
labs
.ansible labs -i digital_ocean.py -u USER -m command --args uptime
-
Configure a Droplet with the real Ansible playbook.
ansible-playbook -i digital_ocean.py -u USER -l DROPLET_NAME playbooks/base.yml
-
Configure all
labs
Droplets with the real Ansible playbook.ansible-playbook -i digital_ocean.py -l labs -u USER playbooks/base.yml
-
Configure a Dokku Droplet with the Dokku playbook.
ansible-playbook -i digital_ocean.py -l labs-01 -u USER playbooks/dokku.yml
-
Configure a Docker Droplet with the Geosearch playbook and a local copy of the geosearch repository at
repo_local_path
, relative to the playbook. Note you'll need aDOMAIN
pointing to the instance in advance.ansible-playbook \ -i digital_ocean.py -l labs-geosearch -u USER \ -e productiondomain=DOMAIN \ -e repo_local_path=../../labs-geosearch-dockerfiles \ playbooks/geosearch.yml
-
Configure a Docker Droplet with the ZAP database playbook.
ansible-playbook -i digital_ocean.py -l zap-database -u USER playbooks/zap_db.yml
-
When done with changes, stop the virtualenv.
exit
- Have them add their SSH key to their GitHub account.
- Add GitHub username to the
users
variable in the variables file. - Run the playbook.
- Move username from the
users
toformer_users
variable in the variables file. - Run the playbook.
Every server/Droplet should:
- Use an Ubuntu LTS as the operating system, unless there's a good reason to use something else
- Why: Consistency
- Be tagged with
labs
- Use a floating IP
- Why: So that the server can be replaced without modifying DNS, if need be
- ...especially if a
*.planning.nyc.gov
domain is going to be pointed at it
- Have a Cloud Firewall and/or
ufw
enabled- Why: To avoid unwanted traffic
- Use as restrictive of rules as possible
- Use private networking where possible
- Have an Ansible playbook with the
common
role - Have instructions to recreate from scratch, ideally with one
ansible-playbook
command (infrastructure as code) - Have smoke tests in the playbook, by using things like Ansible's
uri
module to ensure that an API responds- Why: So Ansible can let you know right away if the deployment failed
- Have automated database backups (if applicable)
- Why: So that the data can be restored if worse comes to worse
- ...especially if it's a canonical data source
- Ideally backups are stored off the machine
- Why: In case the server goes :pow: ๐ฃ
- Have modifications tested agaist a non-production server, and then submitted as pull requests
- Why: Lower stakes
- Have credentials for talking to external services with the least privilege possible (if applicable)
- Why: In case the credentials get leaked or the server gets compromised, limit the potential damage
- Have the services/containers/etc. start properly after machine reboot
- Why: Services/machines need to be rebooted occassionally for things like upgrades, and this will make the recovery afterwards as smooth as possible
- This needs to be tested manually
Be careful not to check secrets into this repository.