HDFS-9854. Log cipher suite negotiation more verbosely. Contributed by Wei-Chiu Chuang.

(cherry picked from commit d1dd248b75)
(cherry picked from commit 59cd23e279)
This commit is contained in:
cnauroth 2016-02-24 12:11:35 -08:00
parent 69acab5f23
commit d5dfb278d6
3 changed files with 54 additions and 18 deletions

View File

@ -238,7 +238,7 @@ private IOStreamPair send(InetAddress addr, OutputStream underlyingOut,
if (encryptionKey != null) { if (encryptionKey != null) {
LOG.debug("SASL client doing encrypted handshake for addr = {}, " LOG.debug("SASL client doing encrypted handshake for addr = {}, "
+ "datanodeId = {}", addr, datanodeId); + "datanodeId = {}", addr, datanodeId);
return getEncryptedStreams(underlyingOut, underlyingIn, return getEncryptedStreams(addr, underlyingOut, underlyingIn,
encryptionKey); encryptionKey);
} else if (!UserGroupInformation.isSecurityEnabled()) { } else if (!UserGroupInformation.isSecurityEnabled()) {
LOG.debug("SASL client skipping handshake in unsecured configuration for " LOG.debug("SASL client skipping handshake in unsecured configuration for "
@ -275,13 +275,15 @@ private IOStreamPair send(InetAddress addr, OutputStream underlyingOut,
/** /**
* Sends client SASL negotiation for specialized encrypted handshake. * Sends client SASL negotiation for specialized encrypted handshake.
* *
* @param addr connection address
* @param underlyingOut connection output stream * @param underlyingOut connection output stream
* @param underlyingIn connection input stream * @param underlyingIn connection input stream
* @param encryptionKey for an encrypted SASL handshake * @param encryptionKey for an encrypted SASL handshake
* @return new pair of streams, wrapped after SASL negotiation * @return new pair of streams, wrapped after SASL negotiation
* @throws IOException for any error * @throws IOException for any error
*/ */
private IOStreamPair getEncryptedStreams(OutputStream underlyingOut, private IOStreamPair getEncryptedStreams(InetAddress addr,
OutputStream underlyingOut,
InputStream underlyingIn, DataEncryptionKey encryptionKey) InputStream underlyingIn, DataEncryptionKey encryptionKey)
throws IOException { throws IOException {
Map<String, String> saslProps = createSaslPropertiesForEncryption( Map<String, String> saslProps = createSaslPropertiesForEncryption(
@ -294,8 +296,8 @@ private IOStreamPair getEncryptedStreams(OutputStream underlyingOut,
char[] password = encryptionKeyToPassword(encryptionKey.encryptionKey); char[] password = encryptionKeyToPassword(encryptionKey.encryptionKey);
CallbackHandler callbackHandler = new SaslClientCallbackHandler(userName, CallbackHandler callbackHandler = new SaslClientCallbackHandler(userName,
password); password);
return doSaslHandshake(underlyingOut, underlyingIn, userName, saslProps, return doSaslHandshake(addr, underlyingOut, underlyingIn, userName,
callbackHandler); saslProps, callbackHandler);
} }
/** /**
@ -384,8 +386,8 @@ private IOStreamPair getSaslStreams(InetAddress addr,
char[] password = buildClientPassword(accessToken); char[] password = buildClientPassword(accessToken);
CallbackHandler callbackHandler = new SaslClientCallbackHandler(userName, CallbackHandler callbackHandler = new SaslClientCallbackHandler(userName,
password); password);
return doSaslHandshake(underlyingOut, underlyingIn, userName, saslProps, return doSaslHandshake(addr, underlyingOut, underlyingIn, userName,
callbackHandler); saslProps, callbackHandler);
} }
/** /**
@ -418,6 +420,7 @@ private char[] buildClientPassword(Token<BlockTokenIdentifier> blockToken) {
/** /**
* This method actually executes the client-side SASL handshake. * This method actually executes the client-side SASL handshake.
* *
* @param addr connection address
* @param underlyingOut connection output stream * @param underlyingOut connection output stream
* @param underlyingIn connection input stream * @param underlyingIn connection input stream
* @param userName SASL user name * @param userName SASL user name
@ -426,8 +429,9 @@ private char[] buildClientPassword(Token<BlockTokenIdentifier> blockToken) {
* @return new pair of streams, wrapped after SASL negotiation * @return new pair of streams, wrapped after SASL negotiation
* @throws IOException for any error * @throws IOException for any error
*/ */
private IOStreamPair doSaslHandshake(OutputStream underlyingOut, private IOStreamPair doSaslHandshake(InetAddress addr,
InputStream underlyingIn, String userName, Map<String, String> saslProps, OutputStream underlyingOut, InputStream underlyingIn, String userName,
Map<String, String> saslProps,
CallbackHandler callbackHandler) throws IOException { CallbackHandler callbackHandler) throws IOException {
DataOutputStream out = new DataOutputStream(underlyingOut); DataOutputStream out = new DataOutputStream(underlyingOut);
@ -447,12 +451,12 @@ private IOStreamPair doSaslHandshake(OutputStream underlyingOut,
byte[] remoteResponse = readSaslMessage(in); byte[] remoteResponse = readSaslMessage(in);
byte[] localResponse = sasl.evaluateChallengeOrResponse(remoteResponse); byte[] localResponse = sasl.evaluateChallengeOrResponse(remoteResponse);
List<CipherOption> cipherOptions = null; List<CipherOption> cipherOptions = null;
String cipherSuites = conf.get(
DFS_ENCRYPT_DATA_TRANSFER_CIPHER_SUITES_KEY);
if (requestedQopContainsPrivacy(saslProps)) { if (requestedQopContainsPrivacy(saslProps)) {
// Negotiate cipher suites if configured. Currently, the only supported // Negotiate cipher suites if configured. Currently, the only supported
// cipher suite is AES/CTR/NoPadding, but the protocol allows multiple // cipher suite is AES/CTR/NoPadding, but the protocol allows multiple
// values for future expansion. // values for future expansion.
String cipherSuites = conf.get(
DFS_ENCRYPT_DATA_TRANSFER_CIPHER_SUITES_KEY);
if (cipherSuites != null && !cipherSuites.isEmpty()) { if (cipherSuites != null && !cipherSuites.isEmpty()) {
if (!cipherSuites.equals(CipherSuite.AES_CTR_NOPADDING.getName())) { if (!cipherSuites.equals(CipherSuite.AES_CTR_NOPADDING.getName())) {
throw new IOException(String.format("Invalid cipher suite, %s=%s", throw new IOException(String.format("Invalid cipher suite, %s=%s",
@ -479,6 +483,20 @@ private IOStreamPair doSaslHandshake(OutputStream underlyingOut,
if (sasl.isNegotiatedQopPrivacy()) { if (sasl.isNegotiatedQopPrivacy()) {
// Unwrap the negotiated cipher option // Unwrap the negotiated cipher option
cipherOption = unwrap(response.cipherOption, sasl); cipherOption = unwrap(response.cipherOption, sasl);
if (LOG.isDebugEnabled()) {
if (cipherOption == null) {
// No cipher suite is negotiated
if (cipherSuites != null && !cipherSuites.isEmpty()) {
// the client accepts some cipher suites, but the server does not.
LOG.debug("Client accepts cipher suites {}, "
+ "but server {} does not accept any of them",
cipherSuites, addr.toString());
}
} else {
LOG.debug("Client using cipher suite {} with server {}",
cipherOption.getCipherSuite().getName(), addr.toString());
}
}
} }
// If negotiated cipher option is not null, we will use it to create // If negotiated cipher option is not null, we will use it to create

View File

@ -929,6 +929,9 @@ Release 2.8.0 - UNRELEASED
HDFS-9844. Correct path creation in getTrashRoot to handle root dir. (zhz) HDFS-9844. Correct path creation in getTrashRoot to handle root dir. (zhz)
HDFS-9854. Log cipher suite negotiation more verbosely
(Wei-Chiu Chuang via cnauroth)
OPTIMIZATIONS OPTIMIZATIONS
HDFS-8026. Trace FSOutputSummer#writeChecksumChunks rather than HDFS-8026. Trace FSOutputSummer#writeChecksumChunks rather than

View File

@ -18,6 +18,7 @@
package org.apache.hadoop.hdfs.protocol.datatransfer.sasl; package org.apache.hadoop.hdfs.protocol.datatransfer.sasl;
import static org.apache.hadoop.hdfs.client.HdfsClientConfigKeys.DFS_DATA_TRANSFER_PROTECTION_KEY; import static org.apache.hadoop.hdfs.client.HdfsClientConfigKeys.DFS_DATA_TRANSFER_PROTECTION_KEY;
import static org.apache.hadoop.hdfs.client.HdfsClientConfigKeys.DFS_ENCRYPT_DATA_TRANSFER_CIPHER_SUITES_KEY;
import static org.apache.hadoop.hdfs.protocol.datatransfer.sasl.DataTransferSaslUtil.*; import static org.apache.hadoop.hdfs.protocol.datatransfer.sasl.DataTransferSaslUtil.*;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -40,6 +41,7 @@
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.crypto.CipherOption; import org.apache.hadoop.crypto.CipherOption;
import org.apache.hadoop.hdfs.net.Peer; import org.apache.hadoop.hdfs.net.Peer;
import org.apache.hadoop.hdfs.protocol.DatanodeID; import org.apache.hadoop.hdfs.protocol.DatanodeID;
@ -175,7 +177,7 @@ public char[] apply(String userName) throws IOException {
return encryptionKeyToPassword(getEncryptionKeyFromUserName(userName)); return encryptionKeyToPassword(getEncryptionKeyFromUserName(userName));
} }
}); });
return doSaslHandshake(underlyingOut, underlyingIn, saslProps, return doSaslHandshake(peer, underlyingOut, underlyingIn, saslProps,
callbackHandler); callbackHandler);
} }
@ -295,7 +297,7 @@ public char[] apply(String userName) throws IOException {
return buildServerPassword(userName); return buildServerPassword(userName);
} }
}); });
return doSaslHandshake(underlyingOut, underlyingIn, saslProps, return doSaslHandshake(peer, underlyingOut, underlyingIn, saslProps,
callbackHandler); callbackHandler);
} }
@ -338,6 +340,7 @@ private BlockTokenIdentifier deserializeIdentifier(String str)
/** /**
* This method actually executes the server-side SASL handshake. * This method actually executes the server-side SASL handshake.
* *
* @param peer connection peer
* @param underlyingOut connection output stream * @param underlyingOut connection output stream
* @param underlyingIn connection input stream * @param underlyingIn connection input stream
* @param saslProps properties of SASL negotiation * @param saslProps properties of SASL negotiation
@ -345,7 +348,7 @@ private BlockTokenIdentifier deserializeIdentifier(String str)
* @return new pair of streams, wrapped after SASL negotiation * @return new pair of streams, wrapped after SASL negotiation
* @throws IOException for any error * @throws IOException for any error
*/ */
private IOStreamPair doSaslHandshake(OutputStream underlyingOut, private IOStreamPair doSaslHandshake(Peer peer, OutputStream underlyingOut,
InputStream underlyingIn, Map<String, String> saslProps, InputStream underlyingIn, Map<String, String> saslProps,
CallbackHandler callbackHandler) throws IOException { CallbackHandler callbackHandler) throws IOException {
@ -378,11 +381,23 @@ private IOStreamPair doSaslHandshake(OutputStream underlyingOut,
CipherOption cipherOption = null; CipherOption cipherOption = null;
if (sasl.isNegotiatedQopPrivacy()) { if (sasl.isNegotiatedQopPrivacy()) {
// Negotiate a cipher option // Negotiate a cipher option
cipherOption = negotiateCipherOption(dnConf.getConf(), cipherOptions); Configuration conf = dnConf.getConf();
if (cipherOption != null) { cipherOption = negotiateCipherOption(conf, cipherOptions);
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("Server using cipher suite " + if (cipherOption == null) {
cipherOption.getCipherSuite().getName()); // No cipher suite is negotiated
String cipherSuites =
conf.get(DFS_ENCRYPT_DATA_TRANSFER_CIPHER_SUITES_KEY);
if (cipherSuites != null && !cipherSuites.isEmpty()) {
// the server accepts some cipher suites, but the client does not.
LOG.debug("Server accepts cipher suites {}, "
+ "but client {} does not accept any of them",
cipherSuites, peer.getRemoteAddressString());
}
} else {
LOG.debug("Server using cipher suite {} with client {}",
cipherOption.getCipherSuite().getName(),
peer.getRemoteAddressString());
} }
} }
} }