隔离网络的难处

首先隔离网络是指与互联网隔离的局域网,常见的有党政单位的保密网、政务网、校园网、公司内部网络。
隔离网络有以下几个特点:

  1. 与互联网一定程度的隔离,比较常见做法是使用网控设备设置 ACL 规则实现逻辑隔离,保密级别较高的情况下会断开物理链路实现物理隔离

  2. 无法获取直接获取互联网的公共资源,例如Yum、apt、python-pypi、dockerhub、maven、npm、rubygems、Windows补丁等,内部的设备安装或更新软件都很困难。

  3. 安全防控力度强,需要通过堡垒机、跳板机等才能访问到内部资源,软件、数据进出内部网络都需要经过安全检查;

在运维工作中,自然少不了使用各种工具、各种脚本的

运维人员在日常工作当中,自然少不了使用各种工具、编写各类脚本。能找到现成的 rpm、deb 包还算好的,如果是碰上 Python、Nodejs、Ruby 这类型的脚本程序,装依赖包会让你怀疑人生。

解决方案

最我们可以利用Docker的特性,把我们日常需要的各类 cli 工具打包到 Docker 镜像里面,再拷贝到隔离网络里面,通过 docker run 的方式运行。
事不宜迟,直接上干货。

我们需要准备两台 Linux 机器:

  1. 一台能连接互联网的 A 机,用作 docker 镜像打包;
  2. 一台隔离网络内部的 B 机,运维机,用于运行各类工具;

制作运维工具镜像

打包镜像在 A 机上操作,先在上面安装好打包用的 Docker,由于 A 机在互联网环境,安装 Docker 很简单,这里也不赘述了。

基础镜像选用 Alpine Linux
首先它的体积特别小,最简单的环境只需要 5M,把我们需要软件打包进去之后,镜像也是相对小巧的。
其次,Alpine 拥有自己的包管理工具 apk,在线源也是很丰富,可以通过 https://pkgs.alpinelinux.org/packages 网站上查询包信息,也可以直接通过 apk 命令直接查询和安装各种软件。

网上有很多 alpine、Ubuntu、Debian、CentOS 作为基础镜像的比较,这里就不再赘述

Dockerfile

FROM alpine:3.13.0
LABEL maintainer="LinJiaJian <honos628@foxmail.com>"

# 工作目录设在 /tmp 可以避免产生权限的问题
WORKDIR /tmp

# 替换成国内的清华的 apk 源,提高 Docker Build 的速度
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories && \
    apk add --no-cache \
    # 在这里找需要的软件包,https://pkgs.alpinelinux.org/packages,名字对应加上去就好
        bash \
        bash-completion \
        # vim \
        curl \
        # openssh-client \
        busybox-extras \
        redis \
        mysql-client \
        jq \
        bind-tools \
        # ca-certificates \
        tcptraceroute \
        mtr \
        iproute2 \
        # postgresql-client \
        ansible \
        tzdata && \
    # 调整成上海时区,避免一些时区的问题
    cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    echo "Asia/Shanghai" > /etc/timezone && \
    apk del tzdata

# alpine没有 tcping 现成的软件包,需要使用 tcptraceroute + 脚本的形式来使用,所以要这样装
RUN curl -s 'http://www.vdberg.org/~richard/tcpping' -o /bin/tcpping && \
    chmod 755 /bin/tcpping && \
    ln -s /bin/tcpping /bin/tcping

# ENTRYPOINT设置成这样,在docker run的时候比较方便
ENTRYPOINT ["/bin/bash", "-c"]

构建脚本

打包构建的脚本 build.sh 放在 Dockerfile 同级目录

#!/usr/bin/env bash
# --------------------
# File: build.sh
# Project: ops_tools
# Purpose: 打包构建 ops tools,每次都刷新latest
# Author: Jan Lam (honos628@foxmail.com)
# Last Modified: 2021-01-30 14:24:37
# --------------------

VERSION="1.2.0"

docker build --no-cache \
  -t honos628/ops_tools:${VERSION} \
  -t honos628/ops_tools:latest \
  .

# 清理 <none> 的 docker image
docker images |grep none |awk '{print $3}' |xargs docker rmi

# 打包压缩
rm -f *.tar *.xz
docker save -o honos628__ops_tools.tar honos628/ops_tools:latest
xz honos628__ops_tools.tar

打包

$ sudo bash build.sh

Sending build context to Docker daemon  48.78MB
Step 1/6 : FROM alpine:3.13.0
 ---> 7731472c3f2a
