How can I create a Jenkins Docker image that uses provided ssh keys for jenkins user?

While I create an image based on official Jenkins Docker and copy .ssh directory to jenkins user’s home (/var/jenkins_home), owner of the /var/jenkins_home/.ssh becomes root which prevents me to open ssh session with jenkins user. Using RUN chown -R 1000:1000 /var/jenkins_home/.ssh in Dockerfile does not work.

Also, permissions of the files copied while creating image becomes 644 by default. However, to be able to open ssh session, permissions of /var/jenkins_home/.ssh/id_rsa must be 600.

  • Use Docker in Linux VMWare VM with Volumes?
  • Import data on mongodb from docker-compose
  • Selenium ChromeDriver Failed to load resource: net::ERR_CONNECTION_CLOSED
  • Can't access publicly exposed Docker container port from external machine, only from localhost?
  • Selenium in Docker container, Can we take screen shot
  • Docker, Supervisord and logging - how to consolidate logs in docker logs?
  • How can I create an image from official Jenkins Docker image having provided ssh keys for jenkins user?

  • Unable to connect to an ibmnode:latest-based container with putty over ssh
  • Access to Docker container
  • Pull docker image behind a corporate firewall throws “Server error: Status 0 while fetching image layer”
  • cloudera manager can only inspect one host at a time
  • Chef and Docker
  • Docker seems to ignore DOCKER_HOST and other vars set from `eval $(docker-machine env)`
  • 2 Solutions collect form web for “How can I create a Jenkins Docker image that uses provided ssh keys for jenkins user?”

    I have found a little bit complex but more generic way to achieve that. New solution requires;

    • ssh-agent, credentials and ssh-credentials plugins
    • Plugin installation while creating Docker image (Installing more tools – Preinstalling plugins)
    • Configuring Jenkins upon startup by executing post-initialization script.

    Main idea here is to copy ssh keys into a directory other than JENKINS_HOME, adding them to Jenkins’ credentials by using post-initialization script and using ssh-agent plug-in for ssh.

    I have uploaded necessary setup and instructions to GitHub: https://github.com/kumlali/stackoverflow_answers/tree/master/docker_jenkins_ssh_keys/answer2

    Official Jenkins Docker image defines Jenkins home directory(/var/jenkins_home) as VOLUME which prevents RUN chown -R 1000:1000 /var/jenkins_home/...to be effective:

    $ touch test.txt
    
    $ vi Dockerfile
    --- Dockerfile ---
    FROM jenkins:2.32.3
    
    COPY test.txt /tmp
    COPY test.txt /var/jenkins_home/test.txt
    
    USER root
    
    RUN chown 1000:1000 /tmp/test.txt
    RUN chown 1000:1000 /var/jenkins_home/test.txt
    
    USER jenkins
    --- Dockerfile ---
    
    $ docker build -t myjenkins .
    ...
    
    $ docker run -it myjenkins /bin/bash
    jenkins@750f43b7e9ec:/$ ls -all /var/jenkins_home/test.txt
    -rw-r--r-- 1 root root 0 Mar 24 06:54 /var/jenkins_home/test.txt
    jenkins@750f43b7e9ec:/$ ls -all /tmp/test.txt
    -rw-r--r-- 1 jenkins jenkins 0 Mar 24 06:54 /tmp/test.txt
    

    Official Jenkins Docker has a solution for it: Copying directories and files those must be under jenkins user’s home to /usr/share/jenkins/ref/. When jenkins container starts, it will check /var/jenkins_home has this reference content, and copy them there if required. (See Installing more tools of official Jenkins Docker documentation).

    $ touch test.txt
    
    $ vi Dockerfile
    --- Dockerfile ---
    FROM jenkins:2.32.3
    
    COPY test.txt /usr/share/jenkins/ref/test.txt
    --- Dockerfile ---
    
    $ docker build -t myjenkins .
    ...
    
    $ docker run -it myjenkins /bin/bash
    jenkins@1e9520a92f8e:/$ ls -all /var/jenkins_home/test.txt
    -rw-r--r-- 1 jenkins jenkins 0 Mar 24 08:21 /var/jenkins_home/test.txt
    

    Now we need to set file’s permission to 600:

    $ touch test.txt
    
    $ vi Dockerfile
    --- Dockerfile ---
    FROM jenkins:2.32.3
    
    COPY test.txt /usr/share/jenkins/ref/test.txt
    
    USER root
    
    RUN chmod 600 /usr/share/jenkins/ref/test.txt
    
    USER jenkins
    --- Dockerfile ---
    
    $ docker build -t myjenkins .
    ...
    
    $ docker run -it myjenkins /bin/bash
    cp: cannot open ‘/usr/share/jenkins/ref/test.txt’ for reading: Permission denied
    

    Strange! The error is thrown by Jenkins’ initialization script: jenkins.sh. The script runs while Jenkins container is starting. What we can do here is changing file permission while container starts instead of changing it in Dockerfile. Then we need an entrypoint script that copies the file to /var/jenkins_home, changes it’s permission and, as a last step, calls jenkins.sh. I created entrypoint.sh based on https://github.com/openfrontier/docker-jenkins/blob/master/entrypoint.sh.

    $ touch test.txt
    
    $ vi entrypoint.sh
    --- enrypoint.sh ---
    #! /bin/bash -e
    
    cp /usr/share/jenkins/ref/test.txt /var/jenkins_home
    chmod 600 /var/jenkins_home/test.txt
    
    echo "start JENKINS"
    # if 'docker run' first argument start with '--' the user is passing jenkins launcher arguments
    if [[ $# -lt 1 ]] || [[ "$1" == "--"* ]]; then
        exec /bin/tini -- /usr/local/bin/jenkins.sh "$@"
    fi
    exec "$@"
    --- enrypoint.sh ---
    
    $ vi Dockerfile
    --- Dockerfile ---
    FROM jenkins:2.32.3
    
    COPY test.txt /usr/share/jenkins/ref/test.txt
    COPY entrypoint.sh /entrypoint.sh
    
    USER root
    
    RUN chown 1000:1000 /entrypoint.sh \
      && chmod +x /entrypoint.sh
    
    USER jenkins
    
    ENTRYPOINT ["/entrypoint.sh"]
    --- Dockerfile ---
    
    
    $ docker build -t myjenkins .
    ...
    
    $ docker run -it myjenkins /bin/bash
    start JENKINS
    jenkins@770ba9099cb4:/$ ls -all /var/jenkins_home/test.txt
    -rw------- 1 jenkins jenkins 0 Mar 24 10:36 /var/jenkins_home/test.txt
    

    Let’s make it for ssh directory having id_rsa and id_rsa.pub files. Note that as directory name I used ssh instead of .ssh. Otherwise content of .ssh would directly be copied to /var/jenkins_home. That is how Docker behaves for directories whose names begin with a dot (e.g. .m2).

    Here is all the necessary steps. You can see that I could successfully open an ssh session from within container:

    $ ls -all
    total 8
    drwxr-xr-x 3 myuser mygroup  54 Mar 24 13:41 .
    drwxr-xr-x 6 myuser mygroup  70 Mar 24 09:54 ..
    -rw-r--r-- 1 myuser mygroup 242 Mar 24 13:35 Dockerfile
    -rw-r--r-- 1 myuser mygroup 338 Mar 24 13:33 entrypoint.sh
    drwx------ 2 myuser mygroup  36 Mar 24 11:24 ssh
    
    $ ls -all ssh/
    total 8
    drwx------ 2 myuser mygroup   36 Mar 24 11:24 .
    drwxr-xr-x 3 myuser mygroup   54 Mar 24 13:41 ..
    -rw------- 1 myuser mygroup 1679 Mar 24 11:23 id_rsa
    -rw-r--r-- 1 myuser mygroup  391 Mar 24 11:23 id_rsa.pub
    
    $ vi entrypoint.sh
    --- enrypoint.sh ---
    #! /bin/bash -e
    
    mkdir -p /var/jenkins_home/.ssh
    mv /usr/share/jenkins/ref/.ssh/id_rsa /var/jenkins_home/.ssh
    chmod 600 /var/jenkins_home/.ssh/id_rsa
    
    echo "start JENKINS"
    # if 'docker run' first argument start with '--' the user is passing jenkins launcher arguments
    if [[ $# -lt 1 ]] || [[ "$1" == "--"* ]]; then
        exec /bin/tini -- /usr/local/bin/jenkins.sh "$@"
    fi
    exec "$@"
    --- enrypoint.sh ---
    
    $ vi Dockerfile
    --- Dockerfile ---
    FROM jenkins:2.32.3
    
    # Copy ssh as .ssh
    COPY ssh/ /usr/share/jenkins/ref/.ssh
    COPY entrypoint.sh /entrypoint.sh
    
    USER root
    
    # Change owner of .ssh directory and files under it to
    # jenkins user's owner (1000:1000) and make sure
    # permisson of id_rsa is not 600.
    RUN chown -R 1000:1000 /usr/share/jenkins/ref/.ssh \
        && chmod 644 /usr/share/jenkins/ref/.ssh/id_rsa
    
    RUN chown 1000:1000 /entrypoint.sh \
        && chmod +x /entrypoint.sh
    
    USER jenkins
    
    ENTRYPOINT ["/entrypoint.sh"]
    --- Dockerfile ---
    
    
    $ docker build -t myjenkins .
    ...
    
    $ docker run -it myjenkins /bin/bash
    jenkins@3090dda362d6:/$ ls -all /var/jenkins_home/.ssh/id_rsa
    -rw------- 1 jenkins jenkins 1679 Mar 24 08:23 /var/jenkins_home/.ssh/id_rsa
    
    jenkins@3090dda362d6:/$ ssh rose1
    The authenticity of host 'rose1 (XX.XX.XX.XX)' can't be established.
    ECDSA key fingerprint is XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX.
    Are you sure you want to continue connecting (yes/no)? yes
    Warning: Permanently added 'rose1,XX.XX.XX.XX' (ECDSA) to the list of known hosts.
    Last login: Thu Mar 23 15:55:41 2017 from 10.74.200.56
    [jenkins@rose1 ~]$
    

    Update 1

    I have uploaded given files to GitHub: https://github.com/kumlali/stackoverflow_answers/tree/master/docker_jenkins_ssh_keys/answer1

    Docker will be the best open platform for developers and sysadmins to build, ship, and run distributed applications.