jenkinsci / azure-credentials-plugin

Jenkins Azure Credentials plugin
https://plugins.jenkins.io/azure-credentials/
MIT License
10 stars 26 forks source link

CasC: clientSecret is not exported with encrypted value for Service Principal #209

Closed rmontag-ap closed 1 year ago

rmontag-ap commented 1 year ago

Jenkins and plugins versions report

Environment ``` Jenkins: 2.401.3 OS: Linux - 3.10.0-1160.83.1.el7.x86_64 Java: 11.0.19 - Red Hat, Inc. (OpenJDK 64-Bit Server VM) --- ant:497.v94e7d9fffa_b_9 antisamy-markup-formatter:162.v0e6ec0fcfcf6 apache-httpcomponents-client-4-api:4.5.14-150.v7a_b_9d17134a_5 azure-credentials:254.v64da_8176c83a azure-sdk:132.v62b_48eb_6f32f bootstrap5-api:5.3.0-1 bouncycastle-api:2.29 branch-api:2.1122.v09cb_8ea_8a_724 build-timeout:1.31 caffeine-api:3.1.6-115.vb_8b_b_328e59d8 checks-api:2.0.0 cloudbees-folder:6.815.v0dd5a_cb_40e0e commons-lang3-api:3.13.0-62.v7d18e55f51e2 commons-text-api:1.10.0-68.v0d0b_c439292b_ configuration-as-code:1670.v564dc8b_982d0 credentials:1271.v54b_1c2c6388a_ credentials-binding:631.v861c06d062b_4 display-url-api:2.3.8 durable-task:513.vc48a_a_075a_d93 echarts-api:5.4.0-5 email-ext:2.100 font-awesome-api:6.4.0-2 git:5.2.0 git-client:4.4.0 github:1.37.2 github-api:1.314-431.v78d72a_3fe4c3 github-branch-source:1732.v3f1889a_c475b_ gradle:2.8.2 instance-identity:173.va_37c494ec4e5 ionicons-api:56.v1b_1c8c49374e jackson2-api:2.15.2-350.v0c2f3f8fc595 jakarta-activation-api:2.0.1-3 jakarta-mail-api:2.0.1-3 javax-activation-api:1.2.0-6 javax-mail-api:1.6.2-9 jaxb:2.3.8-1 jjwt-api:0.11.5-77.v646c772fddb_0 jquery3-api:3.7.0-1 junit:1217.v4297208a_a_b_ce ldap:694.vc02a_69c9787f mailer:463.vedf8358e006b_ matrix-auth:3.1.10 matrix-project:802.v8013b_40c7edc mina-sshd-api-common:2.10.0-69.v28e3e36d18eb_ mina-sshd-api-core:2.10.0-69.v28e3e36d18eb_ okhttp-api:4.11.0-157.v6852a_a_fa_ec11 pam-auth:1.10 pipeline-build-step:505.v5f0844d8d126 pipeline-github-lib:42.v0739460cda_c4 pipeline-graph-analysis:202.va_d268e64deb_3 pipeline-groovy-lib:671.v07c339c842e8 pipeline-input-step:477.v339683a_8d55e pipeline-milestone-step:111.v449306f708b_7 pipeline-model-api:2.2144.v077a_d1928a_40 pipeline-model-definition:2.2144.v077a_d1928a_40 pipeline-model-extensions:2.2144.v077a_d1928a_40 pipeline-rest-api:2.33 pipeline-stage-step:305.ve96d0205c1c6 pipeline-stage-tags-metadata:2.2144.v077a_d1928a_40 pipeline-stage-view:2.33 plain-credentials:143.v1b_df8b_d3b_e48 plugin-util-api:3.3.0 resource-disposer:0.23 scm-api:676.v886669a_199a_a_ script-security:1264.vecf66020eb_7d snakeyaml-api:1.33-95.va_b_a_e3e47b_fa_4 ssh-credentials:308.ve4497b_ccd8f4 ssh-slaves:2.916.vd17b_43357ce4 structs:324.va_f5d6774f3a_d timestamper:1.26 token-macro:383.v36161104b_002 trilead-api:2.84.v72119de229b_7 variant:59.vf075fe829ccb workflow-aggregator:596.v8c21c963d92d workflow-api:1251.vd4889a_b_0a_065 workflow-basic-steps:1042.ve7b_140c4a_e0c workflow-cps:3731.ve4b_5b_857b_a_d3 workflow-durable-task-step:1278.v94b_dc2b_50c6f workflow-job:1316.vd2290d3341a_f workflow-multibranch:756.v891d88f2cd46 workflow-scm-step:415.v434365564324 workflow-step-api:639.v6eca_cd8c04a_a_ workflow-support:848.v5a_383b_d14921 ws-cleanup:0.45 ```

