View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.hadoop.hbase.regionserver.wal;
20  
21  import java.io.IOException;
22  import java.security.Key;
23  import java.security.SecureRandom;
24  
25  import javax.crypto.spec.SecretKeySpec;
26  
27  import com.google.protobuf.HBaseZeroCopyByteString;
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  import org.apache.hadoop.hbase.HConstants;
31  import org.apache.hadoop.hbase.io.crypto.Cipher;
32  import org.apache.hadoop.hbase.io.crypto.Encryption;
33  import org.apache.hadoop.hbase.io.crypto.Encryptor;
34  import org.apache.hadoop.hbase.protobuf.generated.WALProtos.WALHeader;
35  import org.apache.hadoop.hbase.security.EncryptionUtil;
36  import org.apache.hadoop.hbase.security.User;
37  
38  public class SecureProtobufLogWriter extends ProtobufLogWriter {
39  
40    private static final Log LOG = LogFactory.getLog(SecureProtobufLogWriter.class);
41    private static final String DEFAULT_CIPHER = "AES";
42  
43    private Encryptor encryptor = null;
44  
45    @Override
46    protected WALHeader buildWALHeader(WALHeader.Builder builder) throws IOException {
47      if (conf.getBoolean(HConstants.ENABLE_WAL_ENCRYPTION, false)) {
48        // Get an instance of our cipher
49        Cipher cipher = Encryption.getCipher(conf,
50          conf.get(HConstants.CRYPTO_WAL_ALGORITHM_CONF_KEY, DEFAULT_CIPHER));
51        if (cipher == null) {
52          throw new RuntimeException("Cipher '" + cipher + "' is not available");
53        }
54  
55        // Generate an encryption key for this WAL
56        SecureRandom rng = new SecureRandom();
57        byte[] keyBytes = new byte[cipher.getKeyLength()];
58        rng.nextBytes(keyBytes);
59        Key key = new SecretKeySpec(keyBytes, cipher.getName());
60        builder.setEncryptionKey(HBaseZeroCopyByteString.wrap(EncryptionUtil.wrapKey(conf,
61            conf.get(HConstants.CRYPTO_WAL_KEY_NAME_CONF_KEY,
62                conf.get(HConstants.CRYPTO_MASTERKEY_NAME_CONF_KEY,
63                    User.getCurrent().getShortName())),
64            key)));
65  
66        // Set up the encryptor
67        encryptor = cipher.getEncryptor();
68        encryptor.setKey(key);
69  
70        if (LOG.isTraceEnabled()) {
71          LOG.trace("Initialized secure protobuf WAL: cipher=" + cipher.getName());
72        }
73      }
74  
75      return super.buildWALHeader(builder);
76    }
77  
78    @Override
79    protected void initAfterHeader(boolean doCompress) throws IOException {
80      if (conf.getBoolean(HConstants.ENABLE_WAL_ENCRYPTION, false) && encryptor != null) {
81        WALCellCodec codec = SecureWALCellCodec.getCodec(this.conf, encryptor);
82        this.cellEncoder = codec.getEncoder(this.output);
83        // We do not support compression
84        this.compressionContext = null;
85      } else {
86        super.initAfterHeader(doCompress);
87      }
88    }
89  
90  }