专栏首页大数据和云计算技术hdfs auditlog(审计日志)

hdfs auditlog(审计日志)

hdfs审计日志(Auditlog)记录了用户针对hdfs的所有操作,详细信息包括操作成功与否、用户名称、客户机地址、操作命令、操作的目录等。对于用户的每一个操作,namenode都会将这些信息以key-value对的形式组织成固定格式的一条日志,然后记录到audit.log文件中。通过审计日志,我们可以实时查看hdfs的各种操作状况、可以追踪各种误操作、可以做一些指标监控等等。

hdfs的审计日志功能是可插拔的,用户可以通过实现默认接口扩展出满足自己所需的插件来替换hdfs默认提供的审计日志功能,或者与之并用。

启用审计日志

如果仅仅只启用默认的AuditLogger(DefaultAuditLogger),则在log4j.properties添加如下配置(hdfs.audit.logger必须配置为INFO级别)即可,审计日志会与namenode的系统日志独立开来保存,log4j.appender.RFAAUDIT.File可配置保存的位置及文件。 FSNamesystem根据log4j.properties中hdfs.audit.logger是否为INFO,以及是否配置了DefaultAuditLogger之外的其他AuditLogger,来决定是否启用审计日志功能。

#
# hdfs audit logging
#
hdfs.audit.logger=INFO,NullAppender
hdfs.audit.log.maxfilesize=256MB
hdfs.audit.log.maxbackupindex=20
log4j.logger.org.apache.hadoop.hdfs.server.namenode.FSNamesystem.audit=${hdfs.audit.logger}
log4j.additivity.org.apache.hadoop.hdfs.server.namenode.FSNamesystem.audit=false
log4j.appender.RFAAUDIT=org.apache.log4j.RollingFileAppender
log4j.appender.RFAAUDIT.File=${hadoop.log.dir}/hdfs-audit.log
log4j.appender.RFAAUDIT.layout=org.apache.log4j.PatternLayout
log4j.appender.RFAAUDIT.layout.ConversionPattern=%d{ISO8601} %p %c{2}: %m%n
log4j.appender.RFAAUDIT.MaxFileSize=${hdfs.audit.log.maxfilesize}
log4j.appender.RFAAUDIT.MaxBackupIndex=${hdfs.audit.log.maxbackupindex}

审计日志的接口及实现

Namenode开放了AuditLogger接口,并定义抽象类HdfsAuditLogger 实现AuditLogger,默认提供实现类DefaultAuditLogger。构造FSNamesystem时通过initAuditLoggers(Configuration conf)方法创建AuditLogger列表。在记录用户操作时,会将操作信息逐一传给列表中的每一个AuditLogger,由其做对应的审计处理。

通过实现Auditloger接口或者扩展HdfsAuditLogger类,用户可以实现自己的AuditLogger来满足所需,例如有针对性的记录审计日志(当集群、访问量上规模之后疯狂刷日志必然对namenode有影响,有针对性的记录有必要的日志是缓解此状况的一种可选方案)、扩展功能、将日志接入实时系统做实时分析或监控等。用户通过配置项dfs.namenode.audit.loggers在hdfs-site.xml中配置Auditloger的实现类,多个实现可以通过逗号分开,更改配置后重启namenode接口生效。FSNamesystem的initAuditLoggers(Configuration conf)方法通过该配置项加载并实例化实现类,初始化后存入集合。如果用户没有配置,那么默认使用DefaultAuditLogger。如果启动了nntop功能,还会使用TopAuditLogger。

FSNamesystem 初始化所有的AuditLogger:

 1private List<AuditLogger> initAuditLoggers(Configuration conf) {
 2    // Initialize the custom access loggers if configured.
 3    //DFS_NAMENODE_AUDIT_LOGGERS_KEY=dfs.namenode.audit.loggers
 4    Collection<String> alClasses = conf.getStringCollection(DFS_NAMENODE_AUDIT_LOGGERS_KEY);
 5    List<AuditLogger> auditLoggers = Lists.newArrayList();
 6    if (alClasses != null && !alClasses.isEmpty()) {
 7      for (String className : alClasses) {
 8        try {
 9          AuditLogger logger;
10          if (DFS_NAMENODE_DEFAULT_AUDIT_LOGGER_NAME.equals(className)) {
11            logger = new DefaultAuditLogger();
12          } else {
13            logger = (AuditLogger) Class.forName(className).newInstance();
14          }
15          logger.initialize(conf);
16          auditLoggers.add(logger);
17        } catch (RuntimeException re) {
18          throw re;
19        } catch (Exception e) {
20          throw new RuntimeException(e);
21        }
22      }
23    }
24
25    // Make sure there is at least one logger installed.
26    // 如果用户没有提供AuditLoggers,则默认使用DefaultAuditLogger
27    if (auditLoggers.isEmpty()) {
28      auditLoggers.add(new DefaultAuditLogger());
29    }
30
31    // Add audit logger to calculate top users
32    // 默认topConf.isEnabled是开启的,用于指标聚合、上报
33    // TopAuditLogger类似 top命令
34    if (topConf.isEnabled) {
35      topMetrics = new TopMetrics(conf, topConf.nntopReportingPeriodsMs);
36      auditLoggers.add(new TopAuditLogger(topMetrics));
37    }
38
39    return Collections.unmodifiableList(auditLoggers);
40  }

