From 0cdea8bfb4bfe016c1e9cc60b07335329304e4b8 Mon Sep 17 00:00:00 2001 From: Reuben Katzen Date: Mon, 3 Mar 2025 09:25:40 +0000 Subject: [PATCH] Issue #375: Allow cross-account AWS IAM role assumption into opt-in regions Added authRegion drop-down list-box & variable to allow explicitly stating the region for authenticating with AWS IAM. --- .../jenkins/plugins/amazonecs/ECSCloud.java | 43 +++++++++++++++---- .../jenkins/plugins/amazonecs/ECSService.java | 10 ++++- .../plugins/amazonecs/ECSTaskTemplate.java | 3 +- .../plugins/amazonecs/ECSCloud/config.jelly | 4 ++ .../plugins/amazonecs/ECSCloudTest.java | 5 +++ 5 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/cloudbees/jenkins/plugins/amazonecs/ECSCloud.java b/src/main/java/com/cloudbees/jenkins/plugins/amazonecs/ECSCloud.java index 2ce3182a..b39bb3a9 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/amazonecs/ECSCloud.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/amazonecs/ECSCloud.java @@ -82,6 +82,7 @@ public class ECSCloud extends Cloud { private final String cluster; private String regionName; private String assumedRoleArn; + private String authRegion; @CheckForNull private String tunnel; private String jenkinsUrl; @@ -121,7 +122,7 @@ public ECSCloud(String name, String cluster, ECSService ecsService) { synchronized ECSService getEcsService() { if (ecsService == null) { - ecsService = new ECSService(credentialsId, assumedRoleArn, regionName); + ecsService = new ECSService(credentialsId, assumedRoleArn, authRegion, regionName); } return ecsService; } @@ -164,6 +165,11 @@ public String getAssumedRoleArn() { return assumedRoleArn; } + + public String getAuthRegion() { + return authRegion; + } + @DataBoundSetter public void setRegionName(String regionName) { this.regionName = regionName; @@ -173,6 +179,11 @@ public void setRegionName(String regionName) { public void setAssumedRoleArn(String assumedRoleArn) { this.assumedRoleArn = assumedRoleArn; } + + @DataBoundSetter + public void setAuthRegion(String authRegion) { + this.authRegion = authRegion; + } public String getTunnel() { return tunnel; @@ -428,12 +439,20 @@ public Node call() throws Exception { } } - public static Region getRegion(String regionName) { - if (StringUtils.isNotEmpty(regionName)) { - return RegionUtils.getRegion(regionName); - } else { - return Region.getRegion(Regions.US_EAST_1); + public ListBoxModel doFillAuthRegionItems() { + final ListBoxModel options = new ListBoxModel(); + for (Region region : RegionUtils.getRegions()) { + options.add(region.getName()); } + return options; + } + + public ListBoxModel doFillRegionNameItems() { + final ListBoxModel options = new ListBoxModel(); + for (Region region : RegionUtils.getRegions()) { + options.add(region.getName()); + } + return options; } public String getJenkinsUrl() { @@ -507,9 +526,17 @@ public ListBoxModel doFillRegionNameItems() { } return options; } + + public ListBoxModel doFillAuthRegionItems() { + final ListBoxModel options = new ListBoxModel(); + for (Region region : RegionUtils.getRegions()) { + options.add(region.getName()); + } + return options; + } - public ListBoxModel doFillClusterItems(@QueryParameter String credentialsId, @QueryParameter String assumedRoleArn, @QueryParameter String regionName) { - ECSService ecsService = new ECSService(credentialsId, assumedRoleArn, regionName); + public ListBoxModel doFillClusterItems(@QueryParameter String credentialsId, @QueryParameter String assumedRoleArn, @QueryParameter String authRegion, @QueryParameter String regionName) { + ECSService ecsService = new ECSService(credentialsId, assumedRoleArn, authRegion, regionName); try { final AmazonECS client = ecsService.getAmazonECSClient(); final List allClusterArns = new ArrayList(); diff --git a/src/main/java/com/cloudbees/jenkins/plugins/amazonecs/ECSService.java b/src/main/java/com/cloudbees/jenkins/plugins/amazonecs/ECSService.java index 639ab136..89f6dcc7 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/amazonecs/ECSService.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/amazonecs/ECSService.java @@ -76,7 +76,7 @@ public class ECSService extends BaseAWSService { @Nonnull private final Supplier clientSupplier; - public ECSService(String credentialsId, String assumedRoleArn, String regionName) { + public ECSService(String credentialsId, String assumedRoleArn, String authRegion, String regionName) { this.clientSupplier = () -> { AmazonECSClientBuilder builder = AmazonECSClientBuilder .standard() @@ -94,7 +94,13 @@ public ECSService(String credentialsId, String assumedRoleArn, String regionName .withCredentials(credentials); } else if (StringUtils.isNotBlank(assumedRoleArn)) { - builder.withCredentials(getCredentialsForRole(assumedRoleArn, regionName)); + if (StringUtils.isNotBlank(authRegion)) { + builder.withCredentials(getCredentialsForRole(assumedRoleArn, authRegion)); + } + else { + builder.withCredentials(getCredentialsForRole(assumedRoleArn, regionName)); + } + } LOGGER.log(Level.FINE, "Selected Region: {0}", regionName); diff --git a/src/main/java/com/cloudbees/jenkins/plugins/amazonecs/ECSTaskTemplate.java b/src/main/java/com/cloudbees/jenkins/plugins/amazonecs/ECSTaskTemplate.java index 97584476..e46eab17 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/amazonecs/ECSTaskTemplate.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/amazonecs/ECSTaskTemplate.java @@ -1429,10 +1429,11 @@ public static class DescriptorImpl extends Descriptor allClusters = new ArrayList(); DescribeClustersResult result = client.describeClusters(new DescribeClustersRequest().withClusters(cluster)); diff --git a/src/main/resources/com/cloudbees/jenkins/plugins/amazonecs/ECSCloud/config.jelly b/src/main/resources/com/cloudbees/jenkins/plugins/amazonecs/ECSCloud/config.jelly index 36031df1..811fef4d 100644 --- a/src/main/resources/com/cloudbees/jenkins/plugins/amazonecs/ECSCloud/config.jelly +++ b/src/main/resources/com/cloudbees/jenkins/plugins/amazonecs/ECSCloud/config.jelly @@ -39,6 +39,10 @@ + + + + diff --git a/src/test/java/com/cloudbees/jenkins/plugins/amazonecs/ECSCloudTest.java b/src/test/java/com/cloudbees/jenkins/plugins/amazonecs/ECSCloudTest.java index d54454e0..6dc6a81b 100644 --- a/src/test/java/com/cloudbees/jenkins/plugins/amazonecs/ECSCloudTest.java +++ b/src/test/java/com/cloudbees/jenkins/plugins/amazonecs/ECSCloudTest.java @@ -170,6 +170,7 @@ public void getProvisioningCapacity_returnsRemainingMaxAgentsWhenWorkloadExceeds ECSCloud sut = new ECSCloud("mycloud", "", "", "mycluster"); sut.setMaxAgents(14); sut.setTemplates(templates); + sut.setAuthRegion("eu-west-1"); sut.setRegionName("eu-west-1"); sut.setNumExecutors(1); sut.setJenkinsUrl("http://jenkins.local"); @@ -192,6 +193,7 @@ public void getProvisioningCapacity_returnsExcessWorkloadWithoutMaxAgents () { ECSCloud sut = new ECSCloud("mycloud", "", "", "mycluster"); sut.setMaxAgents(0); sut.setTemplates(templates); + sut.setAuthRegion("eu-west-1"); sut.setRegionName("eu-west-1"); sut.setJenkinsUrl("http://jenkins.local"); sut.setSlaveTimeoutInSeconds(5); @@ -213,6 +215,7 @@ public void getProvisioningCapacity_returnsExcessWorkloadWhenWorkloadDoesNotExce ECSCloud sut = new ECSCloud("mycloud", "", "", "mycluster"); sut.setMaxAgents(10); sut.setTemplates(templates); + sut.setAuthRegion("eu-west-1"); sut.setRegionName("eu-west-1"); sut.setJenkinsUrl("http://jenkins.local"); sut.setSlaveTimeoutInSeconds(5); @@ -234,6 +237,7 @@ public void getProvisioningCapacity_returnsZeroWhenOverflowEncountered () { ECSCloud sut = new ECSCloud("mycloud", "", "", "mycluster"); sut.setMaxAgents(10); sut.setTemplates(templates); + sut.setAuthRegion("eu-west-1"); sut.setRegionName("eu-west-1"); sut.setJenkinsUrl("http://jenkins.local"); sut.setSlaveTimeoutInSeconds(5); @@ -255,6 +259,7 @@ public void getProvisioningCapacity_returnsZeroWhenCurrentAgentsGreaterThanMaxAg ECSCloud sut = new ECSCloud("mycloud", "", "", "mycluster"); sut.setMaxAgents(1); sut.setTemplates(templates); + sut.setAuthRegion("eu-west-1"); sut.setRegionName("eu-west-1"); sut.setJenkinsUrl("http://jenkins.local"); sut.setSlaveTimeoutInSeconds(5);