diff --git a/.gitignore b/.gitignore index dbc62ee..fa43272 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ id_rsa_proxy id_rsa_proxy.pub +keys/ +authorized_keys diff --git a/Makefile b/Makefile index 3417296..399d661 100644 --- a/Makefile +++ b/Makefile @@ -1,38 +1,49 @@ .PHONY: default -default: remote client +default: server client .PHONY: all -all: remote client +all: server client .PHONY: stop stop: - docker-compose -f ./docker-compose-remote.yml stop + docker-compose -f ./docker-compose-server.yml stop docker-compose -f ./docker-compose-client.yml stop .PHONY: restart restart: - docker-compose -f ./docker-compose-remote.yml restart + docker-compose -f ./docker-compose-server.yml restart docker-compose -f ./docker-compose-client.yml restart .PHONY: down down: - docker-compose -f ./docker-compose-remote.yml down docker-compose -f ./docker-compose-client.yml down + docker-compose -f ./docker-compose-server.yml down -.PHONY: remote -remote: - docker-compose -f ./docker-compose-remote.yml build - docker-compose -f ./docker-compose-remote.yml up -d +.PHONY: server +server: keys + docker-compose -f ./docker-compose-server.yml build + docker-compose -f ./docker-compose-server.yml up -d .PHONY: client client: docker-compose -f ./docker-compose-client.yml build docker-compose -f ./docker-compose-client.yml up -d -.PHONY: remote-logs -remote-logs: - docker-compose -f ./docker-compose-remote.yml logs -f +.PHONY: server-logs +server-logs: + docker-compose -f ./docker-compose-server.yml logs -f .PHONY: client-logs client-logs: docker-compose -f ./docker-compose-client.yml logs -f + +keys: + mkdir -p keys/etc/ssh + ssh-keygen -A -f keys/ + +keys/etc/ssh/ssh_host_dsa_key: keys +keys/etc/ssh/ssh_host_ecdsa_key: keys +keys/etc/ssh/ssh_host_ed25519_key: keys +keys/etc/ssh/ssh_host_rsa_key: keys + +keys/known_hosts: keys diff --git a/Readme.md b/Readme.md index 4a32b22..18c5501 100644 --- a/Readme.md +++ b/Readme.md @@ -49,6 +49,7 @@ Dockamole is configured using environment variables: # Optional MAX_TUNNELS number of tunnels allowed (default 10) SSH_KEY path to ssh private key that should be used (default ~/.ssh/id_rsa) + GEN_KNOWN_HOSTS determines if known hosts should be generated on first start (default 1) ## Use in production diff --git a/docker-compose-remote.yml b/docker-compose-server.yml similarity index 60% rename from docker-compose-remote.yml rename to docker-compose-server.yml index 5aa5b4b..7aca95d 100644 --- a/docker-compose-remote.yml +++ b/docker-compose-server.yml @@ -9,6 +9,11 @@ services: # This key must be provided # - ./id_rsa_proxy.pub:/etc/authorized_keys/mole - ./authorized_keys:/etc/authorized_keys/mole + # Mount host keys + - ./keys/etc/ssh/ssh_host_dsa_key:/etc/ssh/ssh_host_dsa_key + - ./keys/etc/ssh/ssh_host_ecdsa_key:/etc/ssh/ssh_host_ecdsa_key + - ./keys/etc/ssh/ssh_host_ed25519_key:/etc/ssh/ssh_host_ed25519_key + - ./keys/etc/ssh/ssh_host_rsa_key:/etc/ssh/ssh_host_rsa_key environment: - SSH_USERS=mole:101:101 diff --git a/mole/Dockerfile b/mole/Dockerfile index 956839c..9cb9f99 100644 --- a/mole/Dockerfile +++ b/mole/Dockerfile @@ -1,7 +1,9 @@ FROM alpine -RUN apk add bash curl tar -RUN bash -c "bash <(curl -fsSL https://raw.githubusercontent.com/davrodpin/mole/master/tools/install.sh | sed 's/\bsudo\b//g')" +# Install latest mole +RUN apk --no-cache add bash curl tar openssh-client && \ + bash -c "bash <(curl -fsSL https://raw.githubusercontent.com/davrodpin/mole/master/tools/install.sh | sed 's/\bsudo\b//g')" && \ + apk del curl tar RUN mkdir /mole RUN adduser -S -h /mole mole @@ -10,6 +12,10 @@ USER mole RUN mkdir -p /mole/.ssh RUN touch /mole/.ssh/config +# Make a volume to persist keys +VOLUME /mole/.ssh + +ENV GEN_KNOWN_HOSTS=1 COPY ./start.sh ./ diff --git a/mole/start.sh b/mole/start.sh index 2131e8e..28076e1 100755 --- a/mole/start.sh +++ b/mole/start.sh @@ -1,23 +1,67 @@ #! /bin/bash +set -e + +# Tests if the command being passed in is for a shell +function is_shell() { + case "$1" in + bash|sh) + return 0 + ;; + esac + return 1 +} + +# Determines if we should append to known_hosts +function should_append_hosts() { + [ "${GEN_KNOWN_HOSTS:=1}" -eq 1 ] +} + +# Appends server key to known_hosts if it's not already there +function maybe_append_host() { + local host=$(echo $1 | sed -e 's/.*@//' -e 's/:.*//') + local port=$(echo $1 | sed -n 's/.*:\([0-9]*\)/\1/p') + local known_hosts=$HOME/.ssh/known_hosts + touch $known_hosts + echo "Ensuring $host is in $known_hosts..." + echo "grep -q $1 $known_hosts || ssh-keyscan -p ${port:-22} $host >> $known_hosts" + grep -q $host $known_hosts || ssh-keyscan -p ${port:-22} $host >> $known_hosts +} # Executes mole using local and remotes from env variables +function get_local_remote_mapping() { + local local_remote="" + for i in `seq ${MAX_TUNNELS:-10}`; do + local_name=MOLE_LOCAL_$i + remote_name=MOLE_REMOTE_$i + if [ ! -z "${!local_name}" ] && [ ! -z "${!remote_name}" ]; then + local_remote="$local_remote -local ${!local_name} -remote ${!remote_name}" + fi + done + echo $local_remote +} -local_remote="" -for i in `seq ${MAX_TUNNELS:-10}`; do - local_name=MOLE_LOCAL_$i - remote_name=MOLE_REMOTE_$i - if [ ! -z "${!local_name}" ] && [ ! -z "${!remote_name}" ]; then - local_remote="$local_remote -local ${!local_name} -remote ${!remote_name}" +function main() { + if should_append_hosts ;then + maybe_append_host $MOLE_SERVER + fi + local local_remote=$(get_local_remote_mapping) + if [ -z "$local_remote" ]; then + echo "Must provide at least one local and remote via MOLE_LOCAL_1 and MOLE_REMOTE_1" + exit 1 fi -done -if [ -z "$local_remote" ]; then - echo "Must provide at least one local and remote via MOLE_LOCAL_1 and MOLE_REMOTE_1" - exit 1 + mole -v \ + $local_remote \ + $@ \ + -server ${MOLE_SERVER} \ + -key ${SSH_KEY:-~/.ssh/id_rsa} +} + +# If first arg is bash or sh, we'll just execute directly +if is_shell $1 ; then + echo "We think you're trying to just drop into a shell" + exec "$@" + exit 0 fi -mole -v \ - $local_remote \ - -server ${MOLE_SERVER} \ - -key ${SSH_KEY:-~/.ssh/id_rsa} \ - -insecure +main $@