@Test public void testCreate() throws Exception { // Mocks the responses from AWS. CreateKeyRequest createKeyRequest = new CreateKeyRequest().withDescription( "This key is automatically managed by Strongbox"); CreateKeyResult createKeyResult = new CreateKeyResult().withKeyMetadata(new KeyMetadata().withArn(KMS_ARN)); CreateAliasRequest createAliasRequest = new CreateAliasRequest().withAliasName(ALIAS_KEY_NAME).withTargetKeyId(KMS_ARN); when(mockKMSClient.describeKey(describeKeyRequest)) .thenThrow(NotFoundException.class) .thenThrow(NotFoundException.class) // still waiting for creation .thenReturn(enabledKeyResult()); when(mockKMSClient.createKey(createKeyRequest)).thenReturn(createKeyResult); // Check the result from create method. String arn = kmsManager.create(); assertEquals(arn, KMS_ARN); // Verify correct number of calls was made to AWS. verify(mockKMSClient, times(3)).describeKey(describeKeyRequest); verify(mockKMSClient, times(1)).createAlias(createAliasRequest); verify(mockKMSClient, times(1)).createKey(createKeyRequest); }
@Test public void testDeleteNonExisting() throws Exception { when(mockKMSClient.describeKey(describeKeyRequest)).thenThrow(NotFoundException.class); boolean exceptionThrown = false; try { kmsManager.delete(); } catch (DoesNotExistException e) { assertEquals(e.getMessage(), String.format("Failed to find KMS key with alias '%s'", KMS_ALIAS_ARN)); exceptionThrown = true; } verify(mockKMSClient, times(1)).describeKey(describeKeyRequest); verify(mockKMSClient, never()).scheduleKeyDeletion(any()); }
/** * Perform validation and fix some issues. * * When a KMS key policy statement is created and an AWS ARN is specified as a principal, * AWS behind the scene binds that ARNs ID to the statement and not the ARN. * * They do this so that when a role or user is deleted and another team or person recreates the identity * that this new identity does not get permissions that were not meant for it. * * In Cerberus's case we need to support a flow where teams use automation to automatically destroy and recreate IAM roles. * * We can detect that this event has happened because when an Identity that was referenced by an ARN in a KMS policy * statement has been deleted the ARN is replaced by the ID. We can validate that principal matches an ARN pattern * or recreate the policy. * * @param kmsKeyRecord - The CMK record to validate policy on * @param iamPrincipalArn - The principal ARN that should have decrypt permission */ public void validateKeyAndPolicy(AwsIamRoleKmsKeyRecord kmsKeyRecord, String iamPrincipalArn) { if (! kmsPolicyNeedsValidation(kmsKeyRecord)) { // Avoiding extra calls to AWS so that we don't get rate limited. return; } String kmsCMKRegion = kmsKeyRecord.getAwsRegion(); String awsKmsKeyArn = kmsKeyRecord.getAwsKmsKeyId(); try { String keyPolicy = getKmsKeyPolicy(awsKmsKeyArn, kmsCMKRegion); if (!kmsPolicyService.isPolicyValid(keyPolicy)) { logger.info("The KMS key: {} generated for IAM principal: {} contained an invalid policy, regenerating", awsKmsKeyArn, iamPrincipalArn); String updatedPolicy = kmsPolicyService.generateStandardKmsPolicy(iamPrincipalArn); updateKmsKeyPolicy(updatedPolicy, awsKmsKeyArn, kmsCMKRegion); } validateKmsKeyIsUsable(kmsKeyRecord, iamPrincipalArn); // update last validated timestamp OffsetDateTime now = dateTimeSupplier.get(); updateKmsKey(kmsKeyRecord.getAwsIamRoleId(), kmsCMKRegion, SYSTEM_USER, now, now); } catch(NotFoundException nfe) { logger.warn("Failed to validate KMS policy because the KMS key did not exist, but the key record did." + "Deleting the key record to prevent this from failing again: keyId: {} for IAM principal: {} in region: {}", awsKmsKeyArn, iamPrincipalArn, kmsCMKRegion, nfe); deleteKmsKeyById(kmsKeyRecord.getId()); } catch (Exception e) { logger.warn(String.format("Failed to validate KMS policy for keyId: %s for IAM principal: %s in region: %s due to %s", awsKmsKeyArn, iamPrincipalArn, kmsCMKRegion, e.toString()), e); } }
private void assertExists(String keyId) { if (idToArnMap.containsKey(keyId)) { keyId = idToArnMap.get(keyId); } if (keyId == null || !activeKeys.contains(keyId)) { throw new NotFoundException("Key doesn't exist"); } }
@Test public void testExistsKeyDoesNotExist() throws Exception { when(mockKMSClient.describeKey(describeKeyRequest)).thenThrow(NotFoundException.class); assertFalse(kmsManager.exists()); }
@Test(expected = NotFoundException.class) public void getNoExistFile() throws Exception { s3Source.init(); String fileName = "no-exist-file"; s3Source.getConfiguration(new ImmutableEnvironment(fileName)); }