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提前了好几个小时。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
中国的根服务器拥有自主权了吗?
【大咖・来了 第7期】10月24日晚8点观看《智能导购对话机器人实践》 近日,工信部发布公告批复两家国内机构设立域名根服务器运行机构,负责运行、维护和管理域名根服务器(根镜像服务器)。随后,域名国家工程研究中心又推出了搭载龙芯CPU的域名服务器以及国产域名管理软件“红枫系统”2.0版。这一系列动作随即引起社会广泛关注,出现了“中国建设域名根服务器”、“中国互联网不再受制于人”等讨论。 实际上,两家机构建设的仅是域名根服务器的镜像服务器,其在全世界范围内有近一千台。目前,在IPv4协议上,全球13台根服务器都为美国、欧洲、日本所有,中国尚无根服务器。但中国有能力应对来自根服务器上的隐患,让中国网民正常上网不受影响。不过,企业域名一旦出现问题可能出现“断网”现象。 当前,中、美、日等国正在构建下一代互联网协议Ipv6,其中中国部署了4台根服务器。在各国加快发展Ipv6的浪潮下,中国此前似乎出现了“掉队”。但自2018年底起,国内的大规模服务网络开始明显向Ipv6迁移。到今年5月,中国Ipv6互联网用户已快速增长至超过2亿,且有望成为Ipv6最大用户市场。 域名根服务器“三重奏” 2019...
- 下一篇
Django+ PowerShell 管理AD系统
QQ群里的Evan童鞋分享了一个很有意思的博客http://note.youdao.com/noteshare?id=a60709c00fe88cd09155a2ef50815281 大概是如何利用Flask 调用 Powershell API 实现的一个运维管理系统。 豆子依葫芦画瓢,用Django成功地实现了有一个简单的界面。 直接用Bootstrap模板弄个前端页面,Django 框架,然后后台调用PowerShell API实现查询。 下面是一个简单的demo,输入AD的组,显示组成员 Django没啥好说的,基本的MTV框架流程,主要比较好玩的是这个PowerShell API的模块。网上有现成的HttpListener的模块可以下载,QQ群里的童鞋做了些修改,去掉了一个验证的功能,如果有需求,可以自己手动添加一个函数进去。我这里图省事是直接用的去验证的版本。 这个模块下载导入之后就可以执行了,他提供了一个类似restful的接口来执行Powershell的命令,直接Http get请求对应的接口,然后返回json格式的结果 Import-ModuleC:\users\yua...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Hadoop3单机部署,实现最简伪集群
- CentOS7安装Docker,走上虚拟化容器引擎之路
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS7设置SWAP分区,小内存服务器的救世主
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作