Index ¦ Archives ¦ Atom

How To Set Up an EC2 Tor Relay with Ansible

With our Net Neutrality rights hanging in the balance, and the recent scandals around Facebook and Cambridge Analytica, there has been a renewed interest in greater privacy when browsing the web. An excellent tool to keep your web browsing private is a browser called Tor. This browser works by connecting to a special anonymized network of relay nodes that bounce traffic around the web in an encrypted, anonymous fashion. In order to help out, anyone can set up their own relays and contribute bandwith and computing resources to this network. This tutorial will show you how to set up a Tor relay using EC2 and Ansible for configuration management.

All Ansible code used in this tutorial can be found here:

1) Get an Ansible Control Box Set Up and Configured to Work with AWS and Dynamic EC2 Inventory

You can follow my tutorial here on how to do that.

Once you've done that, you're ready to begin. This tutorial (and the accompanying Ansible code) will allow you to set up any number of EC2 instances as middle relays on the Tor network. It does NOT support creating an exit relay, as AWS (last I heard) does not allow exit relays in their TOS, although middle relays are allowed. You can choose to set up however many relay nodes you want-the only limit to how many relays you can spin up with Ansible is how much you want to pay AWS for the ec2 and bandwith costs.

2) Get your Ansible Control Box's CIDR Block

We will want to lock down our Tor relays to only have access on port 22 from our Ansible control box, so we'll be creating a security group in the next step to allow that. For now though, we will need to know the CIDR block/range our Ansible control box is sitting on.

In order to that, go to your EC2 section and click on whichever instance is your control box. Look under the Description tab and copy to your clipboard where it says "subnet ID"

PullUpSubnetID

Go to VPC > Subnets and put in the subnet ID you just copied into the search box. On the subnet that comes up, in the Description tab, look for the field that says 'IPv4 CIDR'. Copy the IP range given there and save it. This is your CIDR block that you will put into the security group for the Ansible box rule.

GetCIDRblock

3) Set up Security Groups

In your AWS account, go to EC2 > Security Groups > Create Security Group. We're going to add 3 inbound rules:

Incoming from ALL on port 9001 (which will be your ORPort)
Incoming from ALL on port 9030 (which will be your DirPort)
Incoming from your Ansible control box's CIDR network on port 22 so that only your control box can connect to your relays on 22.

ALL here meaning 0.0.0.0 or some variation of that (AWS will auto-fill this to All by default)

Add 1 outbound rule:

Outgoing from All on All ports (AWS will fill this in by default, so you can leave it as is.)

Give your security group a descriptive name like "TorRelayRules" and click save.

You should end up with something that looks like this: (the ::/0 is for IPv6 and AWS adds it automatically for you)

FinalSGRules

4) Spin Up Your EC2 Instances

Now that you have your Security Group made, go to EC2 > Instances > "Launch Instance". You're going to spin up one or more instances with the following settings:

-RHEL 7.x AMI (doesn't have to be fancy-whatever AWS presents as their RHEL 7.x image, use that one)
-t2.xlarge (Tor's documentation says Tor doesn't run well on multi-core machines, but AWS's single core t2 instances have "low to moderate" network performance, so I think a t2.xlarge is a good tradeoff of few cores and still Moderate-rated network performance.)
-A US region (you can spin up nodes in any region AWS supports around the world, just note that you'll need to update the NTP template here, if you want to use non-US NTP mirrors.)
-Tagged with the following instance tags:
Name: Tor Relay Node
Purpose: TorRelay
(This tag is crucial-it's what will identify to Ansible that these are the instances you want to be made into Tor nodes, and Ansible will leave all your other EC2 instances alone that do not have this tag)
-Tor nodes need very little disk space, so the default 10GB root volume is fine.

When you finish, your final confirmation screen should look something like this:

FinalOptions

5) Clone Ansible Tor Relay Repo

This is where the fun begins. Wait a few minutes for your new EC2 instances to fully spin up. If they still show as "Initializing" in the GUI, they aren't ready. (Ansible will often have trouble configuring a EC2 machine if it is still starting up.) Once they finish, log into your Ansible box, and while you are in the same dir as your ec2.py and ec2.ini scripts, run the following command to git clone the following repo in the same dir as your ec2.py and ec2.ini scripts are:

sudo yum install git
git clone git@github.com:gloriasilveira/setup_Tor_relay_wAnsible.git

6) Execute the Ansible Tor Relay Configuration Playbook

Once you've git cloned a copy of the Ansible code for relay configuration, go ahead and execute the following command, making sure to edit it first to have the name of your private key you spun up the instances with, and enter values for relay_name (what you want your relay's Nickname on the network to be) and contact_email (this will get published, so pick a email you check regularly, but don't mind getting some spam to):

AWS_PROFILE=default ansible-playbook -i ec2.py ./setup_Tor_relay_wAnsible/setup_tor_node.yml --private-key=YOURPRIVATEKEYHERE -u ec2-user -e "relay_name=YOURRELAYNAMEHERE contact_email=YOUREMAILHERE"

7) Put Your Feet Up

Seriously..this is the beauty of tools like Ansible. The configuration managment script (called a "playbook" in Ansible-land) will run, and configure all your EC2 relay instances in less than five minutes. You can read through the output as it runs, but basically here is everything the playbook will do:

-Install NTP on your relay instances so that the system clock stays synchronized and accurate
-Updates the NTP configuration to use US mirrors
-Installs a crontab to update all packages every night at 2am
-Installs the EPEL repo and configures it to GPG-check packages downloaded from it
-Installs the Tor package from the EPEL repo
-Configures the relay's tor config file (torrc) with all needed settings
-If running multiple relay instances, grabs their fingerprints and updates the MyFamily line in the tor configuration file to list their fingerprints
-Backs up all relay's keys and stores a copy of them locally on your Ansible control box in the dir /tmp/backup_keys (there will be a folder named after the IP of each of your relays, and in that folder will be the .tgz zipped file of the keys...it's dir structure will mirror the relay box, so it'll be like this: /tmp/backup_keys/$RELAYIP/var/lib/tor/keys/tor_keys.tgz)

The playbook will run and you should see output like this if all was successful:

AnsibleOutput

8) Confirm Relay is Working

