Skip to content

Commit 829b33b

Browse files
committed
Added VaultAwsCredentials
1 parent 0a1c04c commit 829b33b

File tree

15 files changed

+403
-4
lines changed

15 files changed

+403
-4
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ work/
1010
tmp/
1111
src/test/resources/com/datapipe/jenkins/vault/util/ssl/
1212
.DS_Store
13+
.vscode/

pom.xml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<?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" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
3-
<modelVersion>4.0.0</modelVersion>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion>
43
<parent>
54
<groupId>org.jenkins-ci.plugins</groupId>
65
<artifactId>plugin</artifactId>
@@ -137,6 +136,11 @@
137136
<groupId>org.jenkins-ci.plugins</groupId>
138137
<artifactId>credentials-binding</artifactId>
139138
</dependency>
139+
<dependency>
140+
<groupId>org.jenkins-ci.plugins</groupId>
141+
<artifactId>aws-credentials</artifactId>
142+
<version>191.vcb_f183ce58b_9</version>
143+
</dependency>
140144
<dependency>
141145
<groupId>io.jenkins</groupId>
142146
<artifactId>configuration-as-code</artifactId>

src/main/java/com/datapipe/jenkins/vault/credentials/VaultAwsIamCredential.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public class VaultAwsIamCredential extends AbstractAuthenticatingVaultTokenCrede
2424

