作者:老Z,中电信数智科技有限公司山东分公司运维架构师,云原生爱好者,现在专心于云原生运维,云原生范畴技术栈涉及 Kubernetes、KubeSphere、DevOps、OpenStack、Ansible 等。

修复 KubeSphere 内置 Jenkins 的 Apache Log4j2 漏洞

简介

出产环境 KubeSphere 3.3.0 部署的 Kubernetes 集群在安全评估的时候发现安全缝隙,其间一项缝隙提示目标或许存在 Apache Log4j2 长途代码履行缝隙 (CVE-2021-44228)

本文记录了该缝隙修正的全部进程,文中介绍了修正该缝隙的两种处理计划,其间涉及自定义构建 KubeSphere 适用的 Jenkins Image 的详细操作。

缝隙修正计划

缝隙详细信息

缝隙陈述中涉及缝隙 目标或许存在 Apache Log4j2 长途代码履行缝隙 (CVE-2021-44228) 的详细信息如下:

修复 KubeSphere 内置 Jenkins 的 Apache Log4j2 漏洞

修复 KubeSphere 内置 Jenkins 的 Apache Log4j2 漏洞

缝隙剖析

  1. 剖析缝隙陈述信息,发现对应的服务端口为 30180,对应的服务为 Jenkins。运用 Curl 拜访服务端口,检查返回头信息。
[root@ks-k8s-master-0 ~]# curl -I http://192.168.9.91:30180
HTTP/1.1 403 Forbidden
Date: Thu, 09 Feb 2023 00:36:45 GMT
X-Content-Type-Options: nosniff
Set-Cookie: JSESSIONID.b1c3bc24=node084x6l5z2ss0ghsb2t9tde2gl16558.node0; Path=/; HttpOnly
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Content-Type: text/html;charset=utf-8
X-Hudson: 1.395
X-Jenkins: 2.319.1
X-Jenkins-Session: 1fde6067
Content-Length: 541
Server: Jetty(9.4.43.v20210629)

阐明: 从成果中能够看到 KubeSphere 3.3.0 选用的 Jenkins 运用的 Jetty 版别为 9.4.43.v20210629,跟漏扫陈述中的成果一致。

  1. 在 K8s 中检查 Jenkins 服务运用的 Image 版别。
[root@ks-k8s-master-0 ~]# kubectl get deploy  devops-jenkins -n kubesphere-devops-system -o wide
NAME             READY   UP-TO-DATE   AVAILABLE   AGE    CONTAINERS       IMAGES                                                                    SELECTOR
devops-jenkins   1/1     1            1           101d   devops-jenkins   registry.cn-beijing.aliyuncs.com/kubesphereio/ks-jenkins:v3.3.0-2.319.1   component=devops-jenkins-master

阐明: 从成果中能够看到 KubeSphere 3.3.0 选用的 Jenkins 版别为 2.319.1,跟漏扫陈述中的成果一致。

  1. 在 K8s 中确认 Jenkins 哪些组件用到了跟 Log4j 有关的 JAR 包。
  • 查找 Jenkins 服务对应的 Pod。
[root@ks-k8s-master-0 ~]# kubectl get pod -n kubesphere-devops-system -o wide
NAME                                 READY   STATUS      RESTARTS        AGE    IP               NODE              NOMINATED NODE   READINESS GATES
devops-27930510-52tck                0/1     Completed   0               87m    10.233.116.224   ks-k8s-master-2   <none>           <none>
devops-27930540-6b7cz                0/1     Completed   0               57m    10.233.116.225   ks-k8s-master-2   <none>           <none>
devops-27930570-t5k6b                0/1     Completed   0               27m    10.233.116.226   ks-k8s-master-2   <none>           <none>
devops-apiserver-6b468c95cb-grx4j    1/1     Running     2 (4h30m ago)   101d   10.233.116.211   ks-k8s-master-2   <none>           <none>
devops-controller-667f8449d7-w8mvf   1/1     Running     2 (4h37m ago)   101d   10.233.117.173   ks-k8s-master-0   <none>           <none>
devops-jenkins-67fbd685bf-4jmn4      1/1     Running     7 (4h23m ago)   101d   10.233.117.162   ks-k8s-master-0   <none>           <none>
s2ioperator-0                        1/1     Running     2 (4h36m ago)   101d   10.233.87.33     ks-k8s-master-1   <none>           <none>
  • 进入 Jenkins Pod 的指令行控制台
[root@ks-k8s-master-0 ~]# kubectl exec -it devops-jenkins-67fbd685bf-4jmn4 -n kubesphere-devops-system -- bash
Defaulted container "devops-jenkins" out of: devops-jenkins, copy-default-config (init)
root@devops-jenkins-67fbd685bf-4jmn4:/# 
  • 在 Jenkins 挂载的主目录中查找跟 Log4j 有关的 JAR 包 (一切操作都是在容器内部)。