Step 2/6 : LABEL maintainer="LinJiaJian <honos628@foxmail.com>"
 ---> Running in 3f76499dfb25

...
Successfully built b2f36a6850c3
Successfully tagged honos628/ops_tools:1.2.0
Successfully tagged honos628/ops_tools:latest

Deleted: sha256:34015687c8512959067cfa75bdf1b7263eda2ef9a811344c0ece998143e844eb
Deleted: sha256:560634b288c41c9204ef9b6d11832873896a4ecbac86402fa8251ffb8c3bd04d
Deleted: sha256:3a11d94fdc0c29dc166b108e80af4ef5c1256b22bc66eb3bbefcb4e4ccb7f89c
...

# 看到 Successfully 基本就没啥问题了。
# 再看看docker镜像
$ sudo docker images
REPOSITORY                         TAG             IMAGE ID       CREATED         SIZE
honos628/ops_tools                 1.2.0           b2f36a6850c3   4 minutes ago   381MB
honos628/ops_tools                 latest          b2f36a6850c3   4 minutes ago   381MB
alpine                             3.13.0          7731472c3f2a   2 weeks ago     5.61MB

# 其实因为我装了 ansible,后面有一大堆 python 的依赖,镜像才会这么大。
# 装装一些编译好的工具,镜像估计只有50M左右。

$ sudo ls -ltrsh
total 47M
4.0K -rw-rw-r-- 1 jan jan 1.1K Jan 30 14:32 Dockerfile
4.0K -rwxrwxr-x 1 jan jan  578 Jan 30 14:32 build.sh
 47M -rw------- 1 jan jan  47M Jan 30 14:34 honos628__ops_tools.tar.xz

# 压缩之后只有47M

honos628_ops_tools.tar.xz 就是我们工具箱镜像了。

配置隔离网络运维机

隔离网络的运维机(B 机),也需要安装 docker 运行环境。这里以 CentOS 7.5 以及最新版本的 Docker 20.10.1 举例。
没有 YUM 源,所以我们将相关 rpm 包都下载好,大概 100M 左右。

$ sudo ls -ltrsh

total 103M
9.1M -rw-r--r-- 1 root root 9.1M Jan  5 10:53 docker-ce-rootless-extras-20.10.1-3.el7.x86_64.rpm
 34M -rw-r--r-- 1 root root  34M Jan  5 10:53 docker-ce-cli-20.10.1-3.el7.x86_64.rpm
 27M -rw-r--r-- 1 root root  27M Jan  5 10:53 docker-ce-20.10.1-3.el7.x86_64.rpm
 34M -rw-r--r-- 1 root root  34M Jan  5 10:53 containerd.io-1.4.3-3.1.el7.x86_64.rpm
 56K -rw-r--r-- 1 root root  55K Jan  5 11:12 fuse-overlayfs-0.7.2-6.el7_8.x86_64.rpm
 84K -rw-r--r-- 1 root root  82K Jan  5 11:12 slirp4netns-0.4.3-4.el7_8.x86_64.rpm
 60K -rw-r--r-- 1 root root  57K Jan  5 11:12 libseccomp-2.3.1-4.el7.x86_64.rpm
 40K -rw-r--r-- 1 root root  40K Jan  5 11:12 container-selinux-2.119.2-1.911c772.el7_8.noarch.rpm
 84K -rw-r--r-- 1 root root  82K Jan  5 11:16 fuse3-libs-3.6.1-4.el7.x86_64.rpm

# 全部装上去就好了。
$ sudo rpm -Uvh *.rpm

$ sudo systemctl start docker
$ sudo docker ps
CONTAINER ID   IMAGE   COMMAND   CREATED   STATUS   PORTS   NAMES

# docker ps有正常返回就好

把刚才我们打包好的honos628__ops_tools.tar.xz也放上去,解压并导入 docker

# 解压
$ sudo xz -d honos628__ops_tools.tar.xz

# 导入
$ sudo docker load -i honos628__ops_tools.tar
Loaded image: honos628/ops_tools:latest

# 查看下镜像
$ sudo docker images
REPOSITORY                         TAG             IMAGE ID       CREATED         SIZE
honos628/ops_tools                 latest          b2f36a6850c3   4 minutes ago   381MB

工具使用方法

工具导入完成之后,直接运行 docker run 就可以达到效果了

$ docker run --rm honos628/ops_tools "mysql --version"
mysql  Ver 15.1 Distrib 10.5.8-MariaDB, for Linux (x86_64) using readline 5.1


