This post describes how to deploy a BIND 9 DNS server to Amazon AWS using bosh-init, a command-line BOSH tool that enables the deployment of VMs without requiring a Director VM. [1]
This blog post is the second of a series; it picks up where the previous one, How to Create a BOSH Release of a DNS Server, left off. Previously we described how to create a BOSH release (i.e. a BOSH software package) of the BIND 9 DNS server and deploy the server to VirtualBox via BOSH Lite.
0. Download Executables, Releases, Stemcells, and CPIs
Let’s begin by installing bosh-init on our OS X development workstation:
- look here for downloading the Linux variant
- note that our download destination, /usr/local/bin, is in our PATH and is writable
- check https://bosh.io/docs/install-bosh-init.html for newer versions of the oft-updated bosh-init
curl -L https://s3.amazonaws.com/bosh-init-artifacts/bosh-init-0.0.29-darwin-amd64 -o /usr/local/bin/bosh-init
chmod 755 /usr/local/bin/bosh-init
bosh-init version # test for successful install
version 0.0.29-9ba06aa-2015-05-14T16:52:13Z
Let’s clone our BIND release’s git repository:
cd ~/workspace/
git clone https://github.com/cunnie/bosh-bind-9-release.git
cd bosh-bind-9-release
1. Create BOSH DNS Release
We install the BOSH CLI ruby gem:
# if using system ruby, you may need to prepend 'sudo' to the following line:
gem install bosh_cli
We create our release (we use –force to create a development release, –with-tarball to create the .tgz file that we need to deploy to our VM):
bosh create release --force --with-tarball --name bind-9
2. Create BOSH Deployment Manifest
We gather the following information, which we will need in order to create our BOSH deployment manifest:
- Elastic IP Address (e.g. 52.0.56.137, must have scope vpc not standard)
- Subnet ID (e.g. subnet-1c90ef6b) (This must be a subnet in your VPC)
- AWS Key Pair name (e.g. aws_nono)
- AWS Key Pair’s path (e.g. /Users/cunnie/.ssh/aws_nono.pem) (must not be passphrase-protected)
- AWS Access Key (e.g. AKIAIZWITxxxxxxxxxxx)
- AWS Secret (e.g. 0+B1XW6VVEYw55J+ZjfqMW+AjELxxxxxxxxxxxxx)
- Security Group (must have the VPC ID of your VPC, e.g. vpc-e4250881)
- A password for your agent (generate a hard-to-guess password, e.g. Lif6@stambha)
We copy the sample AWS deployment manifest to our config directory:
cp examples/bind-9-aws.yml config/
We edit the deployment manifest; we search for all occurrences of “CHANGEME” and replace them with the information we gathered earlier:
vim config/bind-9-aws.yml
# replace all occurences of 'CHANGEME'
# with appropriate values
3. Deploy
Let’s deploy (if you see Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension while installing, you may need to run xcode-select --install
and accept the license in order to install the necessary header files):
bosh-init deploy config/bind-9-aws.yml
Deployment manifest: '/Users/cunnie/workspace/bind-9/config/bind-9-aws.yml'
Deployment state: '/Users/cunnie/workspace/bind-9/config/bind-9-aws-state.json'
Started validating
Validating deployment manifest... Finished (00:00:00)
Validating release 'bind-9'... Finished (00:00:00)
Validating release 'bosh-aws-cpi'... Finished (00:00:00)
Validating jobs... Finished (00:00:00)
Downloading stemcell... Finished (00:00:00)
Validating stemcell... Finished (00:00:00)
Validating cpi release... Finished (00:00:00)
Finished validating (00:00:00)
Started installing CPI
Compiling package 'ruby_aws_cpi/7903f3a543e8ab35fd980a0ca74f9151282d56b2'...
4. Test
We test our newly-deployed DNS server to ensure it refuses to resolve queries for which it is not authoritative (e.g. google.com), but will answer queries for which it is authoritative (nono.com). We assume that no change has been made to the manifest’s jobs/properties/config_file section; i.e. we assume that the server that has been deployed is a slave server for the zone nono.com..
# Substitue your Elastic IP as appropriate, i.e. don't use 52.0.56.137
ELASTIC_IP=52.0.56.137
# status should be 'REFUSED', i.e. no recursive lookups:
dig google.com @$ELASTIC_IP | grep status
;; ->>HEADER<<- opcode: QUERY, status: REFUSED, id: 49040
# status should be 'NOERROR', i.e. authoritative lookups succeed
dig nono.com @$ELASTIC_IP | grep status
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28829
5. Customize and Re-deploy
We have a successful deployment, but not a useful one (a DNS server that acts as a secondary for nono.com does not add much value).
We need to customize our deployment to suit our purposes. Fortunately, our DNS server’s configuration (i.e. named.conf) is embedded in our deployment manifest; we need merely make changes to the manifest’s jobs→properties→config_file section and re-deploy, i.e.
vim config/bind-9-aws.yml
# make changes; be sure the configuration section is indented appropriately!
bosh-init deploy config/bind-9-aws.yml
6. Summary
We have shown the ease with which one can deploy BOSH releases to single-instance VMs in Amazon AWS using bosh-init.
One might be tempted to compare BOSH to configuration management tools such as Ansible, Chef, and Puppet, and on closer inspection one would see that their approaches differ radically:
- BOSH assumes deployment to a cloud infrastructure (AWS, vSphere, OpenStack)
- BOSH depends on specially-built images/AMIs (stemcells); BOSH does not function with, say, a generic Ubuntu AMI.
- BOSH does not install ‘packages’ (e.g. .deb, .rpm), instead, one must build a custom BOSH release or take advantage of community-built releases.
Appendix A. The Importance of Disallowing Recursion
We disable recursive queries on our DNS servers that have been deployed to the Internet because it prevents our server from being used in a DNS Amplification Attack. DNS Amplication Attacks are doubly-damning in the sense that we pay for the attack’s bandwidth charges (we pay in the literal sense: Amazon charges us for the outbound traffic).
The good news is since version 9.4 BIND has a non-recursive default (our BOSH release’s version is 9.10). If you truly need to allow recursion, add the following stanza to the deployment’s manifest’s jobs→properties→config_file stanza; it will configure the BIND server to be an Open Resolver (A DNS server that allows recursive queries/recursion is known as an Open Resolver). Don’t do this unless your server is behind a firewall:
options {
recursion yes;
// DO NOT put the following line on an Internet-accessible DNS server
allow-recursion { any; };
An easy way to test if your server is an Open Resolver is to run the following dig command (substitute 52.6.149.97 with the address of your deployed DNS server):
dig freeinfosys.com ANY @52.6.149.97
...
;; MSG SIZE rcvd: 33
The “MSG SIZE rcvd: 33” means that recursion was denied (i.e. our server is properly configured). If instead you see “MSG SIZE rcvd: 3185”, then you need to edit your deployment’s manifest and re-deploy.
Probed within 3 Hours, Exploited within 3 Days
Our server was probed within 3 hours of deployment (logs from /var/log/daemon.log):
May 6 14:43:51 localhost named[23167]: client 80.82.78.2#7678 (freeinfosys.com): query (cache) 'freeinfosys.com/ANY/IN' denied
Hackers attempted to exploit our DNS server to attack voxility. The attempts did not succeed because we had properly configured our server:
May 9 01:42:41 localhost named[23167]: message repeated 15 times: [ client 109.163.224.34#19903 (067.cz): query (cache) '067.cz/ANY/IN' denied]
Acknowledgements
Dmitriy Kalinin‘s assistance was invaluable when creating the sample manifest, proofreading the draft, and suggesting simplifications.
Footnotes
1 We use bosh-init rather than a Director VM primarily for financial reasons: with bosh-init, we need but spin up the DNS server VM (t2.micro instance, $114/year [2] ). Using a Director VM requires an m3.medium instance ($614/year), ballooning our costs 538%.
2Amazon EC2 Prices are current as of the writing of this document. A t2.micro instance costs $0.013 per hour. Assuming 365.2425 24-hour days/year, this works out to $113.96/year. An m3.medium instances costs $0.070 per hour, $613.60/year. Our calculations do not take into account Spot Instances or Reserved Instances.
Admittedly there are mechanisms to reduce the cost of the Director VM—for example, we could suspend the Director VM instance after it has deployed the DNS server.
About the Author