Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read Jenkins credentials at Folder level

I am trying to migrate credentials from Jenkins to another credentials store.

I want to read the credentials from the Jenkins store, and have found this script (https://github.com/tkrzeminski/jenkins-groovy-scripts/blob/master/show-all-credentials.groovy

The script does the job OK for SystemCredentialsProvider credentials for the global domain at root level.

But my credentials are stored in a Folder, so the script does not work for me.

I am using the Jenkins script console to execute the script.

If I navigate to the Jenkins Credentials configuration page and hover over the icon for one of my credential entries, the tooltip says "Folder Credentials Provider".

====================================================

Question: How do I read all of the the credentials from a Folder in Jenkins?

====================================================

Please see script, below:

import jenkins.model.*
import com.cloudbees.plugins.credentials.*
import com.cloudbees.plugins.credentials.impl.*
import com.cloudbees.plugins.credentials.domains.*
import com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey
import com.cloudbees.jenkins.plugins.awscredentials.AWSCredentialsImpl
import org.jenkinsci.plugins.plaincredentials.StringCredentials
import org.jenkinsci.plugins.plaincredentials.impl.FileCredentialsImpl

def showRow = { credentialType, secretId, username = null, password = null, description = null ->
  println("${credentialType} : ".padLeft(20) + secretId?.padRight(38)+" | " +username?.padRight(20)+" | " +password?.padRight(40) + " | " +description)
}

// set Credentials domain name (null means is it global)
domainName = null

credentialsStore = Jenkins.instance.getExtensionList('com.cloudbees.plugins.credentials.SystemCredentialsProvider')[0]?.getStore()
domain = new Domain(domainName, null, Collections.<DomainSpecification>emptyList())

credentialsStore?.getCredentials(domain).each{
  if(it instanceof UsernamePasswordCredentialsImpl)
    showRow("user/password", it.id, it.username, it.password?.getPlainText(), it.description)
  else if(it instanceof BasicSSHUserPrivateKey)
    showRow("ssh priv key", it.id, it.passphrase?.getPlainText(), it.privateKeySource?.getPrivateKey(), it.description)
  else if(it instanceof AWSCredentialsImpl)
    showRow("aws", it.id, it.accessKey, it.secretKey?.getPlainText(), it.description)
  else if(it instanceof StringCredentials)
    showRow("secret text", it.id, it.secret?.getPlainText(), '', it.description)
  else if(it instanceof FileCredentialsImpl)
    showRow("secret file", it.id, it.content?.text, '', it.description)
  else
    showRow("something else", it.id, '', '', '')
}

return
like image 268
Banoona Avatar asked Jul 19 '19 07:07

Banoona


People also ask

Where is Jenkins credentials stored?

Jenkins uses AES to encrypt and protect secrets, credentials, and their respective encryption keys. These encryption keys are stored in $JENKINS_HOME/secrets/ along with the master key used to protect said keys.

How do I find my Jenkins credential password?

To retrieve Jenkins credentials, you should import cloudbees credentials specific libraries. And use the lookupCredentials function to get all the credentials stored in Jenkins. Here is the full groovy script to list all the Jenkins credentials. You can test this script using the Jenkins script console.


2 Answers

i simply created a Java class to retrieve the credentials from either global or folder scope:

import com.cloudbees.plugins.credentials.CredentialsProvider;
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
import com.cloudbees.hudson.plugins.folder.Folder

class JenkinsCredentials
{
    /**
    * this method gets a 'StandardUsernamePasswordCredentials' for a userName, the 'StandardUsernamePasswordCredentials' object
    * have 2 fields - user and password, which can be used to login to other systems,
    * the username is searched for first in the global jenkins level, and if not found then it is searched at the folder level
     */
    public static StandardUsernamePasswordCredentials getCredentialsByUsername(String userName, String fromFolder) throws Exception
    {
        List credsList = CredentialsProvider.lookupCredentials(StandardUsernamePasswordCredentials.class, Jenkins.getInstance());
        if(credsList == null || credsList.size() == 0)
        {
            credsList = getFolderLevelCredentialsList(fromFolder);
        }
        return credsList.findResult { it.username == userName ? it : null };
    }

    /**
    * this method gets a 'StandardUsernamePasswordCredentials' for a userID, the 'StandardUsernamePasswordCredentials' object
    * have 2 fields - user and password, which can be used to login to other systems,
    * the userID is searched for first in the global jenkins level, and if not found then it is searched at the folder level
     */
    public static StandardUsernamePasswordCredentials getCredentialsByID(String userID, String fromFolder) throws Exception
    {
        List credsList = CredentialsProvider.lookupCredentials(StandardUsernamePasswordCredentials.class, Jenkins.getInstance());
        if(credsList == null || credsList.size() == 0)
        {
            credsList = getFolderLevelCredentialsList(fromFolder);
        }
        return credsList.findResult { it.id == userID ? it : null };
    }

    /**
    * this method gets a 'StandardUsernamePasswordCredentials' for a userName, the 'StandardUsernamePasswordCredentials' object
    * have 2 fields - user and password, which can be used to login to other systems,
    * the username is searched for at the folder level who's name we provided as 'fromFolder'
     */
    public static StandardUsernamePasswordCredentials getFolderCredentialsByUsername(String userName, String fromFolder) throws Exception
    {
        List credsList = getFolderLevelCredentialsList(fromFolder);
        return credsList.findResult { it.username == userName ? it : null };
    }

    /**
    * this method gets a 'StandardUsernamePasswordCredentials' for a userID, the 'StandardUsernamePasswordCredentials' object
    * have 2 fields - user and password, which can be used to login to other systems,
    * the userID is searched for at the folder level who's name we provided as 'fromFolder'
    */
    public static StandardUsernamePasswordCredentials getFolderCredentialsByID(String userID, String fromFolder) throws Exception
    {
        List credsList = getFolderLevelCredentialsList(fromFolder);
        return credsList.findResult { it.id == userID ? it : null };
    }

    /**
    * this method gets a list of credentials set at a folder level, the method receives the folder name to get the credentials from
     */
    public static List getFolderLevelCredentialsList(String folderName)
    {
        return CredentialsProvider.lookupCredentials(StandardUsernamePasswordCredentials.class, getFolderItem(folderName));
    }

    /**
    * this method fetch a 'Folder' item from jenkins instance by a folder name
    * it then can be used in the other methods to search for a user credentials at that folder level
     */
    public static Folder getFolderItem(String folderName)
    {
        def allJenkinsItems = Jenkins.getInstance().getItems();
        for (currentJenkinsItem in allJenkinsItems)
        {
            if(currentJenkinsItem instanceof Folder)
            {
                if(((Folder)currentJenkinsItem).getFullName().contains(folderName))
                {
                    return (Folder)currentJenkinsItem;
                }
            }
        }

    }
}

then you can use it like this:

get credentials for userName 'shay bc' from folder named 'MyJenkinsFolder':

// get the credentials
StandardUsernamePasswordCredentials shaybcCredentials = JenkinsCredentials.getFolderCredentialsByUsername("shay bc", "MyJenkinsFolder")

// login to some system using the credentials
sshSession.login(shaybcCredentials.getUsername(), shaybcCredentials.getPassword())

get credentials for userID 'sbc' from folder named 'MyJenkinsFolder':

// get the credentials
StandardUsernamePasswordCredentials sbcCredentials = JenkinsCredentials.getFolderCredentialsByID("sbc", "MyJenkinsFolder")

// login to some system using the credentials
sshSession.login(sbcCredentials.getUsername(), sbcCredentials.getPassword())
like image 58
Shaybc Avatar answered Sep 18 '22 01:09

Shaybc


The class shared by @Shaybc was most of the solution, and although a commenter suggested it was not a complete solution by itself, I was able to guess how to implement it correctly into such a complete solution in my own Groovy script.

The Folder returned by JenkinsCredentials.getFolderItem('foldername') is taking the same string slug as your folder is addressed by in Jenkins. So if you have a folder with a descriptive name, and a slug, like "Folder Name" and "foldername", the right string to use to retrieve the folder itself is "foldername".

The example provided here shows how to retrieve credentials from the global store, this is Jenkins.instance – for complete documentation the script they provide is copied here:

import jenkins.*
import jenkins.model.* 
import hudson.*
import hudson.model.*
def jenkinsCredentials = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
        com.cloudbees.plugins.credentials.Credentials.class,
        Jenkins.instance,
        null,
        null
);
for (creds in jenkinsCredentials) {
    println(jenkinsCredentials.id)
    }

