Search code examples
gitjenkinssshansiblessh-agent

Public key denied when fetching from Bitbucket in Ansbile with Jenkins


What I am trying to do:

I have an Ansible script which does a git clone from Bitbucket, and I'm running that script from jenkins via the Ansible plugin.

The route:

Jenkins server ---(ansible)---> App server ----(git)---> bitbucket.org

I'm trying to connect to the repo on Bitbucket from the App server, using the ssh private key on the Jenkins server, which should be achievable with the help of ssh-agent.

What's going wrong:

The Ansible script fails connecting to Bitbucket with Public key denied.

What I have checked:

  1. The public key on Jenkins has been added to deploy keys list and it do works without permission problems.
  2. ssh-agent is running on the jenkins node and the private key on jenkins has been added.
  3. AllowFowardAgent has been set to yes on the server.
  4. The ansible plugin for jenkins copies the private key to /tmp and use it when running playbooks. It's not the same file path to what I have ssh-add-ed, but I don't think that's causing the problem.

The Jenkins code

Before running the Ansible task I have the below shell script run first:

eval `ssh-agent -s`
ssh-add ~/.ssh/id_rsa

cat >~/.ssh/config <<EOL
Host *
    ForwardAgent    yes
EOL

cat ~/.ssh/config

git clone git@bitbucket.org:myuser/myrepo.git

The Ansible code

My playbook:

- name: check SSH_AUTH_SOCK
  shell: echo "$SSH_AUTH_SOCK"

- name: check ssh-agent forwarding
  shell: ssh -T git@bitbucket.org

My ansible.cfg:

[ssh_connection]
ssh_args = -o ForwardAgent=yes -o StrictHostKeyChecking=no -C -o ControlMaster=auto -o ControlPersist=60s

The output

In my Ansible script I can see that SSH_AUTH_SOCK is set:

11:29:04 changed: [testserver] => {"changed": true, "cmd": "echo \"$SSH_AUTH_SOCK\"", "delta": "0:00:00.007881", "end": "2016-09-06 11:29:04.576963", "invocation": {"module_args": {"_raw_params": "echo \"$SSH_AUTH_SOCK\"", "_uses_shell": true, "chdir": null, "creates": null, "executable": null, "removes": null, "warn": true}, "module_name": "command"}, "rc": 0, "start": "2016-09-06 11:29:04.569082", "stderr": "", "stdout": "/tmp/ssh-WnmHgtzMBS/agent.13630", "stdout_lines": ["/tmp/ssh-WnmHgtzMBS/agent.13630"], "warnings": []}

But ssh -T git@bitbucket.org fails:

11:29:09 fatal: [testserver]: FAILED! => {"changed": true, "cmd": "ssh -T git@bitbucket.org", "delta": "0:00:05.009720", "end": "2016-09-06 11:29:09.879430", "failed": true, "invocation": {"module_args": {"_raw_params": "ssh -T git@bitbucket.org", "_uses_shell": true, "chdir": null, "creates": null, "executable": null, "removes": null, "warn": true}, "module_name": "command"}, "rc": 255, "start": "2016-09-06 11:29:04.869710", "stderr": "Error reading response length from authentication socket.\r\nPermission denied (publickey).", "stdout": "", "stdout_lines": [], "warnings": []}

Solution

  • When you execute ssh-agent -s it outputs a series of environment variables which are required for agent forwarding feature of SSH, for example:

    SSH_AUTH_SOCK=/var/folders/nw/2vnhg_gj77v_cyfv0p1vdfj80000gn/T//ssh-alCh0yLKdoci/agent.53532; export SSH_AUTH_SOCK; SSH_AGENT_PID=53533; export SSH_AGENT_PID; echo Agent pid 53533;
    

    When you run it through eval these commands get executed in the current shell session and you can see the output of the last one (echo):

    Agent pid 53533
    

    The environment variables however are set for the current process and subprocesses. If you call Ansible playbook from a different process, they won't be seen.

    As you already figured out, the SSH Agent Plugin for Jenkins takes care so that other processes (like Ansible plugin) will inherit these environment variables.