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 cfKey = new SecretKeySpec(keyBytes, "AES");
81
82
83 TEST_UTIL.startMiniCluster(3);
84
85
86 htd = new HTableDescriptor(TableName.valueOf("default", "TestHBaseFsckEncryption"));
87 HColumnDescriptor hcd = new HColumnDescriptor("cf");
88 hcd.setEncryptionType("AES");
89 hcd.setEncryptionKey(EncryptionUtil.wrapKey(conf,
90 conf.get(HConstants.CRYPTO_MASTERKEY_NAME_CONF_KEY, User.getCurrent().getShortName()),
91 cfKey));
92 htd.addFamily(hcd);
93 TEST_UTIL.getHBaseAdmin().createTable(htd);
94 TEST_UTIL.waitTableAvailable(htd.getName(), 5000);
95 }
96
97 @After
98 public void tearDown() throws Exception {
99 TEST_UTIL.shutdownMiniCluster();
100 }
101
102 @Test
103 public void testFsckWithEncryption() throws Exception {
104
105 Table table = new HTable(conf, htd.getTableName());
106 try {
107 byte[] values = { 'A', 'B', 'C', 'D' };
108 for (int i = 0; i < values.length; i++) {
109 for (int j = 0; j < values.length; j++) {
110 Put put = new Put(new byte[] { values[i], values[j] });
111 put.add(Bytes.toBytes("cf"), new byte[] {}, new byte[] { values[i],
112 values[j] });
113 table.put(put);
114 }
115 }
116 } finally {
117 table.close();
118 }
119
120 TEST_UTIL.getHBaseAdmin().flush(htd.getTableName());
121
122
123 final List<Path> paths = findStorefilePaths(htd.getTableName());
124 assertTrue(paths.size() > 0);
125 for (Path path: paths) {
126 assertTrue("Store file " + path + " has incorrect key",
127 Bytes.equals(cfKey.getEncoded(), extractHFileKey(path)));
128 }
129
130
131 HBaseFsck res = HbckTestingUtil.doHFileQuarantine(conf, htd.getTableName());
132 assertEquals(res.getRetCode(), 0);
133 HFileCorruptionChecker hfcc = res.getHFilecorruptionChecker();
134 assertEquals(hfcc.getCorrupted().size(), 0);
135 assertEquals(hfcc.getFailures().size(), 0);
136 assertEquals(hfcc.getQuarantined().size(), 0);
137 assertEquals(hfcc.getMissing().size(), 0);
138 }
139
140 private List<Path> findStorefilePaths(TableName tableName) throws Exception {
141 List<Path> paths = new ArrayList<Path>();
142 for (HRegion region:
143 TEST_UTIL.getRSForFirstRegionInTable(tableName).getOnlineRegions(htd.getTableName())) {
144 for (Store store: region.getStores().values()) {
145 for (StoreFile storefile: store.getStorefiles()) {
146 paths.add(storefile.getPath());
147 }
148 }
149 }
150 return paths;
151 }
152
153 private byte[] extractHFileKey(Path path) throws Exception {
154 HFile.Reader reader = HFile.createReader(TEST_UTIL.getTestFileSystem(), path,
155 new CacheConfig(conf), conf);
156 try {
157 reader.loadFileInfo();
158 Encryption.Context cryptoContext = reader.getFileContext().getEncryptionContext();
159 assertNotNull("Reader has a null crypto context", cryptoContext);
160 Key key = cryptoContext.getKey();
161 assertNotNull("Crypto context has no key", key);
162 return key.getEncoded();
163 } finally {
164 reader.close();
165 }
166 }
167
168 }