Best way to clone a git repository when authenticating via ssh key forwarding

Prerequisites:

  • Host & git authentication happens via ssh key
  • ssh key forwarding is enabled
  • Every user of our team uses a dedicated user account – it is not possible to log in via headless user account

Now we want to deploy an application from a git repository. This should be simple but it’s not.

  • creating jenkins jobs with ansible
  • Pip install of a specific git commit failing via Ansible Playbook
  • Unable to install git and related plugins in Jenkins using Ansible
  • Ansible: how to run task on other host inside one playbook?
  • Triggering Jenkins to run application tests when GitHub PR is created
  • The best way to apply a git patch via Ansible
  • - name: Clone app repo
      git:
        repo: githost:org/repo.git
        dest: /some/location
        version: HEAD
        force: yes
        ssh_opts: -o StrictHostKeyChecking=no
      notify:
        - Restart app
    

    githost is an entry in our .ssh/config

    This above task works. But the repository is (of course) cloned as the user who executed the playbook. What we need instead is:

    • All files should be owned by a headless user, let’s call him zaphod
    • Only zaphod is allowed to read the files. We’re talking about 0600/0700 permissions.

    The following task will not work, because by using become we will lose the forwarded ssh key and therefore git authentication will fail:

    - name: Clone app repo
      git:
        repo: githost:org/repo.git
        dest: /some/location
        version: HEAD
        force: yes
        ssh_opts: -o StrictHostKeyChecking=no
      notify:
        - Restart app
      become: yes
      become_user: zaphod
    

    The following variation would first call a handler which changes ownership of the checkout before (re)starting the application:

    - name: Clone app repo
      git:
        repo: githost:org/repo.git
        dest: /some/location
        version: HEAD
        force: yes
        ssh_opts: -o StrictHostKeyChecking=no
      notify:
        - Fix ownership
        - Restart app
    

    This works once. But if you run the playbook a 2nd time the git task fails because the user who runs the play does not have permissions to modify the clone.

    We have a very ugly solution:

    • Clone into /tmp/foo
    • Fix ownership of /tmp/foo
    • rm -rf /some/location
    • mv /tmp/foo /some/location
    • Finally (re)start application

    The problem with this is that this would:

    • Trigger a restart every single time the playbook is executed
    • The Ansible summary shows 5 changed tasks, even though nothing happened – except the restart which was not required in the first place

    I’m a bit picky here, but I do only want to have changed states if something really changed, so in a perfect world not even the git task would have a changed state. And for this I do not see a solution. Because we require that the cloned files are only accessible by zaphod – but zaphod himself is not able to clone the repo. So there has to be some manipulation is some form resulting in changes.

    Any suggestions how this can be improved in a clean way? I don’t want to add another 20 tasks shuffling around with temporary copies, temporarily changing permissions, comparing files manually and so forth…

    Of course a custom written module would be able to deal with all this – but I’m more interested in something that does not take 2 days in development and battle testing. 😉

  • How many lines of code differs between two commits?
  • What's the difference between “squash” and “fixup” in Git/Git Extension?
  • Git branch diverged after rebase
  • Git: merge conflict and commit message
  • using git to keep exes and dlls?
  • Avoid Christmas tree in Git log --all
  • One Solution collect form web for “Best way to clone a git repository when authenticating via ssh key forwarding”

    It looks like you’re trying to deploy an application/webpage by simply cloning the repo containing the stuff you need rather than needing to be able to then push any changes back to the repo from that server.

    If that’s the case then you could get away with a local task to git archive the repo into a tarball or something and then use unarchive to copy the resulting archive to the target machine and unpack it. unarchive will allow you to set the permissions and ownership.

    So your play could look something like:

    - name: locally clone repo
      git:
        repo: githost:org/repo.git
        dest: /some/tmp/location
        version: HEAD
        force: yes
      delegate_to: localhost
      changed_when: false #
    
    - name: archive app repo
      command: git archive --format zip --output /path/to/archive master
        chdir: /some/tmp/location
      delegate_to: localhost
      changed_when: false
    
    - name: unarchive app repo
      unarchive:
        src: /path/to/archive
        dest: /some/location
        owner: zaphod
        mode: 0700
        creates: /some/location
      notify:
        - Restart app
    
    Git Baby is a git and github fan, let's start git clone.