# 进入 Jenkins 数据主目录
root@devops-jenkins-67fbd685bf-4jmn4:~# cd  /var/jenkins_home
# 查找带 log4j 关键字带一切 jar 包
root@devops-jenkins-67fbd685bf-4jmn4:/var/jenkins_home# find ./ -name "*log4j*"
./war/WEB-INF/lib/log4j-over-slf4j-1.7.32.jar
./plugins/ssh-slaves/WEB-INF/lib/log4j-over-slf4j-1.7.26.jar
./plugins/prometheus/WEB-INF/lib/log4j-over-slf4j-1.7.30.jar

阐明: 并没有搜到到 log4j 的核心包,可是搜索到了 log4j-over-slf4j,该软件包并不归于 log4j 官方 MAVEN 库房(也或许是我没有找到),而且居然有 3 个不同版别,Jenkins 自己用了一个版别,还有两个插件也用了两个不同的版别。

百度了一下 log4j-over-slf4j 是用来把日志结构的 Log4j API 桥接到 SLF4J API,实际上底层运用的 SLF4J,细节我并没有深究,也没有去研讨缝隙扫描东西是怎么判断的。

可是因为搜索不到其他的 log4j 相关的 JAR 包,开始判定是因为 log4j-over-slf4j 包引起的缝隙。

  1. 缝隙原因
  • log4j-over-slf4j 包引起的缝隙
  • Jenkins 服务运转环境运用的 Jetty 版别过低。
  • 以上二者均有。

缝隙修正计划

  1. 计划一: 替换查找到的一切 log4j-over-slf4j 相关的 jar 包
  • 只考虑 Log4j 是形成该缝隙信息的主要原因,应该是 Jenkins 程序调用的 log4j-over-slf4j 引起的,能够只换这一个,可是为了安全起见,我把 3 个都替换了。
  • 硬替 jar 包的方法或许引起某些特别场景的异常,必定要备份好之前的 jar 包,便于回滚。
  • 处理计划或许并不完全,仅仅依据 Log4j 的相关修正主张,替换了有关的 JAR 包,可是并不契合 Jetty 版别要求,现在版别为 9.4.43.v20210629 需求晋级到不低于 11.0.7 的版别。
  • 如果没有特别需求,主张首选这种修正计划,虽然没有处理底子,可是胜在简略,回滚便利,整体出问题的或许性更小。

阐明: 该计划现已验证, 替换 jar 包后重启 devops-jenkins,从头履行缝隙扫描,该缝隙没再次发现。

重启后也履行过相应的流水线使命,现在看来功能也都正常。毕竟没有完全充沛测验,所以不扫除某些特别场景或许存在问题。

  1. 计划二: 晋级 Jenkins 和相应的插件到比较新的版别
  • 晋级比较完全, Jetty 和 Log4j 都晋级到新的版别。
  • 需求考虑版别兼容性问题,是否与 KubeSphere 适配,没在官网找到相关介绍,只能晋级测验。
  • 自己打包比较费事,需求有必定的着手才干,需求自己从头构建 ks-jenkins 运用的 Image。
  • 官方的打包项目文档比较简略,需求有必定的根底。
  • 运用从头构建的 Image 重启已有的 Jenkins 服务后,原有数据装备是否丝毫不受影响?还需求进一步深层次验证。
  • 晋级 Jenkins 和插件还有一个简略方法,直接在 Jenkins 的办理界面把提示晋级的组件都晋级了,这些更简略便捷的处理了版别兼容性的问题,有兴趣的能够自己测验。
  • 如果选全晋级的处理计划,必定要自己做充沛的验证测验,才干够在出产环境晋级。毕竟,未知的永远是可怕的。
  • 本文在实验进程中遇到了许多插件版别兼容性问题,后边文档中的内容都是不断探索、试错收拾的,而且终究也没有完美处理。
  • 再次强调,除非清晰的知道你在做什么,能搞定一切变动带来对危险,不然不要容易的在出产环境用该计划!!!

阐明: 为了 get 一个新的技巧,本文后边的内容要点介绍手动自定义构建 ks-jenkins Image 的实战操作。

自定义构建 Jenkins 镜像

KubeSphere 运用的 Jenkins Image 是选用 GitHub 中 ks-jenkins 项目下的相关东西和装备进行打包的,该项目底层东西运用的是 jcli,详细阐明能够检查项目介绍。

项目文档比较简略,没有必定的代码开发根底,实战起来仍是比较困难的,我也是依据自己的理解和搜索引擎收拾了操作进程,有些细节知识点并没有深化了解,现在也仅仅是处理了能打包的需求。

从头构建的镜像思路和方法是对的,可是整体的功能性与兼容性,并没有进行过充沛测验,而且实战进程中也遇到了许多没有处理的问题,后续操作的价值仅限于参阅。出产环境运用请稳重。

