Jenkins : use withCredentials in global environment section
Asked Answered
A

6

30

I have a Jenkins pipeline with multiple stages that all require the same environment variables, I run this like so:

script {
    withCredentials([usernamePassword(credentialsId: 'COMPOSER_REPO_MAGENTO', passwordVariable: 'MAGE_REPO_PASS', usernameVariable: 'MAGE_REPO_USER')]) {
        def composerAuth = """{
            "http-basic": {
                "repo.magento.com": {
                    "username": "${MAGE_REPO_USER}",
                    "password": "${MAGE_REPO_PASS}"
                }
            }
        }""";
        // do some stuff here that uses composerAuth
    }
}

I don't want to have to re-declare composerAuth every time, so I want to store the credentials in a global variable, so I can do something like:

script {
    // do some stuff here that uses global set composerAuth
}

I've tried putting it in the environment section:

environment {
    DOCKER_IMAGE_NAME = "magento2_website_sibo"
    withCredentials([usernamePassword(credentialsId: 'COMPOSER_REPO_MAGENTO', passwordVariable: 'MAGE_REPO_PASS', usernameVariable: 'MAGE_REPO_USER')]) {
        COMPOSER_AUTH = """{
            "http-basic": {
                "repo.magento.com": {
                    "username": "${MAGE_REPO_USER}",
                    "password": "${MAGE_REPO_PASS}"
                }
            }
        }""";
    }
}

But (groovy noob as I am) that doesn't work. So what's the best approach on setting a globally accessible variable with credentials but only have to declare it once?

Access answered 10/1, 2018 at 8:5 Comment(4)
Hi, probably related? #45743632Marabou
I tried the suggestions in that post, but the do not work (at least, not for me). The issue here is that I have credentials that come from a different plugin and need a way to store these in a (environment?) variable that is globally accessible.Access
Ok, that is probably fine in this case :)Marabou
@Giel Berkers Have you tried using HTTPRequest plugin given that you are trying to make HTTP requests? If that is the case then there is a way to declare username and password globally and use them without 'withCredentials' block.Okubo
A
15

You can use credentials helper method of the environment section. For "Username and passwrd" type of credentials it assigns 2 additional environment variables. Example:

environment {
  MAGE_REPO_CREDENTIALS = credentials('COMPOSER_REPO_MAGENTO')
  COMPOSER_AUTH = """{
      "http-basic": {
          "repo.magento.com": {
              "username": "${env.MAGE_REPO_CREDENTIALS_USR}",
              "password": "${env.MAGE_REPO_CREDENTIALS_PSW}"
          }
      }
  }"""
}

Read more

Arun answered 7/8, 2018 at 18:27 Comment(1)
Insecure practice. "Interpolation of sensitive environment variables Groovy string interpolation should never be used with credentials." jenkins.io/doc/book/pipeline/jenkinsfile/#string-interpolationRhetorical
O
14

After a lot of search (and struggle), i came up with an easy workaround:

As better explained in the jenkins docs for Handling Credentials, when injecting a usernamePassword type credential into an environment variable named VAR_NAME, jenkins automatically generates two other variables ending with _USR and _PSW respectively for usernameVariable and passwordVariable parameters.

What i did was to inject my variables with the values from both USR and PSW new variables.

In @Giel Berkers case, it should be something like this:

environment {
    DOCKER_IMAGE_NAME = "magento2_website_sibo"
    COMPOSER_REPO_MAGENTO_CREDENTIAL = credentials('COMPOSER_REPO_MAGENTO')
    COMPOSER_AUTH = """{
        "http-basic": {
            "repo.magento.com": {
                "username": "${COMPOSER_REPO_MAGENTO_CREDENTIAL_USR}",
                "password": "${COMPOSER_REPO_MAGENTO_CREDENTIAL_PSW}"
            }
        }
    }""";
}
Overburdensome answered 18/10, 2019 at 23:48 Comment(2)
I did something like this recently, and I got a warning that it was insecure to use the e.g. COMPOSER_REPO_MAGENTO_CREDENTIAL in the environment clause like that. I assume because it can't mask it properly at that stage of Jenkinsfile parsing.Rhetorical
"Interpolation of sensitive environment variables Groovy string interpolation should never be used with credentials." jenkins.io/doc/book/pipeline/jenkinsfile/#string-interpolationRhetorical
S
8

Here is how you can accomplish that

