jenkinscredentials

Problem accessing user-specific credentials with withCredentials binding in Jenkins


I have been pulling my hair out for the last couple of days with this.. I know there is a Jenkins bug that may affect this... but really, this hasn't been fixed since 2017??

Also, this worked before, a few months ago, and now it's broken, so I assume either a recent update broke it again, or some conditions/changes on the system broke it and I'm not realizing the connection.

I have the latest stable Jenkins running on Ubuntu on a cloud instance. All plugins are current. I have global credentials and user-specific credentials defined. Logged in as a user who has the user-specific credentials.

Then I try this:

pipeline {
    agent any
    parameters {
        credentials(
            name: 'USER_CREDENTIALS',
            description: 'Select your personal username and password credentials.',
            credentialType: 'com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl',            required: true
        )
    }
    stages {
        stage('Test User Credentials') {
            steps {
                script {
                    withCredentials([usernamePassword(credentialsId: "${params.USER_CREDENTIALS}", usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {
                        echo "Username: ${USERNAME}"
                        echo "Password: ${PASSWORD}"
                    }
                }
            }
        }
    }
}

The system/global credential works fine, but the user-specific/global credential comes back with:

ERROR: Could not find credentials entry with ID 'salainen'

The secret salainen is set up as a user secret under user-specific global credentials (unrestricted), and it shows up in the parameters > credentials selection stage, but as soon as the pipeline hits the withCredentials binding, it fails.

I have Authorize Project installed and configured to run the pipeline as the logged-in user, but trying all kinds of different things, it always comes back as:

ERROR: Could not find credentials entry with ID 'some-secret-id'.

It appears the job can't resolve/call UserCredentialsProperty which would explain why this isn't working. Are the user-specific credentials just broken and useless in Jenkins currently? The global credentials work fine, but I'd need user-specific credentials working for my specific use case. Any thoughts?

Thanks for any insights!


Solution

  • After a lot of experimentation, I resolved this issue. I'm posting the full proof of concept below. This is only to be used in a fairly trusted and secure environment, as anyone with pipeline edit access will be able to add an echo statement that will print the currently selected private SSH key to the log. With that said, here's the working pipeline script that allows a user-specific global key to be used throughout the pipeline and not only within the withCredentials binding.

    void testFunction() {
        def fileExists = fileExists(env.SSH_KEY)
        if (fileExists) {
            def fileContents = readFile(env.SSH_KEY)
            def allLines = fileContents.readLines()
            def firstFiveLines = allLines.take(5).join('\n')
            def displayContent = firstFiveLines + (allLines.size() > 5 ? "\n..." : "")
            echo("First five lines of the private keyfile:\n${displayContent}")
        } else {
            echo("File does not exist.")
        }
    }
    
    pipeline {
        agent any
    
        stages {
            stage('Get params') {
                steps {
                    script {
                        properties([
                            parameters([
                                credentials(
                                    name: 'SELECT_YOUR_SSH_CREDENTIALS',
                                    description: 'Check the "List user credentials" checkbox and select your user credentials from the drop-down menu to proceed.\nNOTE: If you don\'t make a selection here, the pipeline will fail with an obscure \'NullPointerException\' error.',
                                    credentialType: 'com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey',
                                    required: true
                                )
                            ])
                        ])
                    }
                }
            }
    
            stage('Use credentials') {
                steps {
                    script {
                        
                        withCredentials([
                            sshUserPrivateKey(credentialsId: '${SELECT_YOUR_SSH_CREDENTIALS}',
                                keyFileVariable: 'SSH_KEY',
                                usernameVariable: 'SSH_USERNAME')
                        ]) {
                            env.SSH_KEY = "${SSH_KEY}"
                            env.SSH_KEY_ACTUAL = readFile("${SSH_KEY}")
                            env.SSH_USERNAME = "${SSH_USERNAME}"                        
                        }
    
                        // Create a temporary file for the SSH key
                        def tempSSHKeyFileName = "${env.WORKSPACE}@tmp/secretFiles/sshkey_${UUID.randomUUID()}.txt"
    
                        writeFile(file: tempSSHKeyFileName, text: env.SSH_KEY_ACTUAL)
    
                        env.SSH_KEY = tempSSHKeyFileName
                        env.SSH_KEY_ACTUAL = null
                        tempSSHKeyFileName = null
                    }
                }
            }
    
            stage('Use credentials outside of the closure') {
                steps {
                    script {
                        echo "Now outside of the closure"
                        echo("SSH username is ${env.SSH_USERNAME}")
                        echo("SSH key path is ${env.SSH_KEY}")
                        testFunction()
                    }
                }
            }
        }
    
        post {
            always {
                script {
                    // Remove the temporary SSH key file
                    def tempSSHKeyFilePath = env.SSH_KEY
                    if (tempSSHKeyFilePath) {
                        echo "Deleting temporary SSH key file: ${tempSSHKeyFilePath}"
                        sh "ls -l ${tempSSHKeyFilePath}"
                        sh "rm -f ${tempSSHKeyFilePath}"
                    }
                }
            }
        }    
    }