Hadoop运维记录系列(二十一)

Zeppelin启用https过程和Hack内核以满足客户需求的记录。

原因是这客户很有意思,该客户中国分公司的人为了验证内网安全性,从国外找了一个渗透测试小组对Zeppelin和其他产品进行黑客测试,结果发现Zeppelin主要俩问题,一个是在内网没用https,一个是zeppelin里面可以执行shell命令和python语句。其实这不算大问题,zeppelin本来就是干这个用的。但是渗透小组不了解zeppelin是做什么的,认为即使在内网里,执行shell命令能查看操作系统的一些文件是大问题,然后发生的事就不说了,不是我们的问题了。

不过既然他们要求整改,我们也只好配合,虽然大家都觉得内网域名加https属于脱了裤子放屁,然后不让zeppelin干他本来应该干的事就更过分了,但鉴于客户是甲方,也只好hack源码了。

于是某个周末用了4个小时完成所有工作。

先记录下zeppelin加https访问,我们有自己的域名证书,所以直接用即可。如果没有域名证书,需要自签发,那么可以看第二部分,双向认证步骤。

https第一部分,已有域名添加jks:

openssl pkcs12 -export -in xxx.com.crt -inkey xxx.com.key -out xxx.com.pkcs12
keytool -importkeystore -srckeystore xxx.com.pkcs12 -destkeystore xxx.com.jks -srcstoretype pkcs12

https第二部分,自签发证书双向认证添加jks

# 生成root私钥和证书文件。
openssl genrsa -out root.key(pem) 2048 # Generate root key file
openssl req -x509 -new -key root.key(pem) -out root.crt # Generate root cert file
# 创建客户端私钥和证书以及证书请求文件csr
openssl genrsa -out client.key(pem) 2048 # Generate client key file
openssl req -new -key client.key(pem) -out client.csr # Generate client cert request file
openssl x509 -req -in client.csr -CA root.crt -CAkey root.key(pem) -CAcreateserial -days 3650 -out client.crt # Use root cert to generate client cert file
# 生成服务器端私钥,证书和证书请求文件csr
openssl genrsa -out server.key(pem) 2048 # Generate server key file, use in Zeppelin
openssl req -new -key server.key(pem) out server.csr @ Generate server cert request file
openssl x509 -req -in server.csr -CA root.crt -CAkey root.key(pem) -CAcreateserial -days 3650 -out server.crt # Use root cert to generate server cert file
# 生成客户端端jks文件
openssl pkcs12 -export -in client.crt -inkey client.key(pem) -out client.pkcs12 # Package to pkcs12 format, must input a password, you should remember the password
keytool -importkeystore -srckeystore client.pkcs12 -destkeystore client.jks -srcstoretype pkcs12 # The client password you just input at last step
# 生成服务器端jks文件
openssl pkcs12 -export -in server.crt -inkey server.key(pem) -out server.pkcs12 @ Package to pkcs12 format, must input a password, you should remember the password
keytool -importkeystore -srckeystore server.pkcs12 -destkeystore server.jks -srcstoretype pkcs12 # The server password you just input at last step

如果是不需要双向认证,只要单向自签发,不创建客户端的各种就可以了。

然后找个地把这些文件放过去,再修改zeppelin配置即可。

mkdir -p /etc/zeppelin/conf/ssl
cp server.crt server.jks /etc/zeppelin/conf/ssl
<property>
  <name>zeppelin.server.ssl.port</name>
  <value>8443</value>
  <description>Server ssl port. (used when ssl property is set to true)</description>
</property>
<property>
  <name>zeppelin.ssl</name>
  <value>true</value>
  <description>Should SSL be used by the servers?</description>
</property>
<property>
  <name>zeppelin.ssl.client.auth</name>
  <value>false</value>
  <description>Should client authentication be used for SSL connections?</description>
</property>
<property>
  <name>zeppelin.ssl.keystore.path</name>
  <value>/etc/zeppelin/conf/ssl/xxx.com.jks</value>
  <description>Path to keystore relative to Zeppelin configuration directory</description>
</property>
<property>
  <name>zeppelin.ssl.keystore.type</name>
  <value>JKS</value>
  <description>The format of the given keystore (e.g. JKS or PKCS12)</description>
</property>
<property>
  <name>zeppelin.ssl.keystore.password</name>
  <value>password which you input on generating server jks step</value>
  <description>Keystore password. Can be obfuscated by the Jetty Password tool</description>
