mirror of
https://github.com/cmehay/docker-tor-hidden-service.git
synced 2025-04-19 21:39:13 +00:00
Merge pull request #4 from cmehay/v2
Add support for docker-compose v2 and private keys
This commit is contained in:
commit
5463744e49
7 changed files with 210 additions and 17 deletions
|
@ -7,7 +7,7 @@ RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||||
tor \
|
tor \
|
||||||
python3-pip
|
python3-pip
|
||||||
|
|
||||||
RUN pip3 install pyentrypoint==0.3.7
|
RUN pip3 install pyentrypoint==0.3.8
|
||||||
|
|
||||||
ADD assets/entrypoint-config.yml /
|
ADD assets/entrypoint-config.yml /
|
||||||
ADD assets/onions /usr/local/src/onions
|
ADD assets/onions /usr/local/src/onions
|
||||||
|
|
56
README.md
56
README.md
|
@ -20,12 +20,68 @@ $ docker run -ti --link something --volume /path/to/keys:/var/lib/tor/hidden_ser
|
||||||
|
|
||||||
Look at the `docker-compose.yml` file to see how to use it.
|
Look at the `docker-compose.yml` file to see how to use it.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
### Set private key
|
||||||
|
|
||||||
|
Private key is settable by environment or by copying file in `hostname/private_key` in docket volume (`hostname` is the link name).
|
||||||
|
|
||||||
|
It's easier to pass key in environment with `docker-compose`.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
links:
|
||||||
|
- hello
|
||||||
|
- world
|
||||||
|
environment:
|
||||||
|
# Set private key
|
||||||
|
HELLO_KEY: |
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIICXQIBAAKBgQDR8TdQF9fDlGhy1SMgfhMBi9TaFeD12/FK27TZE/tYGhxXvs1C
|
||||||
|
NmFJy1hjVxspF5unmUsCk0yEsvEdcAdp17Vynz6W41VdinETU9yXHlUJ6NyI32AH
|
||||||
|
dnFnHEcsllSEqD1hPAAvMUWwSMJaNmBEFtl8DUMS9tPX5fWGX4w5Xx8dZwIDAQAB
|
||||||
|
AoGBAMb20jMHxaZHWg2qTRYYJa8LdHgS0BZxkWYefnBUbZn7dOz7mM+tddpX6raK
|
||||||
|
8OSqyQu3Tc1tB9GjPLtnVr9KfVwhUVM7YXC/wOZo+u72bv9+4OMrEK/R8xy30XWj
|
||||||
|
GePXEu95yArE4NucYphxBLWMMu2E4RodjyJpczsl0Lohcn4BAkEA+XPaEKnNA3AL
|
||||||
|
1DXRpSpaa0ukGUY/zM7HNUFMW3UP00nxNCpWLSBmrQ56Suy7iSy91oa6HWkDD/4C
|
||||||
|
k0HslnMW5wJBANdz4ehByMJZmJu/b5y8wnFSqep2jmJ1InMvd18BfVoBTQJwGMAr
|
||||||
|
+qwSwNXXK2YYl9VJmCPCfgN0o7h1AEzvdYECQAM5UxUqDKNBvHVmqKn4zShb1ugY
|
||||||
|
t1RfS8XNbT41WhoB96MT9P8qTwlniX8UZiwUrvNp1Ffy9n4raz8Z+APNwvsCQQC9
|
||||||
|
AuaOsReEmMFu8VTjNh2G+TQjgvqKmaQtVNjuOgpUKYv7tYehH3P7/T+62dcy7CRX
|
||||||
|
cwbLaFbQhUUUD2DCHdkBAkB6CbB+qhu67oE4nnBCXllI9EXktXgFyXv/cScNvM9Y
|
||||||
|
FDzzNAAfVc5Nmbmx28Nw+0w6pnpe/3m0Tudbq3nHdHfQ
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Options are set using the following pattern: `LINKNAME_KEY`
|
||||||
|
|
||||||
### Setup port
|
### Setup port
|
||||||
|
|
||||||
|
__DEPECATED:__
|
||||||
By default, ports are the same as linked containers, but a default port can be mapped using `PORT_MAP` environment variable.
|
By default, ports are the same as linked containers, but a default port can be mapped using `PORT_MAP` environment variable.
|
||||||
|
|
||||||
__Caution__: Using `PORT_MAP` with multiple ports on single service will cause `tor` to fail.
|
__Caution__: Using `PORT_MAP` with multiple ports on single service will cause `tor` to fail.
|
||||||
|
|
||||||
|
Use link setting in environment with the following pattern: `LINKNAME_PORTS`.
|
||||||
|
|
||||||
|
Like docker, first port is exposed port and the second one is service internal port.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
links:
|
||||||
|
- hello
|
||||||
|
- world
|
||||||
|
environment:
|
||||||
|
# Set mapping ports
|
||||||
|
HELLO_PORTS: 80:80
|
||||||
|
|
||||||
|
WORLD_PORTS: 8000:80
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compose v2 support
|
||||||
|
|
||||||
|
Links setting are required when using docker-compose v2. See `docker-compose.v2.yml` for example.
|
||||||
|
|
||||||
### Tools
|
### Tools
|
||||||
|
|
||||||
A command line tool `onions` is available in container to get `.onion` url when container is running.
|
A command line tool `onions` is available in container to get `.onion` url when container is running.
|
||||||
|
|
|
@ -3,8 +3,12 @@ command: tor
|
||||||
user: debian-tor
|
user: debian-tor
|
||||||
group: debian-tor
|
group: debian-tor
|
||||||
|
|
||||||
config_files:
|
secret_env:
|
||||||
- /etc/tor/torrc
|
- '*_KEY'
|
||||||
|
- '*_PORTS'
|
||||||
|
|
||||||
|
pre_conf_commands:
|
||||||
|
- onions --setup-hosts
|
||||||
|
|
||||||
post_conf_commands:
|
post_conf_commands:
|
||||||
- timeout 3s tor > /dev/null || true
|
- timeout 3s tor > /dev/null || true
|
||||||
|
|
|
@ -3,16 +3,96 @@
|
||||||
import os
|
import os
|
||||||
from json import dumps
|
from json import dumps
|
||||||
|
|
||||||
|
from re import match
|
||||||
|
|
||||||
|
from pyentrypoint import DockerLinks
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
from jinja2 import Environment
|
||||||
|
from jinja2 import FileSystemLoader
|
||||||
|
|
||||||
class Onions(object):
|
|
||||||
"""Onions"""
|
class Setup(object):
|
||||||
|
|
||||||
hidden_service_dir = "/var/lib/tor/hidden_service/"
|
hidden_service_dir = "/var/lib/tor/hidden_service/"
|
||||||
|
torrc = '/etc/tor/torrc'
|
||||||
|
|
||||||
|
def _add_host(self, host):
|
||||||
|
if host not in self.setup:
|
||||||
|
self.setup[host] = {}
|
||||||
|
|
||||||
|
def _get_ports(self, host, ports):
|
||||||
|
self._add_host(host)
|
||||||
|
if 'ports' not in self.setup[host]:
|
||||||
|
self.setup[host]['ports'] = []
|
||||||
|
port = [int(p) for p in ports.split(':')]
|
||||||
|
assert len(port) == 2
|
||||||
|
if port not in self.setup[host]['ports']:
|
||||||
|
self.setup[host]['ports'].append(port)
|
||||||
|
|
||||||
|
def _get_key(self, host, key):
|
||||||
|
self._add_host(host)
|
||||||
|
assert len(key) > 800
|
||||||
|
self.setup[host]['key'] = key
|
||||||
|
|
||||||
|
def _get_setup_from_env(self):
|
||||||
|
match_map = (
|
||||||
|
(r'([A-Z0-9]*)_PORTS', self._get_ports),
|
||||||
|
(r'([A-Z0-9]*)_KEY', self._get_key),
|
||||||
|
)
|
||||||
|
for key, val in os.environ.items():
|
||||||
|
for reg, call in match_map:
|
||||||
|
m = match(reg, key)
|
||||||
|
if m:
|
||||||
|
call(m.groups()[0].lower(), val)
|
||||||
|
|
||||||
|
def _get_setup_from_links(self):
|
||||||
|
containers = DockerLinks().to_containers()
|
||||||
|
if not containers:
|
||||||
|
return
|
||||||
|
for container in containers:
|
||||||
|
host = container.names[0]
|
||||||
|
self._add_host(host)
|
||||||
|
for link in container.links:
|
||||||
|
if link.protocol != 'tcp':
|
||||||
|
continue
|
||||||
|
port_map = os.environ.get('PORT_MAP')
|
||||||
|
self._get_ports(host, '{exposed}:{internal}'.format(
|
||||||
|
exposed=port_map or link.port,
|
||||||
|
internal=link.port,
|
||||||
|
))
|
||||||
|
|
||||||
|
def _set_keys(self):
|
||||||
|
for link, conf in self.setup.items():
|
||||||
|
if 'key' in conf:
|
||||||
|
serv_dir = os.path.join(self.hidden_service_dir, link)
|
||||||
|
os.makedirs(serv_dir, exist_ok=True)
|
||||||
|
with open(os.path.join(serv_dir, 'private_key'), 'w') as f:
|
||||||
|
f.write(conf['key'])
|
||||||
|
|
||||||
|
def _set_conf(self):
|
||||||
|
env = Environment(loader=FileSystemLoader('/'))
|
||||||
|
temp = env.get_template(self.torrc)
|
||||||
|
with open(self.torrc, mode='w') as f:
|
||||||
|
f.write(temp.render(setup=self.setup,
|
||||||
|
env=os.environ))
|
||||||
|
|
||||||
|
def setup_hosts(self):
|
||||||
|
self.setup = {}
|
||||||
|
try:
|
||||||
|
self._get_setup_from_env()
|
||||||
|
self._get_setup_from_links()
|
||||||
|
self._set_keys()
|
||||||
|
self._set_conf()
|
||||||
|
except:
|
||||||
|
raise Exception('Something wrongs with setup')
|
||||||
|
|
||||||
|
|
||||||
|
class Onions(Setup):
|
||||||
|
"""Onions"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._get_onions()
|
|
||||||
if 'HIDDEN_SERVICE_DIR' in os.environ:
|
if 'HIDDEN_SERVICE_DIR' in os.environ:
|
||||||
self.hidden_service_dir = os.environ['HIDDEN_SERVICE_DIR']
|
self.hidden_service_dir = os.environ['HIDDEN_SERVICE_DIR']
|
||||||
|
|
||||||
|
@ -21,7 +101,7 @@ class Onions(object):
|
||||||
with open(filename, 'r') as hostfile:
|
with open(filename, 'r') as hostfile:
|
||||||
onion = str(hostfile.read()).strip()
|
onion = str(hostfile.read()).strip()
|
||||||
|
|
||||||
with open('/etc/tor/torrc', 'r') as torfile:
|
with open(self.torrc, 'r') as torfile:
|
||||||
self.onions[service] = []
|
self.onions[service] = []
|
||||||
for line in torfile.readlines():
|
for line in torfile.readlines():
|
||||||
find = '# PORT {name}'.format(name=service)
|
find = '# PORT {name}'.format(name=service)
|
||||||
|
@ -33,7 +113,7 @@ class Onions(object):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def _get_onions(self):
|
def get_onions(self):
|
||||||
self.onions = {}
|
self.onions = {}
|
||||||
for root, dirs, _ in os.walk(self.hidden_service_dir,
|
for root, dirs, _ in os.walk(self.hidden_service_dir,
|
||||||
topdown=False):
|
topdown=False):
|
||||||
|
@ -60,8 +140,15 @@ def main():
|
||||||
parser.add_argument('--json', dest='json', action='store_true',
|
parser.add_argument('--json', dest='json', action='store_true',
|
||||||
help='serialize to json')
|
help='serialize to json')
|
||||||
|
|
||||||
|
parser.add_argument('--setup-hosts', dest='setup', action='store_true',
|
||||||
|
help='Setup hosts')
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
onions = Onions()
|
onions = Onions()
|
||||||
|
if args.setup:
|
||||||
|
onions.setup_hosts()
|
||||||
|
return
|
||||||
|
onions.get_onions()
|
||||||
if args.json:
|
if args.json:
|
||||||
print(onions.to_json())
|
print(onions.to_json())
|
||||||
else:
|
else:
|
||||||
|
|
13
assets/torrc
13
assets/torrc
|
@ -1,11 +1,8 @@
|
||||||
{% for container in containers %}
|
{% for service, conf in setup.items() %}
|
||||||
HiddenServiceDir /var/lib/tor/hidden_service/{{container.names[0]}}
|
HiddenServiceDir /var/lib/tor/hidden_service/{{service}}
|
||||||
{% for link in container.links %}
|
{% for ports in conf['ports'] %}
|
||||||
{% set port = env['PORT_MAP'] if 'PORT_MAP' in env else link.port %}
|
# PORT {{service}} {{ports[0]}}
|
||||||
{% if link.protocol == 'tcp' %}
|
HiddenServicePort {{ports[0]}} {{service}}:{{ports[1]}}
|
||||||
# PORT {{container.names[0]}} {{port}}
|
|
||||||
HiddenServicePort {{port}} {{link.ip}}:{{link.port}}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
|
46
docker-compose.v2.yml
Normal file
46
docker-compose.v2.yml
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
# docker version 2 example
|
||||||
|
|
||||||
|
version: "2"
|
||||||
|
|
||||||
|
services:
|
||||||
|
tor:
|
||||||
|
image: goldy/tor-hidden-service
|
||||||
|
# or
|
||||||
|
build: .
|
||||||
|
links:
|
||||||
|
- hello
|
||||||
|
- world
|
||||||
|
environment:
|
||||||
|
# Set mapping ports
|
||||||
|
HELLO_PORTS: 80:80
|
||||||
|
# Set private key
|
||||||
|
HELLO_KEY: |
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIICXQIBAAKBgQDR8TdQF9fDlGhy1SMgfhMBi9TaFeD12/FK27TZE/tYGhxXvs1C
|
||||||
|
NmFJy1hjVxspF5unmUsCk0yEsvEdcAdp17Vynz6W41VdinETU9yXHlUJ6NyI32AH
|
||||||
|
dnFnHEcsllSEqD1hPAAvMUWwSMJaNmBEFtl8DUMS9tPX5fWGX4w5Xx8dZwIDAQAB
|
||||||
|
AoGBAMb20jMHxaZHWg2qTRYYJa8LdHgS0BZxkWYefnBUbZn7dOz7mM+tddpX6raK
|
||||||
|
8OSqyQu3Tc1tB9GjPLtnVr9KfVwhUVM7YXC/wOZo+u72bv9+4OMrEK/R8xy30XWj
|
||||||
|
GePXEu95yArE4NucYphxBLWMMu2E4RodjyJpczsl0Lohcn4BAkEA+XPaEKnNA3AL
|
||||||
|
1DXRpSpaa0ukGUY/zM7HNUFMW3UP00nxNCpWLSBmrQ56Suy7iSy91oa6HWkDD/4C
|
||||||
|
k0HslnMW5wJBANdz4ehByMJZmJu/b5y8wnFSqep2jmJ1InMvd18BfVoBTQJwGMAr
|
||||||
|
+qwSwNXXK2YYl9VJmCPCfgN0o7h1AEzvdYECQAM5UxUqDKNBvHVmqKn4zShb1ugY
|
||||||
|
t1RfS8XNbT41WhoB96MT9P8qTwlniX8UZiwUrvNp1Ffy9n4raz8Z+APNwvsCQQC9
|
||||||
|
AuaOsReEmMFu8VTjNh2G+TQjgvqKmaQtVNjuOgpUKYv7tYehH3P7/T+62dcy7CRX
|
||||||
|
cwbLaFbQhUUUD2DCHdkBAkB6CbB+qhu67oE4nnBCXllI9EXktXgFyXv/cScNvM9Y
|
||||||
|
FDzzNAAfVc5Nmbmx28Nw+0w6pnpe/3m0Tudbq3nHdHfQ
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
|
|
||||||
|
WORLD_PORTS: 8000:80
|
||||||
|
|
||||||
|
# Keep keys in volumes
|
||||||
|
volumes:
|
||||||
|
- ./keys:/var/lib/tor/hidden_service/
|
||||||
|
|
||||||
|
hello:
|
||||||
|
image: tutum/hello-world
|
||||||
|
hostname: hello
|
||||||
|
|
||||||
|
world:
|
||||||
|
image: tutum/hello-world
|
||||||
|
hostname: world
|
|
@ -1,13 +1,16 @@
|
||||||
# docker-compose.yml example
|
# docker-compose.yml example
|
||||||
|
|
||||||
tor:
|
tor:
|
||||||
# image: goldy/tor-hidden-service
|
image: goldy/tor-hidden-service
|
||||||
|
# or
|
||||||
build: .
|
build: .
|
||||||
links:
|
links:
|
||||||
- hello
|
- hello
|
||||||
- world
|
- world
|
||||||
environment:
|
environment:
|
||||||
PORT_MAP: 80 # Map port to detected service
|
PORT_MAP: 80 # Map port to detected service
|
||||||
|
volumes:
|
||||||
|
- ./keys:/var/lib/tor/hidden_service/
|
||||||
|
|
||||||
hello:
|
hello:
|
||||||
image: tutum/hello-world
|
image: tutum/hello-world
|
||||||
|
|
Loading…
Add table
Reference in a new issue