$ docker run --rm honos628/ops_tools "redis-cli --version"
redis-cli 6.0.10 (git:63eb61be-dirty)


$ docker run --rm honos628/ops_tools "curl -sI www.baidu.com"
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
Connection: keep-alive
Content-Length: 277
Content-Type: text/html
Date: Sat, 30 Jan 2021 18:35:14 GMT
Etag: "575e1f6f-115"
Last-Modified: Mon, 13 Jun 2016 02:50:23 GMT
Pragma: no-cache
Server: bfe/1.0.8.18

但是!运行起来实在太麻烦了。敲一大坨命令,一点也不优雅。我们可以利用 shell 脚本再改造一下。

例子 1 redis-cli

我们以 redis-cli 为例,做一个脚本

redis-cli.sh

#!/usr/bin/env bash
# --------------------
# File: redis-cli.sh
# Project: ops_tools
# Purpose: 模拟redis-cli
# Author: Jan Lam (honos628@foxmail.com)
# Last Modified: 2021-01-31 02:44:59
# --------------------
#!/bin/env bash

ARGS="$*"

#echo $ARGS
docker run --rm -it --network host \
  honos628/ops_tools \
  "redis-cli ${ARGS}"

拷贝到 PATH,软连接、赋予执行权限


$ cp ./redis-cli.sh /usr/local/sbin/redis-cli.sh
$ cd /usr/local/sbin/
$ chmod +x redis-cli.sh
$ ln -s redis-cli.sh redis-cli

# OK,我们运行一下试试

$ redis-cli -h 192.168.33.33 -p 3480 -a secret_password info

Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
# Server
redis_version:4.1.1
redis_git_sha1:afb9ef6e
redis_git_dirty:0
redis_build_id:764b9ad3431f8368
redis_mode:cluster
os:Linux 3.10.0-957.27.2.el7.x86_64 x86_64
.....
# Cluster
cluster_enabled:1

# Keyspace
db0:keys=15497,expires=13870,avg_ttl=1069050

例子 2 ansible

ansible 更为复杂点,涉及 ansible.cfg、hosts 文件、playbook 的剧本文件。所以我们要把目录挂载到容器里面。

# ansible 目录我设置在了/opt/ansible_home,随便写了一些配置,下面是目录结构

/opt/ansible_home/
├── ansible.cfg
├── hosts
├── roles
│   ├── nginx_lb
│   │   ├── files
│   │   └── tasks
│   │       └── main.yml
│   └── users
│       ├── files
│       └── tasks
│           └── main.yml
└── setup.yml

ansible.sh

#!/usr/bin/env bash
# --------------------
# File: ansible.sh
# Project: ops_tools
# Purpose: 模拟ansible脚本
# Author: Jan Lam (honos628@foxmail.com)
# Last Modified: 2021-01-31 02:43:57
# --------------------
#!/bin/env bash

ARGS="$*"

#echo $ARGS
WORKDIR="/mnt"
ANSIBLE_HOME="/opt/ansible_home"

[[ ! -d "${ANSIBLE_HOME}" ]] && mkdir -p ${ANSIBLE_HOME}
echo "Ansible Home is: ${ANSIBLE_HOME}"
cd ${ANSIBLE_HOME}
#ls -ltrsh
echo "----"

docker run --rm -it --network host \
  -w ${WORKDIR} \
  -v ${ANSIBLE_HOME}:${WORKDIR} \
  honos628/ops_tools \
  "ansible ${ARGS}"

拷贝到 PATH,软连接、赋予执行权限


$ cp ./ansible.sh /usr/local/sbin/ansible.sh
$ cd /usr/local/sbin/
$ chmod +x ansible.sh
$ ln -s ansible.sh ansible

# 试运行

$ ansible all -mping
Ansible Home is: /opt/ansible_home
----
192.168.34.194 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
192.168.34.217 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
192.168.34.200 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

## 需要注意,因为脚本引号的问题,所以参数带引号的要转义一下

$ ansible all -mshell -a \"ls -ltrsh\"
Ansible Home is: /opt/ansible_home
----
192.168.34.217 | CHANGED | rc=0 >>
total 0
192.168.34.194 | CHANGED | rc=0 >>
total 0
192.168.34.200 | CHANGED | rc=0 >>
total 0

其他命令也类似这样用脚本处理一下就好了。
无论是运行速度,还是运行的手感、反馈结果,都与真实的命令没太大区别。
完美 >_<


 目录