装备开发环境

  1. 装置 Java

从 Oracle 官网下载软件包 jdk-8u361-linux-x64.tar.gz,这个需求自己注册账户才干下载。咱们也能够运用自己习气的方法装备 装置装备 JAVA 环境。

# 创立东西寄存目录,并解压 jdk 软件包
mkdir /data/tools
tar xvf jdk-8u361-linux-x64.tar.gz -C /data/tools
# 装备 java profile
cat >> /etc/profile << "EOF"
# java environment
export JAVA_HOME=/data/tools/jdk1.8.0_361
export CLASSPATH=.:${JAVA_HOME}/jre/lib/rt.jar:${JAVA_HOME}/lib/dt.jar:${JAVA_HOME}/lib/tools.jar
export PATH=$PATH:${JAVA_HOME}/bin
EOF
# 验证 Java
source /etc/profile
java -version
# 输出信息如下,表明 Java 装置成功
java version "1.8.0_361"
Java(TM) SE Runtime Environment (build 1.8.0_361-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.361-b09, mixed mode)
  1. 装置 Maven
# 下载 并解压 Maven
wget https://archive.apache.org/dist/maven/maven-3/3.8.7/binaries/apache-maven-3.8.7-bin.tar.gz
tar xvf apache-maven-3.8.7-bin.tar.gz -C /data/tools/
# 装备 maven profile
cat >> /etc/profile << "EOF"
# maven environment
export M2_HOME=/data/tools/apache-maven-3.8.7
export PATH=$PATH:$M2_HOME/bin
EOF
# 验证 Maven
source /etc/profile
mvn -version
# 输出信息如下,表明 Maven 装置成功
Apache Maven 3.8.6 (84538c9988a25aec085021c365c560670ad80f63)
Maven home: /data/tools/apache-maven
Java version: 1.8.0_361, vendor: Oracle Corporation, runtime: /data/tools/jdk1.8.0_361/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "3.10.0-1160.83.1.el7.x86_64", arch: "amd64", family: "unix"
  1. 装置 jcli
cd /tmp
curl -L https://github.com/jenkins-zh/jenkins-cli/releases/latest/download/jcli-linux-amd64.tar.gz | tar xzv
mv jcli /usr/local/bin/

阐明: 受限于网络原因,或许需求屡次操作,最好是运用其他方法提早下载并传送到服务器。

  1. 装置 Git(可选项)

装置 Git 的目的是从 GitHub 上拉取代码,也能够不运用 Git,直接在 GitHub 上下载打包好的代码文件。考虑 GitOps 装备办理及以后的扩展需求,本文要点介绍 Git 的方法。

CentOS 体系自带的 Git 版别比较老,在某些场景运用时会有版别兼容性问题。因而,选择了第三方的软件源装置新版的 Git。

# CentOS 7 装置 ius 软件源
curl https://setup.ius.io | sh
# 装置新版别 Git
yum install git236
# 验证 Git
git version
# 输出信息如下,表明 Git 装置成功
git version 2.36.4
  1. 装置 Docker

构建镜像的进程中会直接生成 Jenkins Docker 镜像。因而,需求打包服务器装置 Docker 运转环境。

# 装备 Docker 装置源
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/$releasever/$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/gpg
EOF
# 装置 Docker
yum install docker-ce
# 装备 Docker
mkdir /etc/docker
cat >> /etc/docker/daemon.json << "EOF"
{
  "data-root": "/data/docker",
  "registry-mirrors": [
    "https://docker.mirrors.ustc.edu.cn",
    "https://mirror.ccs.tencentyun.com",
    "https://registry.docker-cn.com"
  ]
}
EOF
# 发动 Docker
systemctl start docker --now
# 验证 Docker
docker version
# 输出信息如下,表明装置成功
Client: Docker Engine - Community
 Version:           23.0.0
 API version:       1.42
 Go version:        go1.19.5
 Git commit:        e92dd87
 Built:             Wed Feb  1 17:49:02 2023
 OS/Arch:           linux/amd64
 Context:           default
Server: Docker Engine - Community
 Engine:
  Version:          23.0.0
  API version:      1.42 (minimum version 1.12)
  Go version:       go1.19.5
  Git commit:       d7573ab
  Built:            Wed Feb  1 17:46:49 2023
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.6.16
  GitCommit:        31aa4358a36870b21a992d3ad2bef29e1d693bec
 runc:
  Version:          1.1.4
  GitCommit:        v1.1.4-0-g5fd4c4d
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0
# 装置 docker-compose,运用国内的镜像,官方 GitHub 上下载实在是太慢了。
curl -L https://get.daocloud.io/docker/compose/releases/download/v2.15.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod u+x /usr/local/bin/docker-compose
# 验证 docker-compose
docker-compose version
# 输出信息如下,表明装置成功
Docker Compose version v2.15.1

