1 | /** | |
2 | Copyright 2018 Carlos Macasaet | |
3 | ||
4 | Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | you may not use this file except in compliance with the License. | |
6 | You may obtain a copy of the License at | |
7 | ||
8 | http://www.apache.org/licenses/LICENSE-2.0 | |
9 | ||
10 | Unless required by applicable law or agreed to in writing, software | |
11 | distributed under the License is distributed on an "AS IS" BASIS, | |
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | See the License for the specific language governing permissions and | |
14 | limitations under the License. | |
15 | */ | |
16 | package com.macasaet.fernet.aws.secretsmanager.rotation; | |
17 | ||
18 | import static com.macasaet.fernet.aws.secretsmanager.rotation.Stage.PENDING; | |
19 | ||
20 | import java.nio.ByteBuffer; | |
21 | import java.security.SecureRandom; | |
22 | ||
23 | import com.amazonaws.services.kms.AWSKMS; | |
24 | import com.amazonaws.services.kms.AWSKMSClientBuilder; | |
25 | import com.amazonaws.services.secretsmanager.AWSSecretsManagerClientBuilder; | |
26 | import com.macasaet.fernet.Key; | |
27 | ||
28 | /** | |
29 | * <p>AWS Lambda that rotates Fernet keys. To access a key, retrieve AWSCURRENT, AWSPENDING, or AWSPREVIOUS. To validate | |
30 | * and decrypt a token, it will be necessary to retrieve AWSCURRENT and AWSPREVIOUS as there is no way to know which one | |
31 | * was used to generate the token.</p> | |
32 | * | |
33 | * <p>Grant AWS Secrets Manager permission to execute the Lambda using this:</p> | |
34 | * <pre>aws lambda add-permission --function-name arn:aws:lambda:{region}:{accountId}:function:{functionName} --principal secretsmanager.amazonaws.com --action lambda:InvokeFunction --statement-id SecretsManagerAccess</pre> | |
35 | * | |
36 | * <p>Copyright © 2018 Carlos Macasaet.</p> | |
37 | * @author Carlos Macasaet | |
38 | */ | |
39 | @SuppressWarnings("PMD.LawOfDemeter") | |
40 | public class SimpleFernetKeyRotator extends AbstractFernetKeyRotator { | |
41 | ||
42 | private static final int fernetKeySize = 32; | |
43 | ||
44 | protected SimpleFernetKeyRotator(final SecretsManager secretsManager, final AWSKMS kms, final SecureRandom random) { | |
45 | super(secretsManager, kms, random); | |
46 | } | |
47 | ||
48 | protected SimpleFernetKeyRotator(final SecureRandom random) { | |
49 | this(new SecretsManager(AWSSecretsManagerClientBuilder.standard() | |
50 | .withRequestHandlers(new MemoryOverwritingRequestHandler(random)).build()), | |
51 | AWSKMSClientBuilder.defaultClient(), random); | |
52 | } | |
53 | ||
54 | public SimpleFernetKeyRotator() { | |
55 | this(new SecureRandom()); | |
56 | } | |
57 | ||
58 | protected void createSecret(final String secretId, final String clientRequestToken) { | |
59 | final Key key = Key.generateKey(getRandom()); | |
60 |
1
1. createSecret : removed call to com/macasaet/fernet/aws/secretsmanager/rotation/SecretsManager::putSecretValue → KILLED |
getSecretsManager().putSecretValue(secretId, clientRequestToken, key, PENDING); |
61 | getLogger().info("createSecret: Successfully put secret for ARN {} and version {}.", secretId, clientRequestToken); | |
62 | } | |
63 | ||
64 | protected void testSecret(final String secretId, final String clientRequestToken) { | |
65 | final ByteBuffer buffer = getSecretsManager().getSecretVersion(secretId, clientRequestToken); | |
66 | try { | |
67 |
1
1. testSecret : negated conditional → KILLED |
if (buffer.remaining() != fernetKeySize) { |
68 | throw new IllegalStateException("Fernet key must be exactly " + fernetKeySize + " bytes"); | |
69 | } | |
70 | final byte[] signingKey = new byte[16]; | |
71 | buffer.get(signingKey); | |
72 | final byte[] encryptionKey = new byte[16]; | |
73 | buffer.get(encryptionKey); | |
74 |
1
1. testSecret : negated conditional → KILLED |
if (buffer.hasRemaining()) { |
75 | throw new IllegalStateException("Encountered extra bytes."); | |
76 | } | |
77 | new Key(signingKey, encryptionKey); | |
78 |
1
1. testSecret : removed call to com/macasaet/fernet/aws/secretsmanager/rotation/SimpleFernetKeyRotator::wipe → SURVIVED |
wipe(signingKey); |
79 |
1
1. testSecret : removed call to com/macasaet/fernet/aws/secretsmanager/rotation/SimpleFernetKeyRotator::wipe → SURVIVED |
wipe(encryptionKey); |
80 | } finally { | |
81 |
1
1. testSecret : removed call to com/macasaet/fernet/aws/secretsmanager/rotation/SimpleFernetKeyRotator::wipe → KILLED |
wipe(buffer); |
82 | } | |
83 | getLogger().info("testSecret: Successfully validated Fernet Key for ARN {} and version {}.", secretId, clientRequestToken); | |
84 | } | |
85 | ||
86 | } | |
Mutations | ||
60 |
1.1 |
|
67 |
1.1 |
|
74 |
1.1 |
|
78 |
1.1 |
|
79 |
1.1 |
|
81 |
1.1 |