1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.util;
19
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertTrue;
23
24 import java.security.Key;
25 import java.security.SecureRandom;
26 import java.util.ArrayList;
27 import java.util.List;
28
29 import javax.crypto.spec.SecretKeySpec;
30
31 import org.apache.hadoop.conf.Configuration;
32 import org.apache.hadoop.fs.Path;
33 import org.apache.hadoop.hbase.HBaseTestingUtility;
34 import org.apache.hadoop.hbase.HColumnDescriptor;
35 import org.apache.hadoop.hbase.HConstants;
36 import org.apache.hadoop.hbase.HTableDescriptor;
37 import org.apache.hadoop.hbase.testclassification.LargeTests;
38 import org.apache.hadoop.hbase.TableName;
39 import org.apache.hadoop.hbase.client.HTable;
40 import org.apache.hadoop.hbase.client.Put;
41 import org.apache.hadoop.hbase.io.crypto.Encryption;
42 import org.apache.hadoop.hbase.io.crypto.KeyProviderForTesting;
43 import org.apache.hadoop.hbase.io.crypto.aes.AES;
44 import org.apache.hadoop.hbase.io.hfile.CacheConfig;
45 import org.apache.hadoop.hbase.io.hfile.HFile;
46 import org.apache.hadoop.hbase.regionserver.HRegion;
47 import org.apache.hadoop.hbase.regionserver.Store;
48 import org.apache.hadoop.hbase.regionserver.StoreFile;
49 import org.apache.hadoop.hbase.security.EncryptionUtil;
50 import org.apache.hadoop.hbase.security.User;
51 import org.apache.hadoop.hbase.util.hbck.HFileCorruptionChecker;
52 import org.apache.hadoop.hbase.util.hbck.HbckTestingUtil;
53
54 import org.junit.After;
55 import org.junit.Before;
56 import org.junit.Test;
57 import org.junit.experimental.categories.Category;
58
59 @Category(LargeTests.class)
60 public class TestHBaseFsckEncryption {
61
62 private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
63
64 private Configuration conf;
65 private HTableDescriptor htd;
66 private Key cfKey;
67
68 @Before
69 public void setUp() throws Exception {
70 conf = TEST_UTIL.getConfiguration();
71 conf.setInt("hfile.format.version", 3);
72 conf.set(HConstants.CRYPTO_KEYPROVIDER_CONF_KEY, KeyProviderForTesting.class.getName());
73 conf.set(HConstants.CRYPTO_MASTERKEY_NAME_CONF_KEY, "hbase");
74
75
76 SecureRandom rng = new SecureRandom();
77 byte[] keyBytes = new byte[AES.KEY_LENGTH];
78 rng.nextBytes(keyBytes);
79 String algorithm =
80 conf.get(HConstants.CRYPTO_KEY_ALGORITHM_CONF_KEY, HConstants.CIPHER_AES);
81 cfKey = new SecretKeySpec(keyBytes,algorithm);
82
83
84 TEST_UTIL.startMiniCluster(3);
85
86
87 htd = new HTableDescriptor(TableName.valueOf("default", "TestHBaseFsckEncryption"));
88 HColumnDescriptor hcd = new HColumnDescriptor("cf");
89 hcd.setEncryptionType(algorithm);
90 hcd.setEncryptionKey(EncryptionUtil.wrapKey(conf,
91 conf.get(HConstants.CRYPTO_MASTERKEY_NAME_CONF_KEY, User.getCurrent().getShortName()),
92 cfKey));
93 htd.addFamily(hcd);
94 TEST_UTIL.getHBaseAdmin().createTable(htd);
95 TEST_UTIL.waitTableAvailable(htd.getName(), 5000);
96 }
97
98 @After
99 public void tearDown() throws Exception {
100 TEST_UTIL.shutdownMiniCluster();
101 }
102
103 @Test
104 public void testFsckWithEncryption() throws Exception {
105
106 HTable table = new HTable(conf, htd.getName());
107 try {
108 byte[] values = { 'A', 'B', 'C', 'D' };
109 for (int i = 0; i < values.length; i++) {
110 for (int j = 0; j < values.length; j++) {
111 Put put = new Put(new byte[] { values[i], values[j] });
112 put.add(Bytes.toBytes("cf"), new byte[] {}, new byte[] { values[i],
113 values[j] });
114 table.put(put);
115 }
116 }
117 } finally {
118 table.close();
119 }
120
121 TEST_UTIL.getHBaseAdmin().flush(htd.getName());
122
123
124 final List<Path> paths = findStorefilePaths(htd.getName());
125 assertTrue(paths.size() > 0);
126 for (Path path: paths) {
127 assertTrue("Store file " + path + " has incorrect key",
128 Bytes.equals(cfKey.getEncoded(), extractHFileKey(path)));
129 }
130
131
132 HBaseFsck res = HbckTestingUtil.doHFileQuarantine(conf, htd.getTableName());
133 assertEquals(res.getRetCode(), 0);
134 HFileCorruptionChecker hfcc = res.getHFilecorruptionChecker();
135 assertEquals(hfcc.getCorrupted().size(), 0);
136 assertEquals(hfcc.getFailures().size(), 0);
137 assertEquals(hfcc.getQuarantined().size(), 0);
138 assertEquals(hfcc.getMissing().size(), 0);
139 }
140
141 private List<Path> findStorefilePaths(byte[] tableName) throws Exception {
142 List<Path> paths = new ArrayList<Path>();
143 for (HRegion region:
144 TEST_UTIL.getRSForFirstRegionInTable(tableName).getOnlineRegions(htd.getTableName())) {
145 for (Store store: region.getStores().values()) {
146 for (StoreFile storefile: store.getStorefiles()) {
147 paths.add(storefile.getPath());
148 }
149 }
150 }
151 return paths;
152 }
153
154 private byte[] extractHFileKey(Path path) throws Exception {
155 HFile.Reader reader = HFile.createReader(TEST_UTIL.getTestFileSystem(), path,
156 new CacheConfig(conf), conf);
157 try {
158 reader.loadFileInfo();
159 Encryption.Context cryptoContext = reader.getFileContext().getEncryptionContext();
160 assertNotNull("Reader has a null crypto context", cryptoContext);
161 Key key = cryptoContext.getKey();
162 assertNotNull("Crypto context has no key", key);
163 return key.getEncoded();
164 } finally {
165 reader.close();
166 }
167 }
168
169 }