gitssh-keyssingularity-containerapptainer

Use SSH key of host during Singularity/Apptainer build


When building a Singularity/Apptainer image from a definition file, is there a portable way to make a SSH key of the host system available during the build?

To give some context:

I have a definition file where in the %post section I'm cloning a private git repository using SSH, i.e.:

git clone git@github.com:luator/private_repo.git

This fails because the SSH keys of the host system are not available in the container during the build.

I could probably copy the key in the container and delete it from there at the end of the build process. However, for this, I would need to hard-code the path to the key in the definition file, which is bad when using the same definition file on another machine where the path is different. Is there a more portable way of making the git clone work during the build?


Solution

  • This answer is based on discussions with drdaved on the Apptainer Slack.

    The way we found to do this was to let the Apptainer build process use the host machine's ssh-agent by setting the SSH_AUTH_SOCK environment variable. That way, if your key is known to the agent on the host, it can be used in the container during build.

    The SSH_AUTH_SOCK on the host must be bound into the container. Check where your SSH_AUTH_SOCK is on the host; if it's in a directory that is already bound into the container during build (e.g. /tmp), you're ready to go. Otherwise, you need to bind it in manually. A common location for the socket is something like /run/user/1000/keyring/ssh, so you could add --bind /run into the container build command.

    The advantage of this method is that the key is at no point copied to the container image. The only information that is stored is the socket that your host machine's ssh-agent was running on. AFAIK this is not a security issue.

    Note that we have to do some mild trickery as environment variables on the host are not passed to the build process, and there is no way of directly setting environment variables in the build command. Hence, we set via --build-arg, and use the build arg in %post to set the environment variable.

    Example test.def file:

    Bootstrap: docker
    From: ubuntu:latest
    
    %post
        apt update
        apt install git -y
    
        export SSH_AUTH_SOCK={{ SSH_AUTH_SOCK }}
        git clone git@github.com:luator/private-repo.git
    

    Build command (if your SSH_AUTH_SOCK will already bound to the container):

    apptainer build --build-arg SSH_AUTH_SOCK=$SSH_AUTH_SOCK test.sif test.def
    

    Build command (if your SSH_AUTH_SOCK will not already bound to the container, and is available at /run/...):

    apptainer build --build-arg SSH_AUTH_SOCK=$SSH_AUTH_SOCK --bind /run test.sif test.def