自定义构建镜像

  1. 晋级版别规划
  • Jenkins:2.375.3,运用 LTS 最新版,详细版别信息查询 进口。
  • Jenkins 2.375.3 镜像地址:jenkins/jenkins:2.375.3,详细 Image tag 信息查询 进口。
  • Plugins ssh-slaves:1.834.v622da_57f702c,插件版别及需求的 Jenkins 最低版别等详细信息查询 进口。
  • Plugins prometheus:2.1.1,插件版别及需求的 Jenkins 最低版别等详细信息查询 进口。

阐明: 开始只更新 Jenkins 版别和有关联的两个 Plugins 的版别,其他 Plugins 因为不清楚依靠联系及影响,暂时不动。

这也是一个试错的进程,在后续的测验中发现,仅仅修正两个插件的版别号是远远不够的。

  1. 下载 ks-jenkins 代码
mkdir /data/build
cd /data/build
git clone https://github.com/kubesphere/ks-jenkins.git

阐明: 受限于网络原因,或许需求屡次操作。

  1. 创立一个新的代码分支
# 依据 Master 分支创立新分支,命名方法参阅的已有分支
cd ks-jenkins
git checkout -b v3.3.0-2.375.3
  1. 依据规划修正装备文件 formula.yaml

主要修正 jenkins 根底镜像的版别,插件 ssh-slaves 和 prometheus 的版别,一起因为依靠联系更新了这两个插件依靠的其他插件的版别。

阐明: 这个整理插件之间的版别依靠联系的进程比较费事,我现在也没有找到更好的方法,都是在办理界面依据提示的需求修正的。

一起,还修正了 build 的一些参数,详细原因请检查常见问题。

修正后的主要内容大致如下:

buildSettings:
  docker:
    base: jenkins/jenkins:2.375.3
    tag: {{.tag}}
    outputDir: {{.output}}
    build: true
war:
  groupId: org.jenkins-ci.main
  artifactId: jenkins-war
  source:
    version: 2.375.3
plugins:
  ......
  - groupId: org.jenkins-ci.plugins
    artifactId: ssh-slaves
    source:
      version: 1.834.v622da_57f702c
  - groupId: org.jenkins-ci.plugins
    artifactId: prometheus
    source:
      version: "2.1.1"
  - groupId: org.jenkins-ci.plugins
    artifactId: metrics
    source:
      version: 4.1.6.1
  - groupId: org.jenkins-ci.plugins.pipeline-stage-view
    artifactId: pipeline-rest-api
    source:
      version: "2.21"
  - groupId: org.jenkins-ci.plugins
    artifactId: trilead-api
    source:
      version: 1.57.v6e90e07157e1
  - groupId: org.jenkins-ci.plugins
    artifactId: credentials
    source:
      version: 1139.veb_9579fca_33b_
  - groupId: org.jenkins-ci.plugins
    artifactId: ssh-credentials
    source:
      version: 291.v8211e4f8efb_c
  - groupId: io.jenkins
    artifactId: configuration-as-code
    source:
      version: "1569.vb_72405b_80249"

留意: 上面的装备文件只列出了部分插件的改变信息,并不是完好的,并没有实现完好的作用,仅供参阅。

  1. 修正构建装备文件 Makefile

主要修正 build 相关的内容

build:
	jcli cwp --install-artifacts --config-path formula.yaml \
            --value-set output=tmp \
            --value-set tag=kubesphere/ks-jenkins:v3.3.0-2.375.3
  1. 制作 Image
# 履行构建指令
make build
# 正确的构建会有相似下面的输出
[root@zdevops-main ks-jenkins]# make build
jcli cwp --install-artifacts --config-path formula.yaml \
            --value-set output=tmp \
            --value-set tag=kubesphere/ks-jenkins:v3.3.0-2.375.3