pipeline {
    agent any
    stages {
        stage('first') {
            steps {
                script {
                    withCredentials([usernamePassword(credentialsId: 'COMPOSER_REPO_MAGENTO', passwordVariable: 'MAGE_REPO_PASS', usernameVariable: 'MAGE_REPO_USER')]) {
                        def user = env.MAGE_REPO_USER
                        def password = env.MAGE_REPO_PASS
                        //Initializing a global variable. Notice there is no def here 
                        composerAuth = """{
                            "http-basic": {
                                "repo.magento.com": {
                                    "username": "${user}",
                                    "password": "${password}"
                                }
                            }
                        }"""
                    }
                }
            }
        }
        stage('second') {
            steps {
                script {
                    println composerAuth
                }
            }
        }
    }
}
Sadiesadira answered 12/1, 2018 at 23:6 Comment(1)
Artem's solution, explained by Leonardo, is a more elegant solution to the question "how to use withCredentials in global environment section". Also I prefer to def my variables with @Field or environment {} if they are gonna be global to my pipelineUnmeriting
A
6

I found this and it is helpful: Source: https://wiki.jenkins.io/display/JENKINS/Credentials+Binding+Plugin

   // Basic example
withCredentials([usernamePassword(credentialsId: 'amazon',
                     usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {
    //available as an env variable, but will be masked if you try to print it out any which way
    sh 'echo $PASSWORD'
    echo "${env.USERNAME}"
}

// You can also request multiple credentials in a single call
withCredentials([usernamePassword(credentialsId: 'amazon',
                     usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD'),
                 string(credentialsId: 'slack-url',
                     variable: 'SLACK_URL'),]) {
    sh 'echo $PASSWORD'
    echo "${env.SLACK_URL}"
}

// Older code might not use the new syntax (usernamePassword, string, ...) yet, and directly call the class:
withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: 'amazon',
                  usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD']]) {
    //available as an env variable, but will be masked if you try to print it out any which way
    sh 'echo $PASSWORD'
    echo "${env.USERNAME}"
}
Anjanetteanjela answered 17/6, 2019 at 16:43 Comment(2)
No signature of method: javaposse.jobdsl.dsl.helpers.step.StepContext.usernamePassword() is applicable for argument types: (java.util.LinkedHashMap)Warlock
"${env.USERNAME}" worked for meAdelaideadelaja
M
1

You may need to deal with multi-field credentials or vendor-specific credential types that the plugin does not (yet) support.

In this situation you have a couple of choices:

  1. Use the closest standard multi-field credential (e.g. Username With Password) that fits your requirements.
  2. Use a string credential, serialize all the fields into the secret value (e.g. as JSON or as a delimited string), and parse them in the job script. (This is a last resort when other methods don't work, e.g. when secret rotation would cause multiple fields to change.)

Example: Jenkins authenticates to Secrets Manager using the primary AWS credential (from the environment). You have a job that performs a particular AWS operation in a different account, which uses a secondary AWS credential. You choose to encode the secondary AWS credential as JSON in the string credential foo:

node {
    withCredentials([string(credentialsId: 'foo', variable: 'secret')]) {
        script {
            def creds = readJSON text: secret
            env.AWS_ACCESS_KEY_ID = creds['accessKeyId']
            env.AWS_SECRET_ACCESS_KEY = creds['secretAccessKey']
            env.AWS_REGION = 'us-east-1' // or whatever
        }
        sh "aws sts get-caller-identity" // or whatever
    }
}

A typical example of a username password type credential (example from here) would look like:

withCredentials([usernamePassword(credentialsId: 'amazon', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {
  // available as an env variable, but will be masked if you try to print it out any which way
  // note: single quotes prevent Groovy interpolation; expansion is by Bourne Shell, which is what you want
  sh 'echo $PASSWORD'
  // also available as a Groovy variable
  echo USERNAME
  // or inside double quotes for string interpolation
  echo "username is $USERNAME"
}

ReadMore1

ReadMore2

Mccormac answered 13/7, 2022 at 15:19 Comment(0)
F
0

Here is the straightforward way to get things done:

pipeline {
    agent any    
    stages {
        
        stage('Hello') {
            steps {
                echo 'Hello World'
            }
        }
        stage('Test Python') {
            steps {
                sh 'python3 --version'
            }
        }
        stage('Test H DUT') {
            
            steps {
                sh 'pwd'
                sh 'ls'
                script {
                    withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: 'sfbk',usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD']]) {
                        sh 'python3 test_h_file.py $USERNAME $PASSWORD'
                    }
                }
              
            }
        }
    }
}
Faught answered 18/4 at 10:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.