0x01 前言
Jumpserver 作为一款国产的堡垒机,经过长时间的发展,目前已完善堡垒机应有的功能。但在实际使用的过程中依旧发现一些不足,具体使用的文章将在后续逐一发布,而今天这篇文章主要编写单机部署的流程。
Jumpserver 的官网如下:
这款软件是开源的,可以在这里找到源码:
同时,开发商飞致云提供有偿的技术支持、定制化与物理堡垒机出售等服务。
0x02 架构
以下是简单的架构图:
图中各组件的用途如下:
- Jumpserver:核心功能组件,用于管理整套系统
- KOKO:SSH Server,主要用于 SSH 与 Telnet 协议
- Guacamole:主要处理 RDP 与 VNC 协议
- LUNA:Web Terminal Server 前端
用户通过 IP 地址或者域名与方向代理器通讯,如上图中的 Nginx。Nginx 与 Jumpserver 进行通讯进行鉴权,如果是资产管理或用户管理等操作,也一样需要与 Jumpserver 进行通讯。
当用户需要打开 Web Terminal 时,如通过浏览器使用 SSH、Telnet、RDP、VNC 协议登入资产时, Nginx 则与 LUNA 进行通讯,此时用户会通过 WebSocket 进行连接,而 Jumpserver 则会通过 API 调用 Guacamole 与 KOKO。
目前暂支持用浏览器通过 WebSocket 与用户通讯的方式使用 RDP 与 VNC 协议,而 SSH 协议则支持直接连接至 KOKO 所暴露的端口。但在实际使用中,我会将 KOKO 的端口用 Nginx 代理。
单机部署的结构较为简单,只需要根据官方教程将所有组件部署完成即可。
0x03 准备
在部署过程中需要使用 YUM 安装多个 RPM 包、需要使用 python pip 安装几十个依赖包,还需要使用 Docker 部署两个容器。
为了提高软件的安装速度,需要使用以下镜像:
- Centos yum 源镜像:https://mirrors.tuna.tsinghua.edu.cn/help/centos/
- EPEL yum 源镜像:https://mirrors.tuna.tsinghua.edu.cn/help/epel/
- PYPI 镜像:https://mirrors.tuna.tsinghua.edu.cn/help/pypi/
而 Docker 可以使用微软 Azure 的镜像:
- Azure 镜像地址:dockerhub.azk8s.cn
在部署过程中需要安装 Mariadb,此时可以使用以下 repo 文件:
[mariadb] name = MariaDB baseurl = https://mirrors.ustc.edu.cn/mariadb/yum/10.2/centos7-amd64 gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB gpgcheck=1
如果你不太了解上面所说的,可以尝试逐一执行这些命令:
删除 yum 源:
rm -rf /etc/yum.repos.d/Centos*.repo
写入清华镜像站 Centos 的内容:
cat > /etc/yum.repos.d/centos.repo << EOF [base] name=CentOS-\$releasever - Base baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos/\$releasever/os/\$basearch/ gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 #released updates [updates] name=CentOS-\$releasever - Updates baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos/\$releasever/updates/\$basearch/ gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 #additional packages that may be useful [extras] name=CentOS-\$releasever - Extras baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos/\$releasever/extras/\$basearch/ gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 #additional packages that extend functionality of existing packages [centosplus] name=CentOS-\$releasever - Plus baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos/\$releasever/centosplus/\$basearch/ gpgcheck=1 enabled=0 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 EOF
安装 epel 源
yum install epel-release -y
写入清华镜像站 epel 的内容:
cat > /etc/yum.repos.d/epel.repo << EOF [epel] name=Extra Packages for Enterprise Linux 7 - \$basearch baseurl=https://mirrors.tuna.tsinghua.edu.cn/epel/7/\$basearch failovermethod=priority enabled=1 gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7 EOF
写入 USTC 镜像站 epel 的内容:
cat > /etc/yum.repos.d/mariadb.repo << EOF [mariadb] name = MariaDB baseurl = https://mirrors.ustc.edu.cn/mariadb/yum/10.2/centos7-amd64 gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB gpgcheck=1 EOF
最后添加 docker-ce 稳定版的清华镜像:
cat > /etc/yum.repos.d/docker.repo << EOF [docker-ce-stable] name=Docker CE Stable - \$basearch baseurl=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/7/\$basearch/stable enabled=1 gpgcheck=0 gpgkey=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/gpg EOF
在这里之后要安装 docker-ce:
yum clean all && yum install docker-ce -y
在启动 docker 前,建议使用 Azure docker 仓库镜像:
mkdir /etc/docker/ && cat > /etc/docker/daemon.json << EOF { "registry-mirrors": [ "https://dockerhub.azk8s.cn" ] } EOF
还需要开启系统的 IPv4 转发功能以及调整最大 fd 数量:
cat >> /etc/sysctl.conf << EOF net.ipv4.ip_forward = 1 fs.nr_open = 10245760000 EOF
使其立即生效:
sysctl -p
启动 docker:
systemctl enable docker \ && systemctl restart docker \ && systemctl status docker
至此,准备工作全部完成。
在测试环境中,可以关闭 selinux 以及防火墙;在生产环境中,可以关掉 selinux,但务必打开防火墙并使用白名单模式放行 IP 以及 端口:
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config \ && setenforce 0 \ && systemctl disable firewalld \ && systemctl stop firewalld
建议重启系统,其实不重启也可以。
0x04 Jumpserver
首先使用 yum 安装各类依赖包:
yum install -y wget gcc git redis python36 python36-devel \ openssl-devel GeoIP-devel \ MariaDB-client MariaDB-server MariaDB-devel MariaDB-shared
启动 redis:
systemctl enable redis \ && systemctl start redis
启动 MariaDB:
systemctl enable mariadb \ && systemctl start mariadb
生成 MariaDB 密码并初始化数据库:
DB_PASSWORD=`cat /dev/urandom | tr -dc A-Za-z0-9 | head -c 24` \ && echo -e "\033[31m 你的数据库密码是 $DB_PASSWORD \033[0m" \ && mysql -uroot -e "create database jumpserver default charset 'utf8'; \ grant all on jumpserver.* to 'jumpserver'@'127.0.0.1' identified by '$DB_PASSWORD'; \ flush privileges;"
请将数据库密码复制并即在合适的地方备用:
创建 python3 虚拟环境:
cd /opt \ && python3.6 -m venv py3 \ && source /opt/py3/bin/activate
如果需要退出虚拟环境或进入虚拟环境,可执行以下命令:
# 进入虚拟环境 source /opt/py3/bin/activate # 推出虚拟环境 deactivate
在 opt 目录下 clone jumpserver 的源码到本地,建议使用 git clone,如果遇到网络问题,可以使用 http 或 https proxy;如果服务器无法联网,也可以下载 zip 压缩包到本地压缩,但是在后期升级时会比较繁琐。
# 配置 git 使用 proxy,若网络较好,可以跳过 # 请根据实际情况修正 proxy 服务器地址 git config --global http.proxy http://10.1.1.11:10809
然后克隆源码到本地:
cd /opt \ && git clone --depth=1 \ https://github.com/jumpserver/jumpserver.git
安装 RPM 依赖包:
yum -y install $(cat /opt/jumpserver/requirements/rpm_requirements.txt)
配置 PYPI 镜像:
# 升级 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pip -U # 配置全局默认仓库 pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
安装 Python 库依赖:
pip install wheel \ && pip install setuptools \ && pip install -r /opt/jumpserver/requirements/requirements.txt
最终的结果如下:
如果出现类似首两行的版本错误,可以忽略。
至此,Jumpserver 基础环境已经完成部署,接下来要对他进行配置。
首先进入 Jumpserver 的目录,复制一份配置文件:
cd /opt/jumpserver \ && cp config_example.yml config.yml
然后生成 SECRET_KEY 和 BOOTSTRAP_TOKEN,同时将它们写入 bashrc 文件中用于日后的变量赋值:
# SECRET_KEY SECRET_KEY=`cat /dev/urandom | tr -dc A-Za-z0-9 | head -c 50` \ && echo "SECRET_KEY=$SECRET_KEY" >> ~/.bashrc # BOOTSTRAP_TOKEN BOOTSTRAP_TOKEN=`cat /dev/urandom | tr -dc A-Za-z0-9 | head -c 16` \ && echo "BOOTSTRAP_TOKEN=$BOOTSTRAP_TOKEN" >> ~/.bashrc # 打印 SECRET_KEY echo -e "\033[31m 你的SECRET_KEY是 $SECRET_KEY \033[0m" # 打印 BOOTSTRAP_TOKEN echo -e "\033[31m 你的BOOTSTRAP_TOKEN是 $BOOTSTRAP_TOKEN \033[0m"
接下来对配置文件进行修改,你也可以使用 vim 等方式打开文件逐一修改,可以使用官方文档里的 sed 命令修改。其实配置文件内没有很多需要修改的参数,可以直接使用 sed 修改。
# 填充 SECRET_KEY sed -i "s/SECRET_KEY:/SECRET_KEY: $SECRET_KEY/g" /opt/jumpserver/config.yml # 填充 BOOTSTRAP_TOKEN sed -i "s/BOOTSTRAP_TOKEN:/BOOTSTRAP_TOKEN: $BOOTSTRAP_TOKEN/g" /opt/jumpserver/config.yml # 关闭 DEBUG 模式 sed -i "s/# DEBUG: true/DEBUG: false/g" /opt/jumpserver/config.yml # 修改日志级别 sed -i "s/# LOG_LEVEL: DEBUG/LOG_LEVEL: ERROR/g" /opt/jumpserver/config.yml # 设定当浏览器关闭时将 session 设为已过期 sed -i "s/# SESSION_EXPIRE_AT_BROWSER_CLOSE: false/SESSION_EXPIRE_AT_BROWSER_CLOSE: true/g" /opt/jumpserver/config.yml # 填充 DB_PASSWORD sed -i "s/DB_PASSWORD: /DB_PASSWORD: $DB_PASSWORD/g" /opt/jumpserver/config.yml
至此,所有 Jumpserver 核心部分的安装与配置工作以完成,最后启动即可。在启动的时候要确认处于 py3 虚拟环境内:
source /opt/py3/bin/activate \ && /opt/jumpserver/jms start -d
启动的时候可能会出现以下错误:
[root@b6ae77 ~]# source /opt/py3/bin/activate \ > && /opt/jumpserver/jms start -d Traceback (most recent call last): File "/opt/jumpserver/jms", line 16, in <module> import daemon ModuleNotFoundError: No module named 'daemon'
请在 py3 虚拟环境中执行:
pip install python-daemon
最后再执行上面的启动命令即可,最终的结果如下:
最后还需要将启动命令加入到 rc.local 文件:
echo 'source /opt/py3/bin/activate && /opt/jumpserver/jms start -d' >> /etc/rc.local \ && chmod +x /etc/rc.d/rc.local
到这里,Jumpserver 核心部分的所有工作已经完成。
0x05 前端
前端包含两部分,分别是 LUNA 和 Nginx,首先部署 LUNA。此时如果还在 Python 的虚拟环境里,可以退出:
(py3) [root@b6ae77 jumpserver]# deactivate [root@b6ae77 jumpserver]#
然后下载 LUNA 并解压:
cd /opt \ && wget https://demo.jumpserver.org/download/luna/1.5.5/luna.tar.gz \ && tar xf luna.tar.gz \ && chown -R root:root luna
因为下一篇文章会详细讲解分布式部署的流程,而分布式部署需要使用 Nginx stream 模块,但是这个模块并不是 Nginx 默认的模块,所以需要自行编译。
为了尽可能减少区别,我决定在这一篇文章里也使用自行编译的 Nginx。其实过程及其简单,只需要执行以下命令即可:
curl https://nginx.org/download/nginx-1.16.1.tar.gz -o /tmp/nginx-1.16.1.tar.gz \ && tar zxvf /tmp/nginx-1.16.1.tar.gz -C /tmp/ \ && cd /tmp/nginx-1.16.1/ \ && ./configure \ --prefix=/usr/local/nginx \ --sbin-path=/usr/sbin/nginx \ --conf-path=/usr/local/nginx/nginx.conf \ --pid-path=/var/run/nginx.pid \ --error-log-path=/var/log/nginx/error.log \ --http-log-path=/var/log/nginx/access.log \ --lock-path=/var/lock/nginx.lock \ --with-stream \ --with-http_realip_module \ --with-http_ssl_module \ --with-http_stub_status_module \ --with-http_sub_module \ --with-http_v2_module \ --with-http_geoip_module \ --with-file-aio \ --http-client-body-temp-path=/var/tmp/nginx/client_body \ --http-proxy-temp-path=/var/tmp/nginx/proxy \ --http-fastcgi-temp-path=/var/tmp/nginx/fastcgi \ --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi \ --http-scgi-temp-path=/var/tmp/nginx/scgi \ && make -j 2 \ && make install \ && groupadd nginx \ && useradd -M -s /sbin/nologin -g nginx nginx \ && mkdir -p /var/tmp/nginx/client_body \ && mkdir -p /usr/local/nginx/conf.d
nginx.conf 的配置文件比较简单,如果有需要,请自行定制:
cat > /usr/local/nginx/nginx.conf << EOF user nginx; worker_processes auto; error_log /var/log/nginx/error.log; pid /run/nginx.pid; include /usr/share/nginx/modules/*.conf; events { worker_connections 1024; } http { log_format main '\$remote_addr - \$remote_user [\$time_local] "\$request" ' '\$status \$body_bytes_sent "\$http_referer" ' '"\$http_user_agent" "\$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; include /usr/local/nginx/mime.types; default_type application/octet-stream; include /usr/local/nginx/conf.d/*.conf; } EOF
还需要添加jumpserver.conf配置文件:
cat > /usr/local/nginx/conf.d/jumpserver.conf << EOF server { listen 80; # 录像及文件上传大小限制 client_max_body_size 100m; location /luna/ { try_files $uri / /index.html; # luna 路径, 如果修改安装目录, 此处需要修改 alias /opt/luna/; } location /media/ { add_header Content-Encoding gzip; # 录像位置, 如果修改安装目录, 此处需要修改 root /opt/jumpserver/data/; } location /static/ { # 静态资源, 如果修改安装目录, 此处需要修改 root /opt/jumpserver/data/; } location /koko/ { proxy_pass http://localhost:5000; proxy_buffering off; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; access_log off; } location /ws/ { proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://localhost:8070; proxy_http_version 1.1; proxy_buffering off; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } location /guacamole/ { proxy_pass http://localhost:8081/; proxy_buffering off; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $http_connection; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; access_log off; } location / { proxy_pass http://localhost:8080; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } EOF
最后启动即可:
echo 'nginx' >> /etc/rc.local \ && nginx
前端的部分也已经完成,通过浏览器打开 Jumpserver 的页面并输入默认的超级用户账号与密码即可登入:
- 默认账号:admin
- 默认密码:admin
打开 web终端 可以测试 LUNA 是否工作正常:
0x06 终端
终端包含 KOKO 与 Guacamole,这两个终端正如本文开头所说的,分别对应 CLI 与 GUI 界面。在部署前先检查服务器 IP 是否正确以及系统变量中是否存在 BOOTSTRAP_TOKEN:
Server_IP=`ip addr | grep 'state UP' -A2 | grep inet \ | egrep -v '(127.0.0.1|inet6|docker)' | awk '{print $2}' | tr -d "addr:" \ | head -n 1 | cut -d / -f1` \ && echo -e "\033[31m 你的服务器IP是 $Server_IP \033[0m" \ && echo -e "\033[31m 你的BOOTSTRAP_TOKEN是 $BOOTSTRAP_TOKEN \033[0m"
如果值不对或没有值,可以手动指定:
# 手动指定 Server_IP Server_IP=10.1.1.1 # 手动指定 BOOTSTRAP_TOKEN BOOTSTRAP_TOKEN=aaabbbccc
然后执行以下命令即可完成部署:
# KOKO docker run --name jms_koko -d -p 2222:2222 -p 127.0.0.1:5000:5000 \ -e CORE_HOST=http://$Server_IP:8080 \ -e BOOTSTRAP_TOKEN=$BOOTSTRAP_TOKEN \ --restart=always \ jumpserver/jms_koko:1.5.5
# Guacamole docker run --name jms_guacamole -d -p 127.0.0.1:8081:8080 \ -e JUMPSERVER_SERVER=http://$Server_IP:8080 \ -e BOOTSTRAP_TOKEN=$BOOTSTRAP_TOKEN \ --restart=always \ jumpserver/jms_guacamole:1.5.5
使用以下命令检查运行情况:
docker ps
现在再回到 Jumpserver 前端,进入终端列表,应该可以看到刚才新增的两个终端:
Guacamole 需要添加资产才能测试,但是 SSH 可以立刻测试,KOKO 的默认端口是 TCP 2222,使用以下命令即可登入:
ssh [email protected] -p 2222
如果测试成功,说明服务以完成部署。
0x07 结语
因为篇幅的关系,这里没有详细描述使用方面的信息,下一篇文章将讲解分布式部署的案例与部署方式。
在部署的时候要注意各个组件的版本尽可能一致,以免出现不必要的问题。
更重要的是需要自行考量安全问题,尤其是各个端口的放行与拦截,建议为 Jumpserver 使用白名单模式的防火墙。