Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-50242

withCredentials step masking easily bypassed

    XMLWordPrintable

Details

    Description

      A very common use case of Jenkins is to delegate the responsibility of the creation of pipelines to third parties or developers. These external teams should be able to use secrets given to them via Jenkins credentials, but shouldn't be able to visualize the value of the secret.

      For this use case, withCredentials is broken:

      node {
        stage('Break Security') {
          withCredentials([string(credentialsId: 'AWS_DEFAULT_REGION', variable: 'AWS_DEFAULT_REGION'),
          string(credentialsId: 'AWS_ACCESS_KEY_ID', variable: 'AWS_ACCESS_KEY_ID'),
          string(credentialsId: 'AWS_SECRET_ACCESS_KEY', variable: 'AWS_SECRET_ACCESS_KEY')]) {
            def exposedSecret = ""
            for(letter in env.AWS_SECRET_ACCESS_KEY) {
              exposedSecret = "$exposedSecret $letter"
            }
            echo "$exposedSecret"
          }
        }
      }

      The secret can be easily viewed.

      Letting someone work on a pipeline is basically showing them the secrets that pipeline uses.
      For this example I used "Secret Text", but it also happens with "AWS Credentials".

      Attachments

        Issue Links

          Activity

            apineros Andres Pineros created issue -
            apineros Andres Pineros made changes -
            Field Original Value New Value
            Description A very common use case of Jenkins is to delegate the responsibility of the creation of pipelines to third parties or developers. These external teams should be able to use secrets given to them via Jenkins credentials, but shouldn't be able to visualize the value of the secret.

            For this use case, withCredentials is broken:
            {code:java}
            node {
             stage('Break Security') {
               withCredentials([string(credentialsId: 'AWS_DEFAULT_REGION', variable: 'AWS_DEFAULT_REGION'), string(credentialsId: 'AWS_ACCESS_KEY_ID', variable: 'AWS_ACCESS_KEY_ID'), string(credentialsId: 'AWS_SECRET_ACCESS_KEY', variable: 'AWS_SECRET_ACCESS_KEY')]) {
              def exposedSecret = ""
              for(letter in env.AWS_DEFAULT_REGION) {
              exposedSecret = "$exposedSecret $letter"
             }
             echo "$exposedSecret"
             }
             }
            }{code}
            The secret can be easily viewed.

            Letting someone work on a pipeline is basically showing them the secrets that pipeline uses.
            A very common use case of Jenkins is to delegate the responsibility of the creation of pipelines to third parties or developers. These external teams should be able to use secrets given to them via Jenkins credentials, but shouldn't be able to visualize the value of the secret.

            For this use case, withCredentials is broken:
            {code:java}
            node {
            stage('Break Security') {
            withCredentials([string(credentialsId: 'AWS_DEFAULT_REGION', variable: 'AWS_DEFAULT_REGION'),
            string(credentialsId: 'AWS_ACCESS_KEY_ID', variable: 'AWS_ACCESS_KEY_ID'),
            string(credentialsId: 'AWS_SECRET_ACCESS_KEY', variable: 'AWS_SECRET_ACCESS_KEY')]) {
            def exposedSecret = ""
            for(letter in env.AWS_DEFAULT_REGION) {
            exposedSecret = "$exposedSecret $letter"
            }
            echo "$exposedSecret"
            }
            }
            }{code}
            The secret can be easily viewed.

            Letting someone work on a pipeline is basically showing them the secrets that pipeline uses.
            apineros Andres Pineros made changes -
            Description A very common use case of Jenkins is to delegate the responsibility of the creation of pipelines to third parties or developers. These external teams should be able to use secrets given to them via Jenkins credentials, but shouldn't be able to visualize the value of the secret.

            For this use case, withCredentials is broken:
            {code:java}
            node {
            stage('Break Security') {
            withCredentials([string(credentialsId: 'AWS_DEFAULT_REGION', variable: 'AWS_DEFAULT_REGION'),
            string(credentialsId: 'AWS_ACCESS_KEY_ID', variable: 'AWS_ACCESS_KEY_ID'),
            string(credentialsId: 'AWS_SECRET_ACCESS_KEY', variable: 'AWS_SECRET_ACCESS_KEY')]) {
            def exposedSecret = ""
            for(letter in env.AWS_DEFAULT_REGION) {
            exposedSecret = "$exposedSecret $letter"
            }
            echo "$exposedSecret"
            }
            }
            }{code}
            The secret can be easily viewed.

            Letting someone work on a pipeline is basically showing them the secrets that pipeline uses.
            A very common use case of Jenkins is to delegate the responsibility of the creation of pipelines to third parties or developers. These external teams should be able to use secrets given to them via Jenkins credentials, but shouldn't be able to visualize the value of the secret.

            For this use case, withCredentials is broken:
            {code:java}
            node {
              stage('Break Security') {
                withCredentials([string(credentialsId: 'AWS_DEFAULT_REGION', variable: 'AWS_DEFAULT_REGION'),
                string(credentialsId: 'AWS_ACCESS_KEY_ID', variable: 'AWS_ACCESS_KEY_ID'),
                string(credentialsId: 'AWS_SECRET_ACCESS_KEY', variable: 'AWS_SECRET_ACCESS_KEY')]) {
                  def exposedSecret = ""
                  for(letter in env.AWS_DEFAULT_REGION) {
                    exposedSecret = "$exposedSecret $letter"
                  }
                  echo "$exposedSecret"
                }
              }
            }{code}
            The secret can be easily viewed.

            Letting someone work on a pipeline is basically showing them the secrets that pipeline uses.
            apineros Andres Pineros made changes -
            Description A very common use case of Jenkins is to delegate the responsibility of the creation of pipelines to third parties or developers. These external teams should be able to use secrets given to them via Jenkins credentials, but shouldn't be able to visualize the value of the secret.

            For this use case, withCredentials is broken:
            {code:java}
            node {
              stage('Break Security') {
                withCredentials([string(credentialsId: 'AWS_DEFAULT_REGION', variable: 'AWS_DEFAULT_REGION'),
                string(credentialsId: 'AWS_ACCESS_KEY_ID', variable: 'AWS_ACCESS_KEY_ID'),
                string(credentialsId: 'AWS_SECRET_ACCESS_KEY', variable: 'AWS_SECRET_ACCESS_KEY')]) {
                  def exposedSecret = ""
                  for(letter in env.AWS_DEFAULT_REGION) {
                    exposedSecret = "$exposedSecret $letter"
                  }
                  echo "$exposedSecret"
                }
              }
            }{code}
            The secret can be easily viewed.

            Letting someone work on a pipeline is basically showing them the secrets that pipeline uses.
            A very common use case of Jenkins is to delegate the responsibility of the creation of pipelines to third parties or developers. These external teams should be able to use secrets given to them via Jenkins credentials, but shouldn't be able to visualize the value of the secret.

            For this use case, withCredentials is broken:
            {code:java}
            node {
              stage('Break Security') {
                withCredentials([string(credentialsId: 'AWS_DEFAULT_REGION', variable: 'AWS_DEFAULT_REGION'),
                string(credentialsId: 'AWS_ACCESS_KEY_ID', variable: 'AWS_ACCESS_KEY_ID'),
                string(credentialsId: 'AWS_SECRET_ACCESS_KEY', variable: 'AWS_SECRET_ACCESS_KEY')]) {
                  def exposedSecret = ""
                  for(letter in env.AWS_SECRET_ACCESS_KEY) {
                    exposedSecret = "$exposedSecret $letter"
                  }
                  echo "$exposedSecret"
                }
              }
            }{code}
            The secret can be easily viewed.

            Letting someone work on a pipeline is basically showing them the secrets that pipeline uses.
            For this example I used "Secret Text", but it also happens with "AWS Credentials".
            apineros Andres Pineros made changes -
            Summary withCredentials step masking isn't secure withCredentials step masking easily bypassed
            jglick Jesse Glick made changes -
            Remote Link This issue links to "PR 49 (Web Link)" [ 20272 ]
            jglick Jesse Glick added a comment -

            The easier way is to run env | od -a, or post secrets to Twitter, or whatever.

            A very common use case of Jenkins is to delegate the responsibility of the creation of pipelines to third parties or developers. These external teams should be able to use secrets given to them via Jenkins credentials, but shouldn't be able to visualize the value of the secret.

            This is not a valid use case. If someone is permitted to write Pipeline script in a folder in which a given credentials item is in scope, they must be trusted to use those credentials properly. If you do not trust them, do not let them write Pipeline script (or, more generally, configure jobs).

            jglick Jesse Glick added a comment - The easier way is to run env | od -a , or post secrets to Twitter, or whatever. A very common use case of Jenkins is to delegate the responsibility of the creation of pipelines to third parties or developers. These external teams should be able to use secrets given to them via Jenkins credentials, but shouldn't be able to visualize the value of the secret. This is not a valid use case. If someone is permitted to write Pipeline script in a folder in which a given credentials item is in scope, they must be trusted to use those credentials properly. If you do not trust them, do not let them write Pipeline script (or, more generally, configure jobs).
            jglick Jesse Glick made changes -
            Resolution Not A Defect [ 7 ]
            Status Open [ 1 ] Resolved [ 5 ]

            Code changed in jenkins
            User: Jesse Glick
            Path:
            src/main/resources/org/jenkinsci/plugins/credentialsbinding/impl/BindingStep/help.html
            http://jenkins-ci.org/commit/credentials-binding-plugin/c7aff033605562a138d41c7b28b10e6812ee9111
            Log:
            JENKINS-50242 Improved help text to correct a misunderstanding.

            scm_issue_link SCM/JIRA link daemon added a comment - Code changed in jenkins User: Jesse Glick Path: src/main/resources/org/jenkinsci/plugins/credentialsbinding/impl/BindingStep/help.html http://jenkins-ci.org/commit/credentials-binding-plugin/c7aff033605562a138d41c7b28b10e6812ee9111 Log: JENKINS-50242 Improved help text to correct a misunderstanding.

            Code changed in jenkins
            User: Jesse Glick
            Path:
            src/main/resources/org/jenkinsci/plugins/credentialsbinding/impl/BindingStep/help.html
            http://jenkins-ci.org/commit/credentials-binding-plugin/8a0039503c6b3b394277f67321f8c507cc240d25
            Log:
            Merge pull request #49 from jglick/help-JENKINS-50242

            JENKINS-50242 Improved help text to correct a misunderstanding

            Compare: https://github.com/jenkinsci/credentials-binding-plugin/compare/aeda5de425e4...8a0039503c6b

            scm_issue_link SCM/JIRA link daemon added a comment - Code changed in jenkins User: Jesse Glick Path: src/main/resources/org/jenkinsci/plugins/credentialsbinding/impl/BindingStep/help.html http://jenkins-ci.org/commit/credentials-binding-plugin/8a0039503c6b3b394277f67321f8c507cc240d25 Log: Merge pull request #49 from jglick/help- JENKINS-50242 JENKINS-50242 Improved help text to correct a misunderstanding Compare: https://github.com/jenkinsci/credentials-binding-plugin/compare/aeda5de425e4...8a0039503c6b
            jglick Jesse Glick made changes -
            Remote Link This issue links to "Page (Jenkins Wiki)" [ 20282 ]
            jglick Jesse Glick made changes -
            Remote Link This issue links to "Page (Jenkins Wiki)" [ 20282 ] This issue links to "Page (Jenkins Wiki)" [ 20282 ]
            apineros Andres Pineros added a comment - - edited

            So for the multi-branch model, in which the pipeline is stored inside the project's repository, all the developers should have access to keys that can create EC2 instances? That is crazy.

             

            Then the multibranch model is a very insecure tool for big projects, and this should be stated somewhere in the documentation. For security, pipelines that use credentials of some sort (most of them) must be outside of the dev repository.

            apineros Andres Pineros added a comment - - edited So for the multi-branch model, in which the pipeline is stored inside the project's repository, all the developers should have access to keys that can create EC2 instances? That is crazy.   Then the multibranch model is a very insecure tool for big projects, and this should be stated somewhere in the documentation. For security, pipelines that use credentials of some sort (most of them) must be outside of the dev repository.

            You don't have to move the whole pipeline out of the repository. After all, you can call other parameterized jobs via build() from your pipeline. You just have to make sure that the credentials are not available in the multibranch pipeline folder.

            mb_o Moritz Baumann added a comment - You don't have to move the whole pipeline out of the repository. After all, you can call other parameterized jobs via  build() from your pipeline. You just have to make sure that the credentials are not available in the multibranch pipeline folder.

            If you want people to author pipelines without access to real credentials, set up a second Jenkins instance with a second, smaller set of resources requiring the credentials (such as a second SCM server).  Make sure that the smaller set of resources has nothing sensitive.

            Set credentials there with the same ID as they are in the original instance, but make the passwords and keys different (and matching the smaller resources).  Author your pipelines there.

            This solution is not always possible, but can often be part of a good solution.  It is not limited to those you don't trust with your live data (in which case, reconsider why you're letting them write the pipeline).  Use these with your trustworthy developers, so that you're not testing in production!

             

            rmandeville Rob Mandeville added a comment - If you want people to author pipelines without access to real credentials, set up a second Jenkins instance with a second, smaller set of resources requiring the credentials (such as a second SCM server).  Make sure that the smaller set of resources has nothing sensitive. Set credentials there with the same ID as they are in the original instance, but make the passwords and keys different (and matching the smaller resources).  Author your pipelines there. This solution is not always possible, but can often be part of a good solution.  It is not limited to those you don't trust with your live data (in which case, reconsider why you're letting them write the pipeline).  Use these with your trustworthy developers, so that you're not testing in production!  
            kon Kalle Niemitalo made changes -
            Link This issue is duplicated by JENKINS-60962 [ JENKINS-60962 ]
            kon Kalle Niemitalo made changes -
            Link This issue relates to JENKINS-54538 [ JENKINS-54538 ]
            kon Kalle Niemitalo made changes -
            Link This issue relates to JENKINS-61277 [ JENKINS-61277 ]

            People

              Unassigned Unassigned
              apineros Andres Pineros
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: