├── Dockerfile ├── README.md ├── entry.sh └── run.sh /Dockerfile: -------------------------------------------------------------------------------- 1 | # Docker Image for SSH agent container. Last revision 26.4.2018 2 | # 3 | # Copyright (c) Andreas Urbanski, 2018 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a 6 | # copy of this software and associated documentation files (the "Software"), 7 | # to deal in the Software without restriction, including without limitation 8 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | # and/or sell copies of the Software, and to permit persons to whom the 10 | # Software is furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included 13 | # in all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | FROM alpine:3.4 23 | 24 | MAINTAINER Andreas Urbanski 25 | 26 | # Install dependencies 27 | RUN apk add --no-cache \ 28 | bash \ 29 | openssh \ 30 | socat \ 31 | && rm -rf /var/cache/apk/* 32 | 33 | # Copy entrypoint script to container 34 | COPY entry.sh /entry.sh 35 | RUN chmod a+x /entry.sh 36 | 37 | # Setup environment variables; export SSH_AUTH_SOCK from socket directory 38 | ENV SOCKET_DIR /.ssh-agent 39 | ENV SSH_AUTH_SOCK ${SOCKET_DIR}/socket 40 | ENV SSH_AUTH_PROXY_SOCK ${SOCKET_DIR}/proxy-socket 41 | 42 | VOLUME ${SOCKET_DIR} 43 | 44 | ENTRYPOINT ["/entry.sh"] 45 | 46 | CMD ["ssh-agent"] 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Docker SSH Agent 2 | 3 | [![Pulls](https://img.shields.io/docker/pulls/nardeas/ssh-agent.svg)](https://img.shields.io/docker/pulls/nardeas/ssh-agent.svg?style=flat-square) 4 | [![Size](https://images.microbadger.com/badges/image/nardeas/ssh-agent.svg)](https://microbadger.com/images/nardeas/ssh-agent "Get your own image badge on microbadger.com") 5 | 6 | Lets you store your SSH authentication keys in a dockerized ssh-agent that can provide the SSH authentication socket for other containers. Works in OSX and Linux environments. 7 | 8 | ## Why? 9 | 10 | On OSX you cannot simply forward your authentication socket to a docker container to be able to e.g clone private repositories that you have access to. You don't want to copy your private key to all containers either. The solution is to add your keys only once to a long-lived ssh-agent container that can be used by other containers and stopped when not needed anymore. 11 | 12 | ## hub.docker.com 13 | 14 | You can pull the image from [DockerHub](https://hub.docker.com/r/nardeas/ssh-agent/) via 15 | 16 | ``` 17 | docker pull nardeas/ssh-agent 18 | ``` 19 | 20 | ## How to use 21 | 22 | ### Quickstart 23 | 24 | If you don't want to build your own images, here's a 3-step guide: 25 | 26 | 1\. Run agent 27 | ``` 28 | docker run -d --name=ssh-agent nardeas/ssh-agent 29 | ``` 30 | 31 | 2\. Add your keys 32 | ``` 33 | docker run --rm --volumes-from=ssh-agent -v ~/.ssh:/.ssh -it nardeas/ssh-agent ssh-add /root/.ssh/id_rsa 34 | ``` 35 | 36 | 3\. Now run your actual container: 37 | 38 | ``` 39 | docker run -it --volumes-from=ssh-agent -e SSH_AUTH_SOCK=/.ssh-agent/socket ubuntu:latest /bin/bash 40 | ``` 41 | 42 | **Run script** 43 | 44 | You can run the `run.sh` script which will build the images for you, launch the ssh-agent and add your keys. If your keys are password protected (hopefully) you will just need to input your passphrase. 45 | 46 | Launch everything: 47 | 48 | ``` 49 | ./run.sh 50 | ``` 51 | 52 | Remove your keys from ssh-agent and stop container: 53 | 54 | ``` 55 | ./run.sh -s 56 | ``` 57 | 58 | ### Step by step 59 | 60 | #### 0. Build 61 | Navigate to the project directory and launch the following command to build the image: 62 | 63 | ``` 64 | docker build -t docker-ssh-agent:latest -f Dockerfile . 65 | ``` 66 | 67 | #### 1. Run a long-lived container 68 | ``` 69 | docker run -d --name=ssh-agent docker-ssh-agent:latest 70 | ``` 71 | 72 | #### 2. Add your ssh keys 73 | 74 | Run a temporary container with volume mounted from host that includes your SSH keys. SSH key id_rsa will be added to ssh-agent (you can replace id_rsa with your key name): 75 | 76 | ``` 77 | docker run --rm --volumes-from=ssh-agent -v ~/.ssh:/.ssh -it docker-ssh-agent:latest ssh-add /root/.ssh/id_rsa 78 | ``` 79 | 80 | The ssh-agent container is now ready to use. 81 | 82 | #### 3. Add ssh-agent socket to other container: 83 | 84 | If you're using `docker-compose` this is how you forward the socket to a container: 85 | 86 | ``` 87 | volumes_from: 88 | - ssh-agent 89 | environment: 90 | - SSH_AUTH_SOCK=/.ssh-agent/socket 91 | ``` 92 | 93 | ##### For non-root users 94 | The above only works for root. ssh-agent socket is accessible only to the user which started this agent or for root user. So other users don't have access to `/.ssh-agent/socket`. If you have another user in your container you should do the following: 95 | 96 | 1. Install `socat` utility in your container 97 | 2. Make proxy-socket in your container: 98 | ``` 99 | sudo socat UNIX-LISTEN:~/.ssh/socket,fork UNIX-CONNECT:/.ssh-agent/socket & 100 | ``` 101 | 3. Change the owner of this proxy-socket 102 | ``` 103 | sudo chown $(id -u) ~/.ssh/socket 104 | ``` 105 | 4. You will need to use different SSH_AUTH_SOCK for this user: 106 | ``` 107 | SSH_AUTH_SOCK=~/.ssh/socket 108 | ``` 109 | 110 | ##### Without docker-compose 111 | Here's an example how to run a Ubuntu container that uses the ssh authentication socket: 112 | ``` 113 | docker run -it --volumes-from=ssh-agent -e SSH_AUTH_SOCK=/.ssh-agent/socket ubuntu:latest /bin/bash 114 | ``` 115 | 116 | ### Deleting keys from the container 117 | 118 | Run a temporary container and delete all known keys from ssh-agent: 119 | 120 | ``` 121 | docker run --rm --volumes-from=ssh-agent -it docker-ssh-agent:latest ssh-add -D 122 | ``` 123 | -------------------------------------------------------------------------------- /entry.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) Andreas Urbanski, 2018 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a 5 | # copy of this software and associated documentation files (the "Software"), 6 | # to deal in the Software without restriction, including without limitation 7 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | # and/or sell copies of the Software, and to permit persons to whom the 9 | # Software is furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included 12 | # in all copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | # THE SOFTWARE. 21 | 22 | # Print a debug message if debug mode is on ($DEBUG is not empty) 23 | # @param message 24 | debug_msg () 25 | { 26 | if [ -n "$DEBUG" ]; then 27 | echo "$@" 28 | fi 29 | } 30 | 31 | case "$1" in 32 | # Start ssh-agent 33 | ssh-agent) 34 | 35 | # Create proxy-socket for ssh-agent (to give everyone acceess to the ssh-agent socket) 36 | echo "Creating a proxy socket..." 37 | rm ${SSH_AUTH_SOCK} ${SSH_AUTH_PROXY_SOCK} > /dev/null 2>&1 38 | socat UNIX-LISTEN:${SSH_AUTH_PROXY_SOCK},perm=0666,fork UNIX-CONNECT:${SSH_AUTH_SOCK} & 39 | 40 | echo "Launching ssh-agent..." 41 | exec /usr/bin/ssh-agent -a ${SSH_AUTH_SOCK} -d 42 | ;; 43 | 44 | # Manage SSH identities 45 | ssh-add) 46 | shift # remove argument from array 47 | 48 | # .ssh folder from host is expected to be mounted on /.ssh 49 | # We copy keys from there into /root/.ssh and fix permissions (necessary on Windows hosts) 50 | host_ssh_path="/.ssh" 51 | if [ -d $host_ssh_path ]; then 52 | debug_msg "Copying host SSH keys and setting proper permissions..." 53 | cp -a $host_ssh_path/. ~/.ssh/ 54 | chmod 700 ~/.ssh 55 | chmod 600 ~/.ssh/* 56 | chmod 644 ~/.ssh/*.pub 57 | fi 58 | 59 | # Make sure the key exists if provided. 60 | # When $ssh_key_path is empty, ssh-agent will be looking for both id_rsa and id_dsa in the home directory. 61 | ssh_key_path="" 62 | if [ -n "$1" ] && [ -f "/root/.ssh/$1" ]; then 63 | ssh_key_path="/root/.ssh/$1" 64 | shift # remove argument from array 65 | fi 66 | 67 | # Calling ssh-add. This should handle all cases. 68 | _command="ssh-add $ssh_key_path $@" 69 | debug_msg "Executing: $_command" 70 | 71 | # When $key_path is empty, ssh-agent will be looking for both id_rsa and id_dsa in the home directory. 72 | # NOTE: We do a sed hack here to strip out '/root/.ssh' from the key path in the output from ssh-add, since this 73 | # path may confuse people. 74 | # echo "Press ENTER or CTRL+C to skip entering passphrase (if any)." 75 | $_command 2>&1 0>&1 | sed 's/\/root\/.ssh\///g' 76 | 77 | # Return first command exit code 78 | exit ${PIPESTATUS[0]} 79 | ;; 80 | *) 81 | exec $@ 82 | ;; 83 | esac 84 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) Andreas Urbanski, 2016 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a 5 | # copy of this software and associated documentation files (the "Software"), 6 | # to deal in the Software without restriction, including without limitation 7 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | # and/or sell copies of the Software, and to permit persons to whom the 9 | # Software is furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included 12 | # in all copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | # THE SOFTWARE. 21 | 22 | # Output colors 23 | underline='\033[4;37m' 24 | purple='\033[0;35m' 25 | bold='\033[1;37m' 26 | green='\033[0;32m' 27 | cyan='\033[0;36m' 28 | red='\033[0;31m' 29 | nc='\033[0m' 30 | 31 | # Find image id 32 | image=$(docker images|grep docker-ssh-agent|awk '{print $3}') 33 | 34 | # Find agent container id 35 | id=$(docker ps -a|grep ssh-agent|awk '{print $1}') 36 | 37 | # Stop command 38 | if [ "$1" == "-s" ] && [ $id ]; then 39 | echo -e "Removing ssh-keys..." 40 | docker run --rm --volumes-from=ssh-agent -it docker-ssh-agent:latest ssh-add -D 41 | echo -e "Stopping ssh-agent container..." 42 | docker rm -f $id 43 | exit 44 | fi 45 | 46 | # Build image if not available 47 | if [ -z $image ]; then 48 | echo -e "${bold}The image for docker-ssh-agent has not been built.${nc}" 49 | echo -e "Building image..." 50 | docker build -t docker-ssh-agent:latest -f Dockerfile . 51 | echo -e "${cyan}Image built.${nc}" 52 | fi 53 | 54 | # If container is already running, exit. 55 | if [ $id ]; then 56 | echo -e "A container named 'ssh-agent' is already running." 57 | echo -e "Do you wish to stop it? (y/N): " 58 | read input 59 | 60 | if [ "$input" == "y" ]; then 61 | echo -e "Removing SSH keys..." 62 | docker run --rm --volumes-from=ssh-agent -it docker-ssh-agent:latest ssh-add -D 63 | echo -e "Stopping ssh-agent container..." 64 | docker rm -f $id 65 | echo -e "${red}Stopped.${nc}" 66 | fi 67 | 68 | exit 69 | fi 70 | 71 | # Run ssh-agent 72 | echo -e "${bold}Launching ssh-agent container...${nc}" 73 | docker run -d --name=ssh-agent docker-ssh-agent:latest 74 | 75 | echo -e "Adding your ssh keys to the ssh-agent container..." 76 | docker run --rm --volumes-from=ssh-agent -v ~/.ssh:/.ssh -it docker-ssh-agent:latest ssh-add /root/.ssh/id_rsa 77 | 78 | echo -e "${green}ssh-agent is now ready to use.${nc}" 79 | --------------------------------------------------------------------------------