Jenkins pipeline - ssh to different machine and where to store credentials (using ssh/SSHAgent plugin/etc...) Jenkins pipeline - ssh to different machine and where to store credentials (using ssh/SSHAgent plugin/etc...) jenkins jenkins

Jenkins pipeline - ssh to different machine and where to store credentials (using ssh/SSHAgent plugin/etc...)


So unfortunately, you're right.

It looks like the ssh-agent-plugin only supports stored user,passphrase,public key credentials added through the Credentials Management area in Jenkins. See this unit test that verifies that ssh-agent is working correctly based around a public key. It's unlikely that there is untested functionality in the plugin to support user+password auth.

If you can, make the switch to Public Key based authentication. If for some reason you can't switch ... you COULD install sshpass on your Jenkins box, but this is generally considered bad practice.

node {    stage 'Does sshpass work?'    sh 'sshpass -p \'password\' ssh user@host "ls; hostname; whois google.com;"'}


Stepping up your game running ssh tasks on Jenkins agents, will make your servers more secure. Jenkins is an attack-vector when you run ssh tasks like Ansible, and being in control over releases is desirable.

  • Improving /etc/sshd_config will stop a lot of probes by hackers.

    PasswordAuthentication no

    PubkeyAuthentication yes

    PermitRootLogin no

  • Move over from DSA or RSA key-pairs to the more secure ed25519 elliptic curvecryptography with brute-force protection on the private key-file.

    ssh-keygen -t ed25519 -o -a 300 -C Jenkins

    Because the private key needs hundreds of rounds, each use will take tens of seconds, that is prefect for a build agent where developers might snoop around.

I rather not store the private key as a credential in Jenkins, because Jenkins is a pluggable code execution engine, instead I store only the passphrase as a secret text credential (named mySecretText in the example). I have dedicated agents for environments, each with they own ~/.ssh/id_ed25519 key file with limited blast radius. The passphrase is used to start an ssh-agent, more specifically to load the key per session.

The Jenkinsfile below allows the use of the key-pair to push a tag to git, but there is no plaintext on disk. This implementation was chosen because the ssh-agent plugin did not allow ssh-add.

node {    println("Checkout repository...")    checkout scm}pipeline {    agent {        label "linux"    }    options {        disableConcurrentBuilds()    }    stages {        stage('PushTheTag') {            steps {                script {                    withCredentials([string(credentialsId: 'mySecretText', variable: 'SSH_PASSPHRASE')]) {                        sh "echo 'echo \$SSH_PASSPHRASE' > ~/.ssh/tmp && chmod 700 ~/.ssh/tmp"                        sh "eval `ssh-agent -s` && cat ~/.ssh/id_ed25519|DISPLAY=None SSH_ASKPASS=~/.ssh/tmp ssh-add - && git tag ${env.BUILD_NUMBER} && git push --tags; kill -9 \$SSH_AGENT_PID"                    }                }            }        }    }}


Solution: You want to ssh some machine in your pipeline. I want to offer a different approach, that is more secured (I want to be able managing my ssh credentials on the machine itself) . Make sure that your ssh keys is pre built in your infra under ~/.ssh/id_rsa ( can be preconfigured through ansible/chef/puppet or just use some image snapshot with your aws/gcp/azure cloud environment ). your pipeline should load the ssh private key credentials in the machine and connect to the node (with the public key inside).

_node(with private key) ---> testing/staging/production_node(with public key)

When you use it? Use case for example - you want to run/stop some process in another node, or deploy application on instances x and y in your pipeline

Simple example - Point to Point ( node -> destination_node ) would be:

def ip-address=<some-ip-address> sh """#!/bin/bash        eval "\$(ssh-agent -s)"        ssh-add ~/.ssh/id_rsa        ssh -o StrictHostKeyChecking=no ${ip-address} << 'EOF'        echo 'im in ...' """

Complex example - Bastion using bastion cloud architecture ( node -> vpc-endpoint -> destination-node) would be:

def vpc-endpoint-gw-ip=<some-ip-address>def subnet-ip=<some-subnet-address>sh """#!/bin/bash         eval "\$(ssh-agent -s)"        ssh-add ~/.ssh/id_rsa        ssh -At -o StrictHostKeyChecking=no ${vpc-endpoint-gw-ip} << 'EOF'        ssh -o StrictHostKeyChecking=no ${subnet-ip} << 'EOF2'        echo 'im in ...'  """