DefaultAuditLogger记录日志:

 1@Override
 2    public void logAuditEvent(boolean succeeded, String userName,
 3        InetAddress addr, String cmd, String src, String dst,
 4        FileStatus status, UserGroupInformation ugi,
 5        DelegationTokenSecretManager dtSecretManager) {
 6      if (auditLog.isInfoEnabled()) {
 7        final StringBuilder sb = auditBuffer.get();
 8        sb.setLength(0);
 9        sb.append("allowed=").append(succeeded).append("\t");
10        sb.append("ugi=").append(userName).append("\t");
11        sb.append("ip=").append(addr).append("\t");
12        sb.append("cmd=").append(cmd).append("\t");
13        sb.append("src=").append(src).append("\t");
14        sb.append("dst=").append(dst).append("\t");
15        if (null == status) {
16          sb.append("perm=null");
17        } else {
18          sb.append("perm=");
19          sb.append(status.getOwner()).append(":");
20          sb.append(status.getGroup()).append(":");
21          sb.append(status.getPermission());
22        }
23        if (logTokenTrackingId) {
24          sb.append("\t").append("trackingId=");
25          String trackingId = null;
26          if (ugi != null && dtSecretManager != null
27              && ugi.getAuthenticationMethod() == AuthenticationMethod.TOKEN) {
28            for (TokenIdentifier tid: ugi.getTokenIdentifiers()) {
29              if (tid instanceof DelegationTokenIdentifier) {
30                DelegationTokenIdentifier dtid =
31                    (DelegationTokenIdentifier)tid;
32                trackingId = dtSecretManager.getTokenTrackingId(dtid);
33                break;
34              }
35            }
36          }
37          sb.append(trackingId);
38        }
39        sb.append("\t").append("proto=");
40        sb.append(NamenodeWebHdfsMethods.isWebHdfsInvocation() ? "webhdfs" : "rpc");
41        logAuditMessage(sb.toString());
42      }
43    }
44
45    public void logAuditMessage(String message) {
46      auditLog.info(message);
47    }

审计过程

客户端对hdfs的所有操作,不管成功与否都会由FSNamesystem记录下。以删除操作为例,FSNamesystem在正常删除给定src后调用logAuditEvent(true, "delete", src)记录此次成功的delete操作,如果删除失败抛出异常,则调用logAuditEvent(false, "delete", src)记录此次失败的delete操作。

 1boolean delete(String src, boolean recursive, boolean logRetryCache)
 2      throws IOException {
 3    waitForLoadingFSImage();
 4    BlocksMapUpdateInfo toRemovedBlocks = null;
 5    writeLock();
 6    boolean ret = false;
 7    try {
 8      checkOperation(OperationCategory.WRITE);
 9      checkNameNodeSafeMode("Cannot delete " + src);
10      toRemovedBlocks = FSDirDeleteOp.delete(
11          this, src, recursive, logRetryCache);
12      ret = toRemovedBlocks != null;
13    } catch (AccessControlException e) {
14      logAuditEvent(false, "delete", src);
15      throw e;
16    } finally {
17      writeUnlock();
18    }
19    getEditLog().logSync();
20    if (toRemovedBlocks != null) {
21      removeBlocks(toRemovedBlocks); // Incremental deletion of blocks
22    }
23    logAuditEvent(true, "delete", src);
24    return ret;
25  }
26
27
28
29//判断是否是外部调用,只对rpc调用和webHdfs调用做审计
30  boolean isExternalInvocation() {
31    return Server.isRpcInvocation() || NamenodeWebHdfsMethods.isWebHdfsInvocation();
32  }  
33
34  //判断是否启用审计日志功能
35  public boolean isAuditEnabled() {
36    return !isDefaultAuditLogger || auditLog.isInfoEnabled();
37  }
38
39  //succeeded:操作是否成功     cmd:操作命令     src:操作对象
40  private void logAuditEvent(boolean succeeded, String cmd, String src)
41      throws IOException {
42    logAuditEvent(succeeded, cmd, src, null, null);
43  }
44
45  private void logAuditEvent(boolean succeeded, String cmd, String src,
46      String dst, HdfsFileStatus stat) throws IOException {
47    if (isAuditEnabled() && isExternalInvocation()) {
48      logAuditEvent(succeeded, getRemoteUser(), getRemoteIp(),
49                    cmd, src, dst, stat);
50    }
51  }
52
53  //获取操作对象的信息,调用所有的auditloger 做审计
54  private void logAuditEvent(boolean succeeded,
55      UserGroupInformation ugi, InetAddress addr, String cmd, String src,
56      String dst, HdfsFileStatus stat) {
57    FileStatus status = null;
58    if (stat != null) {
59      Path symlink = stat.isSymlink() ? new Path(stat.getSymlink()) : null;
60      Path path = dst != null ? new Path(dst) : new Path(src);
61      status = new FileStatus(stat.getLen(), stat.isDir(),
62          stat.getReplication(), stat.getBlockSize(), stat.getModificationTime(),
63          stat.getAccessTime(), stat.getPermission(), stat.getOwner(),
64          stat.getGroup(), symlink, path);
65    }
66    for (AuditLogger logger : auditLoggers) {
67      if (logger instanceof HdfsAuditLogger) {
68        HdfsAuditLogger hdfsLogger = (HdfsAuditLogger) logger;
69        hdfsLogger.logAuditEvent(succeeded, ugi.toString(), addr, cmd, src, dst,
70            status, ugi, dtSecretManager);
71      } else {
72        logger.logAuditEvent(succeeded, ugi.toString(), addr,
73            cmd, src, dst, status);
74      }
75    }
76  }

