diff --git a/docs/examples/README.md b/docs/examples/README.md index 0d79a6f3..8c86f095 100644 --- a/docs/examples/README.md +++ b/docs/examples/README.md @@ -80,8 +80,16 @@ Only AWS AccessKey and SecretKey: Sometimes you may want the secret to be able to be consumed by another tool as well that has a different requirement for the data fields. In order to facilitate this the plugin supports the remapping fields. -In order to achieve this you add an attribute begining with `jenkins.io/credentials-keybinding-` and ending with the normal field name and having the value of the new field name. +In order to achieve this you add an attribute beginning with `jenkins.io/credentials-keybinding-` and ending with the normal field name and having the value of the new field name. The following example remaps the `username` and `password` fields to `user` and `pass`: {% highlight yaml linenos %} {% include_relative username-pass-with-custom-mapping.yaml %} {% endhighlight %} + +# Overriding the Credential Name + +By default, the name of the `Secret` will be used as the name of the credential, but as Kubernetes only allows valid DNS names as `Secret` names you may want to override this behaviour. +In order to achieve this you need to add a label to the `Secret` with the name `jenkins.io/credentials-id` and the value of the credential name you wish to configure. +{% highlight yaml linenos %} +{% include_relative username-pass-with-name-override.yaml %} +{% endhighlight %} \ No newline at end of file diff --git a/docs/examples/username-pass-with-name-override.yaml b/docs/examples/username-pass-with-name-override.yaml new file mode 100644 index 00000000..21cbadd2 --- /dev/null +++ b/docs/examples/username-pass-with-name-override.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Secret +metadata: +# this is the jenkins id. + name: "another-test-usernamepass" + labels: +# so we know what type it is. + "jenkins.io/credentials-type": "usernamePassword" +# override the credential id + "jenkins.io/credentials-id": "CUSTOM_ID_OF_CREDENTIAL" + annotations: +# description - can not be a label as spaces are not allowed + "jenkins.io/credentials-description" : "credentials from Kubernetes" +type: Opaque +stringData: + username: myUsername + password: 'Pa$$word' diff --git a/src/main/java/com/cloudbees/jenkins/plugins/kubernetes_credentials_provider/SecretUtils.java b/src/main/java/com/cloudbees/jenkins/plugins/kubernetes_credentials_provider/SecretUtils.java index a35054c9..66ffe3b6 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/kubernetes_credentials_provider/SecretUtils.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/kubernetes_credentials_provider/SecretUtils.java @@ -58,6 +58,8 @@ public abstract class SecretUtils { /** Annotation prefix for the optional custom mapping of data */ private static final String JENKINS_IO_CREDENTIALS_KEYBINDING_ANNOTATION_PREFIX = "jenkins.io/credentials-keybinding-"; + static final String JENKINS_IO_CREDENTIALS_ID_LABEL = "jenkins.io/credentials-id"; + static final String JENKINS_IO_CREDENTIALS_TYPE_LABEL = "jenkins.io/credentials-type"; static final String JENKINS_IO_CREDENTIALS_SCOPE_LABEL = "jenkins.io/credentials-scope"; @@ -128,6 +130,13 @@ public static CredentialsScope getCredentialScope(Secret s) throws CredentialsCo * @return the credential ID for a given secret. */ public static String getCredentialId(Secret s) { + Map labels = s.getMetadata().getLabels(); + if (labels != null) { + String overrideId = labels.get(JENKINS_IO_CREDENTIALS_ID_LABEL); + if (overrideId != null) { + return overrideId; + } + } // we must have a metadata as the label that identifies this as a Jenkins credential needs to be present return s.getMetadata().getName(); } diff --git a/src/test/java/com/cloudbees/jenkins/plugins/kubernetes_credentials_provider/KubernetesCredentialsProviderTest.java b/src/test/java/com/cloudbees/jenkins/plugins/kubernetes_credentials_provider/KubernetesCredentialsProviderTest.java index 4ac1e592..959c5971 100644 --- a/src/test/java/com/cloudbees/jenkins/plugins/kubernetes_credentials_provider/KubernetesCredentialsProviderTest.java +++ b/src/test/java/com/cloudbees/jenkins/plugins/kubernetes_credentials_provider/KubernetesCredentialsProviderTest.java @@ -81,6 +81,7 @@ public void startWatchingForSecrets() { Secret s1 = createSecret("s1"); Secret s2 = createSecret("s2"); Secret s3 = createSecret("s3"); + Secret s4 = createSecretWithNameOverride("s4", "INVALID_SECRET_NAME"); // returns s1 and s3, the credentials map should be reset to this list server.expect().withPath("/api/v1/namespaces/test/secrets?labelSelector=jenkins.io%2Fcredentials-type") @@ -88,7 +89,7 @@ public void startWatchingForSecrets() { .withNewMetadata() .withResourceVersion("1") .endMetadata() - .addToItems(s1, s3) + .addToItems(s1, s3, s4) .build()) .once(); @@ -104,9 +105,10 @@ public void startWatchingForSecrets() { provider.startWatchingForSecrets(); List credentials = provider.getCredentials(UsernamePasswordCredentials.class, (ItemGroup) null, ACL.SYSTEM); - assertEquals("credentials", 2, credentials.size()); + assertEquals("credentials", 3, credentials.size()); assertTrue("secret s1 exists", credentials.stream().anyMatch(c -> "s1".equals(((UsernamePasswordCredentialsImpl) c).getId()))); assertTrue("secret s3 exists", credentials.stream().anyMatch(c -> "s3".equals(((UsernamePasswordCredentialsImpl) c).getId()))); + assertTrue("secret s4 exists", credentials.stream().anyMatch(c -> "INVALID_SECRET_NAME".equals(((UsernamePasswordCredentialsImpl) c).getId()))); } private Secret createSecret(String name) { @@ -121,6 +123,19 @@ private Secret createSecret(String name) { .build(); } + private Secret createSecretWithNameOverride(String name, String nameOverride) { + return new SecretBuilder() + .withNewMetadata() + .withNamespace("test") + .withName(name) + .addToLabels("jenkins.io/credentials-type", "usernamePassword") + .addToLabels("jenkins.io/credentials-id", nameOverride) + .endMetadata() + .addToData("username", "bXlVc2VybmFtZQ==") + .addToData("password", "UGEkJHdvcmQ=") + .build(); + } + @Test public void startWatchingForSecretsKubernetesClientException() throws IOException { KubernetesCredentialProvider provider = new MockedKubernetesCredentialProvider(); diff --git a/src/test/java/com/cloudbees/jenkins/plugins/kubernetes_credentials_provider/SecretUtilsTest.java b/src/test/java/com/cloudbees/jenkins/plugins/kubernetes_credentials_provider/SecretUtilsTest.java index a32d50a9..ae73bd78 100644 --- a/src/test/java/com/cloudbees/jenkins/plugins/kubernetes_credentials_provider/SecretUtilsTest.java +++ b/src/test/java/com/cloudbees/jenkins/plugins/kubernetes_credentials_provider/SecretUtilsTest.java @@ -93,6 +93,18 @@ public void getCredentialId() { assertThat(SecretUtils.getCredentialId(s), is(testName)); } + @Test + public void getCredentialIdWithNameOverride() { + final String secretName = "a-test-name"; + final String credentialName = "A_TEST_NAME"; + Secret s = new SecretBuilder() + .withNewMetadata() + .withName(secretName) + .withLabels(Collections.singletonMap(SecretUtils.JENKINS_IO_CREDENTIALS_ID_LABEL, credentialName)) + .endMetadata().build(); + assertThat(SecretUtils.getCredentialId(s), is(credentialName)); + } + @Test public void getCredentialDescription() { final String testDescription = "a-test-description";