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

3

8

TLDR: how to ssh a different machine and where to store ssh credentials on Jenkins pipeline (using ssh / SSHAgent plugin /etc...) ?

The Problem: In Jenkins pipeline I need a remote ssh to target machine. My old approach was to use "Execute shell scripts on remote host using ssh". I would like to specify both username and password.

I've read that the groovy approach shoud be something like

sshagent(['RemoteCredentials']) {
    sh 'ssh -o StrictHostKeyChecking=no -l remoteusername remotetarget uname -a'
  }

RemoteCredentials: it is the private key with passphrase

Is there a way to make ssh with username/password remote credentials? The sshagent does not support username/password auth

Riccardo

Prelect answered 14/6, 2016 at 7:42 Comment(2)
Check this #29746813Equiangular
you can refer this ssh with user/password jenkins.io/blog/2019/02/06/ssh-steps-for-jenkins-pipeline sshCommand remote: remote, command: 'for i in {1..5}; do echo -n \"Loop \$i \"; date ; sleep 1; done'Mackinaw
L
9

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;"'
}
Litterbug answered 12/7, 2016 at 15:9 Comment(1)
Even if you are using this approach, remember to use at least withCredentials to not expose the password in the Jenkinsfile.Edward
E
0

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 curve cryptography 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"
                    }
                }
            }
        }
    }
}
Elamitic answered 13/1, 2020 at 15:29 Comment(0)
G
0

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 ...'
  """
Griffe answered 3/1, 2021 at 15:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.