Best way to clone a git repository when authenticating via ssh key forwarding
<p>Prerequisites:</p>

<ul>
<li>Host &amp; git authentication happens via ssh key</li>
<li>ssh key forwarding is enabled</li>
<li>Every user of our team uses a dedicated user account - it is not possible to log in via headless user account</li>
</ul>

<p>Now we want to deploy an application from a git repository. This should be simple but it's not.</p>

<pre><code>- 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
</code></pre>

<p><sup><sub><em>githost</em> is an entry in our .ssh/config</sub></sup></p>

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

<ul>
<li>All files should be owned by a headless user, let's call him <code>zaphod</code></li>
<li>Only <code>zaphod</code> is allowed to <strong>read</strong> the files. We're talking about 0600/0700 permissions.</li>
</ul>

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

<pre><code>- 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
</code></pre>

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

<pre><code>- 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
</code></pre>

<p>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.</p>

<p>We have a very ugly solution:</p>

<ul>
<li>Clone into /tmp/foo</li>
<li>Fix ownership of /tmp/foo</li>
<li><code>rm -rf /some/location</code></li>
<li><code>mv /tmp/foo /some/location</code></li>
<li>Finally (re)start application</li>
</ul>

<p>The problem with this is that this would:</p>

<ul>
<li>Trigger a restart every single time the playbook is executed</li>
<li>The Ansible summary shows 5 changed tasks, even though nothing happened - except the restart which was not required in the first place</li>
</ul>

<p>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 <code>zaphod</code> - but <code>zaphod</code> himself is not able to clone the repo. So there has to be some manipulation is some form resulting in changes.</p>

<p>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...</p>

<p>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. ;-)</p>