审计日志接入实时系统的方法

  • 方法1:扩展Log4J的appender,由appender将日志发送到kafka。
  • 方法2:直接让kafka的producer读取日志文件。

本文分享自微信公众号 - 大数据和云计算技术(jiezhu2007),作者:奥斯特•萝卜丝

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-10-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • HBase 的MOB压缩分区策略介绍

    HBase应用场景非常广泛;社区前面有一系列文章。大家可以到社区看看看;张少华同学本篇主要讲HBase的MOB压缩分区策略介绍,非常赞!大力推荐!

    大数据和云计算技术
  • 云​大数据和计算技术周报(第43期)

    “大数据” 三个字其实是个marketing语言,从技术角度看,包含范围很广,计算、存储、网络都涉及,知识点广、学习难度高。

    大数据和云计算技术
  • 算法基础6:二叉树查找

    算法是基础,小蓝同学准备些总结一系列算法分享给大家,这是第6篇《二叉树查找》,非常赞!希望对大家有帮助,大家会喜欢! 前面系列文章: 归并排序 #算法基...

    大数据和云计算技术
  • linux常用命令

    ls命令是Linux系统使用频率最多的命令,它的参数也是Linux命令中最多的。使用ls命令时会有几种不同的颜色,其中蓝色表示是目录,绿色表示是可执行文件,红色...

    用户1491101
  • linux

    ls命令是Linux系统使用频率最多的命令,它的参数也是Linux命令中最多的。使用ls命令时会有几种不同的颜色,其中蓝色表示是目录,绿色表示是可执行文件,红色...

    用户1491101
  • 那些你可能不了解的公有云风险成本

    公有云强调了给企业带来的种种好处,但是它并不十全十美。企业应该意识到其不可预测的成本结构以及其他的一些缺点。 ? 公有云服务给予企业诸多优势。他们允许灵活和经济...

    静一
  • kali更新源

    1.打开命令行输入ping www.baidu.com,停止方法请按CTRL+C 键停止监测,如果虚拟机给出了这个网站的延迟信息和IP就代表网络是正常的,如果没...

    酷酷的繁星
  • 关于谷歌浏览器无法加载安全控件设置说明

    当你安装完安全控件后谷歌无法加载,那是从Chrome 42+以后开始就不再支持安全控件了,使用Chrome浏览器正常安装安全控件后,重启浏览器进入登录页面,安全...

    小陈先生
  • Leetcode 116 Populating Next Right Pointers in Each Node

    Given a binary tree struct TreeLinkNode { TreeLinkNode *left; T...

    triplebee
  • Centos6.5安装配置mongodb

    上面的安装方法比较简单,但是有个问题,就是mongo启动必须同时制定data,也就是要运行mongod --dbpath /usr/local/mongo/da...

    奋斗蒙

扫码关注云+社区

领取腾讯云代金券