Skip to content

Commit 5510bd7

Browse files
authored
Feature: AWS client configuration (#43)
1 parent 8f428ae commit 5510bd7

File tree

51 files changed

+908
-289
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+908
-289
lines changed

docs/README.md

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ This plugin is the high-level counterpart of the [AWS Secrets Manager SecretSour
99

1010
## Contents
1111

12-
- [Authentication](authentication/index.md)
1312
- [Beta Features](beta/index.md)
1413
- [Caching](caching/index.md)
14+
- [Client](client/index.md)
1515
- [Filters](filters/index.md)
1616
- [Networking](networking/index.md)
1717
- [Screenshots](screenshots/index.md)
@@ -64,7 +64,7 @@ Example:
6464

6565
### Jenkins
6666

67-
The plugin uses the AWS Java SDK to communicate with Secrets Manager. If you are running Jenkins outside EC2 or EKS you may need to manually configure the SDK to authenticate with AWS. See the [authentication](authentication/index.md) guide for more information.
67+
The plugin uses the AWS Java SDK to communicate with Secrets Manager. If you are running Jenkins outside EC2 or EKS you may need to manually configure the SDK to authenticate with AWS. See the [client](client/index.md) configuration guide for more information.
6868

6969
Then, install and [configure](#Configuration) the plugin.
7070

@@ -329,10 +329,11 @@ Go to `Manage Jenkins` > `Configure System` > `AWS Secrets Manager Credentials P
329329

330330
Available settings:
331331

332-
- [Cache](caching/index.md) (on/off)
333-
- Endpoint Configuration
334-
- Service Endpoint
335-
- Signing Region
332+
- [Cache](caching/index.md)
333+
- [Client](client/index.md)
334+
- CredentialsProvider
335+
- Endpoint Configuration
336+
- Region
336337
- ListSecrets configuration
337338
- [Filters](filters/index.md)
338339

@@ -345,11 +346,14 @@ You can set plugin configuration using Jenkins [Configuration As Code](https://g
345346
```yaml
346347
unclassified:
347348
awsCredentialsProvider:
348-
cache: (boolean) # optional
349-
endpointConfiguration: # optional
350-
serviceEndpoint: (URL)
351-
signingRegion: (string)
352-
listSecrets: # optional
349+
cache: (boolean) # optional
350+
client: # optional
351+
credentialsProvider: (object) # optional
352+
endpointConfiguration: # optional
353+
serviceEndpoint: (URL)
354+
signingRegion: (string)
355+
region: (string) # optional
356+
listSecrets: # optional
353357
filters:
354358
- key: name
355359
values:

docs/authentication/index.md

Lines changed: 0 additions & 20 deletions
This file was deleted.

docs/client/index.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Client
2+
3+
The plugin allows you to configure the Secrets Manager client that it uses to access secrets.
4+
5+
**We recommend that you use the defaults whenever possible.** This will allow Jenkins to inherit AWS configuration from the environment. Only set these client options if you really need to (for example you have multiple Jenkins AWS plugins installed, and need the Secrets Manager plugin to behave differently to the others).
6+
7+
## Credentials Provider
8+
9+
The plugin supports the following `AWSCredentialsProvider` implementations to authenticate and authorize with Secrets Manager.
10+
11+
*Note: This is not the same thing as a Jenkins `CredentialsProvider`.*
12+
13+
Recommendations:
14+
15+
- Use EC2 Instance Profiles when running Jenkins on EC2.
16+
- Only use the long-lived access key methods when there is no other choice. For example, when Jenkins is running outside of AWS.
17+
- If you see an error along the lines of "Unable to find a region via the region provider chain. Must provide an explicit region in the builder or setup environment to supply a region.", set the region manually.
18+
19+
### Default
20+
21+
This uses the standard AWS credentials lookup chain.
22+
23+
The authentication methods in the chain are:
24+
25+
- EC2 Instance Profiles.
26+
- EC2 Container Service credentials.
27+
- Environment variables (set `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_REGION` before starting Jenkins).
28+
- Java properties (set `aws.accessKeyId`, `aws.secretKey`, and `aws.region` before starting Jenkins).
29+
- User profile (configure `~/.aws/credentials` before starting Jenkins).
30+
- Web Identity Token credentials.
31+
32+
### Profile
33+
34+
This allows you to use named AWS profiles from `~/.aws/config`.
35+
36+
```yaml
37+
unclassified:
38+
awsCredentialsProvider:
39+
client:
40+
credentialsProvider:
41+
profile:
42+
profileName: "foobar"
43+
```
44+
45+
### STS AssumeRole
46+
47+
This allows you to specify IAM roles inline within Jenkins.
48+
49+
```yaml
50+
unclassified:
51+
awsCredentialsProvider:
52+
client:
53+
credentialsProvider:
54+
assumeRole:
55+
roleArn: "arn:aws:iam::111111111111:role/foo"
56+
roleSessionName: "jenkins"
57+
```
58+
59+
## Endpoint Configuration
60+
61+
You can set the AWS endpoint configuration for the client.
62+
63+
```yaml
64+
unclassified:
65+
awsCredentialsProvider:
66+
client:
67+
endpointConfiguration:
68+
serviceEndpoint: "http://localhost:4584"
69+
signingRegion: "us-east-1"
70+
```
71+
72+
## Region
73+
74+
You can set the AWS region for the client.
75+
76+
```yaml
77+
unclassified:
78+
awsCredentialsProvider:
79+
client:
80+
region: "us-east-1"
81+
```
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package io.jenkins.plugins.credentials.secretsmanager.config;
2+
3+
import com.amazonaws.regions.Regions;
4+
import com.amazonaws.services.secretsmanager.AWSSecretsManager;
5+
import com.amazonaws.services.secretsmanager.AWSSecretsManagerClientBuilder;
6+
import hudson.Extension;
7+
import hudson.Util;
8+
import hudson.model.AbstractDescribableImpl;
9+
import hudson.model.Descriptor;
10+
import hudson.util.ListBoxModel;
11+
import io.jenkins.plugins.credentials.secretsmanager.Messages;
12+
import io.jenkins.plugins.credentials.secretsmanager.config.credentialsProvider.CredentialsProvider;
13+
import io.jenkins.plugins.credentials.secretsmanager.config.credentialsProvider.DefaultAWSCredentialsProviderChain;
14+
import org.jenkinsci.Symbol;
15+
import org.kohsuke.stapler.DataBoundConstructor;
16+
import org.kohsuke.stapler.DataBoundSetter;
17+
18+
import javax.annotation.Nonnull;
19+
import java.io.Serializable;
20+
import java.util.Objects;
21+
22+
public class Client extends AbstractDescribableImpl<Client> implements Serializable {
23+
24+
private static final long serialVersionUID = 1L;
25+
26+
private CredentialsProvider credentialsProvider;
27+
28+
private EndpointConfiguration endpointConfiguration;
29+
30+
private String region;
31+
32+
@DataBoundConstructor
33+
public Client(CredentialsProvider credentialsProvider, EndpointConfiguration endpointConfiguration, String region) {
34+
this.credentialsProvider = credentialsProvider;
35+
this.endpointConfiguration = endpointConfiguration;
36+
this.region = region;
37+
}
38+
39+
public EndpointConfiguration getEndpointConfiguration() {
40+
return endpointConfiguration;
41+
}
42+
43+
@DataBoundSetter
44+
public void setEndpointConfiguration(EndpointConfiguration endpointConfiguration) {
45+
this.endpointConfiguration = endpointConfiguration;
46+
}
47+
48+
public CredentialsProvider getCredentialsProvider() {
49+
return credentialsProvider;
50+
}
51+
52+
@DataBoundSetter
53+
public void setCredentialsProvider(CredentialsProvider credentialsProvider) {
54+
this.credentialsProvider = credentialsProvider;
55+
}
56+
57+
public String getRegion() {
58+
return region;
59+
}
60+
61+
@DataBoundSetter
62+
public void setRegion(String region) {
63+
this.region = Util.fixEmptyAndTrim(region);
64+
}
65+
66+
public AWSSecretsManager build() {
67+
final AWSSecretsManagerClientBuilder builder = AWSSecretsManagerClientBuilder.standard();
68+
69+
if (credentialsProvider != null) {
70+
builder.setCredentials(credentialsProvider.build());
71+
}
72+
73+
if (endpointConfiguration != null) {
74+
builder.setEndpointConfiguration(endpointConfiguration.build());
75+
}
76+
77+
if (region != null && !region.isEmpty()) {
78+
builder.setRegion(region);
79+
}
80+
81+
return builder.build();
82+
}
83+
84+
@Override
85+
public boolean equals(Object o) {
86+
if (this == o) return true;
87+
if (o == null || getClass() != o.getClass()) return false;
88+
Client client = (Client) o;
89+
return Objects.equals(credentialsProvider, client.credentialsProvider) &&
90+
Objects.equals(endpointConfiguration, client.endpointConfiguration) &&
91+
Objects.equals(region, client.region);
92+
}
93+
94+
@Override
95+
public int hashCode() {
96+
return Objects.hash(credentialsProvider, endpointConfiguration, region);
97+
}
98+
99+
@Extension
100+
@Symbol("client")
101+
@SuppressWarnings("unused")
102+
public static class DescriptorImpl extends Descriptor<Client> {
103+
104+
public CredentialsProvider getDefaultCredentialsProvider() {
105+
return new DefaultAWSCredentialsProviderChain();
106+
}
107+
108+
@Override
109+
@Nonnull
110+
public String getDisplayName() {
111+
return Messages.client();
112+
}
113+
114+
public ListBoxModel doFillRegionItems() {
115+
final ListBoxModel regions = new ListBoxModel();
116+
regions.add("", "");
117+
for (Regions s : Regions.values()) {
118+
regions.add(s.getDescription(), s.getName());
119+
}
120+
return regions;
121+
}
122+
}
123+
}

src/main/java/io/jenkins/plugins/credentials/secretsmanager/config/EndpointConfiguration.java

Lines changed: 13 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,20 @@
11
package io.jenkins.plugins.credentials.secretsmanager.config;
22

3-
import com.amazonaws.AmazonClientException;
43
import com.amazonaws.client.builder.AwsClientBuilder;
5-
import com.amazonaws.services.secretsmanager.AWSSecretsManager;
6-
import com.amazonaws.services.secretsmanager.AWSSecretsManagerClient;
7-
import com.amazonaws.services.secretsmanager.model.ListSecretsRequest;
8-
9-
import hudson.util.FormValidation;
10-
4+
import com.amazonaws.regions.Regions;
5+
import hudson.Extension;
6+
import hudson.model.AbstractDescribableImpl;
7+
import hudson.model.Descriptor;
8+
import hudson.util.ListBoxModel;
119
import io.jenkins.plugins.credentials.secretsmanager.Messages;
1210
import org.jenkinsci.Symbol;
1311
import org.kohsuke.stapler.DataBoundConstructor;
1412
import org.kohsuke.stapler.DataBoundSetter;
15-
import org.kohsuke.stapler.QueryParameter;
16-
import org.kohsuke.stapler.verb.POST;
1713

14+
import javax.annotation.Nonnull;
1815
import java.io.Serializable;
1916
import java.util.Objects;
2017

21-
import javax.annotation.Nonnull;
22-
23-
import hudson.Extension;
24-
import hudson.model.AbstractDescribableImpl;
25-
import hudson.model.Descriptor;
26-
import jenkins.model.Jenkins;
27-
2818
public class EndpointConfiguration extends AbstractDescribableImpl<EndpointConfiguration>
2919
implements Serializable {
3020
private static final long serialVersionUID = 1L;
@@ -95,40 +85,14 @@ public String getDisplayName() {
9585
return Messages.endpointConfiguration();
9686
}
9787

98-
/**
99-
* Test the endpoint configuration.
100-
*
101-
* @param serviceEndpoint the AWS service endpoint e.g. http://localhost:4584
102-
* @param signingRegion the AWS signing region e.g. us-east-1
103-
* @return a success or failure indicator
104-
*/
105-
@POST
106-
@SuppressWarnings("unused")
107-
public FormValidation doTestEndpointConfiguration(
108-
@QueryParameter("serviceEndpoint") final String serviceEndpoint,
109-
@QueryParameter("signingRegion") final String signingRegion) {
110-
Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER);
111-
112-
final AwsClientBuilder.EndpointConfiguration ec =
113-
new AwsClientBuilder.EndpointConfiguration(serviceEndpoint, signingRegion);
114-
final AWSSecretsManager client =
115-
AWSSecretsManagerClient.builder().withEndpointConfiguration(ec).build();
116-
117-
final int statusCode;
118-
try {
119-
statusCode = client.listSecrets(new ListSecretsRequest())
120-
.getSdkHttpMetadata()
121-
.getHttpStatusCode();
122-
} catch (AmazonClientException ex) {
123-
final String msg = Messages.awsClientError() + ": '" + ex.getMessage() + "'";
124-
return FormValidation.error(msg);
125-
}
126-
127-
if ((statusCode >= 200) && (statusCode <= 399)) {
128-
return FormValidation.ok(Messages.success());
129-
} else {
130-
return FormValidation.error(Messages.awsServerError() + ": HTTP " + statusCode);
88+
public ListBoxModel doFillSigningRegionItems() {
89+
final ListBoxModel regions = new ListBoxModel();
90+
regions.add("", "");
91+
for (Regions s : Regions.values()) {
92+
regions.add(s.getDescription(), s.getName());
13193
}
94+
return regions;
13295
}
96+
13397
}
13498
}

0 commit comments

Comments
 (0)