Feb 09, 2023 2:31:00 PM io.jenkins.tools.warpackager.lib.impl.Builder buildIfNeeded
INFO: Component org.jenkins-ci.main:jenkins-war:2.375.3: no build required
Feb 09, 2023 2:31:00 PM io.jenkins.tools.warpackager.lib.impl.Builder buildIfNeeded
INFO: Component io.jenkins:configuration-as-code:1.53: no build required
....
Feb 09, 2023 2:31:00 PM io.jenkins.tools.warpackager.lib.impl.Builder checkoutIfNeeded
INFO: Will checkout bundle-plugins from local directory: remove-bundle-plugins.groovy
[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------< io.github.ks-jenkins:ks-jenkins >-------------------
[INFO] Building ks-jenkins 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
Downloading from repo.jenkins-ci.org: https://repo.jenkins-ci.org/public/org/jenkins-ci/main/jenkins-war/2.375.3/jenkins-war-2.375.3.pom
Downloaded from repo.jenkins-ci.org: https://repo.jenkins-ci.org/public/org/jenkins-ci/main/jenkins-war/2.375.3/jenkins-war-2.375.3.pom (6.4 kB at 625 B/s)
Downloading from incrementals: https://repo.jenkins-ci.org/incrementals/com/microsoft/azure/azure-client-runtime/maven-metadata.xml
...
INFO: Discovered hooks: init.groovy.d
Feb 09, 2023 4:14:50 PM io.jenkins.tools.warpackager.lib.util.DockerfileBuilder build
INFO: Generating Dockerfile
Feb 09, 2023 4:14:50 PM io.jenkins.tools.warpackager.lib.util.DockerfileBuilder build
INFO: Building Docker image kubesphere/ks-jenkins:v3.3.0-2.375.3
[+] Building 329.0s (7/7) FINISHED                                                               
 => [internal] load .dockerignore                                                           0.6s
 => => transferring context: 2B                                                             0.0s
 => [internal] load build definition from Dockerfile                                        0.8s
 => => transferring dockerfile: 295B                                                        0.0s
 => [internal] load metadata for docker.io/jenkins/jenkins:2.375.3                        126.8s
 => [internal] load build context                                                           2.3s
 => => transferring context: 334.65MB                                                       2.2s
 => [1/2] FROM docker.io/jenkins/jenkins:2.375.3@sha256:8656eb80548f7d9c7be5d1f4c367ef43  177.5s
 => => resolve docker.io/jenkins/jenkins:2.375.3@sha256:8656eb80548f7d9c7be5d1f4c367ef432f  0.2s
 => => sha256:f16216f97fcb99c68e03372f08859d8efd86e075e8bc22a0707d991b05 13.12kB / 13.12kB  0.0s
 => => sha256:8656eb80548f7d9c7be5d1f4c367ef432f2dd62f81efa86795c915525801 2.36kB / 2.36kB  0.0s
 => => sha256:ed0d0b4f22e27ee95718f7e701f5e189b58f8a4ffbc60b9769124ccabfb1 2.77kB / 2.77kB  0.0s
 => => sha256:699c8a97647f5789e5850bcf1a3d5afe9730edb654e1ae0714d5bd198 55.03MB / 55.03MB  47.3s
 => => sha256:656837bc63c37068f9786473270235ab4830753280df7f0350ad09fb0 51.63MB / 51.63MB  47.7s
 => => sha256:81ba850015575dd93d4b7b63eb5cb6a1aea458b325242ab10531b482cba 8.93MB / 8.93MB  34.5s
 => => sha256:f565cdb160feddd496a91f8857376382ff4e1b48333c1c0f994a1765bf3 1.24kB / 1.24kB  66.2s
 => => extracting sha256:699c8a97647f5789e5850bcf1a3d5afe9730edb654e1ae0714d5bd198a67a3ed   2.2s
 => => extracting sha256:656837bc63c37068f9786473270235ab4830753280df7f0350ad09fb0374f1ee   1.9s
 => => extracting sha256:81ba850015575dd93d4b7b63eb5cb6a1aea458b325242ab10531b482cba6d2f1   0.2s
 => => extracting sha256:f565cdb160feddd496a91f8857376382ff4e1b48333c1c0f994a1765bf3dd519   0.0s
 => => sha256:7f0db80857b0730f0a39ac7c71449bb1166d945c66bb6a1ea0fd6d75190e250 189B / 189B  79.0s
 => => extracting sha256:7f0db80857b0730f0a39ac7c71449bb1166d945c66bb6a1ea0fd6d75190e2505   0.0s
 => => sha256:b113c3f8acf6fadd7bf46f1085836b609f006c6582857c849361969394 5.68MB / 5.68MB  112.4s
 => => sha256:a02b1ab95401fafdd2c8a936bba450cdebe3182ffddb7d6ca8a319e52a8f3f5 199B / 199B  96.8s
 => => sha256:b51e09c8a0bdd4feb08358353f7214e20375f292d3e18ce11dabb77e 94.02MB / 94.02MB  112.3s
 => => sha256:90c616f07a2df86bef2ad9cc09ca44f34c9d0bc5e7bf6463c53037c7 76.93MB / 76.93MB  150.1s
 => => extracting sha256:b51e09c8a0bdd4feb08358353f7214e20375f292d3e18ce11dabb77e3b21a2a2   0.6s
 => => extracting sha256:a02b1ab95401fafdd2c8a936bba450cdebe3182ffddb7d6ca8a319e52a8f3f53   0.0s
 => => extracting sha256:b113c3f8acf6fadd7bf46f1085836b609f006c6582857c849361969394671a06   0.2s
 => => sha256:32fdd8eaf030672618b17bb89dfd41e06b48b4e5698b5d749b7df02ceb 1.17kB / 1.17kB  143.6s
 => => sha256:22b92623028315e2f81b64231e48c1e8cc5656c2d95b4d43dbea67f1ff 1.93kB / 1.93kB  143.6s
 => => sha256:e04af8aa1a0565689acfc84c92700ee9726771b3e9f2fb14139c382dce6f39 374B / 374B  174.7s
 => => sha256:3938fe646b557890e41807ff23870f648fd4eed439d13bc617f3d1f267e56a 269B / 269B  174.9s
 => => extracting sha256:90c616f07a2df86bef2ad9cc09ca44f34c9d0bc5e7bf6463c53037c786653ee2   2.0s
 => => extracting sha256:22b92623028315e2f81b64231e48c1e8cc5656c2d95b4d43dbea67f1ff8b7fb4   0.0s
 => => extracting sha256:32fdd8eaf030672618b17bb89dfd41e06b48b4e5698b5d749b7df02ceba2d8db   0.0s
 => => extracting sha256:e04af8aa1a0565689acfc84c92700ee9726771b3e9f2fb14139c382dce6f3979   0.0s
 => => extracting sha256:3938fe646b557890e41807ff23870f648fd4eed439d13bc617f3d1f267e56ae4   0.0s
 => [2/2] ADD target/ks-jenkins-1.0-SNAPSHOT.war /usr/share/jenkins/jenkins.war            21.8s
 => exporting to image                                                                      2.0s
 => => exporting layers                                                                     1.9s
 => => writing image sha256:23c59911c9309bb8436716797ab488e80b3d7dbeea0135c9b8c9faa230d24f  0.0s
 => => naming to docker.io/kubesphere/ks-jenkins:v3.3.0-2.375.3

留意: 构建进程会通过 Maven 下载许多依靠包,详细时长视网络和机器装备而定。

镜像验证

镜像构建完成后,咱们需求验证镜像是否可用,新的镜像是否契合安全需求。

  1. 检查构建的 Image
[root@zdevops-main ks-jenkins]# docker images
REPOSITORY              TAG              IMAGE ID       CREATED              SIZE
kubesphere/ks-jenkins   v3.3.0-2.375.3   23c59911c930   About a minute ago   801MB
  1. 验证 Image 是否可用

必定要验证构建的 Image 是否能创立 Jenkins,并正常运用。

在开发服务器上运用 Docker 发动一个 Jenkins。

# 创立容器运转目录(个人习气)
mkdir -p /data/containers/jenkins/volumes/jenkins_home
cd /data/containers/jenkins/
chown 1000:1000 volumes/jenkins_home/
# 创立 docker-compose.yml
cat >> docker-compose.yml << "EOF"
version: '3'
services:
  jenkins:
    image: 'kubesphere/ks-jenkins:v3.3.0-2.375.3'
    container_name: jenkins
    privileged: true
    restart: always
    ports:
      - '8080:8080'
      - '50000:50000'
    volumes:
      - './volumes/jenkins_home:/var/jenkins_home'
EOF
# 运转 Jenkins
docker-compose up -d
# 运转成果正常如下
[+] Running 2/2
 ⠿ Network jenkins_default  Created                                                                    0.1s
 ⠿ Container jenkins        Started                                                                    0.7s
# 检查容器是否成功发动
[root@zdevops-main jenkins]# docker-compose ps
NAME                IMAGE                                  COMMAND                  SERVICE             CREATED              STATUS              PORTS
jenkins             kubesphere/ks-jenkins:v3.3.0-2.375.3   "tini -- /usr/local/…"   jenkins             About a minute ago   Up About a minute   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp, 0.0.0.0:50000->50000/tcp, :::50000->50000/tcp
  1. 验证 Jenkins 是否正常

登录 Jenkins 办理控制台,需求输入体系初始化暗码 docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword

登录后,越过体系初始化,直接进「体系办理」即可(截图略)。

留意: 实际操作中,插件办理里有许多赤色的正告,我也是依据正告不断的调整不同插件的版别,再次打包再次验证。

简略的计划是在界面把一切存在问题的插件告警都处理完,然后依据终究成果,收拾装备文件中插件版别号,然后再次打包。

  1. 验证缝隙是否修正

检查恳求呼应头,发现 Jetty 版别仍旧不契合要求的 11.0.7

[root@zdevops-main ~]# curl -I 192.168.9.10:8080
HTTP/1.1 403 Forbidden
Date: Fri, 10 Feb 2023 02:43:37 GMT
X-Content-Type-Options: nosniff
Set-Cookie: JSESSIONID.cb5c1002=node0qid22cxyj1f81jjc8verbvj5e2.node0; Path=/; HttpOnly
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Content-Type: text/html;charset=utf-8
X-Hudson: 1.395
X-Jenkins: 2.375.3
X-Jenkins-Session: d2fd27f1
Content-Length: 541
Server: Jetty(10.0.12)

检查 log4j 相关的 jar 包,只存在一个 log4j-over-slf4j 的包且现已是比较新的版别

[root@zdevops-main jenkins_home]# find ./ -name "log4j*"
./war/WEB-INF/lib/log4j-over-slf4j-2.0.3.jar
  1. 验证结论

新构建的镜像 Jetty 版别并不契合安全要求,log4j 相关的包契合要求。

依据装备文件构建的镜像测验作用并不完美,许多插件无法运用,主要问题在于插件的兼容性问题。这个也确实是咱们测验之前忧虑的,暂时我也没有更好的处理方法。

如果有激烈的更新需求,主张运用新版的 Jenkins 构建镜像,部署完成后从插件办理里处理插件依靠问题。

替换 KubeSphere 运用的 Jenkins Image

鉴于自定义构建 Jenkins Image 的成果并不完美。因而,本节后边的操作,切记不要容易在出产环境直接运用!仅把思路和操作方法提供给各位,作为参阅。如果要在出产环境运用,必定要通过充沛的测验验证。

将自定义的 Jenkins 镜像传送到服务

如果运用离线镜像自定义域名部署的集群,推送镜像到内网 Harbor 库房 (此进程略)。

如果用的在线互联网的镜像,比如我的环境便是运用的 registry.cn-beijing.aliyuncs.com/kubesphereio/ks-jenkins:v3.3.0-2.319.1。 手艺推送镜像到服务器并修正 tag 姓名。

# 在打包服务器导出自定义构建的 Image
docker tag kubesphere/ks-jenkins:v3.3.0-2.375.3 registry.cn-beijing.aliyuncs.com/kubesphereio/ks-jenkins:v3.3.0-2.375.3
docker save registry.cn-beijing.aliyuncs.com/kubesphereio/ks-jenkins:v3.3.0-2.375.3 -o ks-jenkins-v3.3.0-2.375.3.tar
# 上传到 devops-jenkins 所在的服务器(进程略)
# 在 devops-jenkins 服务器导入, 没有 docker 指令,只能用 ctr 指令
ctr -n k8s.io image import ks-jenkins-v3.3.0-2.375.3.tar
# 验证镜像是否导入
ctr -n k8s.io image ls |grep jenkins

修正 Deployment devops-jenkins 的装备

如果选用的在线互联网镜像的模式,需求更改两个装备项,imageimagePullPolicy,默许的 imagePullPolicy 为 Always,需求修正为 IfNotPresent

有条件的尽量运用自建的镜像库房,只需求修正 Image 装备即可。

# 履行修正指令
kubectl edit deploy devops-jenkins -n kubesphere-devops-system
# 修正的主要内容如下(一共有两处相同的内容需求修正)
# 原始内容
image: registry.cn-beijing.aliyuncs.com/kubesphereio/ks-jenkins:v3.3.0-2.319.1
imagePullPolicy: Always
# 修正后
image: registry.cn-beijing.aliyuncs.com/kubesphereio/ks-jenkins:v3.3.0-2.375.3
imagePullPolicy: IfNotPresent

留意: 修正完成后保存退出,Deploy 会发现装备改变主动重建 Pod。

验证状态

  1. 检查 deployment

[root@ks-k8s-master-0 ~]# kubectl get  deploy -n kubesphere-devops-system -o wide
NAME                READY   UP-TO-DATE   AVAILABLE   AGE    CONTAINERS       IMAGES                                                                    SELECTOR
devops-apiserver    1/1     1            1           102d   ks-devops        registry.cn-beijing.aliyuncs.com/kubesphereio/devops-apiserver:v3.3.0     app.kubernetes.io/instance=devops,app.kubernetes.io/name=ks-devops,devops.kubesphere.io/component=apiserver
devops-controller   1/1     1            1           102d   ks-devops        registry.cn-beijing.aliyuncs.com/kubesphereio/devops-controller:v3.3.0    app.kubernetes.io/instance=devops,app.kubernetes.io/name=ks-devops,devops.kubesphere.io/component=controller
devops-jenkins      1/1     1            1           102d   devops-jenkins   registry.cn-beijing.aliyuncs.com/kubesphereio/ks-jenkins:v3.3.0-2.375.3   component=devops-jenkins-master
  1. 验证 Pod
# 检查 pod
[root@ks-k8s-master-0 ~]# kubectl get  pod -n kubesphere-devops-system -o wide
NAME                                 READY   STATUS      RESTARTS      AGE     IP               NODE              NOMINATED NODE   READINESS GATES
devops-27932190-njblk                0/1     Completed   0             88m     10.233.116.37    ks-k8s-master-2   <none>           <none>
devops-27932220-xrgnj                0/1     Completed   0             58m     10.233.116.38    ks-k8s-master-2   <none>           <none>
devops-27932250-rvl2r                0/1     Completed   0             28m     10.233.116.39    ks-k8s-master-2   <none>           <none>
devops-apiserver-6b468c95cb-grx4j    1/1     Running     2 (32h ago)   102d    10.233.116.211   ks-k8s-master-2   <none>           <none>
devops-controller-667f8449d7-w8mvf   1/1     Running     2 (32h ago)   102d    10.233.117.173   ks-k8s-master-0   <none>           <none>
devops-jenkins-56d7d75d9-zj7lh       1/1     Running     0             4m34s   10.233.117.177   ks-k8s-master-0   <none>           <none>
s2ioperator-0                        1/1     Running     2 (32h ago)   102d    10.233.87.33     ks-k8s-master-1   <none>           <none>

留意: 发动进程较慢,需求多刷新几回,保证状态 READY 值为 1/1

  1. 登录 Jenkins 办理界面

    保证能正常登录体系。

    体系办理里没有明显报错。

    原有的 Jenkins 项目都能检查。

  2. 验证原有的流水线使命

    履行原有的流水线使命,检查使命是否能正常履行,而且成果契合预期。

常见问题

选用默许装备文件时 build 失败

  • 报错信息
[root@zdevops-main ks-jenkins]# make build
jcli cwp --install-artifacts --config-path formula.yaml \
            --value-set output=load \
            --value-set tag=kubespheredev/ks-jenkins:test \
            --value-set platform=linux/amd64
Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "output" (class io.jenkins.tools.warpackager.lib.config.DockerBuildSettings), not marked as ignorable (5 known properties: "base", "tag", "outputDir", "build", "customSettings"])
 at [Source: (FileInputStream); line: 10, column: 17] (through reference chain: io.jenkins.tools.warpackager.lib.config.Config["buildSettings"]->io.jenkins.tools.warpackager.lib.config.BuildSettings["docker"]->io.jenkins.tools.warpackager.lib.config.DockerBuildSettings["output"])
        at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:61)
        at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:855)
        at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1212)
        at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1604)
        at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1582)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:299)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:156)
        at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:138)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:293)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:156)
        at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:138)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:293)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:156)
        at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4526)
        at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3505)
        at io.jenkins.tools.warpackager.lib.config.Config.load(Config.java:77)
        at io.jenkins.tools.warpackager.lib.config.Config.loadConfig(Config.java:106)
        at io.jenkins.tools.warpackager.cli.Main.main(Main.java:38)