As directed to in the Tor documentation, you'll need to confirm that the new relay started up correctly and the log shows:

Self-testing indicates your ORPort is reachable from the outside. Excellent. Publishing server descriptor.

If you decided to set up, say, six relay instances, this would be a pain to do. Fortunately, Ansible has a feature called "ad-hoc commands" that will allow you to use Ansible to run the same command on all your relay servers at once without having to write a big playbook full of tasks and roles.

So we're going to execute an ad-hoc command to run systemctl status and show us the last few lines of syslog and confirm the tor daemon is running. Go ahead and execute the following command on your Ansible control box, in the same dir as you executed your playbook command earlier:

AWS_PROFILE=default ansible -i ec2.py -u ec2-user --private-key=YOURPRIVATEKEYHERE -m shell -a 'systemctl status tor' 'tag_Purpose_TorRelay'

Ansible will then go out to any EC2 instance tagged with Purpose: TorRelay and run the systemctl status command simultaneously on all of them and report back to you the resulting output. It should look something like this if all went well and your Tor Relay is up and running successfully:

SuccessfulRelay

In the above screenshot, I had set up two relays and as you can see there are two "chunks" of output, corresponding to the two servers. I've circled in red Ansible's note that the command was able to be executed successfully, and in blue, I've circled the message in syslog showing that our relays are now up and running and their server descriptors are now being published.

In the future if you ever want to check and confirm the uptime of your process, you can use this same command. After running it, here is the section that will show you not only that the daemon is currently running, but how long it's been running for:

DaemonRunning

BONUS: Here's another fun command: this one will scan the torrc file and show you which configurations are currently uncommented and active for the relays:

AWS_PROFILE=default ansible -i ec2.py -u ec2-user --private-key=./YOURKEYHERE -m shell -a 'egrep -v "^#|^$" /etc/tor/torrc' 'tag_Purpose_TorRelay'

9) Enjoy Your New Relay

Doing Ansible tutorials are always a bit anti-climactic, because they are like "spin up an instance, run this playbook, and um...have a nice day" hahaha. This tutorial is no different: You've spun up your EC2 instances, attached Security Group rules to them allowing Tor traffic to and from the relays, configured them with Ansible and confirmed they are now successfully working. That's pretty much it-in this case, there are no OfflineMasterKeys that will expire, so you don't have to worry about renewing anything in 30 days, either. You may want to run the above Ansible ad-hoc command once in a while to confirm the daemon is working, or maybe install a tool to monitor cpu or memory if you want, but otherwise, your relays are configured and running. Congratulations!

BONUS: If in the future, you like operating relays and want to spin up more, the Ansible code I've written and used in this tutorial supports that. All you have to do is spin up more EC2 instances just like you did before here in this tutorial, then from your Ansible control box, go ahead and run the Ansible playbook again, and it will not only configure the new instances, but get their fingerprints and update the MyFamily value on all instance's (both existing and new) torrc config with the new fingerprints.

But wait!! You might say-won't it reconfigure and break the existing relays?! Nope...Ansible is "idempotent" meaning it is smart enough to know if an instance has already had a particular configuration step applied to it before and not run that step again if it would break something. So for example...if it logs into the instances and tries to install the EPEL repo, it will first check and see if that EPEL repo is already installed..if it is, it skips doing that task and outputs an "ok" in the playbook output.

Here is an example I ran...I had three Tor relays already set up and configured, and decided I wanted two more for a total of five. I spun up the two additional instances, then kicked off the playbook again. As you can see, Ansible was smart enough to only configure the two new nodes for certain steps, leaving the existing ones alone, except for commands like restarting the daemon or updating the config file (which it would need to do for all, as now the MyFamily config needed to be updated on all five, since there were two new fingerprints that would need to be part of that MyFamily setting.)

NewNodesOutput

So there you have it. One final note, though. Since you've set up your relays in an automated fashion, do be aware that any manual changes you make to these servers have the potential to be overwritten and undone if you run the Ansible playbook again. If you need to make a lot of further changes to your relays, consider forking my repo and adding the steps as Ansible tasks, then run your forked version of the playbook each time to preserve your changes.

If you don't plan on doing much to your relays now that you have them configured with Tor, then feel free to disregard the above note and don't let it worry you. :)

© 2015-2018 Gloria Silveira. Member of the Internet Defense League.