-
Notifications
You must be signed in to change notification settings - Fork 37
Closed
Description
I have an application from where I create, read, update and delete secrets to and from AWS secrets manager. This app is the only place from which the secrets can be updated. I use this library for caching, and I call refreshNow() for that secretId whenever I create/update/delete that secretId value. refreshNow() has a random sleep of 2.5 to 5 seconds in it, which slows down the write operation. My question is, am I using the library wrong, or will it be better to simply have a caching layer in my app code, instead of using this library? My simple requirement is that the read should never be stale, which is easy to implement as my app is the only place where we do writes from.
Here is my code:
@Service
@Slf4j
@RequiredArgsConstructor
public class AwsSecretsManagerService {
private final ObjectMapper objectMapper;
@Qualifier("awsSecretsManagerClient")
private final SecretsManagerClient secretsManagerClient;
@Qualifier("secretCache")
private final SecretCache secretCache;
/**
* Create new secret for the secretId given. Throws exception if secretId already exists.
*
* @param secretId secretId.
* @param secrets secrets as key-value pairs.
*/
public void createSecrets(String secretId, Map<String, String> secrets) {
String secretString;
try {
secretString = objectMapper.writeValueAsString(secrets);
} catch (JsonProcessingException e) {
log.error("Error parsing secrets while creating secretId: {}", secretId, e);
throw new IllegalArgumentException("Cannot convert secrets to string", e);
}
final CreateSecretRequest createSecretRequest =
CreateSecretRequest.builder().name(secretId).secretString(secretString).build();
final CreateSecretResponse createSecretResponse =
secretsManagerClient.createSecret(createSecretRequest);
log.info("Created secret: {}", createSecretResponse);
refreshCache(secretId);
}
/**
* Update the secret for the secretId given. Throws exception if secretId does not exist already.
*
* @param secretId secretId.
* @param secrets secrets as key-value pairs.
*/
public void updateSecrets(String secretId, Map<String, String> secrets) {
String secretString;
try {
secretString = objectMapper.writeValueAsString(secrets);
} catch (JsonProcessingException e) {
log.error("Error parsing secrets while updating secretId: {}", secretId, e);
throw new IllegalArgumentException("Cannot convert secrets to string", e);
}
final UpdateSecretRequest updateSecretRequest =
UpdateSecretRequest.builder().secretId(secretId).secretString(secretString).build();
final UpdateSecretResponse updateSecretResponse =
secretsManagerClient.updateSecret(updateSecretRequest);
log.info("Updated secret: {}", updateSecretResponse);
refreshCache(secretId);
}
/**
* Deletes the entire secret object for the provided secretId.
*
* @param secretId secretId.
*/
public void deleteSecrets(String secretId) {
DeleteSecretResponse deleteSecretResponse =
secretsManagerClient.deleteSecret(DeleteSecretRequest.builder().secretId(secretId).build());
log.info("Deleted secret: {}", deleteSecretResponse);
refreshCache(secretId);
}
public void restoreSecrets(String secretId) {
RestoreSecretResponse restoreSecretResponse =
secretsManagerClient.restoreSecret(
RestoreSecretRequest.builder().secretId(secretId).build());
log.info("Restored secret: {}", restoreSecretResponse);
refreshCache(secretId);
}
/**
* Refresh the cache. To be called whenever we are writing to AWS Secrets Manager.
*
* @param secretId the secretId for which the cache needs to be refreshed.
*/
private void refreshCache(String secretId) {
try {
secretCache.refreshNow(secretId);
} catch (InterruptedException e) {
log.error("Interrupted exception while refreshing secretCache", e);
}
}
/** {@inheritDoc} */
public Map<String, String> getSecrets(String secretId) {
try {
return objectMapper.readValue(
secretCache.getSecretString(secretId), new TypeReference<Map<String, String>>() {});
} catch (IOException e) {
log.error("Error in parsing secrets string to Map for secretId {}", secretId, e);
throw new IllegalArgumentException(
String.format("Cannot parse secrets string to map for secretId %s", secretId), e);
}
}
}
And the @Configuration class
@Bean("awsSecretsManagerClient")
public SecretsManagerClient awsSecretsManagerClient() {
return SecretsManagerClient.builder().region(BUILD_REGION).build();
}
@Bean("secretCache")
public SecretCache secretCache() {
return new SecretCache(new SecretCacheConfiguration().withClient(awsSecretsManagerClient()));
}
simonmarty
Metadata
Metadata
Assignees
Labels
No labels