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