2525
@DataBoundConstructor
2626
public VaultAwsIamCredential(@CheckForNull CredentialsScope scope, @CheckForNull String id,
27-
@CheckForNull String description) {
27+
@CheckForNull String description) {
2828
super(scope, id, description);
2929
}
3030

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.datapipe.jenkins.vault.credentials.common;
2+
3+
import com.cloudbees.jenkins.plugins.awscredentials.AmazonWebServicesCredentials;
4+
import com.cloudbees.plugins.credentials.CredentialsNameProvider;
5+
import com.cloudbees.plugins.credentials.NameWith;
6+
import edu.umd.cs.findbugs.annotations.NonNull;
7+
import hudson.Util;
8+
9+
@NameWith(value = VaultAwsCredential.NameProvider.class, priority = 32)
10+
public interface VaultAwsCredential extends AmazonWebServicesCredentials {
11+
12+
String getDisplayName();
13+
14+
class NameProvider extends CredentialsNameProvider<VaultAwsCredential> {
15+
16+
@NonNull
17+
@Override
18+
public String getName(VaultAwsCredential hashicorpVaultCredentials) {
19+
String description = Util.fixEmpty(hashicorpVaultCredentials.getDescription());
20+
return hashicorpVaultCredentials.getDisplayName() + (description == null ? ""
21+
: " (" + description + ")");
22+
}
23+
}
24+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package com.datapipe.jenkins.vault.credentials.common;
2+
3+
import com.amazonaws.auth.AWSCredentials;
4+
import edu.umd.cs.findbugs.annotations.Nullable;
5+
import hudson.Extension;
6+
import hudson.FilePath;
7+
import hudson.Launcher;
8+
import hudson.model.Item;
9+
import hudson.model.Run;
10+
import hudson.model.TaskListener;
11+
import hudson.util.ListBoxModel;
12+
import java.io.IOException;
13+
import java.util.HashMap;
14+
import java.util.HashSet;
15+
import java.util.Map;
16+
import java.util.Set;
17+
import javax.annotation.Nonnull;
18+
import org.jenkinsci.plugins.credentialsbinding.BindingDescriptor;
19+
import org.jenkinsci.plugins.credentialsbinding.MultiBinding;
20+
import org.kohsuke.stapler.AncestorInPath;
21+
import org.kohsuke.stapler.DataBoundConstructor;
22+
23+
import com.amazonaws.auth.AWSCredentials;
24+
25+
import static com.datapipe.jenkins.vault.configuration.VaultConfiguration.engineVersions;
26+
import static org.apache.commons.lang.StringUtils.defaultIfBlank;
27+
28+
public class VaultAwsCredentialBinding extends
29+
MultiBinding<VaultAwsCredential> {
30+
31+
public static final String DEFAULT_ACCESS_KEY_ID_VARIABLE = "AWS_ACCESS_KEY_ID";
32+
public static final String DEFAULT_SECRET_ACCESS_KEY_VARIABLE = "AWS_SECRET_ACCESS_KEY";
33+
private String accessKeyVariable;
34+
private String secretKeyVariable;
35+
36+
@DataBoundConstructor
37+
public VaultAwsCredentialBinding(@Nullable String accessKeyVariable,
38+
@Nullable String secretKeyVariable,
39+
String credentialsId) {
40+
super(credentialsId);
41+
this.accessKeyVariable = defaultIfBlank(accessKeyVariable, DEFAULT_ACCESS_KEY_ID_VARIABLE);
42+
this.secretKeyVariable = defaultIfBlank(secretKeyVariable, DEFAULT_SECRET_ACCESS_KEY_VARIABLE);
43+
}
44+
45+
@Override
46+
protected Class<VaultAwsCredential> type() {
47+
return VaultAwsCredential.class;
48+
}
49+
50+
@Override
51+
public MultiEnvironment bind(@Nonnull Run<?, ?> build, FilePath workspace, Launcher launcher,
52+
TaskListener listener)
53+
throws IOException, InterruptedException {
54+
AWSCredentials credentials = this.getCredentials(build).getCredentials();
55+
Map<String, String> map = new HashMap<String, String>();
56+
map.put(this.accessKeyVariable, credentials.getAWSAccessKeyId());
57+
map.put(this.secretKeyVariable, credentials.getAWSSecretKey());
58+
return new MultiEnvironment(map);
59+
}
60+
61+
public String getaccessKeyVariable() {
62+
return accessKeyVariable;
63+
}
64+
65+
public String getsecretKeyVariable() {
66+
return secretKeyVariable;
67+
}
68+
69+
@Override
70+
public Set<String> variables() {
71+
Set<String> variables = new HashSet<String>();
72+
variables.add(this.accessKeyVariable);
73+
variables.add(this.secretKeyVariable);
74+
return variables;
75+
}
76+
77+
@Extension
78+
public static class DescriptorImpl extends BindingDescriptor<VaultAwsCredential> {
79+
80+
@Override
81+
protected Class<VaultAwsCredential> type() {
82+
return VaultAwsCredential.class;
83+
}
84+
85+
@Override
86+
public String getDisplayName() {
87+
return "Vault AWS Credentials";
88+
}
89+
90+
@SuppressWarnings("unused") // used by stapler
91+
public ListBoxModel doFillEngineVersionItems(@AncestorInPath Item context) {
92+
return engineVersions(context);
93+
}
94+
}
95+
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
package com.datapipe.jenkins.vault.credentials.common;
2+
3+
import com.amazonaws.auth.AWSCredentials;
4+
import com.amazonaws.auth.BasicAWSCredentials;
5+
import com.cloudbees.jenkins.plugins.awscredentials.AmazonWebServicesCredentials;
6+
import com.cloudbees.plugins.credentials.CredentialsScope;
7+
import edu.umd.cs.findbugs.annotations.NonNull;
8+
import hudson.Extension;
9+
import hudson.model.Item;
10+
import hudson.model.ItemGroup;
11+
import hudson.util.FormValidation;
12+
import hudson.util.ListBoxModel;
13+
import hudson.util.Secret;
14+
import jenkins.model.Jenkins;
15+
import org.kohsuke.stapler.AncestorInPath;
16+
import org.kohsuke.stapler.DataBoundConstructor;
17+
import org.kohsuke.stapler.DataBoundSetter;
18+
import org.kohsuke.stapler.QueryParameter;
19+
20+
import static com.datapipe.jenkins.vault.configuration.VaultConfiguration.engineVersions;
21+
import static com.datapipe.jenkins.vault.credentials.common.VaultHelper.getVaultSecretKey;
22+
import static org.apache.commons.lang.StringUtils.defaultIfBlank;
23+
24+
@SuppressWarnings("ALL")
25+
public class VaultAwsCredentialImpl extends AbstractVaultBaseStandardCredentials implements
26+
VaultAwsCredential {
27+
28+
public static final String DEFAULT_ACCESS_KEY_ID = "accessKeyID";
29+
public static final String DEFAULT_SECRET_ACCESS_KEY = "secretAccessKey";
30+
31+
private static final long serialVersionUID = 1L;
32+
33+
private String accessKey;
34+
private String secretKey;
35+
36+
@DataBoundConstructor
37+
public VaultAwsCredentialImpl(CredentialsScope scope, String id,
38+
String description) {
39+
super(scope, id, description);
40+
}
41+
42+
@NonNull
43+
public String getAccessKey() {
44+
return accessKey;
45+
}
46+
47+
@DataBoundSetter
48+
public void setAccessKey(String accessKey) {
49+
this.accessKey = defaultIfBlank(accessKey, DEFAULT_ACCESS_KEY_ID);
50+
}
51+
52+
@NonNull
53+
public String getSecretKey() {
54+
return secretKey;
55+
}
56+
57+
@DataBoundSetter
58+
public void setSecretKey(String secretKey) {
59+
this.secretKey = defaultIfBlank(secretKey, DEFAULT_SECRET_ACCESS_KEY);
60+
}
61+
62+
// @NonNull
63+
// @Override
64+
public String getAWSAccessKeyId() {
65+
String accessKeyId = defaultIfBlank(accessKey, DEFAULT_ACCESS_KEY_ID);
66+
return getVaultSecretKeyValue(accessKeyId);
67+
}
68+
69+
// @NonNull
70+
// @Override
71+
public Secret getAWSSecretKey() {
72+
String secretKeyId = defaultIfBlank(secretKey, DEFAULT_SECRET_ACCESS_KEY);
73+
String secret = getVaultSecretKeyValue(secretKeyId);
74+
return Secret.fromString(secret);
75+
}
76+
77+
@NonNull
78+
@Override
79+
public AWSCredentials getCredentials(String mfaToken) {
80+
return AmazonWebServicesCredentials.getCredentials(mfaToken);
81+
}
82+
83+
@NonNull
84+
@Override
85+
public void refresh() {
86+
// no-op
87+
}
88+
89+
@Extension
90+
public static class DescriptorImpl extends BaseStandardCredentialsDescriptor {
91+
92+
@Override
93+
public String getDisplayName() {
94+
return "Vault AWSAccessKeyId-AWSSecretKey Credential";
95+
}
96+
97+
public FormValidation doTestConnection(
98+
@AncestorInPath ItemGroup<Item> context,
99+
@QueryParameter("path") String path,
100+
@QueryParameter("accessKey") String accessKey,
101+
@QueryParameter("secretKey") String secretKey,
102+
@QueryParameter("prefixPath") String prefixPath,
103+
@QueryParameter("namespace") String namespace,
104+
@QueryParameter("engineVersion") Integer engineVersion) {
105+
106+
Jenkins.get().checkPermission(Jenkins.ADMINISTER);
107+
108+
String AWSAccessKeyId = null;
109+
try {
110+
AWSAccessKeyId = getVaultSecretKey(path, defaultIfBlank(accessKey, DEFAULT_ACCESS_KEY_ID),
111+
prefixPath,
112+
namespace, engineVersion, context);
113+
} catch (Exception e) {
114+
return FormValidation.error("FAILED to retrieve AWSAccessKeyId key: \n" + e);
115+
}
116+
117+
try {
118+
getVaultSecretKey(path, defaultIfBlank(secretKey, DEFAULT_SECRET_ACCESS_KEY), prefixPath,
119+
namespace,
120+
engineVersion, context);
121+
} catch (Exception e) {
122+
return FormValidation.error("FAILED to retrieve AWSSecretKey key: \n" + e);
123+
}
124+
125+
return FormValidation
126+
.ok("Successfully retrieved AWSAccessKeyId " + AWSAccessKeyId + " and the AWSSecretKey");
127+
}
128+
129+
@SuppressWarnings("unused") // used by stapler
130+
public ListBoxModel doFillEngineVersionItems(@AncestorInPath Item context) {
131+
return engineVersions(context);
132+
}
133+
}
134+
}

src/main/java/com/datapipe/jenkins/vault/credentials/common/VaultFileCredentialBinding.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import hudson.Extension;
44
import hudson.FilePath;
5-
import java.io.IOException;;
5+
import java.io.IOException;
66
import org.jenkinsci.Symbol;
77
import org.jenkinsci.plugins.credentialsbinding.BindingDescriptor;
88
import org.jenkinsci.plugins.credentialsbinding.impl.AbstractOnDiskBinding;

src/main/java/com/datapipe/jenkins/vault/jcasc/secrets/VaultAuthenticator.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,23 @@
66

77
public interface VaultAuthenticator {
88
void authenticate(Vault vault, VaultConfig config) throws VaultException;
9+
910
static VaultAuthenticator of(String token) {
1011
return new VaultSingleTokenAuthenticator(token);
1112
}
13+
1214
static VaultAuthenticator of(VaultAppRole appRole, String mountPath) {
1315
return new VaultAppRoleAuthenticator(appRole, mountPath);
1416
}
17+
1518
static VaultAuthenticator of(VaultUsernamePassword vaultUsernamePassword, String mountPath) {
1619
return new VaultUserPassAuthenticator(vaultUsernamePassword, mountPath);
1720
}
21+
1822
static VaultAuthenticator of(VaultKubernetes vaultKubernetes, String mountPath) {
1923
return new VaultKubernetesAuthenticator(vaultKubernetes, mountPath);
2024
}
25+
2126
static VaultAuthenticator of(VaultAwsIam vaultAwsIam, String mountPath) {
2227
return new VaultAwsIamAuthenticator(vaultAwsIam, mountPath);
2328
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<?jelly escape-by-default='true'?>
3+
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form" xmlns:st="jelly:stapler" xmlns:c="/lib/credentials">
4+
<f:entry title="${%Access Key Variable}" field="accessKeyVariable">
5+
<f:textbox default="AWS_ACCESS_KEY_ID"/>
6+
</f:entry>
7+
<f:entry title="${%Secret Key Variable}" field="secretKeyVariable">
8+
<f:textbox default="AWS_SECRET_ACCESS_KEY"/>
9+
</f:entry>
10+
</j:jelly>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<div>
2+
AWS Jenkins credential backed by a Hashicorp Vault AWS engine
3+
</div>

0 commit comments

Comments
 (0)