make: *** [build] Error 1
  • 处理计划

通过简略剖析,判断应该是现有的 ks-jenkins 代码库现已好几个月没有更新,运用的底层 jcli 不断在更新,导致现有版别的 cwp-cli.jar 的输入参数与默许装备文件中运用的装备不匹配。处理计划有两种:

  • 下载老版别的 cwp-cli 的 jar 包,详细方法只能靠各位自己研讨了,我不熟悉也没深化探求。
  • 依据当前版别的参数要求,修正装备文件 formula.yaml(比较简略,因而本文选用了该计划)。
# 原装备文件内容
buildSettings:
  docker:
    base: jenkins/jenkins:2.319.1
    tag: {{.tag}}
    output: {{.output}}
    platform: {{.platform}}
    buildx: true
    build: true
# 修正后的装备文件
buildSettings:
  docker:
    base: jenkins/jenkins:2.375.3
    tag: {{.tag}}
    outputDir: {{.output}}
    build: true

Jenkins 体系办理界面中插件办理显现许多赤色正告信息

  • 报错信息

不截图了,主要是在 Jenkins 的体系办理界面中插件办理的页面,会显现许多赤色正告信息。有插件版别依靠联系、插件降级等赤色或是黄色的提示。

  • 处理计划

现在看来最简略的处理计划是在插件办理的页面依据提示处理。

如果想主动打包镜像的时候就处理好插件的依靠,我感觉仍是需求在 jcli 这个东西入手。官方文档不够详细,材料也少,暂时没时刻和精力去深化探求。所以先放弃了,后续有新的研讨成果再共享。

可是 Jenkins 自身的问题处理后,与现有的 KubeSphere 是否兼容还需求充沛验证。

结束语

本文以修正 Jenkins 存在的 Apache Log4j2 缝隙为布景,介绍了修正该缝隙的两种处理计划。而且,开始探求了在 KubeSphere 中集成的 Jenkins 怎么自定义构建镜像以及怎么晋级更新。

探求进程并不是很完美,作用并没有达到预期。主要是因为插件依靠性的问题,导致自定义构建的镜像部署的 Jenkins 插件办理里存在许多告警。

因为才干和时刻很有限,只能以一个不完美的成果结束本文了,十分抱歉!

因而,本文仅作为抛砖引玉之作,实战进程不适合在出产环境直接运用。着手才干超强的读者可将文中的思路和操作方法作为参阅,继续改造。如果有更加完美的处理方法,请联系我共享给我,我将不胜感激!

本文由博客一文多发渠道 OpenWrite 发布!