From 441a59f47b76fdddacb3ca3145c0fc99dcf840e9 Mon Sep 17 00:00:00 2001 From: Taylor Daugherty Date: Sun, 31 Jan 2021 00:05:43 -0500 Subject: [PATCH] Support JCasC --- README.md | 55 ++++++++++++++++++- pom.xml | 17 +++++- .../gcp/secretsmanager/config/Filter.java | 6 +- .../config/PluginConfiguration.java | 2 + .../ConfigurationAsCodeTest.java | 24 ++++++++ src/test/resources/configuration-as-code.yml | 6 ++ 6 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 src/test/java/io/jenkins/plugins/credentials/gcp/secretsmanager/ConfigurationAsCodeTest.java create mode 100644 src/test/resources/configuration-as-code.yml diff --git a/README.md b/README.md index 3580638..dabb685 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,47 @@ to the instance running Jenkins. You can use [Workload Identity](https://cloud.g if running Jenkins on Google Kubernetes Engine. If you are not running Jenkins on GCP, set the environment variable `GOOGLE_APPLICATION_CREDENTIALS` for the Jenkins process -to the path of a JSON service account key with the above permissions. +to the path of a [JSON service account key](https://cloud.google.com/iam/docs/creating-managing-service-account-keys) with the above permissions. + +When using JSON service account keys, both the master and agents must have the environment variable `GOOGLE_APPLICATION_CREDENTIALS` +set to an accessible file. For example, when using the Kubernetes plugin it is recommended to provide +a secret volume that mounts the file into the agent pod: + +```groovy +podTemplate(yaml: """ +apiVersion: v1 +kind: Pod +metadata: + labels: + some-label: some-label-value +spec: + containers: + - name: busybox + image: busybox + env: + - name: GOOGLE_APPLICATION_CREDENTIALS + value: /jenkins/sa.json + volumeMounts: + - name: gcp-sa-secret + mountPath: "/jenkins" + readOnly: true + volumes: + - name: gcp-sa-secret + secret: + secretName: gcp-sa-secret +""" +) { + node(POD_LABEL) { + ... + } +} +``` + +Where the secret was created with the following command: + +```shell script +kubectl create secret generic gcp-sa-secret --from-file=/tmp/sa.json +``` ### Filtering @@ -65,6 +105,19 @@ GCP Secrets Manager does not currently support "server-side" filtering. You can use a comma-separated string for the label value, which will tell Jenkins to add the secret to the store if it matches any of the provided values. +### JCasC + +You can use [JCasC](https://www.jenkins.io/projects/jcasc/) to set the GCP project and label filters. + +```yaml +unclassified: + gcpCredentialsProvider: + filter: + label: "my-label" + value: "my-value-1,my-value-2" + project: "my-gcp-project" +``` + ## Examples ### Secret Text diff --git a/pom.xml b/pom.xml index ef54de0..5252c23 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,6 @@ 2.263 8 - 1.35 2.7.0 @@ -85,6 +84,11 @@ org.jenkins-ci.plugins ssh-credentials + + io.jenkins + configuration-as-code + true + com.google.cloud google-cloud-secretmanager @@ -105,6 +109,17 @@ 3.19.0 test + + io.jenkins.configuration-as-code + test-harness + test + + + org.jenkins-ci.plugins + jackson2-api + + + diff --git a/src/main/java/io/jenkins/plugins/credentials/gcp/secretsmanager/config/Filter.java b/src/main/java/io/jenkins/plugins/credentials/gcp/secretsmanager/config/Filter.java index cbd9c4d..328c5a2 100644 --- a/src/main/java/io/jenkins/plugins/credentials/gcp/secretsmanager/config/Filter.java +++ b/src/main/java/io/jenkins/plugins/credentials/gcp/secretsmanager/config/Filter.java @@ -15,8 +15,8 @@ public class Filter extends AbstractDescribableImpl implements Serializa private String value; @DataBoundConstructor - public Filter(String key, String value) { - this.label = key; + public Filter(String label, String value) { + this.label = label; this.value = value; } @@ -41,7 +41,7 @@ public void setValue(String value) { } @Extension - @Symbol("filters") + @Symbol("filter") @SuppressWarnings("unused") public static class DescriptorImpl extends Descriptor { diff --git a/src/main/java/io/jenkins/plugins/credentials/gcp/secretsmanager/config/PluginConfiguration.java b/src/main/java/io/jenkins/plugins/credentials/gcp/secretsmanager/config/PluginConfiguration.java index cafec51..20d3939 100644 --- a/src/main/java/io/jenkins/plugins/credentials/gcp/secretsmanager/config/PluginConfiguration.java +++ b/src/main/java/io/jenkins/plugins/credentials/gcp/secretsmanager/config/PluginConfiguration.java @@ -3,10 +3,12 @@ import hudson.Extension; import jenkins.model.GlobalConfiguration; import net.sf.json.JSONObject; +import org.jenkinsci.Symbol; import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.StaplerRequest; @Extension +@Symbol("gcpCredentialsProvider") public class PluginConfiguration extends GlobalConfiguration { private String project; diff --git a/src/test/java/io/jenkins/plugins/credentials/gcp/secretsmanager/ConfigurationAsCodeTest.java b/src/test/java/io/jenkins/plugins/credentials/gcp/secretsmanager/ConfigurationAsCodeTest.java new file mode 100644 index 0000000..b088096 --- /dev/null +++ b/src/test/java/io/jenkins/plugins/credentials/gcp/secretsmanager/ConfigurationAsCodeTest.java @@ -0,0 +1,24 @@ +package io.jenkins.plugins.credentials.gcp.secretsmanager; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +import io.jenkins.plugins.casc.misc.ConfiguredWithCode; +import io.jenkins.plugins.casc.misc.JenkinsConfiguredWithCodeRule; +import io.jenkins.plugins.credentials.gcp.secretsmanager.config.PluginConfiguration; +import org.junit.Rule; +import org.junit.Test; + +public class ConfigurationAsCodeTest { + + @Rule public JenkinsConfiguredWithCodeRule r = new JenkinsConfiguredWithCodeRule(); + + @Test + @ConfiguredWithCode("configuration-as-code.yml") + public void should_support_configuration_as_code() throws Exception { + PluginConfiguration configuration = + (PluginConfiguration) r.jenkins.getDescriptor(PluginConfiguration.class); + assertThat(configuration.getProject()).isEqualTo("gcp-project"); + assertThat(configuration.getFilter().getLabel()).isEqualTo("my-label"); + assertThat(configuration.getFilter().getValue()).isEqualTo("my-value"); + } +} diff --git a/src/test/resources/configuration-as-code.yml b/src/test/resources/configuration-as-code.yml new file mode 100644 index 0000000..686d9b5 --- /dev/null +++ b/src/test/resources/configuration-as-code.yml @@ -0,0 +1,6 @@ +unclassified: + gcpCredentialsProvider: + filter: + label: "my-label" + value: "my-value" + project: "gcp-project"