skip to Main Content

I have a docker container where I need to run some commands. Usually, I do this manually by running the following commands:

host> docker exec -it my-container bash
container> eval $(ssh-agent)
container> ssh-add ~/.ssh/my-key
<TYPE PASSPHRASE!!!>
container> pytest

I’ve tried to call docker exec -it from the subprocess, but I couldn’t mimic the same behavior as the manual workflow. I can’t send commands one by one, as the ssh key is loaded only for the current session, if I run it non-interactively I can’t use the key.

I have two problems – I need to type passphrase via stdin (I don’t see a way to provide it together with ssh-add), and I want to know when pytest will exit and the return code.

What is the most seamless way to achieve that? I’d prefer to avoid installing additional dependencies, but if it’s necessary then I can use something.

3

Answers


  1. You have to run this command instead to avoid typing the password

    sshpass -p [PASSWORD] ssh [USER]@172.17.0.2
    
    Login or Signup to reply.
  2. The ssh-agent listens on a Unix socket; its location is in the $SSH_AUTH_SOCK environment variable. You can use a Docker bind mount (docker run -v option) to inject this socket into the container. Then when you run ssh-add on the host, provided the socket is accessible and the environment variable is set correctly on the host, the container can access the credentials in the agent.

    I would not use docker exec here. A container generally runs some single command; say in your case that your container is running a Flask or Django application. You wouldn’t normally "go inside" the Django application while it’s running to run its unit tests inside the server. A separate container and a separate process makes more sense.

    The invocation I might use here would look something a little more like:

    eval $(ssh-agent)                           # if not already done on login
    ssh-add                                     # if not already done on login
    docker run 
      --rm                                     # delete temporary test container when done
      -v "$SSH_AUTH_SOCK:/tmp/ssh-auth.sock"   # mount ssh socket into container
      -e SSH_AUTH_SOCK=/tmp/ssh-auth.sock      # set socket location to mounted socket
      -u $(id -u)                              # run as host user (with permissions on the socket)
      your-image 
      pytest                                    # override command to run in container
    

    I would be surprised to see unit tests that actually depended on access to particular ssh credentials; you also may find it easier to restructure your tests to mock service clients that need these credentials, or to run these tests in a Python virtual environment on the host before you build a Docker image at all.

    Login or Signup to reply.
  3. I have found expect (or in the case of python, pexpect) to be very helpful in situations where you are stuck with having to supply user input. Here’s a simple script to execute your example (admittedly, there are additional dependencies):

    #!/usr/bin/env python
    import pexpect
    from getpass import getpass
    
    prompt = ">"
    child = pexpect.spawn ('docker exec -it my-container bash'))  
    child.expect (prompt)
    child.sendline ('eval $(ssh-agent)')
    child.expect (prompt)
    child.sendline ('ssh-add ~/.ssh/my-key')
    child.expect ('Enter passphrase for /root/.ssh/my-key:')
    password = getpass( prompt="Private Key Password:")
    child.sendline (password)
    child.expect (prompt)
    child.sendline ("pytest")
    

    I took the example from https://pexpect.readthedocs.io/en/stable/overview.html and put in your commands.

    A note on the prompt. When I tested the code above, my bash shell in my container had a ‘$’ prompt. I think that I was lucky that ‘$’ worked for me, since it’s basically a valid regex. Your mileage may vary with the ‘>’ prompt, but you may also want to pay attention to the information regarding CR/LF on the same page mentioned above.

    I assume that when you launched the container, you mounted your ~/.ssh directory. When I launched my container to verify the code above, I added the mount option: -v ~/.ssh:/root/.ssh

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search