From df8c84cba8512058f5097c6faeedf4b65cab3806 Mon Sep 17 00:00:00 2001 From: Alejandro Abdelnur Date: Mon, 8 Sep 2014 10:12:16 -0700 Subject: [PATCH] HADOOP-11071. KMSClientProvider should drain the local generated EEK cache on key rollover. (tucu) --- .../hadoop-common/CHANGES.txt | 3 +++ .../key/KeyProviderCryptoExtension.java | 11 ++++++++++ .../crypto/key/kms/KMSClientProvider.java | 9 +++++++- .../hadoop/crypto/key/kms/ValueQueue.java | 13 +++++++++++ .../hadoop/crypto/key/TestValueQueue.java | 14 ++++++++++++ ...eyGeneratorKeyProviderCryptoExtension.java | 22 +++++++++++++++++++ .../hadoop/crypto/key/kms/server/TestKMS.java | 17 ++++++++++++++ 7 files changed, 88 insertions(+), 1 deletion(-) diff --git a/hadoop-common-project/hadoop-common/CHANGES.txt b/hadoop-common-project/hadoop-common/CHANGES.txt index fe011fd0395..0417b0a638e 100644 --- a/hadoop-common-project/hadoop-common/CHANGES.txt +++ b/hadoop-common-project/hadoop-common/CHANGES.txt @@ -771,6 +771,9 @@ Release 2.6.0 - UNRELEASED HADOOP-11073. Credential Provider related Unit Tests Failure on Windows. (Xiaoyu Yao via cnauroth) + HADOOP-11071. KMSClientProvider should drain the local generated EEK cache + on key rollover. (tucu) + Release 2.5.1 - UNRELEASED INCOMPATIBLE CHANGES diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/KeyProviderCryptoExtension.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/KeyProviderCryptoExtension.java index e2fb5cb3b8e..fed7e9e4d97 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/KeyProviderCryptoExtension.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/KeyProviderCryptoExtension.java @@ -178,6 +178,13 @@ public class KeyProviderCryptoExtension extends public void warmUpEncryptedKeys(String... keyNames) throws IOException; + /** + * Drains the Queue for the provided key. + * + * @param keyName the key to drain the Queue for + */ + public void drain(String keyName); + /** * Generates a key material and encrypts it using the given key version name * and initialization vector. The generated key material is of the same @@ -313,6 +320,10 @@ public class KeyProviderCryptoExtension extends // NO-OP since the default version does not cache any keys } + @Override + public void drain(String keyName) { + // NO-OP since the default version does not cache any keys + } } /** diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/kms/KMSClientProvider.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/kms/KMSClientProvider.java index acbe096e268..899b6c44dc7 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/kms/KMSClientProvider.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/kms/KMSClientProvider.java @@ -590,7 +590,9 @@ public class KMSClientProvider extends KeyProvider implements CryptoExtension, conn.setRequestProperty(CONTENT_TYPE, APPLICATION_JSON_MIME); Map response = call(conn, jsonMaterial, HttpURLConnection.HTTP_OK, Map.class); - return parseJSONKeyVersion(response); + KeyVersion keyVersion = parseJSONKeyVersion(response); + encKeyVersionQueue.drain(name); + return keyVersion; } @@ -712,6 +714,11 @@ public class KMSClientProvider extends KeyProvider implements CryptoExtension, } } + @Override + public void drain(String keyName) { + encKeyVersionQueue.drain(keyName); + } + @Override public Token[] addDelegationTokens(String renewer, Credentials credentials) throws IOException { diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/kms/ValueQueue.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/kms/ValueQueue.java index a415e2ea93e..ee10483185d 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/kms/ValueQueue.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/kms/ValueQueue.java @@ -227,6 +227,19 @@ public class ValueQueue { return getAtMost(keyName, 1).get(0); } + /** + * Drains the Queue for the provided key. + * + * @param keyName the key to drain the Queue for + */ + public void drain(String keyName ) { + try { + keyQueues.get(keyName).clear(); + } catch (ExecutionException ex) { + //NOP + } + } + /** * This removes the "num" values currently at the head of the Queue for the * provided key. Will immediately fire the Queue filler function if key diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/key/TestValueQueue.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/key/TestValueQueue.java index 7946588a309..8e3a093273f 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/key/TestValueQueue.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/key/TestValueQueue.java @@ -187,4 +187,18 @@ public class TestValueQueue { Assert.assertEquals(10, filler.getTop().num); vq.shutdown(); } + + @Test + public void testDrain() throws Exception { + MockFiller filler = new MockFiller(); + ValueQueue vq = + new ValueQueue(10, 0.1f, 300, 1, + SyncGenerationPolicy.ALL, filler); + Assert.assertEquals("test", vq.getNext("k1")); + Assert.assertEquals(1, filler.getTop().num); + vq.drain("k1"); + Assert.assertNull(filler.getTop()); + vq.shutdown(); + } + } diff --git a/hadoop-common-project/hadoop-kms/src/main/java/org/apache/hadoop/crypto/key/kms/server/EagerKeyGeneratorKeyProviderCryptoExtension.java b/hadoop-common-project/hadoop-kms/src/main/java/org/apache/hadoop/crypto/key/kms/server/EagerKeyGeneratorKeyProviderCryptoExtension.java index a952cfeb9b9..a33f4f1f74e 100644 --- a/hadoop-common-project/hadoop-kms/src/main/java/org/apache/hadoop/crypto/key/kms/server/EagerKeyGeneratorKeyProviderCryptoExtension.java +++ b/hadoop-common-project/hadoop-kms/src/main/java/org/apache/hadoop/crypto/key/kms/server/EagerKeyGeneratorKeyProviderCryptoExtension.java @@ -20,6 +20,7 @@ package org.apache.hadoop.crypto.key.kms.server; import java.io.IOException; import java.security.GeneralSecurityException; +import java.security.NoSuchAlgorithmException; import java.util.LinkedList; import java.util.List; import java.util.Queue; @@ -27,6 +28,7 @@ import java.util.concurrent.ExecutionException; import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.crypto.key.KeyProvider; import org.apache.hadoop.crypto.key.KeyProviderCryptoExtension; import org.apache.hadoop.crypto.key.kms.ValueQueue; import org.apache.hadoop.crypto.key.kms.ValueQueue.SyncGenerationPolicy; @@ -112,6 +114,11 @@ public class EagerKeyGeneratorKeyProviderCryptoExtension } } + @Override + public void drain(String keyName) { + encKeyVersionQueue.drain(keyName); + } + @Override public EncryptedKeyVersion generateEncryptedKey(String encryptionKeyName) throws IOException, GeneralSecurityException { @@ -146,4 +153,19 @@ public class EagerKeyGeneratorKeyProviderCryptoExtension new CryptoExtension(conf, keyProviderCryptoExtension)); } + @Override + public KeyVersion rollNewVersion(String name) + throws NoSuchAlgorithmException, IOException { + KeyVersion keyVersion = super.rollNewVersion(name); + getExtension().drain(name); + return keyVersion; + } + + @Override + public KeyVersion rollNewVersion(String name, byte[] material) + throws IOException { + KeyVersion keyVersion = super.rollNewVersion(name, material); + getExtension().drain(name); + return keyVersion; + } } diff --git a/hadoop-common-project/hadoop-kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/TestKMS.java b/hadoop-common-project/hadoop-kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/TestKMS.java index b921c84dc2b..74eab5cdfe0 100644 --- a/hadoop-common-project/hadoop-kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/TestKMS.java +++ b/hadoop-common-project/hadoop-kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/TestKMS.java @@ -531,6 +531,7 @@ public class TestKMS { Assert.assertEquals("d", meta.getDescription()); Assert.assertEquals(attributes, meta.getAttributes()); + // test delegation token retrieval KeyProviderDelegationTokenExtension kpdte = KeyProviderDelegationTokenExtension. createKeyProviderDelegationTokenExtension(kp); @@ -542,6 +543,22 @@ public class TestKMS { Assert.assertEquals(new Text("kms-dt"), credentials.getToken( SecurityUtil.buildTokenService(kmsAddr)).getKind()); + + + // test rollover draining + KeyProviderCryptoExtension kpce = KeyProviderCryptoExtension. + createKeyProviderCryptoExtension(kp); + options = new KeyProvider.Options(conf); + options.setCipher("AES/CTR/NoPadding"); + options.setBitLength(128); + kpce.createKey("k6", options); + + EncryptedKeyVersion ekv1 = kpce.generateEncryptedKey("k6"); + kpce.rollNewVersion("k6"); + EncryptedKeyVersion ekv2 = kpce.generateEncryptedKey("k6"); + Assert.assertNotEquals(ekv1.getEncryptionKeyVersionName(), + ekv2.getEncryptionKeyVersionName()); + return null; } });