Reputation: 1056
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
Upvotes: 8
Views: 52264
Reputation: 14527
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 ...'
"""
Upvotes: 0
Reputation: 6812
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"
}
}
}
}
}
}
Upvotes: 0
Reputation: 2060
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;"'
}
Upvotes: 9