From 059c6555842eb11bbb2f90c91d4d507c58e6ef21 Mon Sep 17 00:00:00 2001 From: xiezhineng Date: Thu, 9 Mar 2023 21:50:15 +0800 Subject: [PATCH 1/2] RBF: add RouterSecurityAuditLogger for router security manager --- .../security/RouterSecurityAuditLogger.java | 91 +++++++++++++++++++ .../security/RouterSecurityManager.java | 32 +++++-- .../TestRouterSecurityAuditLogger.java | 53 +++++++++++ 3 files changed, 166 insertions(+), 10 deletions(-) create mode 100644 hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/router/security/RouterSecurityAuditLogger.java create mode 100644 hadoop-hdfs-project/hadoop-hdfs-rbf/src/test/java/org/apache/hadoop/hdfs/server/federation/security/TestRouterSecurityAuditLogger.java diff --git a/hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/router/security/RouterSecurityAuditLogger.java b/hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/router/security/RouterSecurityAuditLogger.java new file mode 100644 index 0000000000000..0c4b4b9d27524 --- /dev/null +++ b/hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/router/security/RouterSecurityAuditLogger.java @@ -0,0 +1,91 @@ +package org.apache.hadoop.hdfs.server.federation.router.security; + +import org.apache.hadoop.classification.VisibleForTesting; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.ipc.CallerContext; +import org.apache.hadoop.ipc.Server; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.InetAddress; + +import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.*; +import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_CALLER_CONTEXT_SIGNATURE_MAX_SIZE_DEFAULT; + +public class RouterSecurityAuditLogger { + + public static final Logger auditLog = LoggerFactory.getLogger( + RouterSecurityManager.class.getName() + ".audit"); + + private static final ThreadLocal STRING_BUILDER = + new ThreadLocal() { + @Override + protected StringBuilder initialValue() { + return new StringBuilder(); + } + }; + + private int callerContextMaxLen; + private int callerSignatureMaxLen; + + public RouterSecurityAuditLogger(Configuration conf) { + callerContextMaxLen = conf.getInt( + HADOOP_CALLER_CONTEXT_MAX_SIZE_KEY, + HADOOP_CALLER_CONTEXT_MAX_SIZE_DEFAULT); + callerSignatureMaxLen = conf.getInt( + HADOOP_CALLER_CONTEXT_SIGNATURE_MAX_SIZE_KEY, + HADOOP_CALLER_CONTEXT_SIGNATURE_MAX_SIZE_DEFAULT); + } + + public void logAuditEvent(boolean succeeded, String userName, + InetAddress addr, String cmd, + CallerContext callerContext, String tokenId) { + if (auditLog.isDebugEnabled() || auditLog.isInfoEnabled()) { + logAuditMessage( + creatAuditLog(succeeded, userName, addr, cmd, callerContext, + tokenId)); + } + } + + @VisibleForTesting + public String creatAuditLog(boolean succeeded, String userName, + InetAddress addr, String cmd, + CallerContext callerContext, String tokenId) { + final StringBuilder sb = STRING_BUILDER.get(); + sb.setLength(0); + sb.append("allowed=").append(succeeded).append("\t"); + sb.append("ugi=").append(userName).append("\t"); + sb.append("ip=").append(addr).append("\t"); + sb.append("cmd=").append(cmd).append("\t"); + + sb.append("\t").append("toeknId="); + sb.append(tokenId); + + sb.append("\t").append("proto="); + sb.append(Server.getProtocol()); + if ( + callerContext != null && + callerContext.isContextValid()) { + sb.append("\t").append("callerContext="); + if (callerContext.getContext().length() > callerContextMaxLen) { + sb.append(callerContext.getContext().substring(0, + callerContextMaxLen)); + } else { + sb.append(callerContext.getContext()); + } + if (callerContext.getSignature() != null && + callerContext.getSignature().length > 0 && + callerContext.getSignature().length <= callerSignatureMaxLen) { + sb.append(":"); + sb.append(new String(callerContext.getSignature(), + CallerContext.SIGNATURE_ENCODING)); + } + } + return sb.toString(); + } + + private void logAuditMessage(String message) { + auditLog.info(message); + } + +} \ No newline at end of file diff --git a/hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/router/security/RouterSecurityManager.java b/hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/router/security/RouterSecurityManager.java index f2c24eeb5a2c7..0af0d7b80f6b7 100644 --- a/hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/router/security/RouterSecurityManager.java +++ b/hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/router/security/RouterSecurityManager.java @@ -26,6 +26,8 @@ import org.apache.hadoop.hdfs.server.federation.router.RouterRpcServer; import org.apache.hadoop.hdfs.server.federation.router.Router; import org.apache.hadoop.io.Text; +import org.apache.hadoop.ipc.CallerContext; +import org.apache.hadoop.ipc.Server; import org.apache.hadoop.security.AccessControlException; import org.apache.hadoop.security.Credentials; import org.apache.hadoop.security.SecurityUtil; @@ -38,6 +40,7 @@ import org.slf4j.LoggerFactory; import java.io.IOException; +import java.net.InetAddress; import java.net.InetSocketAddress; /** @@ -51,6 +54,8 @@ public class RouterSecurityManager { private AbstractDelegationTokenSecretManager dtSecretManager = null; + private RouterSecurityAuditLogger auditLogger; + public RouterSecurityManager(Configuration conf) throws IOException { AuthenticationMethod authMethodConfigured = SecurityUtil.getAuthenticationMethod(conf); @@ -62,12 +67,14 @@ public RouterSecurityManager(Configuration conf) throws IOException { throw new IOException("Failed to create SecretManager"); } } + auditLogger = new RouterSecurityAuditLogger(conf); } @VisibleForTesting public RouterSecurityManager(AbstractDelegationTokenSecretManager dtSecretManager) { this.dtSecretManager = dtSecretManager; + auditLogger = new RouterSecurityAuditLogger(new Configuration()); } public AbstractDelegationTokenSecretManager @@ -127,6 +134,7 @@ public Token getDelegationToken(Text renewer) final String operationName = "getDelegationToken"; boolean success = false; String tokenId = ""; + String user = ""; Token token; try { if (!isAllowedDelegationTokenOp()) { @@ -139,7 +147,7 @@ public Token getDelegationToken(Text renewer) return null; } UserGroupInformation ugi = getRemoteUser(); - String user = ugi.getUserName(); + user = ugi.getUserName(); Text owner = new Text(user); Text realUser = null; if (ugi.getRealUser() != null) { @@ -152,7 +160,8 @@ public Token getDelegationToken(Text renewer) tokenId = dtId.toStringStable(); success = true; } finally { - logAuditEvent(success, operationName, tokenId); + logAuditEvent(success, user, Server.getRemoteIp(), operationName, + CallerContext.getCurrent(), tokenId); } return token; } @@ -169,6 +178,7 @@ public long renewDelegationToken(Token token) final String operationName = "renewDelegationToken"; boolean success = false; String tokenId = ""; + String user = ""; long expiryTime; try { if (!isAllowedDelegationTokenOp()) { @@ -186,7 +196,8 @@ public long renewDelegationToken(Token token) tokenId = id.toStringStable(); throw ace; } finally { - logAuditEvent(success, operationName, tokenId); + logAuditEvent(success, user, Server.getRemoteIp(), operationName, + CallerContext.getCurrent(), tokenId); } return expiryTime; } @@ -201,6 +212,7 @@ public void cancelDelegationToken(Token token) final String operationName = "cancelDelegationToken"; boolean success = false; String tokenId = ""; + String user = ""; try { String canceller = getRemoteUser().getUserName(); LOG.info("Cancel request by " + canceller); @@ -213,7 +225,8 @@ public void cancelDelegationToken(Token token) tokenId = id.toStringStable(); throw ace; } finally { - logAuditEvent(success, operationName, tokenId); + logAuditEvent(success, user, Server.getRemoteIp(), operationName, + CallerContext.getCurrent(), tokenId); } } @@ -249,11 +262,10 @@ public void verifyToken(DelegationTokenIdentifier identifier, * Log status of delegation token related operation. * Extend in future to use audit logger instead of local logging. */ - void logAuditEvent(boolean succeeded, String cmd, String tokenId) - throws IOException { - LOG.debug( - "Operation:" + cmd + - " Status:" + succeeded + - " TokenId:" + tokenId); + void logAuditEvent(boolean succeeded, String userName, + InetAddress addr, String cmd, + CallerContext callerContext, String tokenId) { + auditLogger.logAuditEvent(succeeded, userName, addr, cmd, + callerContext, tokenId); } } diff --git a/hadoop-hdfs-project/hadoop-hdfs-rbf/src/test/java/org/apache/hadoop/hdfs/server/federation/security/TestRouterSecurityAuditLogger.java b/hadoop-hdfs-project/hadoop-hdfs-rbf/src/test/java/org/apache/hadoop/hdfs/server/federation/security/TestRouterSecurityAuditLogger.java new file mode 100644 index 0000000000000..a16cad5323d73 --- /dev/null +++ b/hadoop-hdfs-project/hadoop-hdfs-rbf/src/test/java/org/apache/hadoop/hdfs/server/federation/security/TestRouterSecurityAuditLogger.java @@ -0,0 +1,53 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hdfs.server.federation.security; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hdfs.server.federation.router.security.RouterSecurityAuditLogger; +import org.apache.hadoop.ipc.CallerContext; +import org.apache.hadoop.ipc.Server; +import org.junit.Test; + +import java.io.IOException; + +import static org.junit.Assert.*; + +public class TestRouterSecurityAuditLogger { + + @Test + public void testRouterSecurityAuditLog() throws IOException { + RouterSecurityAuditLogger auditLogger = + new RouterSecurityAuditLogger(new Configuration()); + String fLog1 = auditLogger.creatAuditLog(false, "foo_user", + Server.getRemoteIp(), "getDelegationToken", CallerContext.getCurrent(), + "tokenId-123"); + String expLog1 = + "allowed=false\tugi=foo_user\tip=null\tcmd=getDelegationToken\t" + + "\ttoeknId=tokenId-123\tproto=null"; + assertEquals(expLog1, fLog1); + + String fLog2 = auditLogger.creatAuditLog(true, "foo2_user", + Server.getRemoteIp(), "renewDelegationToken", CallerContext.getCurrent(), + "tokenId-456"); + String expLog2 = + "allowed=true\tugi=foo2_user\tip=null\tcmd=renewDelegationToken\t" + + "\ttoeknId=tokenId-456\tproto=null"; + assertEquals(expLog2, fLog2); + } +} \ No newline at end of file From bc47cf6e258b58b7cb8cd5a0cdef20eaa5563f3a Mon Sep 17 00:00:00 2001 From: xiezhineng Date: Fri, 10 Mar 2023 10:07:46 +0800 Subject: [PATCH 2/2] fix checkstyle & add license --- .../security/RouterSecurityAuditLogger.java | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/router/security/RouterSecurityAuditLogger.java b/hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/router/security/RouterSecurityAuditLogger.java index 0c4b4b9d27524..6eb5fe0ac8025 100644 --- a/hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/router/security/RouterSecurityAuditLogger.java +++ b/hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/router/security/RouterSecurityAuditLogger.java @@ -1,3 +1,21 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.hadoop.hdfs.server.federation.router.security; import org.apache.hadoop.classification.VisibleForTesting; @@ -14,7 +32,7 @@ public class RouterSecurityAuditLogger { - public static final Logger auditLog = LoggerFactory.getLogger( + public static final Logger AUDIT_LOG = LoggerFactory.getLogger( RouterSecurityManager.class.getName() + ".audit"); private static final ThreadLocal STRING_BUILDER = @@ -40,7 +58,7 @@ public RouterSecurityAuditLogger(Configuration conf) { public void logAuditEvent(boolean succeeded, String userName, InetAddress addr, String cmd, CallerContext callerContext, String tokenId) { - if (auditLog.isDebugEnabled() || auditLog.isInfoEnabled()) { + if (AUDIT_LOG.isDebugEnabled() || AUDIT_LOG.isInfoEnabled()) { logAuditMessage( creatAuditLog(succeeded, userName, addr, cmd, callerContext, tokenId)); @@ -85,7 +103,7 @@ public String creatAuditLog(boolean succeeded, String userName, } private void logAuditMessage(String message) { - auditLog.info(message); + AUDIT_LOG.info(message); } } \ No newline at end of file