</property>

然后反代那里也加上443的ssl证书以及443转8443的upstream即可。

然后是hack zeppelin源码加入关键字限制,这个确实找了一小会zeppelin发送执行源码给interpreter的地方,zeppelin架构比较清晰,但是代码挺复杂的,用到了很多小花活儿。比如thrift,interpreter脚本里建立nc监听。然后各个解释器插件用socket跟interpreter脚本通信,前端angular,后端jetty,还用shiro做验证和授权。回头可以单开好几篇说说zeppelin安装,使用和详细配置,做这项目基本把zeppelin摸透了。

找到发送前端编写内容给interpreter的java代码,然后用很生硬的办法限制执行命令。具体那个.java文件的名字我就不说了,有悬念有惊喜。我不写java,只负责读源码找到代码位置,hack的java是同事写的。然后编译,替换jar包,完成。后面改了改配置,后续的渗透测试顺利通过。

static HashSet<String[]> blockedCodeString = new HashSet<>();
  static {
    blockedCodeString.add(new String[]{"import", "os"});
    blockedCodeString.add(new String[]{"import", "sys"});
    blockedCodeString.add(new String[]{"import", "subprocess"});
    blockedCodeString.add(new String[]{"import", "pty"});
    blockedCodeString.add(new String[]{"import", "socket"});
    blockedCodeString.add(new String[]{"import", "commands"});
    blockedCodeString.add(new String[]{"import", "paramiko"});
    blockedCodeString.add(new String[]{"import", "pexpect"});
    blockedCodeString.add(new String[]{"import", "BaseHTTPServer"});
    blockedCodeString.add(new String[]{"import", "ConfigParser"});
    blockedCodeString.add(new String[]{"import", "platform"});
    blockedCodeString.add(new String[]{"import", "popen2"});
    blockedCodeString.add(new String[]{"import", "copy"});
    blockedCodeString.add(new String[]{"import", "SocketServer"});
    blockedCodeString.add(new String[]{"import", "sysconfig"});
    blockedCodeString.add(new String[]{"import", "tty"});
    blockedCodeString.add(new String[]{"import", "xmlrpmlib"});
    blockedCodeString.add(new String[]{"etc"});
    blockedCodeString.add(new String[]{"boot"});
    blockedCodeString.add(new String[]{"dev"});
    blockedCodeString.add(new String[]{"lib"});
    blockedCodeString.add(new String[]{"lib64"});
    blockedCodeString.add(new String[]{"lost+found"});
    blockedCodeString.add(new String[]{"mnt"});
    blockedCodeString.add(new String[]{"proc"});
    blockedCodeString.add(new String[]{"root"});
    blockedCodeString.add(new String[]{"sbin"});
    blockedCodeString.add(new String[]{"selinux"});
    blockedCodeString.add(new String[]{"usr"});
    blockedCodeString.add(new String[]{"passwd"});
    blockedCodeString.add(new String[]{"useradd"});
    blockedCodeString.add(new String[]{"userdel"});
    blockedCodeString.add(new String[]{"rm"});
    blockedCodeString.add(new String[]{"akka "});
    blockedCodeString.add(new String[]{"groupadd"});
    blockedCodeString.add(new String[]{"groupdel"});
    blockedCodeString.add(new String[]{"mkdir"});
    blockedCodeString.add(new String[]{"rmdir"});
    blockedCodeString.add(new String[]{"ping"});
    blockedCodeString.add(new String[]{"nc"});
    blockedCodeString.add(new String[]{"telnet"});
    blockedCodeString.add(new String[]{"ftp"});
    blockedCodeString.add(new String[]{"scp"});
    blockedCodeString.add(new String[]{"ssh"});
    blockedCodeString.add(new String[]{"ps"});
    blockedCodeString.add(new String[]{"hostname"});
    blockedCodeString.add(new String[]{"uname"});
    blockedCodeString.add(new String[]{"vim"});
    blockedCodeString.add(new String[]{"nano"});
    blockedCodeString.add(new String[]{"top"});
    blockedCodeString.add(new String[]{"cat"});
    blockedCodeString.add(new String[]{"more"});
    blockedCodeString.add(new String[]{"less"});
    blockedCodeString.add(new String[]{"chkconfig"});
    blockedCodeString.add(new String[]{"service"});
    blockedCodeString.add(new String[]{"netstat"});
    blockedCodeString.add(new String[]{"iptables"});
    blockedCodeString.add(new String[]{"ip"});
    blockedCodeString.add(new String[]{"route "});
    blockedCodeString.add(new String[]{"curl"});
    blockedCodeString.add(new String[]{"wget"});
    blockedCodeString.add(new String[]{"sysctl"});
    blockedCodeString.add(new String[]{"touch"});
    blockedCodeString.add(new String[]{"scala.sys.process"});
    blockedCodeString.add(new String[]{"0.0.0.0"});
    blockedCodeString.add(new String[]{"git"});
    blockedCodeString.add(new String[]{"svn"});
    blockedCodeString.add(new String[]{"hg"});
    blockedCodeString.add(new String[]{"cvs"});
    blockedCodeString.add(new String[]{"exec"});
    blockedCodeString.add(new String[]{"ln"});
    blockedCodeString.add(new String[]{"kill"});
    blockedCodeString.add(new String[]{"rsync"});
    blockedCodeString.add(new String[]{"lsof"});
    blockedCodeString.add(new String[]{"crontab"});
    blockedCodeString.add(new String[]{"libtool"});
    blockedCodeString.add(new String[]{"automake"});
    blockedCodeString.add(new String[]{"autoconf"});
    blockedCodeString.add(new String[]{"make"});
    blockedCodeString.add(new String[]{"gcc"});
    blockedCodeString.add(new String[]{"cc"});
  }
  static boolean allMatch(String aim, String[] checker){
    if(checker == null || checker.length < 1){
      return false;
    }else {
      // by default, treat as match, every not match change it
      for (String i : checker) {
        if (!aim.matches(".*\\b" + i + "\\b.*")){
          return false;
        }
      }
      return true;
    }
  }
  static String anyMatch(String aim, HashSet<String[]> all) throws Exception{
    if(aim.contains("FUCK P&G")){
      throw  new Exception("How do you know this ????");
    } else {
      for (String[] one : all) {
        if (allMatch(aim, one)) {
          StringBuilder sb = new StringBuilder();
          for (String s : one) {
            sb.append(s + " ");
          }
          return sb.toString();
        }
      }
      throw new Exception("No one match");
    }
  }
  
  //......此处是个public类
  try{
      String matchesStrings = anyMatch(st, blockedCodeString);
      result = new InterpreterResult(Code.ERROR, "Contains dangerous code : " + matchesStrings);
    }catch (Exception me){ // no match any
      scheduler.submit(job);
      while (!job.isTerminated()) {
        synchronized (jobListener) {
          try {
            jobListener.wait(1000);
          } catch (InterruptedException e) {
            logger.info("Exception in RemoteInterpreterServer while interpret, jobListener.wait", e);
          }
        }
      }
      if (job.getStatus() == Status.ERROR) {
        result = new InterpreterResult(Code.ERROR, Job.getStack(job.getException()));
      } else {
        result = (InterpreterResult) job.getReturn();
        // in case of job abort in PENDING status, result can be null
        if (result == null) {
          result = new InterpreterResult(Code.KEEP_PREVIOUS_RESULT);
        }
      }
    }
  //......直到该public类结束