So, start your script by defining class JenkinsCredentials as @Shaybc described, then instead of calling CredentialsProvider.lookupCredentials with Jenkins.instance, retrieve the folder and pass it in there instead.

My folder was called "ft" and (skipping over the import/boilerplate at the top and the definition of JenkinsCredentials helper class,) the remainder of my invocation in the Groovy script looked like:

def folder = JenkinsCredentials.getFolderItem('ft');

def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
        com.cloudbees.plugins.credentials.Credentials.class,
        folder,
        null,
        null
);
for (c in creds) {
    println(c.id + ": " + c.description)
}

Hope this helped someone! and by the way, if your credentials are stored in a file instead of a string, you have one more step... the file will not have any useful content in the "description" attribute, you need the byte stream stored at c.getContent()

So, that final loop with some metaprogramming to dynamically check for the availability of a getContent() method to call:

for (c in creds) {
 if (c.metaClass.respondsTo(c, 'getContent')) {
  println(
   IOUtils.toString(c.getContent(), StandardCharsets.UTF_8)
  )
 }
 println(c.id + ": " + c.description)
}

That last part was borrowed from this answer, which shows as well how you can import StandardCharsets and IOUtils: https://stackoverflow.com/a/42360792/661659

like image 24
Kingdon Avatar answered Sep 20 '22 01:09

Kingdon