Trying to put together a sample project cloning a repository (hosted in GOGS) using SSH and am getting the following error:
Failed to start SSH session: Unable to exchange encryption keys
I'm on windows, the keys are generated using ssh-keygen, and I have the following nuget packages referenced
LibGit2Sharp 0.25.3
LibGit2Sharp.NativeBinaries 1.0.235
LibGit2Sharp-SSH 1.0.22
LibGit2Sharp-SSH.NativeBinaries 1.0.14
We're able to pull files from a test bit bucket account, but not from the GOGS repository url, using code like the following (the same keys have been uploaded to both accounts).
var co = new CloneOptions
{
CredentialsProvider = (_url, _user, _cred) => new SshUserKeyCredentials()
{
PrivateKey = #"C:\Users\username\.ssh\keygen\gen",
PublicKey = #"C:\Users\username\.ssh\keygen\gen.pub",
Passphrase = string.Empty,
Username = "git"
},
};
Repository.Clone("ssh://git#<site_url>:443/Project/Project.git ", TestPath, co);
I'd also add that we can clone from both urls using a variety of git clients (git exe, tortoise git, gitkraken) without issue. Also we can connect over https with username and password with LibGit2Sharp.
Things I've tried so far:
Generating new keys with ssh-keygen
Converting the private key file to openssh using puttygen > Conversions > Export OpenSSH
Converting the private key to PEM format using "openssl rsa -in key-out key.pem"
Made sure that the Public key was single line, starting with type, followed by base64 key, no comment at the end
Related
Basically, I am trying to create a credential on jenkins via Rest API. Using xml data below:
<?xml version='1.0' encoding='UTF-8'?>
<com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey>
<scope>GLOBAL</scope>
<id>jenkins-github-ssh</id>
<description>jenkins-github-ssh</description>
<username>username</username>
<directEntryPrivateKeySource>
<privateKey>-----BEGIN OPENSSH PRIVATE KEY-----
*****************************************
-----END OPENSSH PRIVATE KEY-----</privateKey>
</directEntryPrivateKeySource>
</com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey>
I can see the credential after calling REST post request. But when I use this credential for a GitHub repository, Jenkins says:
Failed to connect to repository : Command "git ls-remote -h -- git#github.com:***.git HEAD" returned status code 128:
stdout:
stderr: Load key "/tmp/ssh3978703187838467164.key": invalid format
git#github.com: Permission denied (publickey).
fatal: Could not read from remote repository.
But If I update the credential which is created by rest api with same private key above manually. It works. Somehow key is broken while posting. Do you guys have any idea to point me the solution?
Jenkins 2.198 & SSH Credentials Plugin 1.17.3
Thanks
I faced exactly the same problem while pushing private SSH keys to Jenkins by a Python script. I'm using the Requests library to create and update SSH key credential sets in arbitrary credential stores on the Jenkins server.
The general problem is that your XML structure is partially wrong. The tag
<directEntryPrivateKeySource>
must be replaced by
<privateKeySource class="com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey$DirectEntryPrivateKeySource">
Getting the basic XML structure
You can get the correct XML structure by yourself from the Jenkins server when you follow these steps:
Create a SSH key credential item manually. In the example below the key's id is test-sshkey. Let's place it in a credential store which is located in the folder "API-Test" which is a subfolder of "Playground", i.e. Playground/API-Test.
When you click on the newly created credential item in the Jenkins UI its URL should look like this:
https://JENKINS_HOSTNAME/job/Playground/job/API-Test/credentials/store/folder/domain/_/credential/test-sshkey/
Add /config.xml to the URL above so that it looks like this:
https://JENKINS_HOSTNAME/job/Playground/job/API-Test/credentials/store/folder/domain/_/credential/test-sshkey/config.xml
The XML structure returned by the URL in step 3 has almost the structure that we need for using with the Credentials API but is partially incomplete:
<com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey plugin="ssh-credentials#1.18.1">
<id>test-sshkey</id>
<description>DELETE AFTER USE</description>
<username>test</username>
<privateKeySource class="com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey$DirectEntryPrivateKeySource">
<privateKey>
<secret-redacted/>
</privateKey>
</privateKeySource>
</com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey>
Using the Credentials API
Add the tags <scope> and <passphrase> for a valid XML scaffold that you can POST to the Credentials API:
<com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey>
<scope>GLOBAL</scope>
<id>CREDENTIAL_ID</id>
<description>MY_DESCRIPTION</description>
<username>A_USERNAME</username>
<passphrase>OPTIONAL_KEY_PASSWORD</passphrase>
<privateKeySource class="com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey$DirectEntryPrivateKeySource">
<privateKey>YOUR_PRIVATE_SSH_KEY_GOES_HERE</privateKey>
</privateKeySource>
</com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey>
Caveat: If the submitted XML has a wrong structure the REST API of the Credentials Plugin will nevertheless accept it and return a misleading HTTP status code 200!
Now we can use this XML structure to POST it to the API endpoints for creating or updating by cURL or similar tools. We assume that all operations are executed in the credential store of the folder "Playground/API-Test".
The following code example in Python is "dumbed down" completely to focus on the general approach:
def addCredentialSetSshPrivateKey(self, credentialDataObj):
"""
Adds a credential set with a private SSH key to a credential store
credentialDataObj: An instance of a simple DTO
"""
jenkinsRequestUrl = "https://ci-yoda-new.codemanufaktur.com/job/Playground/job/API-Test/credentials/store/folder/domain/_/createCredentials"
authentication = ("jenkins_admin_user", "API-TOKEN_FOR_THE_USER")
completeSamlData = """
<com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey>
<scope>GLOBAL</scope>
<id>{0}</id>
<description>{1}</description>
<username>{2}</username>
<passphrase>{3}</passphrase>
<privateKeySource class="com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey$DirectEntryPrivateKeySource">
<privateKey>{4}</privateKey>
</privateKeySource>
</com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey>
""".format(credentialDataObj.id(), credentialDataObj.description(), credentialDataObj.username(), credentialDataObj.key_passphrase(), credentialDataObj.private_ssh_key())
# When using CSRF protection in Jenkins a API crumb must be included in the actual REST call.
# The following method requests the Jenkins Crumb Issuer for a API crumb and returns a JSON object like this:
# {'_class': 'hudson.security.csrf.DefaultCrumbIssuer', 'crumb': 'a5d36ef09e063322169888f0b81341fe13b4109482a7936bc08c6f9a01badd39', 'crumbRequestField': 'Jenkins-Crumb'}
jsonCrumb = self._requestApiCrumb()
# The actual REST call with headers, XML payload and all other bells and whistles.
remoteSession = requests.Session()
return remoteSession.post(jenkinsRequestUrl, auth = authentication, headers = {"content-type":"application/xml", jsonCrumb['crumbRequestField']:jsonCrumb['crumb']}, data = completeSamlData)
REST endpoint for creating a SSH credential item:
https://JENKINS_HOSTNAME/job/Playground/job/API-Test/credentials/store/folder/domain/_/createCredentials
REST endpoint for updating a SSH credential item:
https://ci-yoda-new.codemanufaktur.com/job/Playground/job/API-Test/credentials/store/folder/domain/_/credential/credential_ci-yoda-new-project-apex_privatekey/config.xml
Apparently in the latter case you just update the config.xml file of an existing credential item.
Also see the user guide for the Credentials Plugin, section REST API, expecially for constructing the correct REST URLs. For requesting the Jenkins crumb issuer with Python see this StackOverflow answer.
Solution tested with:
Jenkins 2.214
Credentials Plugin 2.3.1
SSH Credentials Plugin 1.18.1
For the people who are having the exact same problem;
I've tried uploading it as a file, uploading it with API, using jenkins CLI, etc. Everything I tried has failed. Same issue is alsoposted in here;
https://issues.jenkins.io/browse/JENKINS-60714
So steps that finally worked is explained as follows;
Install and configure the Jenkins Configuration as Code Plugin.
Upload your configuration similar to yaml file below.
You might also want to define the private key content as an environment variable in the Jenkins instance and use it as "${private_key}" instead of pasting it visibly.
jenkins:
systemMessage: "Example of configuring credentials in Jenkins"
credentials:
system:
domainCredentials:
- credentials:
- basicSSHUserPrivateKey:
description: "kro"
id: "kro"
scope: GLOBAL
username: "kro"
privateKeySource:
directEntry:
privateKey: |
-----BEGIN RSA PRIVATE KEY-----
MIIG5AIBAAKCAYEAvuiaIDs+ydzR7Xxo5Owvv+G9/arbqN0YwhaGQQlicJjM4ZvI
..........YOUR KEY.............
53Zg4QmSb1XGKUTXxIeGd27OIvgkwAn7K/cjQsU9t802iYV3tisnfA==
-----END RSA PRIVATE KEY-----
I need to perform a check on the SSH Credentials in a Jenkins server against some of our accounts in GitHub.
Now, using the GitHub API, I can pull a list of pubkeys associated to an account.
Using com.cloudbees.plugins.credentials I can dump the credentials in the Jenkins server. For SSH Credentials, I only get the Private Key (and its password), but neither the Public Key nor Keysig is available.
Is there a way to get SSH Public Key and/or SSH Key Signature from the retrieved Private Key?
Once you got the private keys from jenkins using the com.cloudbees.plugins.credentials, you can generate the the public key associated to each one using the next commands:
For example:
ssh-keygen -e -f private_key > private_key.pub
You can also identify the user in GitHub using the private key by executing:
ssh -i /path/to/private_key -T git#github.com
Cheers
I Have installed 'Publish Over SSH' plugin in Jenkins and would like to transfer few files to SSH Server after each Build .
I have generated the private key using puttygen with passphrase and have given the OpenSSH Public Key in 'authorization_keys' in SSH Server.
Using the generated private key and passphrase , I'm able to login to the SSH Server through PuTTY.
But in Jenkins I'm not able to add the SSH Key. Getting the below Error.
jenkins.plugins.publish_over.BapPublisherException: Failed to add SSH key. Message [The cipher 'aes256-cbc' is required, but it is not available.
Most of the tools (including Jenkins) support keys in OpenSSH format (generated using ssh-keygen), not in the PuTTY format (generated using PuTTYgen). Generate a new key using ssh-keygen or convert the PPK to OpenSSH format.
I wrote the following information in the SO Documentation.
Convert PPK (PuTTY key) to OpenSSH format
You might receive from your peer private key in PPK format, which seems it does not work in OpenSSH (command-line ssh). The client will be asking for the passphrase, because of OpenSSH bug.
$ ssh -i mykey.ppk example.com
Enter passphrase for mykey.ppk:
You need to convert the key to OpenSSH format using PuTTYgen (command-line version):
puttygen mykey.ppk -o mykey.key -O private-openssh
Or in GUI version:
Open PuttyGen
Click Load
Load your private key
Go to Conversions->Export OpenSSH and export your private key
Copy your private key to ~/.ssh/id_rsa
Source: SO answer, Unix SE answer
I've checked several threads regarding CLI access:
Jenkins CLI Authentication
Using the jenkins CLI (on fedora 23)
Jenkins CLI connection refused
And unfortunately it's not my case.
I'm trying to run the following command:
java.exe -jar jenkins-cli.jar -i C:\Users\myuser\.ssh\id_rsa -s http://MasterJenkins:port/ list-jobs All
And I'm getting the following execption:
Exception in thread "main" java.io.EOFException
at java.io.DataInputStream.readBoolean(DataInputStream.java:244)
at hudson.cli.Connection.readBoolean(Connection.java:93)
at hudson.cli.CLI.authenticate(CLI.java:565)
at hudson.cli.CLI._main(CLI.java:476)
at hudson.cli.CLI.main(CLI.java:387)
Going to : http://MasterJenkins:port/me/configure I made sure that the "SSH Public Keys" section is the same key I have in my public key. I was a month abroad, before leaving it worked, now it doesn't and my team member swears nothing changed in the system.
Any ideas?
I had a similar issue last week with my own ssh private/public key.
I fixed it by
Generating a new public/private key combination using ssh-keygen
bash-4.1$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/users/xxxxx/.ssh/id_rsa): JenkinsCLI
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in JenkinsCLI.
Your public key has been saved in JenkinsCLI.pub.
The key fingerprint is:
f6:4c:be:fc:cb:cd:d3:ee:8c:80:26:a2:57:df:67:14 xxxxx#eeeee
The key's randomart image is:
+--[ RSA 2048]----+
Private file
Copy and paste the content of JenkinsCLI in your .private file
Public file
log into Jenkins>Click your Login id dropdown>Configure>SSH Public Keys
copy and paste the content of JenkinsCLI.pub file into SSH Public Keys text area
You should be able to authenticate.
I'm expericing the following error when trying to use the Publish Over SSH plugin to jenkins when using a different key.
jenkins.plugins.publish_over.BapPublisherException: Failed to add SSH key. Message [invalid privatekey: TheKey]
I've tried different alternatives of using the path to key and the key field itself.
Has anyone experienced / solved this issue?
If someone came across this type of error.
Jenkins "Publish Over SSH plugin" accept private key in OpenSSH format format.
Please use below steps, to convert private key in OpenSSH format.
Using Putty gen.
Open PuttyGen
Click Load
Load your private key (Enter passphrase if required)
Go to Conversions->Export OpenSSH and export your private key
Copy and paste the private key into the Key section of Jenkins SSH Server.
Enter Passphrase.
Click on "Test Configuration" button, "Success" :)
In your path (to the key), do you have both public and private keys in this folder?
I think It's mandatory when you pair 2 machines.
Since you are using a different key, you will have a public and private key pair. The public key has to be added to the target server autorized_keys file with in the <$HOME user>/.ssh/ and the private key has to configured in the Jenkins either using the path to key and the key field itself.