因为客户有deadline限制,所以快速定位源码位置的过程还是挺有意思的,比较紧张刺激,在这个以小时计算deadline压力下,什么intelliJ, Eclipse都不好使啊,就grep和vi最好用,从找到到改完,比客户定的deadline提前了好几个小时。

时间: 2025-01-09 03:20:36

Hadoop运维记录系列(二十一)的相关文章

Hadoop运维记录系列(二十三)

最近做集群机房迁移,在旧机房和新机房之间接了根专线,做集群不停机搬迁,也就是跨机房,同时要新加百多台服务器,遇到几个问题,记录一下. 旧集群的机器是centos 6, 新机房加的机器是centos 7. 一.丢包问题 在跨机房的时候,datanode显示很多Slow BlockReceiver的日志 WARN  org.apache.hadoop.hdfs.server.datanode.DataNode: Slow BlockReceiver write packet to mirror to

Hadoop运维记录系列(二十四)

从这篇开始记录一下集群迁移的事情 早先因为机房没地方,就已经开始规划集群搬机房的事情,最近终于开始动手了,我会把这次不停机迁移的过程遇到的主要问题和矛盾以及各种解决方法记录下来. 集群规模说大不大,几百台,总容量30PB左右.Hadoop使用CDH 5.5.1加一些自定义patch的rpm打包编译版本. 总的方案是集群不停机,在两个机房之间架设专线,旧机房decommission,拉到新机房recommission.每天不能下线太多机器,要保证计算. 新机房提前架设90台机器,测试带宽.带宽的测

