HADOOP-14705. Add batched interface reencryptEncryptedKeys to KMS.
This commit is contained in:
parent
27ab5f7385
commit
4ec5acc704
@ -22,6 +22,8 @@
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
@ -247,6 +249,25 @@ public KeyVersion decryptEncryptedKey(
|
||||
*/
|
||||
EncryptedKeyVersion reencryptEncryptedKey(EncryptedKeyVersion ekv)
|
||||
throws IOException, GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* Batched version of {@link #reencryptEncryptedKey(EncryptedKeyVersion)}.
|
||||
* <p>
|
||||
* For each encrypted key version, re-encrypts an encrypted key version,
|
||||
* using its initialization vector and key material, but with the latest
|
||||
* key version name of its key name. If the latest key version name in the
|
||||
* provider is the same as the one encrypted the passed-in encrypted key
|
||||
* version, the same encrypted key version is returned.
|
||||
* <p>
|
||||
* NOTE: The generated key is not stored by the <code>KeyProvider</code>
|
||||
*
|
||||
* @param ekvs List containing the EncryptedKeyVersion's
|
||||
* @throws IOException If any EncryptedKeyVersion could not be re-encrypted
|
||||
* @throws GeneralSecurityException If any EncryptedKeyVersion could not be
|
||||
* re-encrypted because of a cryptographic issue.
|
||||
*/
|
||||
void reencryptEncryptedKeys(List<EncryptedKeyVersion> ekvs)
|
||||
throws IOException, GeneralSecurityException;
|
||||
}
|
||||
|
||||
private static class DefaultCryptoExtension implements CryptoExtension {
|
||||
@ -315,7 +336,7 @@ public EncryptedKeyVersion reencryptEncryptedKey(EncryptedKeyVersion ekv)
|
||||
.checkNotNull(ekNow, "KeyVersion name '%s' does not exist", ekName);
|
||||
Preconditions.checkArgument(ekv.getEncryptedKeyVersion().getVersionName()
|
||||
.equals(KeyProviderCryptoExtension.EEK),
|
||||
"encryptedKey version name must be '%s', is '%s'",
|
||||
"encryptedKey version name must be '%s', but found '%s'",
|
||||
KeyProviderCryptoExtension.EEK,
|
||||
ekv.getEncryptedKeyVersion().getVersionName());
|
||||
|
||||
@ -336,30 +357,67 @@ public EncryptedKeyVersion reencryptEncryptedKey(EncryptedKeyVersion ekv)
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyVersion decryptEncryptedKey(
|
||||
EncryptedKeyVersion encryptedKeyVersion) throws IOException,
|
||||
GeneralSecurityException {
|
||||
// Fetch the encryption key material
|
||||
public void reencryptEncryptedKeys(List<EncryptedKeyVersion> ekvs)
|
||||
throws IOException, GeneralSecurityException {
|
||||
Preconditions.checkNotNull(ekvs, "Input list is null");
|
||||
KeyVersion ekNow = null;
|
||||
Decryptor decryptor = null;
|
||||
Encryptor encryptor = null;
|
||||
try (CryptoCodec cc = CryptoCodec.getInstance(keyProvider.getConf())) {
|
||||
decryptor = cc.createDecryptor();
|
||||
encryptor = cc.createEncryptor();
|
||||
ListIterator<EncryptedKeyVersion> iter = ekvs.listIterator();
|
||||
while (iter.hasNext()) {
|
||||
final EncryptedKeyVersion ekv = iter.next();
|
||||
Preconditions.checkNotNull(ekv, "EncryptedKeyVersion is null");
|
||||
final String ekName = ekv.getEncryptionKeyName();
|
||||
Preconditions.checkNotNull(ekName, "Key name is null");
|
||||
Preconditions.checkNotNull(ekv.getEncryptedKeyVersion(),
|
||||
"EncryptedKeyVersion is null");
|
||||
Preconditions.checkArgument(
|
||||
ekv.getEncryptedKeyVersion().getVersionName()
|
||||
.equals(KeyProviderCryptoExtension.EEK),
|
||||
"encryptedKey version name must be '%s', but found '%s'",
|
||||
KeyProviderCryptoExtension.EEK,
|
||||
ekv.getEncryptedKeyVersion().getVersionName());
|
||||
|
||||
if (ekNow == null) {
|
||||
ekNow = keyProvider.getCurrentKey(ekName);
|
||||
Preconditions
|
||||
.checkNotNull(ekNow, "Key name '%s' does not exist", ekName);
|
||||
} else {
|
||||
Preconditions.checkArgument(ekNow.getName().equals(ekName),
|
||||
"All keys must have the same key name. Expected '%s' "
|
||||
+ "but found '%s'", ekNow.getName(), ekName);
|
||||
}
|
||||
|
||||
final String encryptionKeyVersionName =
|
||||
encryptedKeyVersion.getEncryptionKeyVersionName();
|
||||
ekv.getEncryptionKeyVersionName();
|
||||
final KeyVersion encryptionKey =
|
||||
keyProvider.getKeyVersion(encryptionKeyVersionName);
|
||||
Preconditions.checkNotNull(encryptionKey,
|
||||
"KeyVersion name '%s' does not exist", encryptionKeyVersionName);
|
||||
Preconditions.checkArgument(
|
||||
encryptedKeyVersion.getEncryptedKeyVersion().getVersionName()
|
||||
.equals(KeyProviderCryptoExtension.EEK),
|
||||
"encryptedKey version name must be '%s', is '%s'",
|
||||
KeyProviderCryptoExtension.EEK,
|
||||
encryptedKeyVersion.getEncryptedKeyVersion().getVersionName()
|
||||
);
|
||||
if (encryptionKey.equals(ekNow)) {
|
||||
// no-op if same key version
|
||||
continue;
|
||||
}
|
||||
|
||||
final KeyVersion ek =
|
||||
decryptEncryptedKey(decryptor, encryptionKey, ekv);
|
||||
iter.set(generateEncryptedKey(encryptor, ekNow, ek.getMaterial(),
|
||||
ekv.getEncryptedKeyIv()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private KeyVersion decryptEncryptedKey(final Decryptor decryptor,
|
||||
final KeyVersion encryptionKey,
|
||||
final EncryptedKeyVersion encryptedKeyVersion)
|
||||
throws IOException, GeneralSecurityException {
|
||||
// Encryption key IV is determined from encrypted key's IV
|
||||
final byte[] encryptionIV =
|
||||
EncryptedKeyVersion.deriveIV(encryptedKeyVersion.getEncryptedKeyIv());
|
||||
|
||||
CryptoCodec cc = CryptoCodec.getInstance(keyProvider.getConf());
|
||||
Decryptor decryptor = cc.createDecryptor();
|
||||
decryptor.init(encryptionKey.getMaterial(), encryptionIV);
|
||||
final KeyVersion encryptedKV =
|
||||
encryptedKeyVersion.getEncryptedKeyVersion();
|
||||
@ -372,10 +430,35 @@ public KeyVersion decryptEncryptedKey(
|
||||
bbOut.flip();
|
||||
byte[] decryptedKey = new byte[keyLen];
|
||||
bbOut.get(decryptedKey);
|
||||
cc.close();
|
||||
return new KeyVersion(encryptionKey.getName(), EK, decryptedKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyVersion decryptEncryptedKey(
|
||||
EncryptedKeyVersion encryptedKeyVersion)
|
||||
throws IOException, GeneralSecurityException {
|
||||
// Fetch the encryption key material
|
||||
final String encryptionKeyVersionName =
|
||||
encryptedKeyVersion.getEncryptionKeyVersionName();
|
||||
final KeyVersion encryptionKey =
|
||||
keyProvider.getKeyVersion(encryptionKeyVersionName);
|
||||
Preconditions
|
||||
.checkNotNull(encryptionKey, "KeyVersion name '%s' does not exist",
|
||||
encryptionKeyVersionName);
|
||||
Preconditions.checkArgument(
|
||||
encryptedKeyVersion.getEncryptedKeyVersion().getVersionName()
|
||||
.equals(KeyProviderCryptoExtension.EEK),
|
||||
"encryptedKey version name must be '%s', but found '%s'",
|
||||
KeyProviderCryptoExtension.EEK,
|
||||
encryptedKeyVersion.getEncryptedKeyVersion().getVersionName());
|
||||
|
||||
try (CryptoCodec cc = CryptoCodec.getInstance(keyProvider.getConf())) {
|
||||
final Decryptor decryptor = cc.createDecryptor();
|
||||
return decryptEncryptedKey(decryptor, encryptionKey,
|
||||
encryptedKeyVersion);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warmUpEncryptedKeys(String... keyNames)
|
||||
throws IOException {
|
||||
@ -470,6 +553,28 @@ public EncryptedKeyVersion reencryptEncryptedKey(EncryptedKeyVersion ekv)
|
||||
return getExtension().reencryptEncryptedKey(ekv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Batched version of {@link #reencryptEncryptedKey(EncryptedKeyVersion)}.
|
||||
* <p>
|
||||
* For each encrypted key version, re-encrypts an encrypted key version,
|
||||
* using its initialization vector and key material, but with the latest
|
||||
* key version name of its key name. If the latest key version name in the
|
||||
* provider is the same as the one encrypted the passed-in encrypted key
|
||||
* version, the same encrypted key version is returned.
|
||||
* <p>
|
||||
* NOTE: The generated key is not stored by the <code>KeyProvider</code>
|
||||
*
|
||||
* @param ekvs List containing the EncryptedKeyVersion's
|
||||
* @return The re-encrypted EncryptedKeyVersion's, in the same order.
|
||||
* @throws IOException If any EncryptedKeyVersion could not be re-encrypted
|
||||
* @throws GeneralSecurityException If any EncryptedKeyVersion could not be
|
||||
* re-encrypted because of a cryptographic issue.
|
||||
*/
|
||||
public void reencryptEncryptedKeys(List<EncryptedKeyVersion> ekvs)
|
||||
throws IOException, GeneralSecurityException {
|
||||
getExtension().reencryptEncryptedKeys(ekvs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a <code>KeyProviderCryptoExtension</code> using a given
|
||||
* {@link KeyProvider}.
|
||||
|
@ -70,7 +70,6 @@
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
@ -84,6 +83,13 @@
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import static org.apache.hadoop.util.KMSUtil.checkNotEmpty;
|
||||
import static org.apache.hadoop.util.KMSUtil.checkNotNull;
|
||||
import static org.apache.hadoop.util.KMSUtil.parseJSONEncKeyVersion;
|
||||
import static org.apache.hadoop.util.KMSUtil.parseJSONEncKeyVersions;
|
||||
import static org.apache.hadoop.util.KMSUtil.parseJSONKeyVersion;
|
||||
import static org.apache.hadoop.util.KMSUtil.parseJSONMetadata;
|
||||
|
||||
/**
|
||||
* KMS client <code>KeyProvider</code> implementation.
|
||||
*/
|
||||
@ -219,77 +225,11 @@ public KMSEncryptedKeyVersion(String keyName, String keyVersionName,
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static List<EncryptedKeyVersion>
|
||||
parseJSONEncKeyVersions(String keyName, List valueList) {
|
||||
List<EncryptedKeyVersion> ekvs = new LinkedList<EncryptedKeyVersion>();
|
||||
if (!valueList.isEmpty()) {
|
||||
for (Object values : valueList) {
|
||||
Map valueMap = (Map) values;
|
||||
ekvs.add(parseJSONEncKeyVersion(keyName, valueMap));
|
||||
}
|
||||
}
|
||||
return ekvs;
|
||||
}
|
||||
|
||||
private static EncryptedKeyVersion parseJSONEncKeyVersion(String keyName,
|
||||
Map valueMap) {
|
||||
String versionName = checkNotNull(
|
||||
(String) valueMap.get(KMSRESTConstants.VERSION_NAME_FIELD),
|
||||
KMSRESTConstants.VERSION_NAME_FIELD);
|
||||
|
||||
byte[] iv = Base64.decodeBase64(checkNotNull(
|
||||
(String) valueMap.get(KMSRESTConstants.IV_FIELD),
|
||||
KMSRESTConstants.IV_FIELD));
|
||||
|
||||
Map encValueMap = checkNotNull((Map)
|
||||
valueMap.get(KMSRESTConstants.ENCRYPTED_KEY_VERSION_FIELD),
|
||||
KMSRESTConstants.ENCRYPTED_KEY_VERSION_FIELD);
|
||||
|
||||
String encVersionName = checkNotNull((String)
|
||||
encValueMap.get(KMSRESTConstants.VERSION_NAME_FIELD),
|
||||
KMSRESTConstants.VERSION_NAME_FIELD);
|
||||
|
||||
byte[] encKeyMaterial = Base64.decodeBase64(checkNotNull((String)
|
||||
encValueMap.get(KMSRESTConstants.MATERIAL_FIELD),
|
||||
KMSRESTConstants.MATERIAL_FIELD));
|
||||
|
||||
return new KMSEncryptedKeyVersion(keyName, versionName, iv,
|
||||
encVersionName, encKeyMaterial);
|
||||
}
|
||||
|
||||
private static KeyVersion parseJSONKeyVersion(Map valueMap) {
|
||||
KeyVersion keyVersion = null;
|
||||
if (!valueMap.isEmpty()) {
|
||||
byte[] material = (valueMap.containsKey(KMSRESTConstants.MATERIAL_FIELD))
|
||||
? Base64.decodeBase64((String) valueMap.get(KMSRESTConstants.MATERIAL_FIELD))
|
||||
: null;
|
||||
String versionName = (String)valueMap.get(KMSRESTConstants.VERSION_NAME_FIELD);
|
||||
String keyName = (String)valueMap.get(KMSRESTConstants.NAME_FIELD);
|
||||
keyVersion = new KMSKeyVersion(keyName, versionName, material);
|
||||
}
|
||||
return keyVersion;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Metadata parseJSONMetadata(Map valueMap) {
|
||||
Metadata metadata = null;
|
||||
if (!valueMap.isEmpty()) {
|
||||
metadata = new KMSMetadata(
|
||||
(String) valueMap.get(KMSRESTConstants.CIPHER_FIELD),
|
||||
(Integer) valueMap.get(KMSRESTConstants.LENGTH_FIELD),
|
||||
(String) valueMap.get(KMSRESTConstants.DESCRIPTION_FIELD),
|
||||
(Map<String, String>) valueMap.get(KMSRESTConstants.ATTRIBUTES_FIELD),
|
||||
new Date((Long) valueMap.get(KMSRESTConstants.CREATED_FIELD)),
|
||||
(Integer) valueMap.get(KMSRESTConstants.VERSIONS_FIELD));
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private static void writeJson(Map map, OutputStream os) throws IOException {
|
||||
private static void writeJson(Object obj, OutputStream os)
|
||||
throws IOException {
|
||||
Writer writer = new OutputStreamWriter(os, StandardCharsets.UTF_8);
|
||||
ObjectMapper jsonMapper = new ObjectMapper();
|
||||
jsonMapper.writerWithDefaultPrettyPrinter().writeValue(writer, map);
|
||||
jsonMapper.writerWithDefaultPrettyPrinter().writeValue(writer, obj);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -360,25 +300,6 @@ private KeyProvider createProvider(Configuration conf,
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T o, String name)
|
||||
throws IllegalArgumentException {
|
||||
if (o == null) {
|
||||
throw new IllegalArgumentException("Parameter '" + name +
|
||||
"' cannot be null");
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
public static String checkNotEmpty(String s, String name)
|
||||
throws IllegalArgumentException {
|
||||
checkNotNull(s, name);
|
||||
if (s.isEmpty()) {
|
||||
throw new IllegalArgumentException("Parameter '" + name +
|
||||
"' cannot be empty");
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
private String kmsUrl;
|
||||
private SSLFactory sslFactory;
|
||||
private ConnectionConfigurator configurator;
|
||||
@ -560,12 +481,12 @@ public HttpURLConnection run() throws Exception {
|
||||
return conn;
|
||||
}
|
||||
|
||||
private <T> T call(HttpURLConnection conn, Map jsonOutput,
|
||||
private <T> T call(HttpURLConnection conn, Object jsonOutput,
|
||||
int expectedResponse, Class<T> klass) throws IOException {
|
||||
return call(conn, jsonOutput, expectedResponse, klass, authRetry);
|
||||
}
|
||||
|
||||
private <T> T call(HttpURLConnection conn, Map jsonOutput,
|
||||
private <T> T call(HttpURLConnection conn, Object jsonOutput,
|
||||
int expectedResponse, Class<T> klass, int authRetryCount)
|
||||
throws IOException {
|
||||
T ret = null;
|
||||
@ -884,6 +805,48 @@ public EncryptedKeyVersion reencryptEncryptedKey(EncryptedKeyVersion ekv)
|
||||
return parseJSONEncKeyVersion(ekv.getEncryptionKeyName(), response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reencryptEncryptedKeys(List<EncryptedKeyVersion> ekvs)
|
||||
throws IOException, GeneralSecurityException {
|
||||
checkNotNull(ekvs, "ekvs");
|
||||
if (ekvs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final List<Map> jsonPayload = new ArrayList<>();
|
||||
String keyName = null;
|
||||
for (EncryptedKeyVersion ekv : ekvs) {
|
||||
checkNotNull(ekv.getEncryptionKeyName(), "keyName");
|
||||
checkNotNull(ekv.getEncryptionKeyVersionName(), "versionName");
|
||||
checkNotNull(ekv.getEncryptedKeyIv(), "iv");
|
||||
checkNotNull(ekv.getEncryptedKeyVersion(), "encryptedKey");
|
||||
Preconditions.checkArgument(ekv.getEncryptedKeyVersion().getVersionName()
|
||||
.equals(KeyProviderCryptoExtension.EEK),
|
||||
"encryptedKey version name must be '%s', is '%s'",
|
||||
KeyProviderCryptoExtension.EEK,
|
||||
ekv.getEncryptedKeyVersion().getVersionName());
|
||||
if (keyName == null) {
|
||||
keyName = ekv.getEncryptionKeyName();
|
||||
} else {
|
||||
Preconditions.checkArgument(keyName.equals(ekv.getEncryptionKeyName()),
|
||||
"All EncryptedKey must have the same key name.");
|
||||
}
|
||||
jsonPayload.add(KMSUtil.toJSON(ekv));
|
||||
}
|
||||
final URL url = createURL(KMSRESTConstants.KEY_RESOURCE, keyName,
|
||||
KMSRESTConstants.REENCRYPT_BATCH_SUB_RESOURCE, null);
|
||||
final HttpURLConnection conn = createConnection(url, HTTP_POST);
|
||||
conn.setRequestProperty(CONTENT_TYPE, APPLICATION_JSON_MIME);
|
||||
final List<Map> response =
|
||||
call(conn, jsonPayload, HttpURLConnection.HTTP_OK, List.class);
|
||||
Preconditions.checkArgument(response.size() == ekvs.size(),
|
||||
"Response size is different than input size.");
|
||||
for (int i = 0; i < response.size(); ++i) {
|
||||
final Map item = response.get(i);
|
||||
final EncryptedKeyVersion ekv = parseJSONEncKeyVersion(keyName, item);
|
||||
ekvs.set(i, ekv);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyVersion> getKeyVersions(String name) throws IOException {
|
||||
checkNotEmpty(name, "name");
|
||||
|
@ -37,6 +37,7 @@ public class KMSRESTConstants {
|
||||
public static final String EEK_SUB_RESOURCE = "_eek";
|
||||
public static final String CURRENT_VERSION_SUB_RESOURCE = "_currentversion";
|
||||
public static final String INVALIDATECACHE_RESOURCE = "_invalidatecache";
|
||||
public static final String REENCRYPT_BATCH_SUB_RESOURCE = "_reencryptbatch";
|
||||
|
||||
public static final String KEY = "key";
|
||||
public static final String EEK_OP = "eek_op";
|
||||
|
@ -312,6 +312,26 @@ public EncryptedKeyVersion call(KMSClientProvider provider)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reencryptEncryptedKeys(final List<EncryptedKeyVersion> ekvs)
|
||||
throws IOException, GeneralSecurityException {
|
||||
try {
|
||||
doOp(new ProviderCallable<Void>() {
|
||||
@Override
|
||||
public Void call(KMSClientProvider provider)
|
||||
throws IOException, GeneralSecurityException {
|
||||
provider.reencryptEncryptedKeys(ekvs);
|
||||
return null;
|
||||
}
|
||||
}, nextIdx());
|
||||
} catch (WrapperException we) {
|
||||
if (we.getCause() instanceof GeneralSecurityException) {
|
||||
throw (GeneralSecurityException) we.getCause();
|
||||
}
|
||||
throw new IOException(we.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyVersion getKeyVersion(final String versionName) throws IOException {
|
||||
return doOp(new ProviderCallable<KeyVersion>() {
|
||||
|
@ -17,15 +17,24 @@
|
||||
*/
|
||||
package org.apache.hadoop.util;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
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.EncryptedKeyVersion;
|
||||
import org.apache.hadoop.crypto.key.KeyProviderFactory;
|
||||
import org.apache.hadoop.crypto.key.kms.KMSClientProvider;
|
||||
import org.apache.hadoop.crypto.key.kms.KMSRESTConstants;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Utils for KMS.
|
||||
@ -71,4 +80,129 @@ public static KeyProvider createKeyProviderFromUri(final Configuration conf,
|
||||
}
|
||||
return keyProvider;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map toJSON(KeyProvider.KeyVersion keyVersion) {
|
||||
Map json = new HashMap();
|
||||
if (keyVersion != null) {
|
||||
json.put(KMSRESTConstants.NAME_FIELD,
|
||||
keyVersion.getName());
|
||||
json.put(KMSRESTConstants.VERSION_NAME_FIELD,
|
||||
keyVersion.getVersionName());
|
||||
json.put(KMSRESTConstants.MATERIAL_FIELD,
|
||||
Base64.encodeBase64URLSafeString(
|
||||
keyVersion.getMaterial()));
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map toJSON(EncryptedKeyVersion encryptedKeyVersion) {
|
||||
Map json = new HashMap();
|
||||
if (encryptedKeyVersion != null) {
|
||||
json.put(KMSRESTConstants.VERSION_NAME_FIELD,
|
||||
encryptedKeyVersion.getEncryptionKeyVersionName());
|
||||
json.put(KMSRESTConstants.IV_FIELD, Base64
|
||||
.encodeBase64URLSafeString(encryptedKeyVersion.getEncryptedKeyIv()));
|
||||
json.put(KMSRESTConstants.ENCRYPTED_KEY_VERSION_FIELD,
|
||||
toJSON(encryptedKeyVersion.getEncryptedKeyVersion()));
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T o, String name)
|
||||
throws IllegalArgumentException {
|
||||
if (o == null) {
|
||||
throw new IllegalArgumentException("Parameter '" + name +
|
||||
"' cannot be null");
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
public static String checkNotEmpty(String s, String name)
|
||||
throws IllegalArgumentException {
|
||||
checkNotNull(s, name);
|
||||
if (s.isEmpty()) {
|
||||
throw new IllegalArgumentException("Parameter '" + name +
|
||||
"' cannot be empty");
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static List<EncryptedKeyVersion>
|
||||
parseJSONEncKeyVersions(String keyName, List valueList) {
|
||||
checkNotNull(valueList, "valueList");
|
||||
List<EncryptedKeyVersion> ekvs = new ArrayList<>(valueList.size());
|
||||
if (!valueList.isEmpty()) {
|
||||
for (Object values : valueList) {
|
||||
Map valueMap = (Map) values;
|
||||
ekvs.add(parseJSONEncKeyVersion(keyName, valueMap));
|
||||
}
|
||||
}
|
||||
return ekvs;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static EncryptedKeyVersion parseJSONEncKeyVersion(String keyName,
|
||||
Map valueMap) {
|
||||
checkNotNull(valueMap, "valueMap");
|
||||
String versionName = checkNotNull(
|
||||
(String) valueMap.get(KMSRESTConstants.VERSION_NAME_FIELD),
|
||||
KMSRESTConstants.VERSION_NAME_FIELD);
|
||||
|
||||
byte[] iv = Base64.decodeBase64(checkNotNull(
|
||||
(String) valueMap.get(KMSRESTConstants.IV_FIELD),
|
||||
KMSRESTConstants.IV_FIELD));
|
||||
|
||||
Map encValueMap = checkNotNull((Map)
|
||||
valueMap.get(KMSRESTConstants.ENCRYPTED_KEY_VERSION_FIELD),
|
||||
KMSRESTConstants.ENCRYPTED_KEY_VERSION_FIELD);
|
||||
|
||||
String encVersionName = checkNotNull((String)
|
||||
encValueMap.get(KMSRESTConstants.VERSION_NAME_FIELD),
|
||||
KMSRESTConstants.VERSION_NAME_FIELD);
|
||||
|
||||
byte[] encKeyMaterial = Base64.decodeBase64(checkNotNull((String)
|
||||
encValueMap.get(KMSRESTConstants.MATERIAL_FIELD),
|
||||
KMSRESTConstants.MATERIAL_FIELD));
|
||||
|
||||
return new KMSClientProvider.KMSEncryptedKeyVersion(keyName, versionName,
|
||||
iv, encVersionName, encKeyMaterial);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static KeyProvider.KeyVersion parseJSONKeyVersion(Map valueMap) {
|
||||
checkNotNull(valueMap, "valueMap");
|
||||
KeyProvider.KeyVersion keyVersion = null;
|
||||
if (!valueMap.isEmpty()) {
|
||||
byte[] material =
|
||||
(valueMap.containsKey(KMSRESTConstants.MATERIAL_FIELD)) ?
|
||||
Base64.decodeBase64(
|
||||
(String) valueMap.get(KMSRESTConstants.MATERIAL_FIELD)) :
|
||||
null;
|
||||
String versionName =
|
||||
(String) valueMap.get(KMSRESTConstants.VERSION_NAME_FIELD);
|
||||
String keyName = (String) valueMap.get(KMSRESTConstants.NAME_FIELD);
|
||||
keyVersion =
|
||||
new KMSClientProvider.KMSKeyVersion(keyName, versionName, material);
|
||||
}
|
||||
return keyVersion;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static KeyProvider.Metadata parseJSONMetadata(Map valueMap) {
|
||||
checkNotNull(valueMap, "valueMap");
|
||||
KeyProvider.Metadata metadata = null;
|
||||
if (!valueMap.isEmpty()) {
|
||||
metadata = new KMSClientProvider.KMSMetadata(
|
||||
(String) valueMap.get(KMSRESTConstants.CIPHER_FIELD),
|
||||
(Integer) valueMap.get(KMSRESTConstants.LENGTH_FIELD),
|
||||
(String) valueMap.get(KMSRESTConstants.DESCRIPTION_FIELD),
|
||||
(Map<String, String>) valueMap.get(KMSRESTConstants.ATTRIBUTES_FIELD),
|
||||
new Date((Long) valueMap.get(KMSRESTConstants.CREATED_FIELD)),
|
||||
(Integer) valueMap.get(KMSRESTConstants.VERSIONS_FIELD));
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@ -40,7 +41,9 @@
|
||||
import static org.apache.hadoop.crypto.key.KeyProvider.KeyVersion;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class TestKeyProviderCryptoExtension {
|
||||
@ -90,13 +93,7 @@ public void testGenerateEncryptedKey() throws Exception {
|
||||
KeyVersion k1 = kpExt.decryptEncryptedKey(ek1);
|
||||
assertEquals(KeyProviderCryptoExtension.EK, k1.getVersionName());
|
||||
assertEquals(encryptionKey.getMaterial().length, k1.getMaterial().length);
|
||||
if (Arrays.equals(k1.getMaterial(), encryptionKey.getMaterial())) {
|
||||
fail("Encrypted key material should not equal encryption key material");
|
||||
}
|
||||
if (Arrays.equals(ek1.getEncryptedKeyVersion().getMaterial(),
|
||||
encryptionKey.getMaterial())) {
|
||||
fail("Encrypted key material should not equal decrypted key material");
|
||||
}
|
||||
|
||||
// Decrypt it again and it should be the same
|
||||
KeyVersion k1a = kpExt.decryptEncryptedKey(ek1);
|
||||
assertArrayEquals(k1.getMaterial(), k1a.getMaterial());
|
||||
@ -153,9 +150,6 @@ public void testReencryptEncryptedKey() throws Exception {
|
||||
final KeyVersion k1 = kpExt.decryptEncryptedKey(ek1);
|
||||
assertEquals(KeyProviderCryptoExtension.EK, k1.getVersionName());
|
||||
assertEquals(encryptionKey.getMaterial().length, k1.getMaterial().length);
|
||||
if (Arrays.equals(k1.getMaterial(), encryptionKey.getMaterial())) {
|
||||
fail("Encrypted key material should not equal encryption key material");
|
||||
}
|
||||
|
||||
// Roll the EK
|
||||
kpExt.rollNewVersion(ek1.getEncryptionKeyName());
|
||||
@ -173,10 +167,7 @@ public void testReencryptEncryptedKey() throws Exception {
|
||||
assertEquals("Length of encryption key material and EEK material should "
|
||||
+ "be the same", encryptionKey.getMaterial().length,
|
||||
ek2.getEncryptedKeyVersion().getMaterial().length);
|
||||
if (Arrays.equals(ek2.getEncryptedKeyVersion().getMaterial(),
|
||||
encryptionKey.getMaterial())) {
|
||||
fail("Encrypted key material should not equal decrypted key material");
|
||||
}
|
||||
|
||||
if (Arrays.equals(ek2.getEncryptedKeyVersion().getMaterial(),
|
||||
ek1.getEncryptedKeyVersion().getMaterial())) {
|
||||
fail("Re-encrypted EEK should have different material");
|
||||
@ -186,9 +177,6 @@ public void testReencryptEncryptedKey() throws Exception {
|
||||
final KeyVersion k2 = kpExt.decryptEncryptedKey(ek2);
|
||||
assertEquals(KeyProviderCryptoExtension.EK, k2.getVersionName());
|
||||
assertEquals(encryptionKey.getMaterial().length, k2.getMaterial().length);
|
||||
if (Arrays.equals(k2.getMaterial(), encryptionKey.getMaterial())) {
|
||||
fail("Encrypted key material should not equal encryption key material");
|
||||
}
|
||||
|
||||
// Re-encrypting the same EEK with the same EK should be deterministic
|
||||
final KeyProviderCryptoExtension.EncryptedKeyVersion ek2a =
|
||||
@ -203,10 +191,7 @@ public void testReencryptEncryptedKey() throws Exception {
|
||||
assertEquals("Length of encryption key material and EEK material should "
|
||||
+ "be the same", encryptionKey.getMaterial().length,
|
||||
ek2a.getEncryptedKeyVersion().getMaterial().length);
|
||||
if (Arrays.equals(ek2a.getEncryptedKeyVersion().getMaterial(),
|
||||
encryptionKey.getMaterial())) {
|
||||
fail("Encrypted key material should not equal decrypted key material");
|
||||
}
|
||||
|
||||
if (Arrays.equals(ek2a.getEncryptedKeyVersion().getMaterial(),
|
||||
ek1.getEncryptedKeyVersion().getMaterial())) {
|
||||
fail("Re-encrypted EEK should have different material");
|
||||
@ -227,10 +212,6 @@ public void testReencryptEncryptedKey() throws Exception {
|
||||
assertEquals("Length of encryption key material and EEK material should "
|
||||
+ "be the same", encryptionKey.getMaterial().length,
|
||||
ek3.getEncryptedKeyVersion().getMaterial().length);
|
||||
if (Arrays.equals(ek3.getEncryptedKeyVersion().getMaterial(),
|
||||
encryptionKey.getMaterial())) {
|
||||
fail("Encrypted key material should not equal decrypted key material");
|
||||
}
|
||||
|
||||
if (Arrays.equals(ek3.getEncryptedKeyVersion().getMaterial(),
|
||||
ek1.getEncryptedKeyVersion().getMaterial())) {
|
||||
@ -240,6 +221,78 @@ public void testReencryptEncryptedKey() throws Exception {
|
||||
ek3.getEncryptedKeyVersion().getMaterial());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReencryptEncryptedKeys() throws Exception {
|
||||
List<EncryptedKeyVersion> ekvs = new ArrayList<>(4);
|
||||
// Generate 2 new EEKs @v0 and add to the list
|
||||
ekvs.add(kpExt.generateEncryptedKey(encryptionKey.getName()));
|
||||
ekvs.add(kpExt.generateEncryptedKey(encryptionKey.getName()));
|
||||
|
||||
// Roll the EK
|
||||
kpExt.rollNewVersion(ekvs.get(0).getEncryptionKeyName());
|
||||
// Generate 1 new EEK @v1 add to the list.
|
||||
ekvs.add(kpExt.generateEncryptedKey(encryptionKey.getName()));
|
||||
|
||||
// Roll the EK again
|
||||
kpExt.rollNewVersion(ekvs.get(0).getEncryptionKeyName());
|
||||
// Generate 1 new EEK @v2 add to the list.
|
||||
ekvs.add(kpExt.generateEncryptedKey(encryptionKey.getName()));
|
||||
|
||||
// leave a deep copy of the original, for verification purpose.
|
||||
List<EncryptedKeyVersion> ekvsOrig = new ArrayList<>(ekvs.size());
|
||||
for (EncryptedKeyVersion ekv : ekvs) {
|
||||
ekvsOrig.add(new EncryptedKeyVersion(ekv.getEncryptionKeyName(),
|
||||
ekv.getEncryptionKeyVersionName(), ekv.getEncryptedKeyIv(),
|
||||
ekv.getEncryptedKeyVersion()));
|
||||
}
|
||||
|
||||
// Reencrypt ekvs
|
||||
kpExt.reencryptEncryptedKeys(ekvs);
|
||||
|
||||
// Verify each ekv
|
||||
for (int i = 0; i < ekvs.size(); ++i) {
|
||||
final EncryptedKeyVersion ekv = ekvs.get(i);
|
||||
final EncryptedKeyVersion orig = ekvsOrig.get(i);
|
||||
assertEquals("Version name should be EEK",
|
||||
KeyProviderCryptoExtension.EEK,
|
||||
ekv.getEncryptedKeyVersion().getVersionName());
|
||||
assertEquals("Encryption key name should be " + ENCRYPTION_KEY_NAME,
|
||||
ENCRYPTION_KEY_NAME, ekv.getEncryptionKeyName());
|
||||
assertNotNull("Expected encrypted key material",
|
||||
ekv.getEncryptedKeyVersion().getMaterial());
|
||||
assertEquals("Length of encryption key material and EEK material should "
|
||||
+ "be the same", encryptionKey.getMaterial().length,
|
||||
ekv.getEncryptedKeyVersion().getMaterial().length);
|
||||
assertFalse(
|
||||
"Encrypted key material should not equal encryption key material",
|
||||
Arrays.equals(ekv.getEncryptedKeyVersion().getMaterial(),
|
||||
encryptionKey.getMaterial()));
|
||||
|
||||
if (i < 3) {
|
||||
assertFalse("Re-encrypted EEK should have different material",
|
||||
Arrays.equals(ekv.getEncryptedKeyVersion().getMaterial(),
|
||||
orig.getEncryptedKeyVersion().getMaterial()));
|
||||
} else {
|
||||
assertTrue("Re-encrypted EEK should have same material",
|
||||
Arrays.equals(ekv.getEncryptedKeyVersion().getMaterial(),
|
||||
orig.getEncryptedKeyVersion().getMaterial()));
|
||||
}
|
||||
|
||||
// Decrypt the new EEK into an EK and check it
|
||||
final KeyVersion kv = kpExt.decryptEncryptedKey(ekv);
|
||||
assertEquals(KeyProviderCryptoExtension.EK, kv.getVersionName());
|
||||
|
||||
// Decrypt it again and it should be the same
|
||||
KeyVersion kv1 = kpExt.decryptEncryptedKey(ekv);
|
||||
assertArrayEquals(kv.getMaterial(), kv1.getMaterial());
|
||||
|
||||
// Verify decrypting the new EEK and orig EEK gives the same material.
|
||||
final KeyVersion origKv = kpExt.decryptEncryptedKey(orig);
|
||||
assertTrue("Returned EEK and original EEK should both decrypt to the "
|
||||
+ "same kv.", Arrays.equals(origKv.getMaterial(), kv.getMaterial()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonDefaultCryptoExtensionSelectionWithCachingKeyProvider()
|
||||
throws Exception {
|
||||
@ -341,6 +394,11 @@ public EncryptedKeyVersion reencryptEncryptedKey(EncryptedKeyVersion ekv)
|
||||
return ekv;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reencryptEncryptedKeys(List<EncryptedKeyVersion> ekvs)
|
||||
throws IOException, GeneralSecurityException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyVersion decryptEncryptedKey(
|
||||
EncryptedKeyVersion encryptedKeyVersion)
|
||||
@ -453,5 +511,10 @@ public EncryptedKeyVersion reencryptEncryptedKey(EncryptedKeyVersion ekv)
|
||||
throws IOException, GeneralSecurityException {
|
||||
return ekv;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reencryptEncryptedKeys(List<EncryptedKeyVersion> ekvs)
|
||||
throws IOException, GeneralSecurityException {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -141,6 +141,12 @@ public EncryptedKeyVersion reencryptEncryptedKey(EncryptedKeyVersion ekv)
|
||||
throws IOException, GeneralSecurityException {
|
||||
return keyProviderCryptoExtension.reencryptEncryptedKey(ekv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reencryptEncryptedKeys(List<EncryptedKeyVersion> ekvs)
|
||||
throws IOException, GeneralSecurityException {
|
||||
keyProviderCryptoExtension.reencryptEncryptedKeys(ekvs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -17,6 +17,9 @@
|
||||
*/
|
||||
package org.apache.hadoop.crypto.key.kms.server;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Stopwatch;
|
||||
import org.apache.hadoop.util.KMSUtil;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.hadoop.classification.InterfaceAudience;
|
||||
import org.apache.hadoop.crypto.key.KeyProvider;
|
||||
@ -53,6 +56,9 @@
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.apache.hadoop.util.KMSUtil.checkNotEmpty;
|
||||
import static org.apache.hadoop.util.KMSUtil.checkNotNull;
|
||||
|
||||
/**
|
||||
* Class providing the REST bindings, via Jersey, for the KMS.
|
||||
*/
|
||||
@ -64,7 +70,7 @@ public enum KMSOp {
|
||||
CREATE_KEY, DELETE_KEY, ROLL_NEW_VERSION, INVALIDATE_CACHE,
|
||||
GET_KEYS, GET_KEYS_METADATA,
|
||||
GET_KEY_VERSIONS, GET_METADATA, GET_KEY_VERSION, GET_CURRENT_KEY,
|
||||
GENERATE_EEK, DECRYPT_EEK, REENCRYPT_EEK
|
||||
GENERATE_EEK, DECRYPT_EEK, REENCRYPT_EEK, REENCRYPT_EEK_BATCH
|
||||
}
|
||||
|
||||
private KeyProviderCryptoExtension provider;
|
||||
@ -72,6 +78,8 @@ public enum KMSOp {
|
||||
|
||||
static final Logger LOG = LoggerFactory.getLogger(KMS.class);
|
||||
|
||||
private static final int MAX_NUM_PER_BATCH = 10000;
|
||||
|
||||
public KMS() throws Exception {
|
||||
provider = KMSWebApp.getKeyProvider();
|
||||
kmsAudit= KMSWebApp.getKMSAudit();
|
||||
@ -109,7 +117,7 @@ public Response createKey(Map jsonKey) throws Exception {
|
||||
KMSWebApp.getAdminCallsMeter().mark();
|
||||
UserGroupInformation user = HttpUserGroupInformation.get();
|
||||
final String name = (String) jsonKey.get(KMSRESTConstants.NAME_FIELD);
|
||||
KMSClientProvider.checkNotEmpty(name, KMSRESTConstants.NAME_FIELD);
|
||||
checkNotEmpty(name, KMSRESTConstants.NAME_FIELD);
|
||||
assertAccess(KMSACLs.Type.CREATE, user, KMSOp.CREATE_KEY, name);
|
||||
String cipher = (String) jsonKey.get(KMSRESTConstants.CIPHER_FIELD);
|
||||
final String material;
|
||||
@ -158,7 +166,7 @@ public KeyVersion run() throws Exception {
|
||||
if (!KMSWebApp.getACLs().hasAccess(KMSACLs.Type.GET, user)) {
|
||||
keyVersion = removeKeyMaterial(keyVersion);
|
||||
}
|
||||
Map json = KMSServerJSONUtils.toJSON(keyVersion);
|
||||
Map json = KMSUtil.toJSON(keyVersion);
|
||||
String requestURL = KMSMDCFilter.getURL();
|
||||
int idx = requestURL.lastIndexOf(KMSRESTConstants.KEYS_RESOURCE);
|
||||
requestURL = requestURL.substring(0, idx);
|
||||
@ -181,7 +189,7 @@ public Response deleteKey(@PathParam("name") final String name)
|
||||
KMSWebApp.getAdminCallsMeter().mark();
|
||||
UserGroupInformation user = HttpUserGroupInformation.get();
|
||||
assertAccess(KMSACLs.Type.DELETE, user, KMSOp.DELETE_KEY, name);
|
||||
KMSClientProvider.checkNotEmpty(name, "name");
|
||||
checkNotEmpty(name, "name");
|
||||
LOG.debug("Deleting key with name {}.", name);
|
||||
user.doAs(new PrivilegedExceptionAction<Void>() {
|
||||
@Override
|
||||
@ -212,7 +220,7 @@ public Response rolloverKey(@PathParam("name") final String name,
|
||||
KMSWebApp.getAdminCallsMeter().mark();
|
||||
UserGroupInformation user = HttpUserGroupInformation.get();
|
||||
assertAccess(KMSACLs.Type.ROLLOVER, user, KMSOp.ROLL_NEW_VERSION, name);
|
||||
KMSClientProvider.checkNotEmpty(name, "name");
|
||||
checkNotEmpty(name, "name");
|
||||
LOG.debug("Rolling key with name {}.", name);
|
||||
final String material = (String)
|
||||
jsonMaterial.get(KMSRESTConstants.MATERIAL_FIELD);
|
||||
@ -242,7 +250,7 @@ public KeyVersion run() throws Exception {
|
||||
if (!KMSWebApp.getACLs().hasAccess(KMSACLs.Type.GET, user)) {
|
||||
keyVersion = removeKeyMaterial(keyVersion);
|
||||
}
|
||||
Map json = KMSServerJSONUtils.toJSON(keyVersion);
|
||||
Map json = KMSUtil.toJSON(keyVersion);
|
||||
LOG.trace("Exiting rolloverKey Method.");
|
||||
return Response.ok().type(MediaType.APPLICATION_JSON).entity(json)
|
||||
.build();
|
||||
@ -260,7 +268,7 @@ public Response invalidateCache(@PathParam("name") final String name)
|
||||
try {
|
||||
LOG.trace("Entering invalidateCache Method.");
|
||||
KMSWebApp.getAdminCallsMeter().mark();
|
||||
KMSClientProvider.checkNotEmpty(name, "name");
|
||||
checkNotEmpty(name, "name");
|
||||
UserGroupInformation user = HttpUserGroupInformation.get();
|
||||
assertAccess(KMSACLs.Type.ROLLOVER, user, KMSOp.INVALIDATE_CACHE, name);
|
||||
LOG.debug("Invalidating cache with key name {}.", name);
|
||||
@ -369,7 +377,7 @@ public Response getMetadata(@PathParam("name") final String name)
|
||||
try {
|
||||
LOG.trace("Entering getMetadata method.");
|
||||
UserGroupInformation user = HttpUserGroupInformation.get();
|
||||
KMSClientProvider.checkNotEmpty(name, "name");
|
||||
checkNotEmpty(name, "name");
|
||||
KMSWebApp.getAdminCallsMeter().mark();
|
||||
assertAccess(KMSACLs.Type.GET_METADATA, user, KMSOp.GET_METADATA, name);
|
||||
LOG.debug("Getting metadata for key with name {}.", name);
|
||||
@ -403,7 +411,7 @@ public Response getCurrentVersion(@PathParam("name") final String name)
|
||||
try {
|
||||
LOG.trace("Entering getCurrentVersion method.");
|
||||
UserGroupInformation user = HttpUserGroupInformation.get();
|
||||
KMSClientProvider.checkNotEmpty(name, "name");
|
||||
checkNotEmpty(name, "name");
|
||||
KMSWebApp.getKeyCallsMeter().mark();
|
||||
assertAccess(KMSACLs.Type.GET, user, KMSOp.GET_CURRENT_KEY, name);
|
||||
LOG.debug("Getting key version for key with name {}.", name);
|
||||
@ -417,7 +425,7 @@ public KeyVersion run() throws Exception {
|
||||
}
|
||||
);
|
||||
|
||||
Object json = KMSServerJSONUtils.toJSON(keyVersion);
|
||||
Object json = KMSUtil.toJSON(keyVersion);
|
||||
kmsAudit.ok(user, KMSOp.GET_CURRENT_KEY, name, "");
|
||||
LOG.trace("Exiting getCurrentVersion method.");
|
||||
return Response.ok().type(MediaType.APPLICATION_JSON).entity(json)
|
||||
@ -436,7 +444,7 @@ public Response getKeyVersion(
|
||||
try {
|
||||
LOG.trace("Entering getKeyVersion method.");
|
||||
UserGroupInformation user = HttpUserGroupInformation.get();
|
||||
KMSClientProvider.checkNotEmpty(versionName, "versionName");
|
||||
checkNotEmpty(versionName, "versionName");
|
||||
KMSWebApp.getKeyCallsMeter().mark();
|
||||
assertAccess(KMSACLs.Type.GET, user, KMSOp.GET_KEY_VERSION);
|
||||
LOG.debug("Getting key with version name {}.", versionName);
|
||||
@ -453,7 +461,7 @@ public KeyVersion run() throws Exception {
|
||||
if (keyVersion != null) {
|
||||
kmsAudit.ok(user, KMSOp.GET_KEY_VERSION, keyVersion.getName(), "");
|
||||
}
|
||||
Object json = KMSServerJSONUtils.toJSON(keyVersion);
|
||||
Object json = KMSUtil.toJSON(keyVersion);
|
||||
LOG.trace("Exiting getKeyVersion method.");
|
||||
return Response.ok().type(MediaType.APPLICATION_JSON).entity(json)
|
||||
.build();
|
||||
@ -477,8 +485,8 @@ public Response generateEncryptedKeys(
|
||||
try {
|
||||
LOG.trace("Entering generateEncryptedKeys method.");
|
||||
UserGroupInformation user = HttpUserGroupInformation.get();
|
||||
KMSClientProvider.checkNotEmpty(name, "name");
|
||||
KMSClientProvider.checkNotNull(edekOp, "eekOp");
|
||||
checkNotEmpty(name, "name");
|
||||
checkNotNull(edekOp, "eekOp");
|
||||
LOG.debug("Generating encrypted key with name {}," +
|
||||
" the edek Operation is {}.", name, edekOp);
|
||||
|
||||
@ -512,7 +520,7 @@ public Void run() throws Exception {
|
||||
kmsAudit.ok(user, KMSOp.GENERATE_EEK, name, "");
|
||||
retJSON = new ArrayList();
|
||||
for (EncryptedKeyVersion edek : retEdeks) {
|
||||
((ArrayList) retJSON).add(KMSServerJSONUtils.toJSON(edek));
|
||||
((ArrayList) retJSON).add(KMSUtil.toJSON(edek));
|
||||
}
|
||||
} else {
|
||||
StringBuilder error;
|
||||
@ -535,6 +543,64 @@ public Void run() throws Exception {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@POST
|
||||
@Path(KMSRESTConstants.KEY_RESOURCE + "/{name:.*}/" +
|
||||
KMSRESTConstants.REENCRYPT_BATCH_SUB_RESOURCE)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8)
|
||||
public Response reencryptEncryptedKeys(
|
||||
@PathParam("name") final String name,
|
||||
final List<Map> jsonPayload)
|
||||
throws Exception {
|
||||
LOG.trace("Entering reencryptEncryptedKeys method.");
|
||||
try {
|
||||
final Stopwatch sw = new Stopwatch().start();
|
||||
checkNotEmpty(name, "name");
|
||||
checkNotNull(jsonPayload, "jsonPayload");
|
||||
final UserGroupInformation user = HttpUserGroupInformation.get();
|
||||
KMSWebApp.getReencryptEEKBatchCallsMeter().mark();
|
||||
if (jsonPayload.size() > MAX_NUM_PER_BATCH) {
|
||||
LOG.warn("Payload size {} too big for reencryptEncryptedKeys from"
|
||||
+ " user {}.", jsonPayload.size(), user);
|
||||
}
|
||||
assertAccess(KMSACLs.Type.GENERATE_EEK, user, KMSOp.REENCRYPT_EEK_BATCH,
|
||||
name);
|
||||
LOG.debug("Batch reencrypting {} Encrypted Keys for key name {}",
|
||||
jsonPayload.size(), name);
|
||||
final List<EncryptedKeyVersion> ekvs =
|
||||
KMSUtil.parseJSONEncKeyVersions(name, jsonPayload);
|
||||
Preconditions.checkArgument(ekvs.size() == jsonPayload.size(),
|
||||
"EncryptedKey size mismatch after parsing from json");
|
||||
for (EncryptedKeyVersion ekv : ekvs) {
|
||||
Preconditions.checkArgument(name.equals(ekv.getEncryptionKeyName()),
|
||||
"All EncryptedKeys must be under the given key name " + name);
|
||||
}
|
||||
|
||||
user.doAs(new PrivilegedExceptionAction<Void>() {
|
||||
@Override
|
||||
public Void run() throws Exception {
|
||||
provider.reencryptEncryptedKeys(ekvs);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
List retJSON = new ArrayList<>(ekvs.size());
|
||||
for (EncryptedKeyVersion ekv: ekvs) {
|
||||
retJSON.add(KMSUtil.toJSON(ekv));
|
||||
}
|
||||
kmsAudit.ok(user, KMSOp.REENCRYPT_EEK_BATCH, name,
|
||||
"reencrypted " + ekvs.size() + " keys");
|
||||
LOG.info("reencryptEncryptedKeys {} keys for key {} took {}",
|
||||
jsonPayload.size(), name, sw.stop());
|
||||
LOG.trace("Exiting reencryptEncryptedKeys method.");
|
||||
return Response.ok().type(MediaType.APPLICATION_JSON).entity(retJSON)
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
LOG.debug("Exception in reencryptEncryptedKeys.", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@POST
|
||||
@Path(KMSRESTConstants.KEY_VERSION_RESOURCE + "/{versionName:.*}/" +
|
||||
@ -548,8 +614,8 @@ public Response handleEncryptedKeyOp(
|
||||
try {
|
||||
LOG.trace("Entering decryptEncryptedKey method.");
|
||||
UserGroupInformation user = HttpUserGroupInformation.get();
|
||||
KMSClientProvider.checkNotEmpty(versionName, "versionName");
|
||||
KMSClientProvider.checkNotNull(eekOp, "eekOp");
|
||||
checkNotEmpty(versionName, "versionName");
|
||||
checkNotNull(eekOp, "eekOp");
|
||||
LOG.debug("Decrypting key for {}, the edek Operation is {}.",
|
||||
versionName, eekOp);
|
||||
|
||||
@ -558,13 +624,14 @@ public Response handleEncryptedKeyOp(
|
||||
String ivStr = (String) jsonPayload.get(KMSRESTConstants.IV_FIELD);
|
||||
String encMaterialStr =
|
||||
(String) jsonPayload.get(KMSRESTConstants.MATERIAL_FIELD);
|
||||
KMSClientProvider.checkNotNull(ivStr, KMSRESTConstants.IV_FIELD);
|
||||
checkNotNull(ivStr, KMSRESTConstants.IV_FIELD);
|
||||
final byte[] iv = Base64.decodeBase64(ivStr);
|
||||
KMSClientProvider.checkNotNull(encMaterialStr,
|
||||
checkNotNull(encMaterialStr,
|
||||
KMSRESTConstants.MATERIAL_FIELD);
|
||||
final byte[] encMaterial = Base64.decodeBase64(encMaterialStr);
|
||||
Object retJSON;
|
||||
if (eekOp.equals(KMSRESTConstants.EEK_DECRYPT)) {
|
||||
KMSWebApp.getDecryptEEKCallsMeter().mark();
|
||||
assertAccess(KMSACLs.Type.DECRYPT_EEK, user, KMSOp.DECRYPT_EEK,
|
||||
keyName);
|
||||
|
||||
@ -582,9 +649,10 @@ public KeyVersion run() throws Exception {
|
||||
}
|
||||
);
|
||||
|
||||
retJSON = KMSServerJSONUtils.toJSON(retKeyVersion);
|
||||
retJSON = KMSUtil.toJSON(retKeyVersion);
|
||||
kmsAudit.ok(user, KMSOp.DECRYPT_EEK, keyName, "");
|
||||
} else if (eekOp.equals(KMSRESTConstants.EEK_REENCRYPT)) {
|
||||
KMSWebApp.getReencryptEEKCallsMeter().mark();
|
||||
assertAccess(KMSACLs.Type.GENERATE_EEK, user, KMSOp.REENCRYPT_EEK,
|
||||
keyName);
|
||||
|
||||
@ -599,7 +667,7 @@ public EncryptedKeyVersion run() throws Exception {
|
||||
}
|
||||
});
|
||||
|
||||
retJSON = KMSServerJSONUtils.toJSON(retEncryptedKeyVersion);
|
||||
retJSON = KMSUtil.toJSON(retEncryptedKeyVersion);
|
||||
kmsAudit.ok(user, KMSOp.REENCRYPT_EEK, keyName, "");
|
||||
} else {
|
||||
StringBuilder error;
|
||||
@ -612,7 +680,6 @@ public EncryptedKeyVersion run() throws Exception {
|
||||
LOG.error(error.toString());
|
||||
throw new IllegalArgumentException(error.toString());
|
||||
}
|
||||
KMSWebApp.getDecryptEEKCallsMeter().mark();
|
||||
LOG.trace("Exiting handleEncryptedKeyOp method.");
|
||||
return Response.ok().type(MediaType.APPLICATION_JSON).entity(retJSON)
|
||||
.build();
|
||||
@ -631,7 +698,7 @@ public Response getKeyVersions(@PathParam("name") final String name)
|
||||
try {
|
||||
LOG.trace("Entering getKeyVersions method.");
|
||||
UserGroupInformation user = HttpUserGroupInformation.get();
|
||||
KMSClientProvider.checkNotEmpty(name, "name");
|
||||
checkNotEmpty(name, "name");
|
||||
KMSWebApp.getKeyCallsMeter().mark();
|
||||
assertAccess(KMSACLs.Type.GET, user, KMSOp.GET_KEY_VERSIONS, name);
|
||||
LOG.debug("Getting key versions for key {}", name);
|
||||
|
@ -31,21 +31,23 @@
|
||||
import java.io.InputStream;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Provider
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@InterfaceAudience.Private
|
||||
public class KMSJSONReader implements MessageBodyReader<Map> {
|
||||
public class KMSJSONReader implements MessageBodyReader<Object> {
|
||||
|
||||
@Override
|
||||
public boolean isReadable(Class<?> type, Type genericType,
|
||||
Annotation[] annotations, MediaType mediaType) {
|
||||
return type.isAssignableFrom(Map.class);
|
||||
return type.isAssignableFrom(Map.class) || type
|
||||
.isAssignableFrom(List.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map readFrom(Class<Map> type, Type genericType,
|
||||
public Object readFrom(Class<Object> type, Type genericType,
|
||||
Annotation[] annotations, MediaType mediaType,
|
||||
MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
|
||||
throws IOException, WebApplicationException {
|
||||
|
@ -17,11 +17,10 @@
|
||||
*/
|
||||
package org.apache.hadoop.crypto.key.kms.server;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.hadoop.classification.InterfaceAudience;
|
||||
import org.apache.hadoop.crypto.key.KeyProvider;
|
||||
import org.apache.hadoop.crypto.key.KeyProviderCryptoExtension.EncryptedKeyVersion;
|
||||
import org.apache.hadoop.crypto.key.kms.KMSRESTConstants;
|
||||
import org.apache.hadoop.util.KMSUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
@ -33,47 +32,18 @@
|
||||
*/
|
||||
@InterfaceAudience.Private
|
||||
public class KMSServerJSONUtils {
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map toJSON(KeyProvider.KeyVersion keyVersion) {
|
||||
Map json = new LinkedHashMap();
|
||||
if (keyVersion != null) {
|
||||
json.put(KMSRESTConstants.NAME_FIELD,
|
||||
keyVersion.getName());
|
||||
json.put(KMSRESTConstants.VERSION_NAME_FIELD,
|
||||
keyVersion.getVersionName());
|
||||
json.put(KMSRESTConstants.MATERIAL_FIELD,
|
||||
Base64.encodeBase64URLSafeString(
|
||||
keyVersion.getMaterial()));
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static List toJSON(List<KeyProvider.KeyVersion> keyVersions) {
|
||||
List json = new ArrayList();
|
||||
if (keyVersions != null) {
|
||||
for (KeyProvider.KeyVersion version : keyVersions) {
|
||||
json.add(toJSON(version));
|
||||
json.add(KMSUtil.toJSON(version));
|
||||
}
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map toJSON(EncryptedKeyVersion encryptedKeyVersion) {
|
||||
Map json = new LinkedHashMap();
|
||||
if (encryptedKeyVersion != null) {
|
||||
json.put(KMSRESTConstants.VERSION_NAME_FIELD,
|
||||
encryptedKeyVersion.getEncryptionKeyVersionName());
|
||||
json.put(KMSRESTConstants.IV_FIELD,
|
||||
Base64.encodeBase64URLSafeString(
|
||||
encryptedKeyVersion.getEncryptedKeyIv()));
|
||||
json.put(KMSRESTConstants.ENCRYPTED_KEY_VERSION_FIELD,
|
||||
toJSON(encryptedKeyVersion.getEncryptedKeyVersion()));
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map toJSON(String keyName, KeyProvider.Metadata meta) {
|
||||
Map json = new LinkedHashMap();
|
||||
|
@ -60,6 +60,10 @@ public class KMSWebApp implements ServletContextListener {
|
||||
"generate_eek.calls.meter";
|
||||
private static final String DECRYPT_EEK_METER = METRICS_PREFIX +
|
||||
"decrypt_eek.calls.meter";
|
||||
private static final String REENCRYPT_EEK_METER = METRICS_PREFIX +
|
||||
"reencrypt_eek.calls.meter";
|
||||
private static final String REENCRYPT_EEK_BATCH_METER = METRICS_PREFIX +
|
||||
"reencrypt_eek_batch.calls.meter";
|
||||
|
||||
private static Logger LOG;
|
||||
private static MetricRegistry metricRegistry;
|
||||
@ -72,6 +76,8 @@ public class KMSWebApp implements ServletContextListener {
|
||||
private static Meter unauthorizedCallsMeter;
|
||||
private static Meter unauthenticatedCallsMeter;
|
||||
private static Meter decryptEEKCallsMeter;
|
||||
private static Meter reencryptEEKCallsMeter;
|
||||
private static Meter reencryptEEKBatchCallsMeter;
|
||||
private static Meter generateEEKCallsMeter;
|
||||
private static Meter invalidCallsMeter;
|
||||
private static KMSAudit kmsAudit;
|
||||
@ -131,6 +137,10 @@ public void contextInitialized(ServletContextEvent sce) {
|
||||
new Meter());
|
||||
decryptEEKCallsMeter = metricRegistry.register(DECRYPT_EEK_METER,
|
||||
new Meter());
|
||||
reencryptEEKCallsMeter = metricRegistry.register(REENCRYPT_EEK_METER,
|
||||
new Meter());
|
||||
reencryptEEKBatchCallsMeter = metricRegistry.register(
|
||||
REENCRYPT_EEK_BATCH_METER, new Meter());
|
||||
adminCallsMeter = metricRegistry.register(ADMIN_CALLS_METER, new Meter());
|
||||
keyCallsMeter = metricRegistry.register(KEY_CALLS_METER, new Meter());
|
||||
invalidCallsMeter = metricRegistry.register(INVALID_CALLS_METER,
|
||||
@ -239,6 +249,14 @@ public static Meter getDecryptEEKCallsMeter() {
|
||||
return decryptEEKCallsMeter;
|
||||
}
|
||||
|
||||
public static Meter getReencryptEEKCallsMeter() {
|
||||
return reencryptEEKCallsMeter;
|
||||
}
|
||||
|
||||
public static Meter getReencryptEEKBatchCallsMeter() {
|
||||
return reencryptEEKBatchCallsMeter;
|
||||
}
|
||||
|
||||
public static Meter getUnauthorizedCallsMeter() {
|
||||
return unauthorizedCallsMeter;
|
||||
}
|
||||
|
@ -288,6 +288,25 @@ public EncryptedKeyVersion reencryptEncryptedKey(EncryptedKeyVersion ekv)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reencryptEncryptedKeys(List<EncryptedKeyVersion> ekvs)
|
||||
throws IOException, GeneralSecurityException {
|
||||
if (ekvs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
readLock.lock();
|
||||
try {
|
||||
for (EncryptedKeyVersion ekv : ekvs) {
|
||||
verifyKeyVersionBelongsToKey(ekv);
|
||||
}
|
||||
final String keyName = ekvs.get(0).getEncryptionKeyName();
|
||||
doAccessCheck(keyName, KeyOpType.GENERATE_EEK);
|
||||
provider.reencryptEncryptedKeys(ekvs);
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyVersion getKeyVersion(String versionName) throws IOException {
|
||||
readLock.lock();
|
||||
|
@ -506,7 +506,7 @@ $H5 Key ACLs
|
||||
KMS supports access control for all non-read operations at the Key level. All Key Access operations are classified as :
|
||||
|
||||
* MANAGEMENT - createKey, deleteKey, rolloverNewVersion
|
||||
* GENERATE_EEK - generateEncryptedKey, reencryptEncryptedKey, warmUpEncryptedKeys
|
||||
* GENERATE_EEK - generateEncryptedKey, reencryptEncryptedKey, reencryptEncryptedKeys, warmUpEncryptedKeys
|
||||
* DECRYPT_EEK - decryptEncryptedKey
|
||||
* READ - getKeyVersion, getKeyVersions, getMetadata, getKeysMetadata, getCurrentKey
|
||||
* ALL - all of the above
|
||||
@ -983,6 +983,64 @@ This is usually useful after a [Rollover](#Rollover_Key) of an encryption key. R
|
||||
}
|
||||
}
|
||||
|
||||
$H4 Batch Re-encrypt Encrypted Keys With The Latest KeyVersion
|
||||
|
||||
Batched version of the above re-encrypt Encrypted Key. This command takes a list of previously generated encrypted key, and re-encrypts them using the latest KeyVersion encryption key in the KeyProvider, and return the re-encrypted encrypted keys in the same sequence. For each encrypted key, if the latest KeyVersion is the same as the one used to generate the encrypted key, no action is taken and the same encrypted key is returned.
|
||||
|
||||
This is usually useful after a [Rollover](#Rollover_Key) of an encryption key. Re-encrypting the encrypted key will allow it to be encrypted using the latest version of the encryption key, but still with the same key material and initialization vector.
|
||||
|
||||
All Encrypted keys for a batch request must be under the same encryption key name, but could be potentially under different versions of the encryption key.
|
||||
|
||||
*REQUEST:*
|
||||
|
||||
POST http://HOST:PORT/kms/v1/key/<key-name>/_reencryptbatch
|
||||
Content-Type: application/json
|
||||
|
||||
[
|
||||
{
|
||||
"versionName" : "<encryptionVersionName>",
|
||||
"iv" : "<iv>", //base64
|
||||
"encryptedKeyVersion" : {
|
||||
"versionName" : "EEK",
|
||||
"material" : "<material>", //base64
|
||||
}
|
||||
},
|
||||
{
|
||||
"versionName" : "<encryptionVersionName>",
|
||||
"iv" : "<iv>", //base64
|
||||
"encryptedKeyVersion" : {
|
||||
"versionName" : "EEK",
|
||||
"material" : "<material>", //base64
|
||||
}
|
||||
},
|
||||
...
|
||||
]
|
||||
|
||||
*RESPONSE:*
|
||||
|
||||
200 OK
|
||||
Content-Type: application/json
|
||||
|
||||
[
|
||||
{
|
||||
"versionName" : "<encryptionVersionName>",
|
||||
"iv" : "<iv>", //base64
|
||||
"encryptedKeyVersion" : {
|
||||
"versionName" : "EEK",
|
||||
"material" : "<material>", //base64
|
||||
}
|
||||
},
|
||||
{
|
||||
"versionName" : "<encryptionVersionName>",
|
||||
"iv" : "<iv>", //base64
|
||||
"encryptedKeyVersion" : {
|
||||
"versionName" : "EEK",
|
||||
"material" : "<material>", //base64
|
||||
}
|
||||
},
|
||||
...
|
||||
]
|
||||
|
||||
$H4 Get Key Version
|
||||
|
||||
*REQUEST:*
|
||||
|
@ -97,6 +97,7 @@
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class TestKMS {
|
||||
@ -722,6 +723,22 @@ public Void call() throws Exception {
|
||||
assertArrayEquals(k1.getMaterial(), k1r.getMaterial());
|
||||
assertEquals(kv.getMaterial().length, k1r.getMaterial().length);
|
||||
|
||||
// test re-encrypt batch
|
||||
EncryptedKeyVersion ek3 = kpExt.generateEncryptedKey(kv.getName());
|
||||
KeyVersion latest = kpExt.rollNewVersion(kv.getName());
|
||||
List<EncryptedKeyVersion> ekvs = new ArrayList<>(3);
|
||||
ekvs.add(ek1);
|
||||
ekvs.add(ek2);
|
||||
ekvs.add(ek3);
|
||||
ekvs.add(ek1);
|
||||
ekvs.add(ek2);
|
||||
ekvs.add(ek3);
|
||||
kpExt.reencryptEncryptedKeys(ekvs);
|
||||
for (EncryptedKeyVersion ekv: ekvs) {
|
||||
assertEquals(latest.getVersionName(),
|
||||
ekv.getEncryptionKeyVersionName());
|
||||
}
|
||||
|
||||
// deleteKey()
|
||||
kp.deleteKey("k1");
|
||||
|
||||
@ -1134,6 +1151,10 @@ public Void run() throws Exception {
|
||||
KeyProviderCryptoExtension.createKeyProviderCryptoExtension(kp);
|
||||
EncryptedKeyVersion ekv = kpce.generateEncryptedKey("k1");
|
||||
kpce.reencryptEncryptedKey(ekv);
|
||||
List<EncryptedKeyVersion> ekvs = new ArrayList<>(2);
|
||||
ekvs.add(ekv);
|
||||
ekvs.add(ekv);
|
||||
kpce.reencryptEncryptedKeys(ekvs);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
@ -1563,6 +1584,10 @@ public Void run() throws Exception {
|
||||
KeyProviderCryptoExtension kpCE = KeyProviderCryptoExtension.
|
||||
createKeyProviderCryptoExtension(kp);
|
||||
kpCE.reencryptEncryptedKey(encKv);
|
||||
List<EncryptedKeyVersion> ekvs = new ArrayList<>(2);
|
||||
ekvs.add(encKv);
|
||||
ekvs.add(encKv);
|
||||
kpCE.reencryptEncryptedKeys(ekvs);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
@ -1669,8 +1694,27 @@ public Void run() throws Exception {
|
||||
KeyProviderCryptoExtension kpCE = KeyProviderCryptoExtension.
|
||||
createKeyProviderCryptoExtension(kp);
|
||||
kpCE.reencryptEncryptedKey(encKv);
|
||||
fail("Should not have been able to reencryptEncryptedKey");
|
||||
} catch (AuthorizationException ex) {
|
||||
LOG.info("Caught expected exception.", ex);
|
||||
LOG.info("reencryptEncryptedKey caught expected exception.", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
doAs("GENERATE_EEK", new PrivilegedExceptionAction<Void>() {
|
||||
@Override
|
||||
public Void run() throws Exception {
|
||||
KeyProvider kp = createProvider(uri, conf);
|
||||
try {
|
||||
KeyProviderCryptoExtension kpCE = KeyProviderCryptoExtension.
|
||||
createKeyProviderCryptoExtension(kp);
|
||||
List<EncryptedKeyVersion> ekvs = new ArrayList<>(2);
|
||||
ekvs.add(encKv);
|
||||
ekvs.add(encKv);
|
||||
kpCE.reencryptEncryptedKeys(ekvs);
|
||||
fail("Should not have been able to reencryptEncryptedKeys");
|
||||
} catch (AuthorizationException ex) {
|
||||
LOG.info("reencryptEncryptedKeys caught expected exception.", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -115,6 +115,9 @@ public void testAggregation() throws Exception {
|
||||
kmsAudit.ok(luser, KMSOp.REENCRYPT_EEK, "k1", "testmsg");
|
||||
kmsAudit.ok(luser, KMSOp.REENCRYPT_EEK, "k1", "testmsg");
|
||||
kmsAudit.evictCacheForTesting();
|
||||
kmsAudit.ok(luser, KMSOp.REENCRYPT_EEK_BATCH, "k1", "testmsg");
|
||||
kmsAudit.ok(luser, KMSOp.REENCRYPT_EEK_BATCH, "k1", "testmsg");
|
||||
kmsAudit.evictCacheForTesting();
|
||||
String out = getAndResetLogOutput();
|
||||
System.out.println(out);
|
||||
Assert.assertTrue(
|
||||
@ -128,7 +131,9 @@ public void testAggregation() throws Exception {
|
||||
+ "OK\\[op=DECRYPT_EEK, key=k1, user=luser, accessCount=6, interval=[^m]{1,4}ms\\] testmsg"
|
||||
+ "OK\\[op=DECRYPT_EEK, key=k1, user=luser, accessCount=1, interval=[^m]{1,4}ms\\] testmsg"
|
||||
+ "OK\\[op=REENCRYPT_EEK, key=k1, user=luser, accessCount=1, interval=[^m]{1,4}ms\\] testmsg"
|
||||
+ "OK\\[op=REENCRYPT_EEK, key=k1, user=luser, accessCount=3, interval=[^m]{1,4}ms\\] testmsg"));
|
||||
+ "OK\\[op=REENCRYPT_EEK, key=k1, user=luser, accessCount=3, interval=[^m]{1,4}ms\\] testmsg"
|
||||
+ "OK\\[op=REENCRYPT_EEK_BATCH, key=k1, user=luser\\] testmsg"
|
||||
+ "OK\\[op=REENCRYPT_EEK_BATCH, key=k1, user=luser\\] testmsg"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
Loading…
Reference in New Issue
Block a user