HADOOP-10429. KeyStores should have methods to generate the materials themselves, KeyShell should use them. (tucu)

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1586105 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Alejandro Abdelnur 2014-04-09 19:46:41 +00:00
parent 98a98ea0c5
commit 9a1f15532f
4 changed files with 158 additions and 29 deletions

View File

@ -132,6 +132,9 @@ Trunk (Unreleased)
HADOOP-10427. KeyProvider implementations should be thread safe. (tucu) HADOOP-10427. KeyProvider implementations should be thread safe. (tucu)
HADOOP-10429. KeyStores should have methods to generate the materials
themselves, KeyShell should use them. (tucu)
BUG FIXES BUG FIXES
HADOOP-9451. Fault single-layer config if node group topology is enabled. HADOOP-9451. Fault single-layer config if node group topology is enabled.

View File

@ -24,6 +24,7 @@ import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.net.URI; import java.net.URI;
import java.security.NoSuchAlgorithmException;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -34,6 +35,8 @@ import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.Path;
import javax.crypto.KeyGenerator;
/** /**
* A provider of secret key material for Hadoop applications. Provides an * A provider of secret key material for Hadoop applications. Provides an
* abstraction to separate key storage from users of encryption. It * abstraction to separate key storage from users of encryption. It
@ -316,6 +319,56 @@ public abstract class KeyProvider {
public abstract KeyVersion createKey(String name, byte[] material, public abstract KeyVersion createKey(String name, byte[] material,
Options options) throws IOException; Options options) throws IOException;
/**
* Get the algorithm from the cipher.
*
* @return the algorithm name
*/
private String getAlgorithm(String cipher) {
int slash = cipher.indexOf('/');
if (slash == -1) {
return cipher;
} else {
return cipher.substring(0, slash);
}
}
/**
* Generates a key material.
*
* @param size length of the key.
* @param algorithm algorithm to use for generating the key.
* @return the generated key.
* @throws NoSuchAlgorithmException
*/
protected byte[] generateKey(int size, String algorithm)
throws NoSuchAlgorithmException {
algorithm = getAlgorithm(algorithm);
KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);
keyGenerator.init(size);
byte[] key = keyGenerator.generateKey().getEncoded();
return key;
}
/**
* Create a new key generating the material for it.
* The given key must not already exist.
* <p/>
* This implementation generates the key material and calls the
* {@link #createKey(String, byte[], Options)} method.
*
* @param name the base name of the key
* @param options the options for the new key.
* @return the version name of the first version of the key.
* @throws IOException
* @throws NoSuchAlgorithmException
*/
public KeyVersion createKey(String name, Options options)
throws NoSuchAlgorithmException, IOException {
byte[] material = generateKey(options.getBitLength(), options.getCipher());
return createKey(name, material, options);
}
/** /**
* Delete the given key. * Delete the given key.
* @param name the name of the key to delete * @param name the name of the key to delete
@ -334,6 +387,23 @@ public abstract class KeyProvider {
byte[] material byte[] material
) throws IOException; ) throws IOException;
/**
* Roll a new version of the given key generating the material for it.
* <p/>
* This implementation generates the key material and calls the
* {@link #rollNewVersion(String, byte[])} method.
*
* @param name the basename of the key
* @return the name of the new version of the key
* @throws IOException
*/
public KeyVersion rollNewVersion(String name) throws NoSuchAlgorithmException,
IOException {
Metadata meta = getMetadata(name);
byte[] material = generateKey(meta.getBitLength(), meta.getCipher());
return rollNewVersion(name, material);
}
/** /**
* Ensures that any changes to the keys are written to persistent store. * Ensures that any changes to the keys are written to persistent store.
* @throws IOException * @throws IOException

View File

@ -185,16 +185,6 @@ public class KeyShell extends Configured implements Tool {
return provider; return provider;
} }
protected byte[] generateKey(int size, String algorithm)
throws NoSuchAlgorithmException {
out.println("Generating key using size: " + size + " and algorithm: "
+ algorithm);
KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);
keyGenerator.init(size);
byte[] key = keyGenerator.generateKey().getEncoded();
return key;
}
protected void printProviderWritten() { protected void printProviderWritten() {
out.println(provider.getClass().getName() + " has been updated."); out.println(provider.getClass().getName() + " has been updated.");
} }
@ -289,9 +279,7 @@ public class KeyShell extends Configured implements Tool {
out.println("Rolling key version from KeyProvider: " out.println("Rolling key version from KeyProvider: "
+ provider.toString() + " for key name: " + keyName); + provider.toString() + " for key name: " + keyName);
try { try {
byte[] material = null; provider.rollNewVersion(keyName);
material = generateKey(md.getBitLength(), md.getAlgorithm());
provider.rollNewVersion(keyName, material);
out.println(keyName + " has been successfully rolled."); out.println(keyName + " has been successfully rolled.");
provider.flush(); provider.flush();
printProviderWritten(); printProviderWritten();
@ -423,9 +411,7 @@ public class KeyShell extends Configured implements Tool {
warnIfTransientProvider(); warnIfTransientProvider();
try { try {
Options options = KeyProvider.options(getConf()); Options options = KeyProvider.options(getConf());
String alg = getAlgorithm(options.getCipher()); provider.createKey(keyName, options);
byte[] material = generateKey(options.getBitLength(), alg);
provider.createKey(keyName, material, options);
out.println(keyName + " has been successfully created."); out.println(keyName + " has been successfully created.");
provider.flush(); provider.flush();
printProviderWritten(); printProviderWritten();
@ -441,19 +427,6 @@ public class KeyShell extends Configured implements Tool {
} }
} }
/**
* Get the algorithm from the cipher.
* @return the algorithm name
*/
public String getAlgorithm(String cipher) {
int slash = cipher.indexOf('/');
if (slash == - 1) {
return cipher;
} else {
return cipher.substring(0, slash);
}
}
@Override @Override
public String getUsage() { public String getUsage() {
return USAGE + ":\n\n" + DESC; return USAGE + ":\n\n" + DESC;

View File

@ -17,6 +17,7 @@
*/ */
package org.apache.hadoop.crypto.key; package org.apache.hadoop.crypto.key;
import junit.framework.Assert;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.Path;
@ -24,9 +25,11 @@ import org.junit.Test;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.List;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@ -34,6 +37,8 @@ import static org.junit.Assert.assertArrayEquals;
public class TestKeyProvider { public class TestKeyProvider {
private static final String CIPHER = "AES";
@Test @Test
public void testBuildVersionName() throws Exception { public void testBuildVersionName() throws Exception {
assertEquals("/a/b@3", KeyProvider.buildVersionName("/a/b", 3)); assertEquals("/a/b@3", KeyProvider.buildVersionName("/a/b", 3));
@ -109,4 +114,82 @@ public class TestKeyProvider {
assertEquals(new Path("user:///"), assertEquals(new Path("user:///"),
KeyProvider.unnestUri(new URI("outer://user/"))); KeyProvider.unnestUri(new URI("outer://user/")));
} }
private static class MyKeyProvider extends KeyProvider {
private String algorithm;
private int size;
private byte[] material;
@Override
public KeyVersion getKeyVersion(String versionName)
throws IOException {
return null;
}
@Override
public List<String> getKeys() throws IOException {
return null;
}
@Override
public List<KeyVersion> getKeyVersions(String name)
throws IOException {
return null;
}
@Override
public Metadata getMetadata(String name) throws IOException {
return new Metadata(CIPHER, 128, new Date(), 0);
}
@Override
public KeyVersion createKey(String name, byte[] material,
Options options) throws IOException {
this.material = material;
return null;
}
@Override
public void deleteKey(String name) throws IOException {
}
@Override
public KeyVersion rollNewVersion(String name, byte[] material)
throws IOException {
this.material = material;
return null;
}
@Override
public void flush() throws IOException {
}
@Override
protected byte[] generateKey(int size, String algorithm)
throws NoSuchAlgorithmException {
this.size = size;
this.algorithm = algorithm;
return super.generateKey(size, algorithm);
}
}
@Test
public void testMaterialGeneration() throws Exception {
MyKeyProvider kp = new MyKeyProvider();
KeyProvider.Options options = new KeyProvider.Options(new Configuration());
options.setCipher(CIPHER);
options.setBitLength(128);
kp.createKey("hello", options);
Assert.assertEquals(128, kp.size);
Assert.assertEquals(CIPHER, kp.algorithm);
Assert.assertNotNull(kp.material);
kp = new MyKeyProvider();
kp.rollNewVersion("hello");
Assert.assertEquals(128, kp.size);
Assert.assertEquals(CIPHER, kp.algorithm);
Assert.assertNotNull(kp.material);
}
} }