Hadoop运维记录系列(十四)

周末去了趟外地,受托给某省移动公司做了一下Hadoop集群故障分析和性能调优,把一些问题点记录下来. 该系统用于运营商的信令数据,大约每天1T多数据量,20台Hadoop服务器,赞叹一下运营商乃真土豪,256G内存,32核CPU,却挂了6块2T硬盘.还有10台左右的服务器是64G内存,32核CPU,4~6块硬盘,据用户反馈,跑数据很慢,而且会有失败,重跑一下就好了. 软件环境是RedHat 6.2,CDH Hadoop 4.2.1. 总容量260多TB,已使用200多T. 首先,这硬件配置属于倒

Hadoop运维记录系列(十六)

应了一个国内某电信运营商集群恢复的事,集群故障很严重,做了HA的集群Namenode挂掉了.具体过程不详,但是从受害者的只言片语中大概回顾一下历史的片段. Active的namenode元数据硬盘满了,满了,满了...上来第一句话就如雷贯耳. 运维人员发现硬盘满了以后执行了对active namenode的元数据日志执行了 echo "" > edit_xxxx-xxxx...第二句话如五雷轰顶. 然后发现standby没法切换,切换也没用,因为standby的元数据和日志是5月

Hadoop运维记录系列(十五)

早期搭建Hadoop集群的时候,在做主机和IP解析的时候,通常的做法是写hosts文件,但是Hadoop集群大了以后做hosts文件很麻烦,每次加新的服务器都需要整个集群重新同步一次hosts文件,另外,如果在同一个域下面做两个集群,做distcp,也需要把两个集群的hosts文件全写完整并完全同步,很麻烦.那么,一劳永逸的办法就是做DNS.DNS我这边已经用了很长时间了,几年前为了学这个还专门买了一本巨厚的BIND手册. 做DNS服务器最常用的就是BIND,ISC开发并维护的开源系统. 以ce

openstack运维实战系列(二十)之neutron创建网络并指定vlan号码

1. 背景说明   neutron在openstack中负责instance的网络,如虚拟机内部网络,虚拟机外部网络等,和实体网络相类似,openstack中的网络也存在路由器router,交换机switch,网络network,子网subnet,端口port等概念,这些功能都有neutron来完成,neutron由有个不同的插件plugins组成,如二层插件neutron-openvswitch-agent,三层插件neutron-l3-agent,动态地址分配neutron-dhcp-age

轻松精通数据库管理之道——运维巡检系列

巡检是数据库管理员保证数据库健康的必要维护项,全面的巡检可以及早的发现问题.解决问题.预防问题. 很多数据库维护人员其实对数据库了解的并不深入(常常集中在传统行业),不是专业的DBA,同时又身兼多职(业务.软件.网络.硬件),在每天繁杂的工作中已经身心俱疲.这样的一种状态也必然让系统管理员即使有意精心呵护系统,但由于精力有限,不能深入学习,也找不到合适高效的方法去全面巡检自己的系统. 最终会导致什么样的结果的? 系统中存在大量的隐患,经常充当救火队员.拆弹兵的角色. 那么本系列用简单工具.易懂的

PowerShell 运维菜鸟系列-02-批量取n台Windows KEY(2018年大年初一奉献)

系列博文: PowerShell 运维菜鸟系列-01-批量为n台服务器导入PFX证书(2017年除夕奉献) http://blog.51cto.com/dynamic/2071716 项目场景: 2017年,某客户忽然来电:"我们单位正在查正版,我想知道所有加域的Windows电脑的激活KEY分别是什么?". 详细需求: 1. 操作系统版本 Windows XP.Windows 7.Windows 10.Windows Server 2003.Windows Server 2008 R

Linux运维 第二阶段 (二)vi编辑器

Linux运维第二阶段(二)vi编辑器 vi编辑器(全屏幕纯文本编辑器) 1.命令模式.插入模式.末行模式 2.   a       在光标所在字符后插入 A       在光标所在行行尾插入 i         在光标所在字符前插入 I       在光标所在行行首插入 o         在光标下插入新行 O       在光标上插入新行 :w       保存 :q        不保存退出 :wq     保存退出 :q!       强制退出 :w 文件名        另存为 3.H