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

Cannot find user credentials when job is triggered with parameters

    • Icon: Bug Bug
    • Resolution: Not A Defect
    • Icon: Major Major
    • credentials-plugin
    • None

      Given I have a job A
      And job A has Credentials Parameter
      And job A triggers job B sending job A's parameters
      And job B has Credentials Parameter
      And job B uses ssh-agent
      And job B uses Authorize Project plugin
      And job B uses Run as user who triggered the build
      When I build job A
      And choose a credential from logged in user
      Then job B should find the credentials

      The result unfortunately is this:

      Started by upstream project "jobA" build number 4
      originally caused by:
       Started by user Superman
      Running as Superman
      Building in workspace /app/jenkins/jobs/jobB/workspace
      FATAL: [ssh-agent] Could not find specified credentials
      [ssh-agent] Looking for ssh-agent implementation...
      [ssh-agent]   Java/JNR ssh-agent
      [ssh-agent] Started.
      

        1. build_downstream.xml
          8 kB
        2. build_manual.xml
          3 kB
        3. log_downstream
          2 kB
        4. log_manual
          2 kB

          [JENKINS-24750] Cannot find user credentials when job is triggered with parameters

          Doru Căilean added a comment -

          Attached you can find both build.xml and log files from the manual and triggered (in downstream) builds. I've replaced most of the elements with fake values due to security measures. Let me know if I can provide any other info.

          Doru Căilean added a comment - Attached you can find both build.xml and log files from the manual and triggered (in downstream) builds. I've replaced most of the elements with fake values due to security measures. Let me know if I can provide any other info.

          Hello again. This is resolvable doing this:
          Given I have a job A
          And job A has Credentials Parameter named CREDENTIAL
          And job A triggers job B sending job A's parameters
          And job B has Credentials Parameter named CREDENTIAL
          And job B uses ssh-agent
          And job B gets the chosen credential from Parameter expression
          And job B uses Authorize Project plugin
          And job B uses Run as user who triggered the build
          When I build job A
          And choose a credential from logged in user
          Then job B should find the credentials

          This seems to work fine

          Ole Christian Langfjæran added a comment - Hello again. This is resolvable doing this: Given I have a job A And job A has Credentials Parameter named CREDENTIAL And job A triggers job B sending job A's parameters And job B has Credentials Parameter named CREDENTIAL And job B uses ssh-agent And job B gets the chosen credential from Parameter expression And job B uses Authorize Project plugin And job B uses Run as user who triggered the build When I build job A And choose a credential from logged in user Then job B should find the credentials This seems to work fine

          Me again. I must have made the last test (many months ago) wrong.
          That scenario only works if I set
          And job B uses Run as user 'Superman'

          And does not work when using "Run as user who triggered the build"

          The output of those two are the same, eg:
          Started by upstream project "jobA" build number 4
          originally caused by:
          Started by user Superman
          Running as Superman

          But the latter fails with FATAL: [ssh-agent] Could not find specified credentials
          I'm guessing this is a Authorize plugin bug/problem and not ssh-agent

          Ole Christian Langfjæran added a comment - Me again. I must have made the last test (many months ago) wrong. That scenario only works if I set And job B uses Run as user 'Superman' And does not work when using "Run as user who triggered the build" The output of those two are the same, eg: Started by upstream project "jobA" build number 4 originally caused by: Started by user Superman Running as Superman But the latter fails with FATAL: [ssh-agent] Could not find specified credentials I'm guessing this is a Authorize plugin bug/problem and not ssh-agent

          ikedam added a comment -

          Reproduced in my environment.

          This looks an issue of credentials-plugin.

          Credentials plugin doesn't use the authorization decided when the build starts by authorize-project.
          Instead, it uses "default authorization", which means the autorization that can be decided only with the project configuration itself, without contexts like who triggered the build.

          This looks intended limitation of credentials-plugin:
          https://github.com/jenkinsci/credentials-plugin/blob/credentials-1.16.1/src/main/java/com/cloudbees/plugins/credentials/CredentialsProvider.java#L807

                      // we use the default authentication of the job as those are the only ones that can be configured
                      // if a different strategy is in play it doesn't make sense to consider the run-time authentication
                      // as you would have no way to configure it
          

          ikedam added a comment - Reproduced in my environment. This looks an issue of credentials-plugin. Credentials plugin doesn't use the authorization decided when the build starts by authorize-project. Instead, it uses "default authorization", which means the autorization that can be decided only with the project configuration itself, without contexts like who triggered the build. This looks intended limitation of credentials-plugin: https://github.com/jenkinsci/credentials-plugin/blob/credentials-1.16.1/src/main/java/com/cloudbees/plugins/credentials/CredentialsProvider.java#L807 // we use the default authentication of the job as those are the only ones that can be configured // if a different strategy is in play it doesn't make sense to consider the run-time authentication // as you would have no way to configure it

          I see and thanks for the reply! Is it strange that "Run as Specific User" still works ikedam?

          Ole Christian Langfjæran added a comment - I see and thanks for the reply! Is it strange that "Run as Specific User" still works ikedam ?

          ikedam added a comment -

          It's not strange, and looks rather an intended behavior of credentials plugin.
          Consider a case that you are an administrator, and developers can't modify configurations of builds.
          Once you configures the project with Run as Specific user, the authorization is always same however developers teigger a build.
          But if you configures the project with Run as User who Triggered, the authorization can be different depending on who triggered the build.
          Credentials plugin doesn't allow the latter case, and it does't work.

          ikedam added a comment - It's not strange, and looks rather an intended behavior of credentials plugin. Consider a case that you are an administrator, and developers can't modify configurations of builds. Once you configures the project with Run as Specific user, the authorization is always same however developers teigger a build. But if you configures the project with Run as User who Triggered, the authorization can be different depending on who triggered the build. Credentials plugin doesn't allow the latter case, and it does't work.

          Downstream jobs can get merged together on the queue, so the net result is you can end up with a job that has been "triggered by" multiple users.

          Now let's consider the case of workflow usage, wherein you need to define say a credential with a fixed id. In that case all the users will have a credential with an ID of ssh-deploy-key or something like that...

          Thus when I select my ssh-deploy-key in Job A and trigger it and you select your ssh-depoy-key in Job A and trigger it, both jobs will schedule Job B with the same parameter and they can get collapsed into a single execution... so you end up deploying with my key.

          I would recommend that this kind of complex build job is much better served using a job type designed to allow for such complex flows, i.e. s/Workflow/Pipelines/g;

          I need to think about whether it makes sense to add some logic into https://github.com/jenkinsci/credentials-plugin/blob/credentials-1.16.1/src/main/java/com/cloudbees/plugins/credentials/CredentialsProvider.java#L798 so that it doesn't use ANONYMOUS if Jenkins.getAuthentication() != ACL.SYSTEM as there are a lot of potential side-effects of such a change

          Stephen Connolly added a comment - Downstream jobs can get merged together on the queue, so the net result is you can end up with a job that has been "triggered by" multiple users. Now let's consider the case of workflow usage, wherein you need to define say a credential with a fixed id. In that case all the users will have a credential with an ID of ssh-deploy-key or something like that... Thus when I select my ssh-deploy-key in Job A and trigger it and you select your ssh-depoy-key in Job A and trigger it, both jobs will schedule Job B with the same parameter and they can get collapsed into a single execution... so you end up deploying with my key. I would recommend that this kind of complex build job is much better served using a job type designed to allow for such complex flows, i.e. s/Workflow/Pipelines/g; I need to think about whether it makes sense to add some logic into https://github.com/jenkinsci/credentials-plugin/blob/credentials-1.16.1/src/main/java/com/cloudbees/plugins/credentials/CredentialsProvider.java#L798 so that it doesn't use ANONYMOUS if Jenkins.getAuthentication() != ACL.SYSTEM as there are a lot of potential side-effects of such a change

          The key security constraint to remember here is that anyone can add a job that gets triggered by a completed run of any job that they can see...

          Thus in your scenario above. Malicious user can create Job C that is parameterized and has the same parameter names as Job B and is triggered by a build of Job A. The malicious user may even be able to restrict visibility of Job C such that users cannot see that Job C exists at all (in which case you will not see Job C as a downstream job in the UI)

          If we let the permissions propagate then Job C will be able to access the user's credentials to do whatever they want with them. This is the reason for this comment here: https://github.com/jenkinsci/credentials-plugin/blob/credentials-1.16.1/src/main/java/com/cloudbees/plugins/credentials/CredentialsProvider.java#L804 which is why I have made up my mind, we will not be changing the existing behaviour.

          Stephen Connolly added a comment - The key security constraint to remember here is that anyone can add a job that gets triggered by a completed run of any job that they can see... Thus in your scenario above. Malicious user can create Job C that is parameterized and has the same parameter names as Job B and is triggered by a build of Job A. The malicious user may even be able to restrict visibility of Job C such that users cannot see that Job C exists at all (in which case you will not see Job C as a downstream job in the UI) If we let the permissions propagate then Job C will be able to access the user's credentials to do whatever they want with them. This is the reason for this comment here: https://github.com/jenkinsci/credentials-plugin/blob/credentials-1.16.1/src/main/java/com/cloudbees/plugins/credentials/CredentialsProvider.java#L804 which is why I have made up my mind, we will not be changing the existing behaviour.

          Security constraints mandate that this is the only safe way to handle credentials as long as there is no way to prevent J.Random.User from adding a job you cannot see as downstream from your job and thereby be able to capture the triggering user's credentials parameters

          Stephen Connolly added a comment - Security constraints mandate that this is the only safe way to handle credentials as long as there is no way to prevent J.Random.User from adding a job you cannot see as downstream from your job and thereby be able to capture the triggering user's credentials parameters

          Doru Căilean added a comment -

          The security constraints do make sense, but I can think of a lot of cases where allowing the user that triggered the job to access its own credentials would be useful. In the case of the Authorize Project Plugin, specifying a user ID also allows one to select a 'No need for re-authentication' option. Their documentation warns about the security threats by saying:

          This can threaten your Jenkins security. Be careful to use.

          Do not require authentication in the next configuration if the User ID is not changed. Use this feature carefully, for a malicious user can run unintended commands without authentication by changing configuration of the project. You should also watch CONFIGURE privilege for this project is granted only to proper users. This does not work when configuring via REST/CLI.

          So, in the flow that we are discussing, by explicitly specifying the user id which has access to the desired credentials AND also checking 'No need for re-authentication' presents another security threat, albeit a different one. However, this is agreed by the administrator or the user configuring the job since he or she actively checks that box. If the malicious user J.Random.User would have permissions to add a job in downstream (even if it were hidden), that means he could also take advantage of the previously described threat.

          Following the same thought pattern, it would make sense to have a similar logic allowed for the 'Run as the user who triggered the build.' option.
          Just a thought.

          Doru Căilean added a comment - The security constraints do make sense, but I can think of a lot of cases where allowing the user that triggered the job to access its own credentials would be useful. In the case of the Authorize Project Plugin, specifying a user ID also allows one to select a 'No need for re-authentication' option. Their documentation warns about the security threats by saying: This can threaten your Jenkins security. Be careful to use. Do not require authentication in the next configuration if the User ID is not changed. Use this feature carefully, for a malicious user can run unintended commands without authentication by changing configuration of the project. You should also watch CONFIGURE privilege for this project is granted only to proper users. This does not work when configuring via REST/CLI. So, in the flow that we are discussing, by explicitly specifying the user id which has access to the desired credentials AND also checking 'No need for re-authentication' presents another security threat, albeit a different one. However, this is agreed by the administrator or the user configuring the job since he or she actively checks that box. If the malicious user J.Random.User would have permissions to add a job in downstream (even if it were hidden), that means he could also take advantage of the previously described threat. Following the same thought pattern, it would make sense to have a similar logic allowed for the 'Run as the user who triggered the build.' option. Just a thought.

            stephenconnolly Stephen Connolly
            judoole Ole Christian Langfjæran
            Votes:
            0 Vote for this issue
            Watchers:
            6 Start watching this issue

              Created:
              Updated:
              Resolved: