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

Pipeline-as-Code CredentialsProvider for a job

      There should be an analogue of FolderCredentialsProvider limited to a single Job, allowing credentials to be set on the narrowest possible scope.

      Not Workflow specific, but arguably more important for flows since they are likely to replace a whole set of freestyle projects that might otherwise have been segregated into a distinct folder.

          [JENKINS-27398] Pipeline-as-Code CredentialsProvider for a job

          Feel free to implement this in a plugin

          Stephen Connolly added a comment - Feel free to implement this in a plugin

          Jesse Glick added a comment -

          An idea inspired by a conversation with kohsuke:

          A new Pipeline Step which is able to define certain kinds of IdCredentials, probably limited to UsernamePasswordCredentialsImpl and StringCredentialsImpl to start with (but could be an extension point to add other options). The configuration would be similar to the credentials configuration view, except that Secret-valued fields would be data-bound specially: the secret would be salted with the job name (or a folder prefix—so that you could use Snippetizer from a WorkflowMultiBranchProject or OrganizationFolder), encrypted against InstanceIdentity.public¹, and the result Base64-encoded. When run, the text would be Base64-decoded, decrypted against InstanceIdentity.private, the salt stripped off and verified (must be the job name or a folder prefix thereof), the resulting Secret used to create the desired IdCredentials, and this would be cached² in a special CredentialsProvider keeping a per-job list. So then usage would look like (pending JENKINS-29922):

          credentials [$class: 'UsernamePassword', id: 'hipchat-login', username: 'bob', password: 'abc/def+GHI0123=']
          hipchat server: …, message: …, credentialsId: 'hipchat-login'
          

          ¹Or perhaps a subclass of RSAConfidentialKey is the more modern way to do this? RSADigitalSignatureConfidentialKey does not look appropriate.

          ²The credentials must be persisted to disk somehow, to support builds running across Jenkins restarts, though they could be deleted when the Run finishes. The CredentialsProvider API provides no way to limit the credentials to a single Run of the Job, which could lead to surprises if you change the secret and are running concurrent builds: an earlier build might wind up picking up a secret edited in a later build. I think this is an acceptable limitation. There should not be a security risk for pull request builds since (a) credentials are set per job and thus per branch/PR; (b) an origin Jenkinsfile could simply decline to run the step if running in a PR. Merely seeing the encrypted text in the Jenkinsfile does not let you recover the secret without knowing the instance’s private key, nor could you use it in another job because of the salt.

          Jesse Glick added a comment - An idea inspired by a conversation with kohsuke : A new Pipeline Step which is able to define certain kinds of IdCredentials , probably limited to UsernamePasswordCredentialsImpl and StringCredentialsImpl to start with (but could be an extension point to add other options). The configuration would be similar to the credentials configuration view, except that Secret -valued fields would be data-bound specially: the secret would be salted with the job name (or a folder prefix—so that you could use Snippetizer from a WorkflowMultiBranchProject or OrganizationFolder ), encrypted against InstanceIdentity.public ¹, and the result Base64-encoded. When run, the text would be Base64-decoded, decrypted against InstanceIdentity.private , the salt stripped off and verified (must be the job name or a folder prefix thereof), the resulting Secret used to create the desired IdCredentials , and this would be cached² in a special CredentialsProvider keeping a per-job list. So then usage would look like (pending JENKINS-29922 ): credentials [$class: 'UsernamePassword' , id: 'hipchat-login' , username: 'bob' , password: 'abc/def+GHI0123=' ] hipchat server: …, message: …, credentialsId: 'hipchat-login' ¹Or perhaps a subclass of RSAConfidentialKey is the more modern way to do this? RSADigitalSignatureConfidentialKey does not look appropriate. ²The credentials must be persisted to disk somehow, to support builds running across Jenkins restarts, though they could be deleted when the Run finishes. The CredentialsProvider API provides no way to limit the credentials to a single Run of the Job , which could lead to surprises if you change the secret and are running concurrent builds: an earlier build might wind up picking up a secret edited in a later build. I think this is an acceptable limitation. There should not be a security risk for pull request builds since (a) credentials are set per job and thus per branch/PR; (b) an origin Jenkinsfile could simply decline to run the step if running in a PR. Merely seeing the encrypted text in the Jenkinsfile does not let you recover the secret without knowing the instance’s private key, nor could you use it in another job because of the salt.

          Yes that is an interesting idea.

          Stephen Connolly added a comment - Yes that is an interesting idea.

          Jesse Glick added a comment -

          JENKINS-29922 is implemented, so assuming a @Symbol is defined for each credentials kind, and a credentials step is marked metaStep, you could write more simply:

          usernamePassword id: 'hipchat-login', username: 'bob', password: 'abc/def+GHI0123='
          hipchat server: …, message: …, credentialsId: 'hipchat-login'
          

          or even allow the id to be generated, and return it from the step:

          hipchat server: …, message: …, credentialsId: usernamePassword(username: 'bob', password: 'abc/def+GHI0123=')
          

          Jesse Glick added a comment - JENKINS-29922 is implemented, so assuming a @Symbol is defined for each credentials kind, and a credentials step is marked metaStep , you could write more simply: usernamePassword id: 'hipchat-login' , username: 'bob' , password: 'abc/def+GHI0123=' hipchat server: …, message: …, credentialsId: 'hipchat-login' or even allow the id to be generated, and return it from the step: hipchat server: …, message: …, credentialsId: usernamePassword(username: 'bob' , password: 'abc/def+GHI0123=' )

          Jesse Glick added a comment -

          abayer is there a variant of this that would work sanely with Declarative?

          Jesse Glick added a comment - abayer is there a variant of this that would work sanely with Declarative?

          Andrew Bayer added a comment -

          Hrm, not that I can think of off the top of my head.

          Andrew Bayer added a comment - Hrm, not that I can think of off the top of my head.

          Jesse Glick added a comment -

          Let me see, perhaps this section could be something like

          environment { 
              AWS_KEY = credentials(string('abc/def+GHI0123=')) 
          }
          steps {
              sh 'aws -key $AWS_KEY deploy' // whatever
          }
          

          Jesse Glick added a comment - Let me see, perhaps this section  could be something like environment { AWS_KEY = credentials(string( 'abc/def+GHI0123=' )) } steps { sh 'aws -key $AWS_KEY deploy' // whatever }

          Andrew Bayer added a comment -

          That might work, but I wouldn't want to make any assumptions or implementations until after JENKINS-42753 has landed, given how drastically it changes parsing.

          Andrew Bayer added a comment - That might work, but I wouldn't want to make any assumptions or implementations until after JENKINS-42753 has landed, given how drastically it changes parsing.

          Jesse Glick added a comment -

          Sure, I just meant to draw a sketch of what it might look like from a user perspective, not a concrete syntax.

          Jesse Glick added a comment - Sure, I just meant to draw a sketch of what it might look like from a user perspective, not a concrete syntax.

          R. Tyler Croy added a comment -

          I would love for this work to exist, so I could ditch my experimental inline-pipeline-secrets work.

          The key thing from a user perspective (IMHO), is that somebody who is authorized to modify the Jenkinsfile should be able to easily create the ciphertext (or Credential, I don't care what it is), which could be written into the Jenkinsfile.

          This would be conceptually similar to how Travis CI allows creating encrypted tokens per-job.

          R. Tyler Croy added a comment - I would love for this work to exist, so I could ditch my experimental inline-pipeline-secrets work . The key thing from a user perspective (IMHO), is that somebody who is authorized to modify the Jenkinsfile should be able to easily create the ciphertext (or Credential, I don't care what it is), which could be written into the Jenkinsfile . This would be conceptually similar to how Travis CI allows creating encrypted tokens per-job.

          Jesse Glick added a comment -

          rtyler yes that is the idea exactly.

          Jesse Glick added a comment - rtyler yes that is the idea exactly.

          R. Tyler Croy added a comment -

          Then yes please, i'll take eleventy of those immediately thanks.

          R. Tyler Croy added a comment - Then yes please, i'll take eleventy of those immediately thanks.

            jglick Jesse Glick
            jglick Jesse Glick
            Votes:
            0 Vote for this issue
            Watchers:
            9 Start watching this issue

              Created:
              Updated: