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