Skip to content
This repository has been archived by the owner on Jan 12, 2024. It is now read-only.

Commit

Permalink
Merge pull request #53 from Nike-Inc/bugfix/cms_cannot_delete_kms_keys
Browse files Browse the repository at this point in the history
Give CMS permissions to schedule and cancel KMS key deletion
  • Loading branch information
sdford authored Jul 17, 2017
2 parents 322eeb4 + 25d0168 commit 7200cdf
Show file tree
Hide file tree
Showing 13 changed files with 643 additions and 113 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@
# limitations under the License.
#

version=0.22.0
version=0.24.0
groupId=com.nike.cerberus
artifactId=cms
2 changes: 1 addition & 1 deletion gradle/dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def riposteVersion = '0.9.4'
def logbackVersion = '1.1.7'
// Request version 4 for full java 8 support
def guiceVersion = '4.0'
def awsSdkVersion = '1.11.108'
def awsSdkVersion = '1.11.160'
def groovyVersion = '2.3.9'

dependencies {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import com.nike.cerberus.service.CleanUpService;
import com.nike.riposte.server.http.RequestInfo;
import com.nike.riposte.server.http.ResponseInfo;
import com.nike.riposte.server.http.impl.FullResponseInfo;
import com.nike.riposte.util.AsyncNettyHelper;
import com.nike.riposte.util.Matcher;
import io.netty.channel.ChannelHandlerContext;
Expand All @@ -50,8 +49,6 @@ public class CleanUpInactiveOrOrphanedRecords extends AdminStandardEndpoint<Clea

private final Logger log = LoggerFactory.getLogger(getClass());

private static final int DEFAULT_KMS_KEY_INACTIVE_AFTER_N_DAYS = 30;

private final CleanUpService cleanUpService;

@Inject
Expand All @@ -64,29 +61,22 @@ public CompletableFuture<ResponseInfo<Void>> doExecute(final RequestInfo<CleanUp
final Executor longRunningTaskExecutor,
final ChannelHandlerContext ctx,
final SecurityContext securityContext) {
return CompletableFuture.supplyAsync(
AsyncNettyHelper.supplierWithTracingAndMdc(() -> cleanUp(request, securityContext), ctx),
longRunningTaskExecutor
);
}

private FullResponseInfo<Void> cleanUp(final RequestInfo<CleanUpRequest> request,
final SecurityContext securityContext) {

final VaultAuthPrincipal vaultAuthPrincipal = (VaultAuthPrincipal) securityContext.getUserPrincipal();
final String principal = vaultAuthPrincipal.getName();

log.info("Clean Up Event: the principal {} is attempting to clean up kms keys", principal);

Integer expirationPeriodInDays = request.getContent().getKmsExpirationPeriodInDays();
int kmsKeysInactiveAfterNDays = (expirationPeriodInDays == null) ? DEFAULT_KMS_KEY_INACTIVE_AFTER_N_DAYS : expirationPeriodInDays;

cleanUpService.cleanUpInactiveAndOrphanedKmsKeys(kmsKeysInactiveAfterNDays);
cleanUpService.cleanUpOrphanedIamRoles();
longRunningTaskExecutor.execute(AsyncNettyHelper.runnableWithTracingAndMdc(
() -> cleanUpService.cleanUp(request.getContent()),
ctx
));

return ResponseInfo.<Void>newBuilder()
.withHttpStatusCode(HttpResponseStatus.NO_CONTENT.code())
.build();
return CompletableFuture.completedFuture(
ResponseInfo.<Void>newBuilder()
.withHttpStatusCode(HttpResponseStatus.NO_CONTENT.code())
.build()
);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,7 @@ protected String getKeyId(IamPrincipalCredentials credentials) {
kmsKeyRecord = kmsKey.get();
kmsKeyId = kmsKeyRecord.getAwsKmsKeyId();
kmsService.validatePolicy(kmsKeyRecord, iamPrincipalArn);
kmsService.validateKmsKeyIsUsable(kmsKeyRecord, iamPrincipalArn);
}

return kmsKeyId;
Expand Down
31 changes: 22 additions & 9 deletions src/main/java/com/nike/cerberus/service/CleanUpService.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.nike.cerberus.dao.AwsIamRoleDao;
import com.nike.cerberus.domain.CleanUpRequest;
import com.nike.cerberus.record.AwsIamRoleKmsKeyRecord;
import com.nike.cerberus.record.AwsIamRoleRecord;
import com.nike.cerberus.util.DateTimeSupplier;
import org.mybatis.guice.transactional.Transactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -42,6 +44,8 @@ public class CleanUpService {

private static final int DEFAULT_SLEEP_BETWEEN_KMS_CALLS = 10; // in seconds

private static final int DEFAULT_KMS_KEY_INACTIVE_AFTER_N_DAYS = 30;

private final KmsService kmsService;

private final AwsIamRoleDao awsIamRoleDao;
Expand All @@ -57,11 +61,19 @@ public CleanUpService(KmsService kmsService,
this.dateTimeSupplier = dateTimeSupplier;
}

public void cleanUp(final CleanUpRequest cleanUpRequest) {
Integer expirationPeriodInDays = cleanUpRequest.getKmsExpirationPeriodInDays();
int kmsKeysInactiveAfterNDays = (expirationPeriodInDays == null) ? DEFAULT_KMS_KEY_INACTIVE_AFTER_N_DAYS : expirationPeriodInDays;

cleanUpInactiveAndOrphanedKmsKeys(kmsKeysInactiveAfterNDays);
cleanUpOrphanedIamRoles();
}

/**
* Delete all AWS KMS keys and DB records for KMS keys that have not been used recently
* or are no longer associated with an SDB.
*/
public void cleanUpInactiveAndOrphanedKmsKeys(final int kmsKeysInactiveAfterNDays) {
protected void cleanUpInactiveAndOrphanedKmsKeys(final int kmsKeysInactiveAfterNDays) {

cleanUpInactiveAndOrphanedKmsKeys(kmsKeysInactiveAfterNDays, DEFAULT_SLEEP_BETWEEN_KMS_CALLS);
}
Expand All @@ -81,25 +93,25 @@ protected void cleanUpInactiveAndOrphanedKmsKeys(final int kmsKeysInactiveAfterN
if (inactiveAndOrphanedKmsKeys.isEmpty()) {
logger.info("No keys to clean up.");
} else {

// delete inactive and orphaned kms key records from DB
logger.info("Cleaning up orphaned or inactive KMS keys...");
inactiveAndOrphanedKmsKeys.forEach(kmsKeyRecord -> {
final String kmsKeyArn = kmsKeyRecord.getAwsKmsKeyId();
final String kmsKeyRegion = kmsKeyRecord.getAwsRegion();
try {
logger.info("Deleting orphaned or inactive KMS key: id={}, region={}, lastValidated={}",
kmsKeyRecord.getAwsKmsKeyId(), kmsKeyRecord.getAwsRegion(), kmsKeyRecord.getLastValidatedTs());

kmsService.scheduleKmsKeyDeletion(kmsKeyRecord.getAwsKmsKeyId(), kmsKeyRecord.getAwsRegion(), SOONEST_A_KMS_KEY_CAN_BE_DELETED);
awsIamRoleDao.deleteKmsKeyById(kmsKeyRecord.getId());

kmsKeyArn, kmsKeyRegion, kmsKeyRecord.getLastValidatedTs());
kmsService.validatePolicyAllowsCMSToDeleteCMK(kmsKeyArn, kmsKeyRegion);
kmsService.scheduleKmsKeyDeletion(kmsKeyArn, kmsKeyRegion, SOONEST_A_KMS_KEY_CAN_BE_DELETED);
kmsService.deleteKmsKeyById(kmsKeyRecord.getId());
TimeUnit.SECONDS.sleep(sleepInSeconds);
} catch (InterruptedException ie) {
logger.error("Timeout between KMS key deletion was interrupted", ie);
Thread.currentThread().interrupt();
} catch (Exception e) {
logger.error("There was a problem deleting KMS key with id: {}, region: {}",
kmsKeyRecord.getAwsIamRoleId(),
kmsKeyRecord.getAwsRegion(),
kmsKeyRegion,
e);
}
});
Expand All @@ -109,7 +121,8 @@ protected void cleanUpInactiveAndOrphanedKmsKeys(final int kmsKeysInactiveAfterN
/**
* Delete all IAM role records that are no longer associated with an SDB.
*/
public void cleanUpOrphanedIamRoles() {
@Transactional
protected void cleanUpOrphanedIamRoles() {

// get orphaned iam role ids
final List<AwsIamRoleRecord> orphanedIamRoleIds = awsIamRoleDao.getOrphanedIamRoles();
Expand Down
Loading

0 comments on commit 7200cdf

Please sign in to comment.