From fc9f8d89c6c27b7a3f6cf8b6f7fe54d2ca6a3c44 Mon Sep 17 00:00:00 2001 From: tpedone1 Date: Mon, 21 Oct 2019 14:43:42 -0700 Subject: [PATCH 1/5] Added logic to check aws account number --- .../cloudraider/model/BasicCredentials.java | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/cloudraider-core/src/main/java/com/intuit/cloudraider/model/BasicCredentials.java b/cloudraider-core/src/main/java/com/intuit/cloudraider/model/BasicCredentials.java index 9497075..b6e1622 100644 --- a/cloudraider-core/src/main/java/com/intuit/cloudraider/model/BasicCredentials.java +++ b/cloudraider-core/src/main/java/com/intuit/cloudraider/model/BasicCredentials.java @@ -30,6 +30,8 @@ import com.amazonaws.services.securitytoken.AWSSecurityTokenService; import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder; import com.amazonaws.services.securitytoken.model.AssumeRoleRequest; +import com.amazonaws.services.securitytoken.model.GetCallerIdentityRequest; +import com.amazonaws.services.securitytoken.model.GetCallerIdentityResult; import com.google.common.base.Strings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -57,7 +59,9 @@ public class BasicCredentials implements Credentials{ private String AWSSecretKey; private String AWSSessionToken; - /** + private String targetAccount; + + /** * Reads from config.properties to search for potential AWS account credentials. * The aws.region must be specified to proceed. * A "aws.keyless" option exists and requires "aws.assumerRole", "aws.deployerRole", "aws.uuid" to be specified within @@ -79,7 +83,10 @@ public BasicCredentials() { if(Strings.isNullOrEmpty(region)){ throw new RuntimeException("No Region defined in the configuration file"); } - + + // Get the target account from env or properties if env var is not set + targetAccount = System.getenv("aws.targetAccount") != null ? System.getenv("aws.targetAccount") : prop.getProperty("aws.targetAccount"); + String profile = prop.getProperty("aws.profile"); boolean keyless = Boolean.valueOf(prop.getProperty("aws.keyless")); @@ -157,7 +164,9 @@ public BasicCredentials() { */ public AWSCredentials getAwsCredentials() { if (awsCredentials == null) { - awsCredentials = new DefaultAWSCredentialsProviderChain().getCredentials(); + AWSCredentialsProvider provider = new DefaultAWSCredentialsProviderChain(); + validateAccount(provider); + awsCredentials = provider.getCredentials(); } return awsCredentials; } @@ -174,4 +183,20 @@ public String getRegion() { return region; } + private void validateAccount(AWSCredentialsProvider provider) { + + if (targetAccount != null) { + AWSSecurityTokenService sts = getSecurityTokenService(provider); + GetCallerIdentityRequest getCallerIdentityRequest = new GetCallerIdentityRequest(); + GetCallerIdentityResult result = sts.getCallerIdentity(getCallerIdentityRequest); + if (!result.getAccount().equals(targetAccount.replace("-", "").trim())) { + throw new RuntimeException(String.format("account: %s does not match target account: %s", result.getAccount(), targetAccount)); + } + } + } + + protected AWSSecurityTokenService getSecurityTokenService(AWSCredentialsProvider provider) { + return AWSSecurityTokenServiceClientBuilder.standard().withCredentials(provider).build(); + } + } From 5cd6f80ce9e5df9536fd0f1a7e4e725e9ecfc1cc Mon Sep 17 00:00:00 2001 From: tpedone1 Date: Mon, 21 Oct 2019 16:11:42 -0700 Subject: [PATCH 2/5] Implemented account validation logic Fixes issue #8 --- .../cloudraider/model/BasicCredentials.java | 39 ++--- .../utils/AWSAccountValidator.java | 36 +++++ .../model/BasicCredentialsTest.java | 67 ++++++++ .../utils/AWSAccountValidatorTest.java | 148 ++++++++++++++++++ java-example/README.md | 9 ++ 5 files changed, 281 insertions(+), 18 deletions(-) create mode 100644 cloudraider-core/src/main/java/com/intuit/cloudraider/utils/AWSAccountValidator.java create mode 100644 cloudraider-core/src/test/java/com/intuit/cloudraider/model/BasicCredentialsTest.java create mode 100644 cloudraider-core/src/test/java/com/intuit/cloudraider/utils/AWSAccountValidatorTest.java diff --git a/cloudraider-core/src/main/java/com/intuit/cloudraider/model/BasicCredentials.java b/cloudraider-core/src/main/java/com/intuit/cloudraider/model/BasicCredentials.java index b6e1622..7234040 100644 --- a/cloudraider-core/src/main/java/com/intuit/cloudraider/model/BasicCredentials.java +++ b/cloudraider-core/src/main/java/com/intuit/cloudraider/model/BasicCredentials.java @@ -30,9 +30,9 @@ import com.amazonaws.services.securitytoken.AWSSecurityTokenService; import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder; import com.amazonaws.services.securitytoken.model.AssumeRoleRequest; -import com.amazonaws.services.securitytoken.model.GetCallerIdentityRequest; -import com.amazonaws.services.securitytoken.model.GetCallerIdentityResult; import com.google.common.base.Strings; +import com.intuit.cloudraider.utils.AWSAccountValidator; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -60,6 +60,16 @@ public class BasicCredentials implements Credentials{ private String AWSSessionToken; private String targetAccount; + + public String getTargetAccount() { + return targetAccount; + } + + public void setTargetAccount(String targetAccount) { + this.targetAccount = targetAccount; + } + + private AWSAccountValidator validator; /** * Reads from config.properties to search for potential AWS account credentials. @@ -157,6 +167,10 @@ public BasicCredentials() { //ignore to use amazon default provider } } + + public BasicCredentials(AWSAccountValidator validator) { + this.validator = validator; + } /** * Returns AWSCredentials for the given user/account. Reverts to default credentials provider if no credentials exist. @@ -165,7 +179,11 @@ public BasicCredentials() { public AWSCredentials getAwsCredentials() { if (awsCredentials == null) { AWSCredentialsProvider provider = new DefaultAWSCredentialsProviderChain(); - validateAccount(provider); + if (validator == null) { + validator = new AWSAccountValidator(provider); + } + + validator.validateAccount(targetAccount); awsCredentials = provider.getCredentials(); } return awsCredentials; @@ -183,20 +201,5 @@ public String getRegion() { return region; } - private void validateAccount(AWSCredentialsProvider provider) { - - if (targetAccount != null) { - AWSSecurityTokenService sts = getSecurityTokenService(provider); - GetCallerIdentityRequest getCallerIdentityRequest = new GetCallerIdentityRequest(); - GetCallerIdentityResult result = sts.getCallerIdentity(getCallerIdentityRequest); - if (!result.getAccount().equals(targetAccount.replace("-", "").trim())) { - throw new RuntimeException(String.format("account: %s does not match target account: %s", result.getAccount(), targetAccount)); - } - } - } - - protected AWSSecurityTokenService getSecurityTokenService(AWSCredentialsProvider provider) { - return AWSSecurityTokenServiceClientBuilder.standard().withCredentials(provider).build(); - } } diff --git a/cloudraider-core/src/main/java/com/intuit/cloudraider/utils/AWSAccountValidator.java b/cloudraider-core/src/main/java/com/intuit/cloudraider/utils/AWSAccountValidator.java new file mode 100644 index 0000000..2da7468 --- /dev/null +++ b/cloudraider-core/src/main/java/com/intuit/cloudraider/utils/AWSAccountValidator.java @@ -0,0 +1,36 @@ +package com.intuit.cloudraider.utils; + +import com.amazonaws.auth.AWSCredentialsProvider; +import com.amazonaws.services.securitytoken.AWSSecurityTokenService; +import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder; +import com.amazonaws.services.securitytoken.model.GetCallerIdentityRequest; +import com.amazonaws.services.securitytoken.model.GetCallerIdentityResult; + +public class AWSAccountValidator { + + private AWSSecurityTokenService sts; + + + public AWSSecurityTokenService getSts() { + return sts; + } + + public void setSts(AWSSecurityTokenService sts) { + this.sts = sts; + } + + public AWSAccountValidator(AWSCredentialsProvider provider) { + sts = AWSSecurityTokenServiceClientBuilder.standard().withCredentials(provider).build(); + } + + public void validateAccount(String targetAccount) { + + if (targetAccount != null) { + GetCallerIdentityRequest getCallerIdentityRequest = new GetCallerIdentityRequest(); + GetCallerIdentityResult result = sts.getCallerIdentity(getCallerIdentityRequest); + if (!result.getAccount().equals(targetAccount.trim().replace("-", ""))) { + throw new RuntimeException(String.format("account: %s does not match target account: %s", result.getAccount(), targetAccount)); + } + } + } +} diff --git a/cloudraider-core/src/test/java/com/intuit/cloudraider/model/BasicCredentialsTest.java b/cloudraider-core/src/test/java/com/intuit/cloudraider/model/BasicCredentialsTest.java new file mode 100644 index 0000000..3ea706b --- /dev/null +++ b/cloudraider-core/src/test/java/com/intuit/cloudraider/model/BasicCredentialsTest.java @@ -0,0 +1,67 @@ +package com.intuit.cloudraider.model; + +import org.mockito.Mockito; + +import com.amazonaws.auth.AWSCredentialsProvider; +import com.intuit.cloudraider.utils.AWSAccountValidator; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.*; + +import org.junit.Test; + +public class BasicCredentialsTest { + + @Test + public void testValidateAccountNull() { + AWSAccountValidator mockValidator = Mockito.mock(AWSAccountValidator.class); + BasicCredentials creds = new BasicCredentials(mockValidator); + + creds.getAwsCredentials(); + + verify(mockValidator).validateAccount(null); + + } + + @Test + public void testValidateAccount() { + AWSAccountValidator mockValidator = Mockito.mock(AWSAccountValidator.class); + BasicCredentials creds = new BasicCredentials(mockValidator); + creds.setTargetAccount("1234"); + + creds.getAwsCredentials(); + + verify(mockValidator).validateAccount("1234"); + + } + + + @Test + public void testValidateAccountInvalid() { + AWSAccountValidator mockValidator = Mockito.mock(AWSAccountValidator.class); + BasicCredentials creds = new BasicCredentials(mockValidator); + creds.setTargetAccount("1234"); + RuntimeException expected = new RuntimeException(); + + doThrow(expected).when(mockValidator).validateAccount("1234"); + + try { + creds.getAwsCredentials(); + fail("getAwsCredentials did not throw an exception"); + } catch(RuntimeException e) { + assertSame(expected, e); + } + + + } + + @Test + public void testSetTargetAccountViaSystemProperties() { + System.setProperty("aws.targetAccount", "76543"); + BasicCredentials creds = new BasicCredentials(); + assertEquals("76543", creds.getTargetAccount()); + } + +} diff --git a/cloudraider-core/src/test/java/com/intuit/cloudraider/utils/AWSAccountValidatorTest.java b/cloudraider-core/src/test/java/com/intuit/cloudraider/utils/AWSAccountValidatorTest.java new file mode 100644 index 0000000..a5c6744 --- /dev/null +++ b/cloudraider-core/src/test/java/com/intuit/cloudraider/utils/AWSAccountValidatorTest.java @@ -0,0 +1,148 @@ +package com.intuit.cloudraider.utils; + +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import com.amazonaws.auth.AWSCredentialsProvider; +import com.amazonaws.services.securitytoken.AWSSecurityTokenService; +import com.amazonaws.services.securitytoken.model.GetCallerIdentityRequest; +import com.amazonaws.services.securitytoken.model.GetCallerIdentityResult; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.*; + +import org.junit.Test; + +public class AWSAccountValidatorTest { + + @Test + public void validateAccountNullTest() { + + AWSCredentialsProvider mockProvider = Mockito.mock(AWSCredentialsProvider.class); + AWSAccountValidator validator = new AWSAccountValidator(mockProvider); + + AWSSecurityTokenService mockSts = Mockito.mock(AWSSecurityTokenService.class); + + assertNotNull(validator.getSts()); + + validator.setSts(mockSts); + + validator.validateAccount(null); + + verifyZeroInteractions(mockSts); + + } + + @Test + public void validateAccountNotValid() { + + AWSCredentialsProvider mockProvider = Mockito.mock(AWSCredentialsProvider.class); + AWSAccountValidator validator = new AWSAccountValidator(mockProvider); + + AWSSecurityTokenService mockSts = Mockito.mock(AWSSecurityTokenService.class); + + assertNotNull(validator.getSts()); + + validator.setSts(mockSts); + + when(mockSts.getCallerIdentity((GetCallerIdentityRequest) notNull())).thenAnswer(new Answer() { + + @Override + public GetCallerIdentityResult answer(InvocationOnMock invocation) throws Throwable { + GetCallerIdentityResult result = new GetCallerIdentityResult(); + result.setAccount("5678"); + return result; + } + + }); + + try { + validator.validateAccount("1234"); + fail("validateAccount did not throw an exception"); + } catch (RuntimeException e) { + assertEquals("account: 5678 does not match target account: 1234", e.getMessage()); + } + } + + @Test + public void validateAccountValid() { + + AWSCredentialsProvider mockProvider = Mockito.mock(AWSCredentialsProvider.class); + AWSAccountValidator validator = new AWSAccountValidator(mockProvider); + + AWSSecurityTokenService mockSts = Mockito.mock(AWSSecurityTokenService.class); + + assertNotNull(validator.getSts()); + + validator.setSts(mockSts); + + when(mockSts.getCallerIdentity((GetCallerIdentityRequest) notNull())).thenAnswer(new Answer() { + + @Override + public GetCallerIdentityResult answer(InvocationOnMock invocation) throws Throwable { + GetCallerIdentityResult result = new GetCallerIdentityResult(); + result.setAccount("1234"); + return result; + } + + }); + + validator.validateAccount("1234"); + } + + @Test + public void validateAccountValidWithDashes() { + + AWSCredentialsProvider mockProvider = Mockito.mock(AWSCredentialsProvider.class); + AWSAccountValidator validator = new AWSAccountValidator(mockProvider); + + AWSSecurityTokenService mockSts = Mockito.mock(AWSSecurityTokenService.class); + + assertNotNull(validator.getSts()); + + validator.setSts(mockSts); + + when(mockSts.getCallerIdentity((GetCallerIdentityRequest) notNull())).thenAnswer(new Answer() { + + @Override + public GetCallerIdentityResult answer(InvocationOnMock invocation) throws Throwable { + GetCallerIdentityResult result = new GetCallerIdentityResult(); + result.setAccount("1234"); + return result; + } + + }); + + validator.validateAccount("12-3-4-"); + } + + @Test + public void validateAccountValidWithWhitespace() { + + AWSCredentialsProvider mockProvider = Mockito.mock(AWSCredentialsProvider.class); + AWSAccountValidator validator = new AWSAccountValidator(mockProvider); + + AWSSecurityTokenService mockSts = Mockito.mock(AWSSecurityTokenService.class); + + assertNotNull(validator.getSts()); + + validator.setSts(mockSts); + + when(mockSts.getCallerIdentity((GetCallerIdentityRequest) notNull())).thenAnswer(new Answer() { + + @Override + public GetCallerIdentityResult answer(InvocationOnMock invocation) throws Throwable { + GetCallerIdentityResult result = new GetCallerIdentityResult(); + result.setAccount("1234"); + return result; + } + + }); + + validator.validateAccount("12-3-4- "); + } + +} diff --git a/java-example/README.md b/java-example/README.md index f2d3cad..3133f5c 100644 --- a/java-example/README.md +++ b/java-example/README.md @@ -31,6 +31,15 @@ if you are using passphrase ``` aws.ec2.privateKeyPassPhrase= ``` + +if you want to validate that the credentials you configured are for the expected AWS Account you can set the property + +``` +aws.targetAccount= +``` + +either in the config.properties file, a System Property or an Environment Variable + ## How to add new Test case? Let's look an example EC2FMEATest class that invokes termination of EC2 Instance. From 1461023fbc5e0f2aae2ff3885d1570a8fecb14b3 Mon Sep 17 00:00:00 2001 From: tpedone1 Date: Thu, 24 Oct 2019 11:07:26 -0700 Subject: [PATCH 3/5] Added logging --- .../cloudraider/utils/AWSAccountValidator.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/cloudraider-core/src/main/java/com/intuit/cloudraider/utils/AWSAccountValidator.java b/cloudraider-core/src/main/java/com/intuit/cloudraider/utils/AWSAccountValidator.java index 2da7468..eeab044 100644 --- a/cloudraider-core/src/main/java/com/intuit/cloudraider/utils/AWSAccountValidator.java +++ b/cloudraider-core/src/main/java/com/intuit/cloudraider/utils/AWSAccountValidator.java @@ -1,5 +1,8 @@ package com.intuit.cloudraider.utils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.services.securitytoken.AWSSecurityTokenService; import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder; @@ -8,7 +11,12 @@ public class AWSAccountValidator { - private AWSSecurityTokenService sts; + /** + * The Logger. + */ + Logger logger = LoggerFactory.getLogger(this.getClass()); + + private AWSSecurityTokenService sts; public AWSSecurityTokenService getSts() { @@ -31,6 +39,8 @@ public void validateAccount(String targetAccount) { if (!result.getAccount().equals(targetAccount.trim().replace("-", ""))) { throw new RuntimeException(String.format("account: %s does not match target account: %s", result.getAccount(), targetAccount)); } + } else { + logger.info("No targetAccount was set; skipping AWS Account validation"); } } } From 2ad61cef3d240b65cb330ebecfaf66aa8bb6fdc3 Mon Sep 17 00:00:00 2001 From: Jayapandian Ponraj Date: Fri, 25 Oct 2019 00:04:15 +0530 Subject: [PATCH 4/5] fixing build --- .travis.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3f8ce93..8260799 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,7 @@ language: java jdk: -- oraclejdk8 + - openjdk8 sudo: false -addons: - apt: - packages: - - oracle-java8-installer install: true script: mvn clean install after_success: From 919893065fe075ecb480dbdea852b9e4020e59db Mon Sep 17 00:00:00 2001 From: tpedone1 Date: Thu, 24 Oct 2019 14:45:43 -0700 Subject: [PATCH 5/5] Fixed test --- .../com/intuit/cloudraider/model/BasicCredentialsTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cloudraider-core/src/test/java/com/intuit/cloudraider/model/BasicCredentialsTest.java b/cloudraider-core/src/test/java/com/intuit/cloudraider/model/BasicCredentialsTest.java index 3ea706b..3650dc1 100644 --- a/cloudraider-core/src/test/java/com/intuit/cloudraider/model/BasicCredentialsTest.java +++ b/cloudraider-core/src/test/java/com/intuit/cloudraider/model/BasicCredentialsTest.java @@ -16,6 +16,8 @@ public class BasicCredentialsTest { @Test public void testValidateAccountNull() { + System.setProperty("aws.accessKeyId", "accessKey"); + System.setProperty("aws.secretKey", "secret"); AWSAccountValidator mockValidator = Mockito.mock(AWSAccountValidator.class); BasicCredentials creds = new BasicCredentials(mockValidator); @@ -27,6 +29,8 @@ public void testValidateAccountNull() { @Test public void testValidateAccount() { + System.setProperty("aws.accessKeyId", "accessKey"); + System.setProperty("aws.secretKey", "secret"); AWSAccountValidator mockValidator = Mockito.mock(AWSAccountValidator.class); BasicCredentials creds = new BasicCredentials(mockValidator); creds.setTargetAccount("1234");