diff --git a/cerberus-core/src/main/java/com/nike/cerberus/error/DefaultApiError.java b/cerberus-core/src/main/java/com/nike/cerberus/error/DefaultApiError.java
index c264a1b92..36970d08c 100644
--- a/cerberus-core/src/main/java/com/nike/cerberus/error/DefaultApiError.java
+++ b/cerberus-core/src/main/java/com/nike/cerberus/error/DefaultApiError.java
@@ -233,6 +233,18 @@ public enum DefaultApiError implements ApiError {
"Failed to validate factor. Please try again or try a different factor.",
SC_UNAUTHORIZED),
+ /** AWS China ARNs are not allowed. */
+ AWS_CHINA_NOT_ALLOWED(
+ 99244,
+ "The AWS China partition is disabled by the admin. If you're creating or updating an SDB, please remove IAM principal ARNs that start with \"arn:aws-cn:\"",
+ SC_UNAUTHORIZED),
+
+ /** AWS Global ARNs are not allowed. */
+ AWS_GLOBAL_NOT_ALLOWED(
+ 99245,
+ "The AWS Global partition is disabled by the admin. If you're creating or updating an SDB, please remove IAM principal ARNs that start with \"arn:aws:\"",
+ SC_UNAUTHORIZED),
+
/** Generic not found error. */
ENTITY_NOT_FOUND(99996, "Not found", SC_NOT_FOUND),
diff --git a/cerberus-domain/src/main/java/com/nike/cerberus/domain/DomainConstants.java b/cerberus-domain/src/main/java/com/nike/cerberus/domain/DomainConstants.java
index a397e52c5..2fe1c7f28 100644
--- a/cerberus-domain/src/main/java/com/nike/cerberus/domain/DomainConstants.java
+++ b/cerberus-domain/src/main/java/com/nike/cerberus/domain/DomainConstants.java
@@ -20,7 +20,11 @@
public class DomainConstants {
- public static final String AWS_IAM_ROLE_ARN_TEMPLATE = "arn:aws:iam::%s:role/%s";
+ public static final String AWS_GLOBAL_PARTITION_NAME = "aws";
+
+ public static final String AWS_CHINA_PARTITION_NAME = "aws-cn";
+
+ public static final String AWS_IAM_ROLE_ARN_TEMPLATE = "arn:%s:iam::%s:role/%s";
/**
* Pattern used to determine if an ARN should be allowed in DB.
@@ -28,7 +32,7 @@ public class DomainConstants {
*
This is also the list of ARN types that are allowed in KMS key policies.
*/
public static final String AWS_IAM_PRINCIPAL_ARN_REGEX_ALLOWED =
- "^arn:aws:(iam|sts)::(?\\d+?):(role|user|federated-user|assumed-role).*/.+(?aws|aws-cn):(iam|sts)::(?\\d+?):(role|user|federated-user|assumed-role).*/.+(?\\d+?):(?!group).+?/(?.+)$";
+ "^arn:(?aws|aws-cn):(iam|sts)::(?\\d+?):(?!group).+?/(?.+)$";
/**
* Pattern used for generating a role from another ARN.
@@ -58,20 +62,21 @@ public class DomainConstants {
public static final Pattern IAM_PRINCIPAL_ARN_PATTERN_ROLE_GENERATION =
Pattern.compile(AWS_IAM_PRINCIPAL_ARN_REGEX_ROLE_GENERATION);
- public static final String AWS_ACCOUNT_ROOT_ARN_REGEX = "^arn:aws:iam::(?\\d+?):root$";
+ public static final String AWS_ACCOUNT_ROOT_ARN_REGEX =
+ "^arn:(?aws|aws-cn):iam::(?\\d+?):root$";
public static final Pattern AWS_ACCOUNT_ROOT_ARN_PATTERN =
Pattern.compile(AWS_ACCOUNT_ROOT_ARN_REGEX);
private static final String AWS_IAM_ROLE_ARN_REGEX =
- "^arn:aws:iam::(?\\d+?):role/(?.+)$";
+ "^arn:(?aws|aws-cn):iam::(?\\d+?):role/(?.+)$";
public static final Pattern IAM_ROLE_ARN_PATTERN = Pattern.compile(AWS_IAM_ROLE_ARN_REGEX);
private static final String AWS_IAM_ASSUMED_ROLE_ARN_REGEX =
- "^arn:aws:sts::(?\\d+?):assumed-role/(?.+)/.+$";
+ "^arn:(?aws|aws-cn):sts::(?\\d+?):assumed-role/(?.+)/.+$";
public static final Pattern IAM_ASSUMED_ROLE_ARN_PATTERN =
Pattern.compile(AWS_IAM_ASSUMED_ROLE_ARN_REGEX);
private static final String GENERIC_ASSUMED_ROLE_REGEX =
- "^arn:aws:sts::(?\\d+?):assumed-role/.+$";
+ "^arn:(?aws|aws-cn):sts::(?\\d+?):assumed-role/.+$";
public static final Pattern GENERIC_ASSUMED_ROLE_PATTERN =
Pattern.compile(GENERIC_ASSUMED_ROLE_REGEX);
private static final Pattern AWS_IAM_ARN_ACCOUNT_ID_PATTERN =
- Pattern.compile("arn:aws:(iam|sts)::(?\\d+?):.+");
+ Pattern.compile("^arn:(?aws|aws-cn):(iam|sts)::(?\\d+?):.+");
}
diff --git a/cerberus-web/src/main/java/com/nike/cerberus/aws/sts/AwsStsHttpClient.java b/cerberus-web/src/main/java/com/nike/cerberus/aws/sts/AwsStsHttpClient.java
index 15aa71dc1..6149e8cf6 100644
--- a/cerberus-web/src/main/java/com/nike/cerberus/aws/sts/AwsStsHttpClient.java
+++ b/cerberus-web/src/main/java/com/nike/cerberus/aws/sts/AwsStsHttpClient.java
@@ -38,6 +38,7 @@ public class AwsStsHttpClient {
MediaType.parse("application/x-www-form-urlencoded");
private static final MediaType DEFAULT_ACCEPTED_MEDIA_TYPE = MediaType.parse("application/json");
private static final String AWS_STS_ENDPOINT_TEMPLATE = "https://sts.%s.amazonaws.com";
+ private static final String AWS_CN_STS_ENDPOINT_TEMPLATE = "https://sts.%s.amazonaws.com.cn";
private static final String DEFAULT_GET_CALLER_IDENTITY_ACTION =
"Action=GetCallerIdentity&Version=2011-06-15";
private static final String DEFAULT_METHOD = "POST";
@@ -115,9 +116,15 @@ public M execute(
/** Build the request */
protected Request buildRequest(String region, Map headers) {
+ String stsEndpointUrl;
+ if (region.startsWith("cn-")) {
+ stsEndpointUrl = String.format(AWS_CN_STS_ENDPOINT_TEMPLATE, region);
+ } else {
+ stsEndpointUrl = String.format(AWS_STS_ENDPOINT_TEMPLATE, region);
+ }
Request.Builder requestBuilder =
new Request.Builder()
- .url(String.format(AWS_STS_ENDPOINT_TEMPLATE, region))
+ .url(stsEndpointUrl)
.addHeader("Accept", DEFAULT_ACCEPTED_MEDIA_TYPE.toString());
if (headers != null) {
diff --git a/cerberus-web/src/main/java/com/nike/cerberus/service/AuthenticationService.java b/cerberus-web/src/main/java/com/nike/cerberus/service/AuthenticationService.java
index 1a1844025..88dcefe9c 100644
--- a/cerberus-web/src/main/java/com/nike/cerberus/service/AuthenticationService.java
+++ b/cerberus-web/src/main/java/com/nike/cerberus/service/AuthenticationService.java
@@ -16,6 +16,7 @@
package com.nike.cerberus.service;
+import static com.nike.cerberus.domain.DomainConstants.AWS_GLOBAL_PARTITION_NAME;
import static com.nike.cerberus.domain.DomainConstants.AWS_IAM_ROLE_ARN_TEMPLATE;
import static com.nike.cerberus.security.CerberusPrincipal.*;
@@ -221,7 +222,10 @@ public EncryptedAuthDataWrapper authenticate(IamRoleCredentials credentials) {
final String iamPrincipalArn =
String.format(
- AWS_IAM_ROLE_ARN_TEMPLATE, credentials.getAccountId(), credentials.getRoleName());
+ AWS_IAM_ROLE_ARN_TEMPLATE,
+ AWS_GLOBAL_PARTITION_NAME, // hardcoding this to AWS Global for backwards compatibility
+ credentials.getAccountId(),
+ credentials.getRoleName());
final String region = credentials.getRegion();
final AwsIamKmsAuthRequest awsIamKmsAuthRequest = new AwsIamKmsAuthRequest();
@@ -243,6 +247,7 @@ public EncryptedAuthDataWrapper authenticate(IamRoleCredentials credentials) {
public EncryptedAuthDataWrapper authenticate(AwsIamKmsAuthRequest awsIamKmsAuthRequest) {
final String iamPrincipalArn = awsIamKmsAuthRequest.getIamPrincipalArn();
+ awsIamRoleArnParser.iamPrincipalPartitionCheck(iamPrincipalArn);
final Map authPrincipalMetadata =
generateCommonIamPrincipalAuthMetadata(iamPrincipalArn, awsIamKmsAuthRequest.getRegion());
authPrincipalMetadata.put(
@@ -258,6 +263,7 @@ public EncryptedAuthDataWrapper authenticate(AwsIamKmsAuthRequest awsIamKmsAuthR
* @return Unencrypted auth response
*/
public AuthTokenResponse stsAuthenticate(final String iamPrincipalArn) {
+ awsIamRoleArnParser.iamPrincipalPartitionCheck(iamPrincipalArn);
final Map authPrincipalMetadata =
generateCommonIamPrincipalAuthMetadata(iamPrincipalArn);
authPrincipalMetadata.put(
diff --git a/cerberus-web/src/main/java/com/nike/cerberus/service/SafeDepositBoxService.java b/cerberus-web/src/main/java/com/nike/cerberus/service/SafeDepositBoxService.java
index bdfd98520..275baed88 100644
--- a/cerberus-web/src/main/java/com/nike/cerberus/service/SafeDepositBoxService.java
+++ b/cerberus-web/src/main/java/com/nike/cerberus/service/SafeDepositBoxService.java
@@ -248,6 +248,7 @@ public SafeDepositBoxV2 createSafeDepositBoxV2(
final Set iamRolePermissionSet =
safeDepositBox.getIamPrincipalPermissions();
+ partitionCheck(iamRolePermissionSet);
final boolean isSlugUnique = safeDepositBoxDao.isSlugUnique(boxRecordToStore.getSdbNameSlug());
@@ -309,6 +310,8 @@ public SafeDepositBoxV2 updateSafeDepositBoxV2(
final Set iamRolePermissionSet =
safeDepositBox.getIamPrincipalPermissions();
+ partitionCheck(iamRolePermissionSet);
+
if (!StringUtils.equals(currentBox.getDescription(), boxToUpdate.getDescription())) {
safeDepositBoxDao.updateSafeDepositBox(boxToUpdate);
}
@@ -636,6 +639,9 @@ protected SafeDepositBoxV2 convertSafeDepositBoxV1ToV2(SafeDepositBoxV1 safeDepo
.withIamPrincipalArn(
String.format(
DomainConstants.AWS_IAM_ROLE_ARN_TEMPLATE,
+ DomainConstants
+ .AWS_GLOBAL_PARTITION_NAME, // hardcoding this to AWS Global for
+ // backwards compatibility
iamRolePermission.getAccountId(),
iamRolePermission.getIamRoleName()))
.withRoleId(iamRolePermission.getRoleId()))
@@ -793,4 +799,12 @@ public SafeDepositBoxV2 getSafeDepositBoxDangerouslyWithoutPermissionValidation(
() ->
ApiException.newBuilder().withApiErrors(DefaultApiError.ENTITY_NOT_FOUND).build()));
}
+
+ private void partitionCheck(Set iamRolePermissionSet) {
+ iamRolePermissionSet.stream()
+ .forEach(
+ iamRolePermission ->
+ awsIamRoleArnParser.iamPrincipalPartitionCheck(
+ iamRolePermission.getIamPrincipalArn()));
+ }
}
diff --git a/cerberus-web/src/main/java/com/nike/cerberus/util/AwsIamRoleArnParser.java b/cerberus-web/src/main/java/com/nike/cerberus/util/AwsIamRoleArnParser.java
index 7c8a4f39c..06dbfddcd 100644
--- a/cerberus-web/src/main/java/com/nike/cerberus/util/AwsIamRoleArnParser.java
+++ b/cerberus-web/src/main/java/com/nike/cerberus/util/AwsIamRoleArnParser.java
@@ -18,14 +18,25 @@
import com.nike.backstopper.exception.ApiException;
import com.nike.cerberus.domain.DomainConstants;
+import com.nike.cerberus.error.DefaultApiError;
import com.nike.cerberus.error.InvalidIamRoleArnApiError;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/** Utility class for concatenating and parsing AWS IAM role ARNs. */
@Component
public class AwsIamRoleArnParser {
+ private final boolean awsChinaEnabled;
+ private final boolean awsGlobalEnabled;
+
+ public AwsIamRoleArnParser(
+ @Value("${cerberus.partitions.awsGlobal.enabled}") boolean awsGlobalEnabled,
+ @Value("${cerberus.partitions.awsChina.enabled}") boolean awsChinaEnabled) {
+ this.awsGlobalEnabled = awsGlobalEnabled;
+ this.awsChinaEnabled = awsChinaEnabled;
+ }
/**
* Gets account ID from a 'role' ARN
@@ -119,8 +130,10 @@ public String convertPrincipalArnToRoleArn(final String principalArn) {
final String accountId =
getNamedGroupFromRegexPattern(patternToMatch, "accountId", principalArn);
final String roleName = getNamedGroupFromRegexPattern(patternToMatch, "roleName", principalArn);
+ final String partition =
+ getNamedGroupFromRegexPattern(patternToMatch, "partition", principalArn);
- return String.format(DomainConstants.AWS_IAM_ROLE_ARN_TEMPLATE, accountId, roleName);
+ return String.format(DomainConstants.AWS_IAM_ROLE_ARN_TEMPLATE, partition, accountId, roleName);
}
public String convertPrincipalArnToRootArn(final String principalArn) {
@@ -133,7 +146,11 @@ public String convertPrincipalArnToRootArn(final String principalArn) {
getNamedGroupFromRegexPattern(
DomainConstants.IAM_PRINCIPAL_ARN_PATTERN_ALLOWED, "accountId", principalArn);
- return String.format("arn:aws:iam::%s:root", accountId);
+ final String partition =
+ getNamedGroupFromRegexPattern(
+ DomainConstants.IAM_PRINCIPAL_ARN_PATTERN_ALLOWED, "partition", principalArn);
+
+ return String.format("arn:%s:iam::%s:root", partition, accountId);
}
/**
@@ -150,6 +167,17 @@ public String stripOutDescription(final String principalArn) {
}
}
+ /**
+ * Checks if the partition of an IAM principal ARN is enabled
+ *
+ * @param iamPrincipalArn The IAM principal ARN to be checked
+ * @throws ApiException Throws an exception if the partition of the IAM principal isn't enabled
+ */
+ public void iamPrincipalPartitionCheck(String iamPrincipalArn) {
+ getNamedGroupFromRegexPattern(
+ DomainConstants.IAM_PRINCIPAL_ARN_PATTERN_ALLOWED, "partition", iamPrincipalArn);
+ }
+
private String getNamedGroupFromRegexPattern(
final Pattern pattern, final String groupName, final String input) {
final Matcher iamRoleArnMatcher = pattern.matcher(input);
@@ -160,7 +188,17 @@ private String getNamedGroupFromRegexPattern(
.withExceptionMessage("ARN does not match pattern: " + pattern.toString())
.build();
}
+ partitionCheck(iamRoleArnMatcher.group("partition"));
return iamRoleArnMatcher.group(groupName);
}
+
+ private void partitionCheck(String partition) {
+ if (DomainConstants.AWS_GLOBAL_PARTITION_NAME.equals(partition) && !awsGlobalEnabled) {
+ throw ApiException.newBuilder().withApiErrors(DefaultApiError.AWS_GLOBAL_NOT_ALLOWED).build();
+ }
+ if (DomainConstants.AWS_CHINA_PARTITION_NAME.equals(partition) && !awsChinaEnabled) {
+ throw ApiException.newBuilder().withApiErrors(DefaultApiError.AWS_CHINA_NOT_ALLOWED).build();
+ }
+ }
}
diff --git a/cerberus-web/src/main/resources/cerberus.yaml b/cerberus-web/src/main/resources/cerberus.yaml
index d1271d62f..5ef6d1928 100644
--- a/cerberus-web/src/main/resources/cerberus.yaml
+++ b/cerberus-web/src/main/resources/cerberus.yaml
@@ -44,6 +44,11 @@ c3p0:
preferredTestQuery: SELECT 1
cerberus:
+ partitions:
+ awsGlobal:
+ enabled: true
+ awsChina:
+ enabled: false
environmentName: TODO
admin:
# These are aws principal that you want to allow to use the admin API
diff --git a/cerberus-web/src/test/java/com/nike/cerberus/aws/sts/AwsStsHttpHeaderTest.java b/cerberus-web/src/test/java/com/nike/cerberus/aws/sts/AwsStsHttpHeaderTest.java
index 0087f51bd..e0ba0c855 100644
--- a/cerberus-web/src/test/java/com/nike/cerberus/aws/sts/AwsStsHttpHeaderTest.java
+++ b/cerberus-web/src/test/java/com/nike/cerberus/aws/sts/AwsStsHttpHeaderTest.java
@@ -39,5 +39,13 @@ public void test_getRegion_returns_region_as_expected() {
"AWS4-HMAC-SHA256 Credential=ASIA5S2FQS2GYQLK5FFF/20180904/us-east-1/sts/aws4_request, SignedHeaders=host;x-amz-date, Signature=ddb9417d2b9bfe6f8b03e31a8f5d8ab98e0f4alkj12312098asdf");
assertEquals("us-east-1", header.getRegion());
+
+ header =
+ new AwsStsHttpHeader(
+ "20180904T205115Z",
+ "FQoGZXIvYXdzEFYaDEYceadsfLKJLKlkj908098oB/rJIdxdo57fx3Ef2wW8WhFbSpLGg3hwNqhuepdkf/c0F7OXJutqM2yjgnZCiO7SPAdnMSJhoEgH7SJlkPaPfiRzZAf0yxxD6e4z0VJU74uQfbgfZpn5RL+JyDpgoYkUrjuyL8zRB1knGSOCi32Q75+asdfasd+7bWxMyJIKEb/HF2Le8xM/9F4WRqa5P0+asdfasdfasdf+MGlDlNG0KTzg1JT6QXf95ozWR5bBFSz5DbrFhXhMegMQ7+7Kvx+asdfasdl.jlkj++5NpRRlE54cct7+aG3HQskow9y73AU=",
+ "AWS4-HMAC-SHA256 Credential=ASIA5S2FQS2GYQLK5FFF/20180904/cn-northwest-1/sts/aws4_request, SignedHeaders=host;x-amz-date, Signature=ddb9417d2b9bfe6f8b03e31a8f5d8ab98e0f4alkj12312098asdf");
+
+ assertEquals("cn-northwest-1", header.getRegion());
}
}
diff --git a/cerberus-web/src/test/java/com/nike/cerberus/service/AuthenticationServiceTest.java b/cerberus-web/src/test/java/com/nike/cerberus/service/AuthenticationServiceTest.java
index d7defb783..085da66dd 100644
--- a/cerberus-web/src/test/java/com/nike/cerberus/service/AuthenticationServiceTest.java
+++ b/cerberus-web/src/test/java/com/nike/cerberus/service/AuthenticationServiceTest.java
@@ -16,7 +16,7 @@
package com.nike.cerberus.service;
-import static com.nike.cerberus.domain.DomainConstants.AWS_IAM_ROLE_ARN_TEMPLATE;
+import static com.nike.cerberus.domain.DomainConstants.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -266,7 +266,8 @@ public void test_that_getKeyId_only_validates_kms_policy_one_time_within_interva
String accountId = "0000000000";
String roleName = "role/path";
String principalArn = String.format("arn:aws:iam::%s:instance-profile/%s", accountId, roleName);
- String roleArn = String.format(AWS_IAM_ROLE_ARN_TEMPLATE, accountId, roleName);
+ String roleArn =
+ String.format(AWS_IAM_ROLE_ARN_TEMPLATE, AWS_GLOBAL_PARTITION_NAME, accountId, roleName);
AwsIamRoleRecord awsIamRoleRecord = mock(AwsIamRoleRecord.class);
when(awsIamRoleDao.getIamRole(principalArn)).thenReturn(Optional.empty());
@@ -311,7 +312,8 @@ public void test_that_findIamRoleAssociatedWithSdb_returns_empty_optional_when_r
String accountId = "0000000000";
String roleName = "role/path";
String principalArn = String.format("arn:aws:iam::%s:instance-profile/%s", accountId, roleName);
- String roleArn = String.format(AWS_IAM_ROLE_ARN_TEMPLATE, accountId, roleName);
+ String roleArn =
+ String.format(AWS_IAM_ROLE_ARN_TEMPLATE, AWS_GLOBAL_PARTITION_NAME, accountId, roleName);
String rootArn = String.format("arn:aws:iam::%s:root", accountId);
AwsIamRoleRecord rootRecord = mock(AwsIamRoleRecord.class);
@@ -332,6 +334,36 @@ public void test_that_findIamRoleAssociatedWithSdb_returns_empty_optional_when_r
assertEquals(roleRecord, result.get());
}
+ @Test
+ public void
+ test_that_findIamRoleAssociatedWithSdb_returns_generic_role_when_iam_principal_not_found_and_root_found_for_aws_china() {
+
+ String accountId = "0000000000";
+ String roleName = "role/path";
+ String principalArn =
+ String.format("arn:aws-cn:iam::%s:instance-profile/%s", accountId, roleName);
+ String roleArn =
+ String.format(AWS_IAM_ROLE_ARN_TEMPLATE, AWS_CHINA_PARTITION_NAME, accountId, roleName);
+ String rootArn = String.format("arn:aws-cn:iam::%s:root", accountId);
+
+ AwsIamRoleRecord rootRecord = mock(AwsIamRoleRecord.class);
+ AwsIamRoleRecord roleRecord = mock(AwsIamRoleRecord.class);
+ when(awsIamRoleDao.getIamRole(principalArn)).thenReturn(Optional.empty());
+ when(awsIamRoleDao.getIamRole(roleArn)).thenReturn(Optional.empty());
+ when(awsIamRoleDao.getIamRole(rootArn)).thenReturn(Optional.of(rootRecord));
+
+ when(awsIamRoleArnParser.isRoleArn(principalArn)).thenReturn(false);
+ when(awsIamRoleArnParser.convertPrincipalArnToRoleArn(principalArn)).thenReturn(roleArn);
+ when(awsIamRoleArnParser.convertPrincipalArnToRootArn(roleArn)).thenReturn(rootArn);
+
+ when(awsIamRoleService.createIamRole(roleArn)).thenReturn(roleRecord);
+
+ Optional result =
+ authenticationService.findIamRoleAssociatedWithSdb(principalArn);
+
+ assertEquals(roleRecord, result.get());
+ }
+
@Test
public void
tests_that_validateAuthPayloadSizeAndTruncateIfLargerThanMaxKmsSupportedSize_returns_the_original_payload_if_the_size_can_be_encrypted_by_kms()
diff --git a/cerberus-web/src/test/java/com/nike/cerberus/service/KmsPolicyServiceTest.java b/cerberus-web/src/test/java/com/nike/cerberus/service/KmsPolicyServiceTest.java
index d0f185ed1..c357af943 100644
--- a/cerberus-web/src/test/java/com/nike/cerberus/service/KmsPolicyServiceTest.java
+++ b/cerberus-web/src/test/java/com/nike/cerberus/service/KmsPolicyServiceTest.java
@@ -51,29 +51,29 @@ public void before() {
String cmsRoleArn = "arn:aws:iam::1111111111:role/cms-iam-role";
kmsPolicyService =
new KmsPolicyService(
- true, rootUserArn, adminRoleArn, cmsRoleArn, new AwsIamRoleArnParser());
+ true, rootUserArn, adminRoleArn, cmsRoleArn, new AwsIamRoleArnParser(true, false));
objectMapper = new ObjectMapper();
}
@Test(expected = NullPointerException.class)
public void test_that_KmsPolicyService_throws_error_when_required_field_null_rootUserArn() {
- new KmsPolicyService(true, null, "foo", "bar", new AwsIamRoleArnParser());
+ new KmsPolicyService(true, null, "foo", "bar", new AwsIamRoleArnParser(true, false));
}
@Test(expected = NullPointerException.class)
public void test_that_KmsPolicyService_throws_error_when_required_field_null_adminRoleArn() {
- new KmsPolicyService(true, "foo", null, "bar", new AwsIamRoleArnParser());
+ new KmsPolicyService(true, "foo", null, "bar", new AwsIamRoleArnParser(true, false));
}
@Test(expected = NullPointerException.class)
public void test_that_KmsPolicyService_throws_error_when_required_field_null_cmsRoleArn() {
- new KmsPolicyService(true, "foo", "bar", null, new AwsIamRoleArnParser());
+ new KmsPolicyService(true, "foo", "bar", null, new AwsIamRoleArnParser(true, false));
}
@Test()
public void
test_that_KmsPolicyService_throws_no_error_when_required_fields_are_null_but_kms_auth_disabled() {
- new KmsPolicyService(false, null, null, null, new AwsIamRoleArnParser());
+ new KmsPolicyService(false, null, null, null, new AwsIamRoleArnParser(true, false));
}
@Test
diff --git a/cerberus-web/src/test/java/com/nike/cerberus/service/KmsServiceTest.java b/cerberus-web/src/test/java/com/nike/cerberus/service/KmsServiceTest.java
index 69d5e2184..3c85619e3 100644
--- a/cerberus-web/src/test/java/com/nike/cerberus/service/KmsServiceTest.java
+++ b/cerberus-web/src/test/java/com/nike/cerberus/service/KmsServiceTest.java
@@ -98,7 +98,7 @@ public void setup() {
kmsClientFactory,
kmsPolicyService,
dateTimeSupplier,
- new AwsIamRoleArnParser(),
+ new AwsIamRoleArnParser(true, false),
3000,
ENV,
slugger,
diff --git a/cerberus-web/src/test/java/com/nike/cerberus/util/AwsIamRoleArnParserTest.java b/cerberus-web/src/test/java/com/nike/cerberus/util/AwsIamRoleArnParserTest.java
index 95f891fac..f289c0991 100644
--- a/cerberus-web/src/test/java/com/nike/cerberus/util/AwsIamRoleArnParserTest.java
+++ b/cerberus-web/src/test/java/com/nike/cerberus/util/AwsIamRoleArnParserTest.java
@@ -27,39 +27,46 @@
/** Tests the AwsIamRoleArnParser class */
public class AwsIamRoleArnParserTest {
- private AwsIamRoleArnParser awsIamRoleArnParser;
+ private AwsIamRoleArnParser awsGlobalIamRoleArnParser;
+ private AwsIamRoleArnParser awsChinaIamRoleArnParser;
@Before
public void setup() {
-
- awsIamRoleArnParser = new AwsIamRoleArnParser();
+ awsGlobalIamRoleArnParser = new AwsIamRoleArnParser(true, false);
+ awsChinaIamRoleArnParser = new AwsIamRoleArnParser(false, true);
}
@Test
public void getAccountId_returns_an_account_id_given_a_valid_arn() {
-
assertEquals(
"1111111111",
- awsIamRoleArnParser.getAccountId("arn:aws:iam::1111111111:role/lamb_dev_health"));
+ awsGlobalIamRoleArnParser.getAccountId("arn:aws:iam::1111111111:role/lamb_dev_health"));
+ assertEquals(
+ "1111111111",
+ awsChinaIamRoleArnParser.getAccountId("arn:aws-cn:iam::1111111111:role/lamb_dev_health"));
}
@Test(expected = RuntimeException.class)
public void getAccountId_fails_on_invalid_arn() {
- awsIamRoleArnParser.getAccountId("hullabaloo");
+ awsGlobalIamRoleArnParser.getAccountId("hullabaloo");
}
@Test
public void getRoleNameHappy_returns_the_role_name_given_a_valid_arn() {
assertEquals(
- "my_roleName", awsIamRoleArnParser.getRoleName("arn:aws:iam::222222:role/my_roleName"));
+ "my_roleName",
+ awsGlobalIamRoleArnParser.getRoleName("arn:aws:iam::222222:role/my_roleName"));
+ assertEquals(
+ "my_roleName",
+ awsChinaIamRoleArnParser.getRoleName("arn:aws-cn:iam::222222:role/my_roleName"));
}
@Test(expected = RuntimeException.class)
public void getRoleName_fails_on_invalid_arn() {
- awsIamRoleArnParser.getRoleName("brouhaha");
+ awsGlobalIamRoleArnParser.getRoleName("brouhaha");
}
@Test
@@ -67,51 +74,87 @@ public void convertPrincipalArnToRoleArn_properly_converts_principals_to_role_ar
assertEquals(
"arn:aws:iam::1111111111:role/lamb_dev_health",
- awsIamRoleArnParser.convertPrincipalArnToRoleArn(
+ awsGlobalIamRoleArnParser.convertPrincipalArnToRoleArn(
"arn:aws:sts::1111111111:federated-user/lamb_dev_health"));
assertEquals(
"arn:aws:iam::2222222222:role/prince_role",
- awsIamRoleArnParser.convertPrincipalArnToRoleArn(
+ awsGlobalIamRoleArnParser.convertPrincipalArnToRoleArn(
"arn:aws:sts::2222222222:assumed-role/prince_role/session-name"));
assertEquals(
"arn:aws:iam::2222222222:role/sir/alfred/role",
- awsIamRoleArnParser.convertPrincipalArnToRoleArn(
+ awsGlobalIamRoleArnParser.convertPrincipalArnToRoleArn(
"arn:aws:sts::2222222222:assumed-role/sir/alfred/role/session-name"));
assertEquals(
"arn:aws:iam::3333333333:role/path/to/foo",
- awsIamRoleArnParser.convertPrincipalArnToRoleArn(
+ awsGlobalIamRoleArnParser.convertPrincipalArnToRoleArn(
"arn:aws:iam::3333333333:role/path/to/foo"));
assertEquals(
"arn:aws:iam::4444444444:role/name",
- awsIamRoleArnParser.convertPrincipalArnToRoleArn("arn:aws:iam::4444444444:role/name"));
+ awsGlobalIamRoleArnParser.convertPrincipalArnToRoleArn(
+ "arn:aws:iam::4444444444:role/name"));
+
+ assertEquals(
+ "arn:aws-cn:iam::1111111111:role/lamb_dev_health",
+ awsChinaIamRoleArnParser.convertPrincipalArnToRoleArn(
+ "arn:aws-cn:sts::1111111111:federated-user/lamb_dev_health"));
+ assertEquals(
+ "arn:aws-cn:iam::2222222222:role/prince_role",
+ awsChinaIamRoleArnParser.convertPrincipalArnToRoleArn(
+ "arn:aws-cn:sts::2222222222:assumed-role/prince_role/session-name"));
+ assertEquals(
+ "arn:aws-cn:iam::2222222222:role/sir/alfred/role",
+ awsChinaIamRoleArnParser.convertPrincipalArnToRoleArn(
+ "arn:aws-cn:sts::2222222222:assumed-role/sir/alfred/role/session-name"));
+ assertEquals(
+ "arn:aws-cn:iam::3333333333:role/path/to/foo",
+ awsChinaIamRoleArnParser.convertPrincipalArnToRoleArn(
+ "arn:aws-cn:iam::3333333333:role/path/to/foo"));
+ assertEquals(
+ "arn:aws-cn:iam::4444444444:role/name",
+ awsChinaIamRoleArnParser.convertPrincipalArnToRoleArn(
+ "arn:aws-cn:iam::4444444444:role/name"));
}
@Test(expected = RuntimeException.class)
public void convertPrincipalArnToRoleArn_fails_on_invalid_arn() {
- awsIamRoleArnParser.convertPrincipalArnToRoleArn("foobar");
+ awsGlobalIamRoleArnParser.convertPrincipalArnToRoleArn("foobar");
}
@Test(expected = RuntimeException.class)
public void convertPrincipalArnToRoleArn_fails_on_group_arn() {
- awsIamRoleArnParser.convertPrincipalArnToRoleArn("arn:aws:iam::1111111111:group/path/to/group");
+ awsGlobalIamRoleArnParser.convertPrincipalArnToRoleArn(
+ "arn:aws:iam::1111111111:group/path/to/group");
}
@Test(expected = RuntimeException.class)
public void convertPrincipalArnToRoleArn_fails_on_invalid_assumed_role_arn() {
- awsIamRoleArnParser.convertPrincipalArnToRoleArn("arn:aws:sts::1111111111:assumed-role/blah");
+ awsGlobalIamRoleArnParser.convertPrincipalArnToRoleArn(
+ "arn:aws:sts::1111111111:assumed-role/blah");
}
@Test
public void isRoleArn_returns_true_when_is_role_arn() {
- assertTrue(awsIamRoleArnParser.isRoleArn("arn:aws:iam::2222222222:role/fancy/role/path"));
- assertTrue(awsIamRoleArnParser.isRoleArn("arn:aws:iam::1111111111:role/name"));
- assertFalse(awsIamRoleArnParser.isRoleArn("arn:aws:iam::3333333333:assumed-role/happy/path"));
- assertFalse(awsIamRoleArnParser.isRoleArn("arn:aws:sts::1111111111:federated-user/my_user"));
- assertFalse(awsIamRoleArnParser.isRoleArn("arn:aws:iam::1111111111:group/path/to/group"));
+ assertTrue(awsGlobalIamRoleArnParser.isRoleArn("arn:aws:iam::2222222222:role/fancy/role/path"));
+ assertTrue(awsGlobalIamRoleArnParser.isRoleArn("arn:aws:iam::1111111111:role/name"));
+ assertFalse(
+ awsGlobalIamRoleArnParser.isRoleArn("arn:aws:iam::3333333333:assumed-role/happy/path"));
+ assertFalse(
+ awsGlobalIamRoleArnParser.isRoleArn("arn:aws:sts::1111111111:federated-user/my_user"));
+ assertFalse(awsGlobalIamRoleArnParser.isRoleArn("arn:aws:iam::1111111111:group/path/to/group"));
+
+ assertTrue(
+ awsChinaIamRoleArnParser.isRoleArn("arn:aws-cn:iam::2222222222:role/fancy/role/path"));
+ assertTrue(awsChinaIamRoleArnParser.isRoleArn("arn:aws-cn:iam::1111111111:role/name"));
+ assertFalse(
+ awsChinaIamRoleArnParser.isRoleArn("arn:aws-cn:iam::3333333333:assumed-role/happy/path"));
+ assertFalse(
+ awsChinaIamRoleArnParser.isRoleArn("arn:aws-cn:sts::1111111111:federated-user/my_user"));
+ assertFalse(
+ awsChinaIamRoleArnParser.isRoleArn("arn:aws-cn:iam::1111111111:group/path/to/group"));
}
@Test
@@ -191,33 +234,33 @@ public void test_IAM_PRINCIPAL_ARN_PATTERN_invalid_ARNs() {
@Test
public void test_isArnThatCanGoInKeyPolicy() {
assertTrue(
- awsIamRoleArnParser.isArnThatCanGoInKeyPolicy(
+ awsGlobalIamRoleArnParser.isArnThatCanGoInKeyPolicy(
"arn:aws:iam::12345678901234:role/some-role"));
assertTrue(
- awsIamRoleArnParser.isArnThatCanGoInKeyPolicy(
+ awsGlobalIamRoleArnParser.isArnThatCanGoInKeyPolicy(
"arn:aws:iam::12345678901234:role/some/path/some-role"));
assertTrue(
- awsIamRoleArnParser.isArnThatCanGoInKeyPolicy(
+ awsGlobalIamRoleArnParser.isArnThatCanGoInKeyPolicy(
"arn:aws:iam::12345678901234:user/some-user"));
assertTrue(
- awsIamRoleArnParser.isArnThatCanGoInKeyPolicy(
+ awsGlobalIamRoleArnParser.isArnThatCanGoInKeyPolicy(
"arn:aws:sts::12345678901234:assumed-role/some-path/some-role"));
assertTrue(
- awsIamRoleArnParser.isArnThatCanGoInKeyPolicy(
+ awsGlobalIamRoleArnParser.isArnThatCanGoInKeyPolicy(
"arn:aws:sts::12345678901234:assumed-role/some-role"));
assertTrue(
- awsIamRoleArnParser.isArnThatCanGoInKeyPolicy(
+ awsGlobalIamRoleArnParser.isArnThatCanGoInKeyPolicy(
"arn:aws:sts::12345678901234:federated-user/my_user"));
// invalid - KMS doesn't allow 'group' or 'instance-profile'
assertFalse(
- awsIamRoleArnParser.isArnThatCanGoInKeyPolicy(
+ awsGlobalIamRoleArnParser.isArnThatCanGoInKeyPolicy(
"arn:aws:iam::12345678901234:group/some-group"));
assertFalse(
- awsIamRoleArnParser.isArnThatCanGoInKeyPolicy(
+ awsGlobalIamRoleArnParser.isArnThatCanGoInKeyPolicy(
"arn:aws:iam::12345678901234:instance-profile/some-profile"));
assertFalse(
- awsIamRoleArnParser.isArnThatCanGoInKeyPolicy(
+ awsGlobalIamRoleArnParser.isArnThatCanGoInKeyPolicy(
"arn:aws:iam::12345678901234:other/some-value"));
}
@@ -225,38 +268,42 @@ public void test_isArnThatCanGoInKeyPolicy() {
public void test_stripOutDescription() {
assertEquals(
"12345678901234/some-role",
- awsIamRoleArnParser.stripOutDescription("arn:aws:iam::12345678901234:role/some-role"));
+ awsGlobalIamRoleArnParser.stripOutDescription(
+ "arn:aws:iam::12345678901234:role/some-role"));
assertEquals(
"12345678901234/some/path/some-role",
- awsIamRoleArnParser.stripOutDescription(
+ awsGlobalIamRoleArnParser.stripOutDescription(
"arn:aws:iam::12345678901234:role/some/path/some-role"));
assertEquals(
"12345678901234/some-user",
- awsIamRoleArnParser.stripOutDescription("arn:aws:iam::12345678901234:user/some-user"));
+ awsGlobalIamRoleArnParser.stripOutDescription(
+ "arn:aws:iam::12345678901234:user/some-user"));
assertEquals(
"12345678901234/some-path/some-role",
- awsIamRoleArnParser.stripOutDescription(
+ awsGlobalIamRoleArnParser.stripOutDescription(
"arn:aws:sts::12345678901234:assumed-role/some-path/some-role"));
assertEquals(
"12345678901234/some-role",
- awsIamRoleArnParser.stripOutDescription(
+ awsGlobalIamRoleArnParser.stripOutDescription(
"arn:aws:sts::12345678901234:assumed-role/some-role"));
assertEquals(
"12345678901234/my_user",
- awsIamRoleArnParser.stripOutDescription(
+ awsGlobalIamRoleArnParser.stripOutDescription(
"arn:aws:sts::12345678901234:federated-user/my_user"));
// invalid - KMS doesn't allow 'group' or 'instance-profile' though some parsing is still
// possible (this behavior isn't important)
assertEquals(
"",
- awsIamRoleArnParser.stripOutDescription("arn:aws:iam::12345678901234:group/some-group"));
+ awsGlobalIamRoleArnParser.stripOutDescription(
+ "arn:aws:iam::12345678901234:group/some-group"));
assertEquals(
"12345678901234/some-value",
- awsIamRoleArnParser.stripOutDescription("arn:aws:iam::12345678901234:other/some-value"));
+ awsGlobalIamRoleArnParser.stripOutDescription(
+ "arn:aws:iam::12345678901234:other/some-value"));
assertEquals(
"12345678901234/some-profile",
- awsIamRoleArnParser.stripOutDescription(
+ awsGlobalIamRoleArnParser.stripOutDescription(
"arn:aws:iam::12345678901234:instance-profile/some-profile"));
}
@@ -274,13 +321,27 @@ public void test_that_an_iam_role_can_not_end_with_whitespace() {
@Test
public void test_isAccountRootArn() {
- assertTrue(awsIamRoleArnParser.isAccountRootArn("arn:aws:iam::0000000000:root"));
+ assertTrue(awsGlobalIamRoleArnParser.isAccountRootArn("arn:aws:iam::0000000000:root"));
- assertFalse(awsIamRoleArnParser.isAccountRootArn("arn:aws:iam::0000000000:role/foo"));
- assertFalse(awsIamRoleArnParser.isAccountRootArn("arn:aws:iam::0000000000:user/bar"));
- assertFalse(awsIamRoleArnParser.isAccountRootArn("arn:aws:sts::0000000000:assumed-role/baz"));
- assertFalse(awsIamRoleArnParser.isAccountRootArn("arn:aws:iam::0000000000:group/foobar"));
+ assertFalse(awsGlobalIamRoleArnParser.isAccountRootArn("arn:aws:iam::0000000000:role/foo"));
+ assertFalse(awsGlobalIamRoleArnParser.isAccountRootArn("arn:aws:iam::0000000000:user/bar"));
assertFalse(
- awsIamRoleArnParser.isAccountRootArn("arn:aws:sts::0000000000:federated-user/foobaz"));
+ awsGlobalIamRoleArnParser.isAccountRootArn("arn:aws:sts::0000000000:assumed-role/baz"));
+ assertFalse(awsGlobalIamRoleArnParser.isAccountRootArn("arn:aws:iam::0000000000:group/foobar"));
+ assertFalse(
+ awsGlobalIamRoleArnParser.isAccountRootArn(
+ "arn:aws:sts::0000000000:federated-user/foobaz"));
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void iamPrincipalPartitionCheck_fails_on_disabled_aws_china_partition() {
+ awsGlobalIamRoleArnParser.iamPrincipalPartitionCheck(
+ "arn:aws-cn:iam::1111111111:role/lamb_dev_health");
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void iamPrincipalPartitionCheck_fails_on_disabled_aws_global_partition() {
+ awsChinaIamRoleArnParser.iamPrincipalPartitionCheck(
+ "arn:aws:iam::1111111111:role/lamb_dev_health");
}
}
diff --git a/gradle.properties b/gradle.properties
index 56bdf4eed..5c1d957dd 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -14,6 +14,6 @@
# limitations under the License.
#
-version=4.6.2
+version=4.7.0
group=com.nike.cerberus
springBootVersion=2.3.2.RELEASE