blog.lazkani.io/content/posts/playing-with-containers-and-tor.md

254 lines
7.5 KiB
Markdown
Raw Normal View History

+++
title = "Playing with containers and Tor"
author = ["Elia el Lazkani"]
date = 2021-06-21T21:00:00+02:00
lastmod = 2021-06-28T00:00:39+02:00
tags = ["docker", "linux", "ubuntu", "fedora", "proxy", "privoxy"]
categories = ["container", "text-editors"]
draft = false
+++
As my followers well know, by now, I am a tinkerer at heart. Why do I do things ? No one knows ! I don't even know.
All I know, all I can tell you is that I like to see what can I do with the tools I have at hand. How can I bend them to my will.
Why, you may ask. The answer is a bit complicated; part of who I am, part of what I do as a DevOps. End line is, this time I was curious.
I went down a road that taught me so much more about _containers_, _docker_, _docker-compose_ and even _Linux_ itself.
The question I had was simple, **can I run a container only through Tor running in another container?**
<!--more-->
## Tor {#tor}
I usually like to start topics that I haven't mentioned before with definitions. In this case, what is [Tor](https://2019.www.torproject.org/index.html.en), you may ask ?
> Tor is free software and an open network that helps you defend against traffic analysis, a form of network surveillance that threatens personal freedom and privacy, confidential business activities and relationships, and state security.
Although that _home_ page is obscure because it was replaced by the new _design_ of the website.
Although I love what **Tor** has done with all the services they offer, don't get me wrong.
But giving so much importance on the browser only and leaving the rest for dead when it comes to website, I have to say, I'm a bit sad.
Anyway, let's share the love for **Tor** and thank them for the beautiful project they offered humanity.
Now that we thanked them, let's abuse it.
### Tor in a container {#tor-in-a-container}
The task I set to discover relied on **Tor** being containerized.
The first thing I do is, simply, not re-invent the wheel.
Let's find out if someone already took that task.
With a litte bit of search, I found the [dperson/torproxy](https://hub.docker.com/r/dperson/torproxy) docker image.
It isn't ideal but I _believe_ it is written to be rebuilt.
Can we run it ?
```bash
docker run -it -p 127.0.0.1:8118:8118 -d dperson/torproxy
```
```bash
curl -Lx http://localhost:8118 http://jsonip.com/
```
And this is **definitely** not your IP. Don't take _my word_ for it!
Go to [http://jsonip.com/](http://jsonip.com/) in a browser and see for yourself.
Now that we **know** we can run **Tor** in a container effectively, let's kick it up a _notch_.
## docker-compose {#docker-compose}
I will be _testing_ and making changes as I go along. For this reason, it's a good idea to use [docker-compose](https://docs.docker.com/compose/) to do this.
> Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your applications services. Then, with a single command, you create and start all the services from your configuration.
_Now_ that we saw what the **docker** team has to say about **docker-compose**, let's go ahead and use it.
First, let's implement what we just ran _ad-hoc_ in **docker-compose**.
```yaml
---
version: '3.9'
services:
torproxy:
image: dperson/torproxy
container_name: torproxy
restart: unless-stopped
```
## Air-gapped container {#air-gapped-container}
The next piece of the puzzle is to figure out **if** and **how** can we create an _air-gapped container_.
It turns out, we can create an `internal` network in _docker_ that has no access to the internet.
First, the _air-gapped container_.
```yaml
air-gapped:
image: ubuntu
container_name: air-gapped
restart: unless-stopped
command:
- bash
- -c
- sleep infinity
networks:
- no-internet
```
Then comes the network.
```yaml
networks:
no-internet:
driver: bridge
internal: true
```
Let's put it all together in a `docker-compose.yaml` file and run it.
```bash
docker-compose up -d
```
Keep that terminal open, and let's put the _hypothesis_ to the test and see if rises up to be a _theory_.
```bash
docker exec air-gapped apt-get update
```
Aaaaand...
```text
Err:1 http://archive.ubuntu.com/ubuntu focal InRelease
Temporary failure resolving 'archive.ubuntu.com'
Err:2 http://security.ubuntu.com/ubuntu focal-security InRelease
Temporary failure resolving 'security.ubuntu.com'
Err:3 http://archive.ubuntu.com/ubuntu focal-updates InRelease
Temporary failure resolving 'archive.ubuntu.com'
Err:4 http://archive.ubuntu.com/ubuntu focal-backports InRelease
Temporary failure resolving 'archive.ubuntu.com'
Reading package lists...
W: Failed to fetch http://archive.ubuntu.com/ubuntu/dists/focal/InRelease Temporary failure resolving 'archive.ubuntu.com'
W: Failed to fetch http://archive.ubuntu.com/ubuntu/dists/focal-updates/InRelease Temporary failure resolving 'archive.ubuntu.com'
W: Failed to fetch http://archive.ubuntu.com/ubuntu/dists/focal-backports/InRelease Temporary failure resolving 'archive.ubuntu.com'
W: Failed to fetch http://security.ubuntu.com/ubuntu/dists/focal-security/InRelease Temporary failure resolving 'security.ubuntu.com'
W: Some index files failed to download. They have been ignored, or old ones used instead.
```
looks like it's real peeps, **hooray** !
## Putting everything together {#putting-everything-together}
Okay, now let's put everything together. The list of changes we need to make are minimal.
First, I will list them, then I will simply write them out in **docker-compose**.
- Create an `internet` network for the **Tor** container
- Attach the `internet` network to the **Tor** container
- Attach the `no-internet` network to the **Tor** container so that our _air-gapped_ container can access it.
Let's get to work.
```yaml
---
version: '3.9'
services:
torproxy:
image: dperson/torproxy
container_name: torproxy
restart: unless-stopped
networks:
- no-internet
- internet
air-gapped:
image: ubuntu
container_name: air-gapped
restart: unless-stopped
command:
- bash
- -c
- sleep infinity
networks:
- no-internet
networks:
no-internet:
driver: bridge
internal: true
internet:
driver: bridge
internal: false
```
Run everything.
```bash
docker-compose up -d
```
Yes, this will run it in the background and there is **no** need for you to open another terminal.
It's always _good_ to know **both** ways. Anyway, let's test.
let's `exec` into the container.
```bash
docker exec -it air-gapped bash
```
Then we configure `apt` to use our `torproxy` service.
```bash
echo 'Acquire::http::Proxy "http://torproxy:8118/";' > /etc/apt/apt.conf.d/proxy
echo "export HTTP_PROXY=http://torproxy:8118/" >> ~/.bashrc
echo "export HTTPS_PROXY=http://torproxy:8118/" >> ~/.bashrc
export HTTP_PROXY=http://torproxy:8118/
export HTTPS_PROXY=http://torproxy:8118/
apt-get update
apt-get upgrade -y
DEBIAN_FRONTEND=noninteractive apt-get install -y curl
```
## Harvesting the fruits of our labour {#harvesting-the-fruits-of-our-labour}
First, we **always** check if everything is set correctly.
While inside the container, we check the _environment variables_.
```bash
env | grep HTTP
```
You should see.
```text
HTTPS_PROXY=http://torproxy:8118/
HTTP_PROXY=http://torproxy:8118/
```
Then, we curl our **IP**.
```bash
curl https://jsonip.com/
```
And that is also not your **IP**.
It works !
## Conclusion {#conclusion}
Is it possible to route a container through another **Tor** container ?
The answer is _obviously_ **Yes** and this is the way to do it. Enjoy.