What Operating System are you using (both controller, and any agents involved in the problem)?

OS: Linux - 3.10.0-1160.83.1.el7.x86_64 CentOS 7.9

Reproduction steps

  1. Install CasC plugin (configuration-as-code:1670.v564dc8b_982d0)
  2. Create a credential of type "Azure Service Principal" with a Client Secret
  3. Create a credential of type "Username with password"
  4. Go to "Manage Jenkins" -> "Configuration as Code" ->"View Configuration"

Expected Results

See actual results; the client secret is exported as "****". For other credential types - like Username with password - secret values are always exported as encrypted values. Having those encrypted values it is possible to re-apply the configuration on the same Jenkins instance. This is not possible with Service Principals, as the client secret got broken after importing, becoming "****". I would expect the value of client secret - encrypted, something like this:

credentials:
  system:
    domainCredentials:
    - credentials:
      - azure:
          azureEnvironmentName: "Azure"
          clientId: "12345"
          clientSecret: "{AQAAABAAAAAQ4ahFKwdhSV5Iu3DrHJuEaThaYnPCYnc35Yf9wUEiXg8=}"
          id: "test-sp"
          scope: GLOBAL
          subscriptionId: "12345"
          tenant: "12345"
      - usernamePassword:
          id: "test-up"
          password: "{AQAAABAAAAAQ4ahFKwdhSV5Iu3DrHJuEaThaYnPCYnc35Yf9wUEiXg8=}"
          scope: GLOBAL
          username: "12345"

Actual Results

The client secret is exported as "****":

credentials:
  system:
    domainCredentials:
    - credentials:
      - azure:
          azureEnvironmentName: "Azure"
          clientId: "12345"
          clientSecret: "****"
          id: "test-sp"
          scope: GLOBAL
          subscriptionId: "12345"
          tenant: "12345"
      - usernamePassword:
          id: "test-up"
          password: "{AQAAABAAAAAQ4ahFKwdhSV5Iu3DrHJuEaThaYnPCYnc35Yf9wUEiXg8=}"
          scope: GLOBAL
          username: "12345"

Anything else?

No response

timja commented 1 year ago

Probably because this returns a String instead of a Secret: https://github.com/jenkinsci/azure-credentials-plugin/blob/95b4d3afcdefdb3642a1955eb44145be118d5a5d/src/main/java/com/microsoft/azure/util/AzureCredentials.java#L602-L606

I doubt anything would be using the encrypted value directly there, would need to evaluate if there's any impact to any plugins to changing it but possibly an easy fix

rmontag-ap commented 1 year ago

In can do this in script console, using plainClientSecret, not clientSecret::

def azureCreds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
    com.microsoft.azure.util.AzureBaseCredentials.class,
    Jenkins.instance,
    hudson.security.ACL.SYSTEM,
    Collections.<com.cloudbees.plugins.credentials.domains.DomainRequirement>emptyList());

for (ac in azureCreds) {
  println(String.format("id=%s  desc=%s clientId=%s clientSecret=%s\n", ac.id, ac.description, ac.clientId, hudson.util.Secret.fromString(ac.plainClientSecret).getEncryptedValue()))
}

which returns what I expect, as plainClientSecret really returns the unencrypted secret as string:

id=test-sp  desc= clientId=12345 clientSecret={AQAAABAAAAAQtj0AOLpSVcNTCNylbtWu5MZuNaIXQE/BItTyZhlf6aQ=}