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:
parent
98a98ea0c5
commit
9a1f15532f
@ -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.
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
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.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 KeyVersion getCurrentKey(String name) throws IOException {
|
|||||||
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 KeyVersion rollNewVersion(String name,
|
|||||||
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
|
||||||
|
@ -185,16 +185,6 @@ protected KeyProvider getKeyProvider() {
|
|||||||
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 void execute() throws NoSuchAlgorithmException, IOException {
|
|||||||
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 void execute() throws IOException, NoSuchAlgorithmException {
|
|||||||
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 void execute() throws IOException, NoSuchAlgorithmException {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
||||||
|
@ -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 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 @@
|
|||||||
|
|
||||||
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 void testUnnestUri() throws Exception {
|
|||||||
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user