Skip to content

Commit 4e7cea1

Browse files
author
Peter Tierno
committed
Initial commit
0 parents  commit 4e7cea1

File tree

15 files changed

+524
-0
lines changed

15 files changed

+524
-0
lines changed

Diff for: .gitignore

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.idea/
2+
*.iml
3+
target/
4+
work/
5+
.classpath
6+
.project
7+
.settings/
8+
*.sublime*
9+
tmp/

Diff for: LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2016 Datapipe, Inc.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Diff for: README.md

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# jenkins-vault-plugin
2+
3+
## TODO: Write documentation
4+

Diff for: pom.xml

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<parent>
7+
<groupId>org.jenkins-ci.plugins</groupId>
8+
<artifactId>plugin</artifactId>
9+
<version>2.3</version>
10+
<relativePath/>
11+
</parent>
12+
<groupId>com.datapipe.jenkins.plugins</groupId>
13+
<artifactId>vault</artifactId>
14+
<version>1.0-SNAPSHOT</version>
15+
<packaging>hpi</packaging>
16+
17+
<properties>
18+
<!-- Baseline Jenkins version you use to build the plugin. Users must have this version or newer to run. -->
19+
<jenkins.version>1.625.3</jenkins.version>
20+
<!-- Java Level to use. Java 7 required when using core >= 1.612 -->
21+
<java.level>7</java.level>
22+
<!-- Jenkins Test Harness version you use to test the plugin. -->
23+
<!-- For Jenkins version >= 1.580.1 use JTH 2.x or higher. -->
24+
<jenkins-test-harness.version>2.1</jenkins-test-harness.version>
25+
<!-- Other properties you may want to use:
26+
~ hpi-plugin.version: The HPI Maven Plugin version used by the plugin..
27+
~ stapler-plugin.version: The Stapler Maven plugin version required by the plugin.
28+
-->
29+
</properties>
30+
31+
<name>vault</name>
32+
<description>Build Wrapper for reading secrets in a HashiCorp Vault</description>
33+
<url>https://github.datapipe.net/datapipe/jenkins-vault-plugin</url>
34+
35+
<!-- The default licence for Jenkins OSS Plugins is MIT. Substitute for the applicable one if needed. -->
36+
37+
<licenses>
38+
<license>
39+
<name>MIT License</name>
40+
<url>http://opensource.org/licenses/MIT</url>
41+
</license>
42+
</licenses>
43+
44+
<!-- If you want this to appear on the wiki page:
45+
<developers>
46+
<developer>
47+
<id>ptierno</id>
48+
<name>Peter A. Tierno</name>
49+
<email>[email protected]</email>
50+
</developer>
51+
</developers>
52+
-->
53+
<!-- Assuming you want to host on @jenkinsci:
54+
<scm>
55+
<connection>scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git</connection>
56+
<developerConnection>scm:git:[email protected]:jenkinsci/${project.artifactId}-plugin.git</developerConnection>
57+
<url>http://github.com/jenkinsci/${project.artifactId}-plugin</url>
58+
</scm>
59+
-->
60+
<scm>
61+
<connection>scm:git:</connection>
62+
<developerConnection>scm:git:[email protected]/datapipe/jenkins-${project.artifactId}-plugin.git</developerConnection>
63+
<url>http://github.datapipe.net/datapipe/jenkins-${project.artifactId}-plugin</url>
64+
</scm>
65+
<repositories>
66+
<repository>
67+
<id>repo.jenkins-ci.org</id>
68+
<url>http://repo.jenkins-ci.org/public/</url>
69+
</repository>
70+
</repositories>
71+
<pluginRepositories>
72+
<pluginRepository>
73+
<id>repo.jenkins-ci.org</id>
74+
<url>http://repo.jenkins-ci.org/public/</url>
75+
</pluginRepository>
76+
</pluginRepositories>
77+
<dependencies>
78+
<!-- possibly adding this
79+
<dependency>
80+
<groupId>org.jenkins-ci.plugins</groupId>
81+
<artifactId>credentials</artifactId>
82+
<version>1.9.4</version>
83+
</dependency>
84+
-->
85+
<dependency>
86+
<groupId>com.bettercloud</groupId>
87+
<artifactId>vault-java-driver</artifactId>
88+
<version>1.1.0</version>
89+
</dependency>
90+
</dependencies>
91+
92+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
/**
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2016 Datapipe, Inc.
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
package com.datapipe.jenkins.vault;
25+
26+
import java.io.IOException;
27+
import java.io.PrintStream;
28+
import java.util.List;
29+
import javax.annotation.CheckForNull;
30+
31+
import com.bettercloud.vault.Vault;
32+
import com.bettercloud.vault.VaultConfig;
33+
import com.bettercloud.vault.VaultException;
34+
35+
import hudson.EnvVars;
36+
import hudson.Extension;
37+
import hudson.FilePath;
38+
import hudson.Launcher;
39+
import hudson.model.AbstractProject;
40+
import hudson.model.Descriptor;
41+
import hudson.model.Run;
42+
import hudson.model.TaskListener;
43+
import hudson.tasks.BuildWrapper;
44+
import jenkins.tasks.SimpleBuildWrapper;
45+
import hudson.util.Secret;
46+
47+
import net.sf.json.JSONNull;
48+
import net.sf.json.JSONObject;
49+
50+
import org.kohsuke.stapler.DataBoundConstructor;
51+
import org.kohsuke.stapler.DataBoundSetter;
52+
import org.kohsuke.stapler.StaplerRequest;
53+
54+
/**
55+
* Sample {@link BuildWrapper}.
56+
*
57+
* <p>
58+
* When the user configures the project and enables this builder,
59+
* {@link DescriptorImpl#newInstance(StaplerRequest)} is invoked and a new {@link VaultBuildWrapper}
60+
* is created. The created instance is persisted to the project configuration XML by using XStream,
61+
* so this allows you to use instance fields (like {@link #vaultUrl}) to remember the configuration.
62+
* </p>
63+
*
64+
* <p>
65+
* When a build is performed, the {@link #preCheckout(AbstractBuild, Launcher, BuildListener)}
66+
* method will be invoked.
67+
* </p>
68+
*
69+
* @author Peter Tierno {@literal <}ptierno{@literal @}datapipe.com{@literal >}
70+
*/
71+
public class VaultBuildWrapper extends SimpleBuildWrapper {
72+
73+
private String vaultUrl;
74+
private Secret authToken;
75+
private List<VaultSecret> vaultSecrets;
76+
77+
// Possibly add these later
78+
// private final int openTimeout;
79+
// private final int readTimeout;
80+
81+
// Fields in config.jelly must match the parameter names in the "DataBoundConstructor"
82+
@DataBoundConstructor
83+
public VaultBuildWrapper(@CheckForNull List<VaultSecret> vaultSecrets) {
84+
this.vaultSecrets = vaultSecrets;
85+
86+
// Defaults to null to allow using global configuration
87+
this.vaultUrl = null;
88+
this.authToken = null;
89+
}
90+
91+
@DataBoundSetter
92+
public void setVaultUrl(String vaultUrl) {
93+
this.vaultUrl = vaultUrl;
94+
}
95+
96+
public String getVaultUrl() {
97+
return this.vaultUrl;
98+
}
99+
100+
@DataBoundSetter
101+
public void setAuthToken(String authToken) {
102+
this.authToken = Secret.fromString(authToken);
103+
}
104+
105+
public Secret getAuthToken() {
106+
return this.authToken;
107+
}
108+
109+
public List<VaultSecret> getVaultSecrets() {
110+
return this.vaultSecrets;
111+
}
112+
113+
private String getUrl() {
114+
if (this.vaultUrl == null || this.vaultUrl.isEmpty()) {
115+
return getDescriptor().getVaultUrl();
116+
}
117+
return this.vaultUrl;
118+
}
119+
120+
private Secret getToken() {
121+
if (this.authToken == null || Secret.toString(this.authToken).isEmpty()) {
122+
return getDescriptor().getAuthToken();
123+
}
124+
return this.authToken;
125+
}
126+
127+
// Overridden for better type safety.
128+
// If your plugin doesn't really define any property on Descriptor
129+
// you don't have to do this.
130+
@Override
131+
public DescriptorImpl getDescriptor() {
132+
return (DescriptorImpl) super.getDescriptor();
133+
}
134+
135+
@Override
136+
public void setUp(Context context, Run<?, ?> build, FilePath workspace,
137+
Launcher launcher, TaskListener listener, EnvVars initialEnvironment)
138+
throws IOException, InterruptedException {
139+
// This is where you 'build' the project.
140+
PrintStream logger = listener.getLogger();
141+
142+
String url = getUrl();
143+
String token = Secret.toString(getToken());
144+
145+
for (VaultSecret vaultSecret : vaultSecrets) {
146+
try {
147+
VaultConfig vaultConfig = new VaultConfig(url, token).build();
148+
149+
Vault vault = new Vault(vaultConfig);
150+
151+
String value = vault.logical().read(vaultSecret.getPath()).getData()
152+
.get(vaultSecret.getSecret());
153+
154+
context.env(vaultSecret.getEnvVar(), value);
155+
156+
} catch (VaultException e) {
157+
e.printStackTrace(logger);
158+
throw new InterruptedException(e.getMessage());
159+
}
160+
}
161+
}
162+
163+
/**
164+
* Descriptor for {@link VaultBuildWrapper}. Used as a singleton. The class is marked as public so
165+
* that it can be accessed from views.
166+
*
167+
* <p>
168+
* See <tt>src/main/resources/com/datapipe/jenkins/vault/VaultBuildWrapper/*.jelly</tt> for the
169+
* actual HTML fragment for the configuration screen.
170+
*/
171+
@Extension // This indicates to Jenkins that this is an implementation of an extension point.
172+
public static final class DescriptorImpl extends Descriptor<BuildWrapper> {
173+
174+
/**
175+
* To persist global configuration information, simply store it in a field and call save().
176+
*
177+
* <p>
178+
* If you don't want fields to be persisted, use <tt>transient</tt>.
179+
*/
180+
private String vaultUrl;
181+
private Secret authToken;
182+
183+
/**
184+
* In order to load the persisted global configuration, you have to call load() in the
185+
* constructor.
186+
*/
187+
public DescriptorImpl() {
188+
super(VaultBuildWrapper.class);
189+
load();
190+
}
191+
192+
public boolean isApplicable(AbstractProject<?, ?> item) {
193+
// Indicates that this builder can be used with all kinds of project types
194+
return true;
195+
}
196+
197+
/**
198+
* This human readable name is used in the configuration screen.
199+
*/
200+
@Override
201+
public String getDisplayName() {
202+
return "Vault Plugin";
203+
}
204+
205+
@Override
206+
public boolean configure(StaplerRequest req, JSONObject formData)
207+
throws FormException {
208+
// To persist global configuration information,
209+
// set that to properties and call save().
210+
Object vaultUrl = formData.getString("vaultUrl");
211+
Object authToken = formData.getString("authToken");
212+
213+
if (!JSONNull.getInstance().equals(vaultUrl)) {
214+
this.vaultUrl = (String) vaultUrl;
215+
} else {
216+
this.vaultUrl = null;
217+
}
218+
219+
if (!JSONNull.getInstance().equals(authToken)) {
220+
this.authToken = Secret.fromString((String) authToken);
221+
} else {
222+
this.authToken = null;
223+
}
224+
225+
save();
226+
return super.configure(req, formData);
227+
}
228+
229+
public String getVaultUrl() {
230+
return this.vaultUrl;
231+
}
232+
233+
public Secret getAuthToken() {
234+
return this.authToken;
235+
}
236+
237+
// Required by external plugins (according to Articfactory plugin)
238+
public void setVaultUrl(String vaultUrl) {
239+
this.vaultUrl = vaultUrl;
240+
}
241+
242+
public void setAuthToken(String authToken) {
243+
this.authToken = Secret.fromString(authToken);
244+
}
245+
}
246+
247+
}

0 commit comments

Comments
 (0)