HADOOP-11096. KMS: KeyAuthorizationKeyProvider should verify the keyversion belongs to the keyname on decrypt. (tucu)
This commit is contained in:
parent
c6b9768b36
commit
94a1e68aa5
|
@ -480,6 +480,9 @@ Release 2.6.0 - UNRELEASED
|
||||||
HADOOP-11088. Unittest TestKeyShell, TestCredShell and TestKMS assume UNIX
|
HADOOP-11088. Unittest TestKeyShell, TestCredShell and TestKMS assume UNIX
|
||||||
path separator for JECKS key store path. (Xiaoyu Yao via cnauroth)
|
path separator for JECKS key store path. (Xiaoyu Yao via cnauroth)
|
||||||
|
|
||||||
|
HADOOP-11096. KMS: KeyAuthorizationKeyProvider should verify the keyversion
|
||||||
|
belongs to the keyname on decrypt. (tucu)
|
||||||
|
|
||||||
Release 2.5.1 - 2014-09-05
|
Release 2.5.1 - 2014-09-05
|
||||||
|
|
||||||
INCOMPATIBLE CHANGES
|
INCOMPATIBLE CHANGES
|
||||||
|
|
|
@ -91,6 +91,8 @@ public class KeyProviderCryptoExtension extends
|
||||||
* returned EncryptedKeyVersion will only partially be populated; it is not
|
* returned EncryptedKeyVersion will only partially be populated; it is not
|
||||||
* necessarily suitable for operations besides decryption.
|
* necessarily suitable for operations besides decryption.
|
||||||
*
|
*
|
||||||
|
* @param keyName Key name of the encryption key use to encrypt the
|
||||||
|
* encrypted key.
|
||||||
* @param encryptionKeyVersionName Version name of the encryption key used
|
* @param encryptionKeyVersionName Version name of the encryption key used
|
||||||
* to encrypt the encrypted key.
|
* to encrypt the encrypted key.
|
||||||
* @param encryptedKeyIv Initialization vector of the encrypted
|
* @param encryptedKeyIv Initialization vector of the encrypted
|
||||||
|
@ -100,12 +102,12 @@ public class KeyProviderCryptoExtension extends
|
||||||
* @param encryptedKeyMaterial Key material of the encrypted key.
|
* @param encryptedKeyMaterial Key material of the encrypted key.
|
||||||
* @return EncryptedKeyVersion suitable for decryption.
|
* @return EncryptedKeyVersion suitable for decryption.
|
||||||
*/
|
*/
|
||||||
public static EncryptedKeyVersion createForDecryption(String
|
public static EncryptedKeyVersion createForDecryption(String keyName,
|
||||||
encryptionKeyVersionName, byte[] encryptedKeyIv,
|
String encryptionKeyVersionName, byte[] encryptedKeyIv,
|
||||||
byte[] encryptedKeyMaterial) {
|
byte[] encryptedKeyMaterial) {
|
||||||
KeyVersion encryptedKeyVersion = new KeyVersion(null, EEK,
|
KeyVersion encryptedKeyVersion = new KeyVersion(null, EEK,
|
||||||
encryptedKeyMaterial);
|
encryptedKeyMaterial);
|
||||||
return new EncryptedKeyVersion(null, encryptionKeyVersionName,
|
return new EncryptedKeyVersion(keyName, encryptionKeyVersionName,
|
||||||
encryptedKeyIv, encryptedKeyVersion);
|
encryptedKeyIv, encryptedKeyVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -121,7 +121,7 @@ public class TestKeyProviderCryptoExtension {
|
||||||
|
|
||||||
// Test the createForDecryption factory method
|
// Test the createForDecryption factory method
|
||||||
EncryptedKeyVersion eek2 =
|
EncryptedKeyVersion eek2 =
|
||||||
EncryptedKeyVersion.createForDecryption(
|
EncryptedKeyVersion.createForDecryption(eek.getEncryptionKeyName(),
|
||||||
eek.getEncryptionKeyVersionName(), eek.getEncryptedKeyIv(),
|
eek.getEncryptionKeyVersionName(), eek.getEncryptedKeyIv(),
|
||||||
eek.getEncryptedKeyVersion().getMaterial());
|
eek.getEncryptedKeyVersion().getMaterial());
|
||||||
|
|
||||||
|
|
|
@ -192,9 +192,21 @@ public class KeyAuthorizationKeyProvider extends KeyProviderCryptoExtension {
|
||||||
return provider.generateEncryptedKey(encryptionKeyName);
|
return provider.generateEncryptedKey(encryptionKeyName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void verifyKeyVersionBelongsToKey(EncryptedKeyVersion ekv)
|
||||||
|
throws IOException {
|
||||||
|
String kn = ekv.getEncryptionKeyName();
|
||||||
|
String kvn = ekv.getEncryptionKeyVersionName();
|
||||||
|
KeyVersion kv = provider.getKeyVersion(kvn);
|
||||||
|
if (!kv.getName().equals(kn)) {
|
||||||
|
throw new IllegalArgumentException(String.format(
|
||||||
|
"KeyVersion '%s' does not belong to the key '%s'", kvn, kn));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeyVersion decryptEncryptedKey(EncryptedKeyVersion encryptedKeyVersion)
|
public KeyVersion decryptEncryptedKey(EncryptedKeyVersion encryptedKeyVersion)
|
||||||
throws IOException, GeneralSecurityException {
|
throws IOException, GeneralSecurityException {
|
||||||
|
verifyKeyVersionBelongsToKey(encryptedKeyVersion);
|
||||||
doAccessCheck(
|
doAccessCheck(
|
||||||
encryptedKeyVersion.getEncryptionKeyName(), KeyOpType.DECRYPT_EEK);
|
encryptedKeyVersion.getEncryptionKeyName(), KeyOpType.DECRYPT_EEK);
|
||||||
return provider.decryptEncryptedKey(encryptedKeyVersion);
|
return provider.decryptEncryptedKey(encryptedKeyVersion);
|
||||||
|
|
|
@ -215,4 +215,57 @@ public class TestKeyAuthorizationKeyProvider {
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testDecryptWithKeyVersionNameKeyMismatch() throws Exception {
|
||||||
|
final Configuration conf = new Configuration();
|
||||||
|
KeyProvider kp =
|
||||||
|
new UserProvider.Factory().createProvider(new URI("user:///"), conf);
|
||||||
|
KeyACLs mock = mock(KeyACLs.class);
|
||||||
|
when(mock.isACLPresent("testKey", KeyOpType.MANAGEMENT)).thenReturn(true);
|
||||||
|
when(mock.isACLPresent("testKey", KeyOpType.GENERATE_EEK)).thenReturn(true);
|
||||||
|
when(mock.isACLPresent("testKey", KeyOpType.DECRYPT_EEK)).thenReturn(true);
|
||||||
|
when(mock.isACLPresent("testKey", KeyOpType.ALL)).thenReturn(true);
|
||||||
|
UserGroupInformation u1 = UserGroupInformation.createRemoteUser("u1");
|
||||||
|
UserGroupInformation u2 = UserGroupInformation.createRemoteUser("u2");
|
||||||
|
UserGroupInformation u3 = UserGroupInformation.createRemoteUser("u3");
|
||||||
|
UserGroupInformation sudo = UserGroupInformation.createRemoteUser("sudo");
|
||||||
|
when(mock.hasAccessToKey("testKey", u1,
|
||||||
|
KeyOpType.MANAGEMENT)).thenReturn(true);
|
||||||
|
when(mock.hasAccessToKey("testKey", u2,
|
||||||
|
KeyOpType.GENERATE_EEK)).thenReturn(true);
|
||||||
|
when(mock.hasAccessToKey("testKey", u3,
|
||||||
|
KeyOpType.DECRYPT_EEK)).thenReturn(true);
|
||||||
|
when(mock.hasAccessToKey("testKey", sudo,
|
||||||
|
KeyOpType.ALL)).thenReturn(true);
|
||||||
|
final KeyProviderCryptoExtension kpExt =
|
||||||
|
new KeyAuthorizationKeyProvider(
|
||||||
|
KeyProviderCryptoExtension.createKeyProviderCryptoExtension(kp),
|
||||||
|
mock);
|
||||||
|
|
||||||
|
sudo.doAs(
|
||||||
|
new PrivilegedExceptionAction<Void>() {
|
||||||
|
@Override
|
||||||
|
public Void run() throws Exception {
|
||||||
|
Options opt = newOptions(conf);
|
||||||
|
Map<String, String> m = new HashMap<String, String>();
|
||||||
|
m.put("key.acl.name", "testKey");
|
||||||
|
opt.setAttributes(m);
|
||||||
|
KeyVersion kv =
|
||||||
|
kpExt.createKey("foo", SecureRandom.getSeed(16), opt);
|
||||||
|
kpExt.rollNewVersion(kv.getName());
|
||||||
|
kpExt.rollNewVersion(kv.getName(), SecureRandom.getSeed(16));
|
||||||
|
EncryptedKeyVersion ekv = kpExt.generateEncryptedKey(kv.getName());
|
||||||
|
ekv = EncryptedKeyVersion.createForDecryption(
|
||||||
|
ekv.getEncryptionKeyName() + "x",
|
||||||
|
ekv.getEncryptionKeyVersionName(),
|
||||||
|
ekv.getEncryptedKeyIv(),
|
||||||
|
ekv.getEncryptedKeyVersion().getMaterial());
|
||||||
|
kpExt.decryptEncryptedKey(ekv);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1321,7 +1321,8 @@ public class DFSClient implements java.io.Closeable, RemotePeerFactory,
|
||||||
" an encrypted file");
|
" an encrypted file");
|
||||||
}
|
}
|
||||||
EncryptedKeyVersion ekv = EncryptedKeyVersion.createForDecryption(
|
EncryptedKeyVersion ekv = EncryptedKeyVersion.createForDecryption(
|
||||||
feInfo.getEzKeyVersionName(), feInfo.getIV(),
|
//TODO: here we have to put the keyName to be provided by HDFS-6987
|
||||||
|
null, feInfo.getEzKeyVersionName(), feInfo.getIV(),
|
||||||
feInfo.getEncryptedDataEncryptionKey());
|
feInfo.getEncryptedDataEncryptionKey());
|
||||||
try {
|
try {
|
||||||
return provider.decryptEncryptedKey(ekv);
|
return provider.decryptEncryptedKey(ekv);
|
||||||
|
|
Loading…
Reference in New Issue