Prevent developers from stealing jenkins credentials

Hi team,

I’m facing a security concern, I have “multibranch pipeline” job which uses Jenkinsfile under Build Configuration.

It seems that anyone (like a developer) that has access to the git repository can change and override the Jenkinsfile code and actually retrieve Jenkins credentials.

Example:

pipeline {
  agent any
  stages {
    stage('usernamePassword') {
      steps {
        script {
          withCredentials([
            usernamePassword(credentialsId: 'mygit-token',
              usernameVariable: 'username',
              passwordVariable: 'password')
          ]) {
            print 'username=' + username + 'password=' + password

            print 'username.collect { it }=' + username.collect { it }
            print 'password.collect { it }=' + password.collect { it }
          }
        }
      }
    }
  }
}

How can I avoid from this?

Some suggestions from my opinion:

  • Disable presenting by default the jenkins secret name “using credential …” and maybe add a new option to enable it, this way nobody will know the jenkins credentials name.

  • Add ability to validate pipeline to avoid from anyone to override the pipeline, so I’ll be able to verify that no one is trying to print/export my creds

  • Mask/hide or exit with error any attempt to print to console or export to file credentials by default

any other idea of how can I avoid from this security concern?

I was facing similar issues… anyone could make changes to the Jenkinsfile, my final decision was to remove it from the repository altogether.
I have been using the Jenkins template engine to externalize my Jenkinsfile (https://boozallen.github.io/sdp-docs/jte/2.2.2/index.html) and I believe it is one of the best Jenkins plugins ever created.
Not only you can fix your issue in this way but it makes updating your pipeline logic way easier… you do not need anymore to update hundreds of Jenkinsfile scattered on as many repositories… everything is centralized. Moreover, it supports parameters, libraries and much more. You should give it a try.

When you do print password jenkins will capture the actual password in the log output and replace it with *****. So it is not so easy to just print it to the console.

You have to trust your developers that they don’t steal the credentials. As soon as you have code inside a withCredentials block that is in some way controllable by a developer he is able to just grab the environment variables and save it into a file that he packs in his build result which is then published somewhere.

Hi @mawinter69 ,

Thank you for your response, but with the pipeline sample above + the credentials name that the Jenkins is printing (see pic above) the Jenkins will print the git credentials without any **** , it’s really easy to reproduce it.

The question now is how to prevent it

When you do print password.collect { it } indeed you get the password in the console.
print password is properly masked.
As mentioned before there is no way to prevent developers from finding a way to get the passwords when you allow them to execute own written code in a withCredentials block.

I would see the mechanism to mask passwords in the output more something to prevent that the password is printed to the log by accident.
People might have access to the logs that have otherwise no way to modify the Jenkinsfile or other things that are executed during the build.

If you have a developer that wants to steal the passwords, then you have a bigger problem I would say.

I agree with @mawinter69 . If you allow execution of code from untrusted sources in a trusted context (like a withCredentials block) then there is a risk that sensitive information could escape.

The ci.jenkins.io instance tries to reduce that risk by not defining sensitive information (like credentials) on the public instance. Operations that require elevated permissions are run on isolated, non-public machines like trusted.ci.jenkins.io and infra.ci.jenkins.io

also on infra install, credentials are scoped to that folder/job, so if one is comprimised, others are not.

At some point you’ll have to trust people, even if you can’t modify the jenkinsfile, you can modify code, or build scripts, or something else. Just try and limit the damage.

Short answer is - no, if you give someone a credential to use with arbitrary code, they will always have a way to steal it. There is a plugin that will mask the credentials if output to console, but that is classic “security theater” - i.e. it is trivial to defeat.

Your best/only approach is probably to not play that game and instead issue each developer their own credentials - in which case they do not need to steal them, as it is their credentials in the first place, but that has other implications (no idea how this can be done on auto-triggered builds where there is no user).

One idea is to encapsulate the code that needs to use these credentials into a global shared library in a way that prevents them from controlling the code being executed - for example if you need to upload a file to S3 with credentials, then write a function uploadToS3(filename) that will do it, however that is not going to really help you as nothing is stopping them from explicitly writing their own withCredentials block and dumping them out.

The other part of this is to make sure to rotate your secrets frequently (write some automation to do so every x minutes) - at least that will contain the damage from a leaked credential

Hi All,

Thank you for answers.
After some research, I would like to share my quick workaround for my scenario:

First, Hide credentials usage in job output:

Second, work with Remote Jenkinsfile Provider plugin (link).

This will help me to limit access and unwelcome jenkinsfile code changes.

Note: I still need to figure out how can I change my “aws secret manager” secrets default behavior that stores them under the global domain or hide them somehow from irrelevant child folders, then create a new domain per folder and attach only the relevant secrets from my aws “aws secret manager” secrets.