修复 KubeSphere 内置 Jenkins 的 Apache Log4j2 漏洞

2023年 7月 9日 140.5k 0

作者:老 Z,运维架构师,云原生爱好者,目前专注于云原生运维,云原生领域技术栈涉及 Kubernetes、KubeSphere、DevOps、OpenStack、Ansible 等。

简介

生产环境 KubeSphere 3.3.0 部署的 Kubernetes 集群在安全评估的时候发现安全漏洞,其中一项漏洞提示目标可能存在 Apache Log4j2 远程代码执行漏洞 (CVE-2021-44228)。

本文记录了该漏洞修复的全部过程,文中介绍了修复该漏洞的两种解决方案,其中涉及自定义构建 KubeSphere 适用的 Jenkins Image 的详细操作。

漏洞修复方案

漏洞详细信息

漏洞报告中涉及漏洞 目标可能存在 Apache Log4j2 远程代码执行漏洞 (CVE-2021-44228) 的具体信息如下:

漏洞分析

  • 分析漏洞报告信息,发现对应的服务端口为 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,跟漏扫报告中的结果一致。

  • 在 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,跟漏扫报告中的结果一致。

  • 在 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              
    devops-27930540-6b7cz                0/1     Completed   0               57m    10.233.116.225   ks-k8s-master-2              
    devops-27930570-t5k6b                0/1     Completed   0               27m    10.233.116.226   ks-k8s-master-2              
    devops-apiserver-6b468c95cb-grx4j    1/1     Running     2 (4h30m ago)   101d   10.233.116.211   ks-k8s-master-2              
    devops-controller-667f8449d7-w8mvf   1/1     Running     2 (4h37m ago)   101d   10.233.117.173   ks-k8s-master-0              
    devops-jenkins-67fbd685bf-4jmn4      1/1     Running     7 (4h23m ago)   101d   10.233.117.162   ks-k8s-master-0              
    s2ioperator-0                        1/1     Running     2 (4h36m ago)   101d   10.233.87.33     ks-k8s-master-1              
    
    • 进入 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 包引起的漏洞。

  • 漏洞原因
    • log4j-over-slf4j 包引起的漏洞
    • Jenkins 服务运行环境使用的 Jetty 版本过低。
    • 以上二者均有。

    漏洞修复方案

  • 方案一: 替换查找到的所有 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,重新执行漏洞扫描,该漏洞没再次发现。

    重启后也执行过相应的流水线任务,目前看来功能也都正常。毕竟没有完全充分测试,所以不排除某些特殊场景可能存在问题。

  • 方案二: 升级 Jenkins 和相应的插件到比较新的版本
    • 升级比较彻底, Jetty 和 Log4j 都升级到新的版本。
    • 需要考虑版本兼容性问题,是否与 KubeSphere 适配,没在官网找到相关介绍,只能升级尝试。
    • 自己打包比较麻烦,需要有一定的动手能力,需要自己重新构建 ks-jenkins 使用的 Image。
    • 官方的打包项目文档比较简单,需要有一定的基础。
    • 利用重新构建的 Image 重启已有的 Jenkins 服务后,原有数据配置是否丝毫不受影响?还需要进一步深层次验证。
    • 升级 Jenkins 和插件还有一个简单方法,直接在 Jenkins 的管理界面把提示升级的组件都升级了,这些更简单便捷的解决了版本兼容性的问题,有兴趣的可以自己尝试。
    • 如果选全升级的解决方案,一定要自己做充分的验证测试,才可以在生产环境升级。毕竟,未知的永远是可怕的。
    • 本文在实验过程中遇到了很多插件版本兼容性问题,后面文档中的内容都是不断摸索、试错整理的,而且最终也没有完美解决。
    • 再次强调,除非明确的知道你在做什么,能搞定所有变动带来对风险,否则不要轻易的在生产环境用该方案!!!

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

    自定义构建 Jenkins 镜像

    KubeSphere 使用的 Jenkins Image 是采用 GitHub 中 ks-jenkins 项目下的相关工具和配置进行打包的,该项目底层工具使用的是 jcli,具体说明可以查看项目介绍。

    项目文档比较简单,没有一定的代码开发基础,实战起来还是比较困难的,我也是根据自己的理解和搜索引擎整理了操作过程,有些细节知识点并没有深入了解,目前也仅仅是解决了能打包的需求。

    重新构建的镜像思路和方法是对的,但是整体的功能性与兼容性,并没有进行过充分测试,而且实战过程中也遇到了很多没有解决的问题,后续操作的价值仅限于参考。生产环境使用请慎重。

    配置开发环境

  • 安装 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 > /etc/profile > /etc/yum.repos.d/docker.repo > /etc/docker/daemon.json  /usr/local/bin/docker-compose
    chmod u+x /usr/local/bin/docker-compose
    
    # 验证 docker-compose
    docker-compose version
    
    # 输出信息如下,表示安装成功
    Docker Compose version v2.15.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 由于不清楚依赖关系及影响,暂时不动。

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

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

    说明: 受限于网络原因,可能需要多次操作。

  • 创建一个新的代码分支
  • # 根据 Master 分支创建新分支,命名方式参考的已有分支
    cd ks-jenkins
    git checkout -b v3.3.0-2.375.3
    
  • 根据规划修改配置文件 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"
    

    注意: 上面的配置文件只列出了部分插件的变更信息,并不是完整的,并没有实现完整的效果,仅供参考。

  • 修改构建配置文件 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
    
  • 制作 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] -------------------------------------
    [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 下载很多依赖包,具体时长视网络和机器配置而定。

    镜像验证

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

  • 查看构建的 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
    
  • 验证 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 8080/tcp, :::8080->8080/tcp, 0.0.0.0:50000->50000/tcp, :::50000->50000/tcp
    
  • 验证 Jenkins 是否正常
  • 登录 Jenkins 管理控制台,需要输入系统初始化密码 docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword

    登录后,跳过系统初始化,直接进「系统管理」即可(截图略)。

    注意: 实际操作中,插件管理里有很多红色的警告,我也是根据警告不断的调整不同插件的版本,再次打包再次验证。

    简单的方案是在界面把所有存在问题的插件告警都处理完,然后根据最终结果,整理配置文件中插件版本号,然后再次打包。

  • 验证漏洞是否修复
  • 检查请求响应头,发现 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
    
  • 验证结论
  • 新构建的镜像 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 的配置

    如果采用的在线互联网镜像的模式,需要更改两个配置项,image 和 imagePullPolicy,默认的 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。

    验证状态

  • 查看 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
    
  • 验证 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              
    devops-27932220-xrgnj                0/1     Completed   0             58m     10.233.116.38    ks-k8s-master-2              
    devops-27932250-rvl2r                0/1     Completed   0             28m     10.233.116.39    ks-k8s-master-2              
    devops-apiserver-6b468c95cb-grx4j    1/1     Running     2 (32h ago)   102d    10.233.116.211   ks-k8s-master-2              
    devops-controller-667f8449d7-w8mvf   1/1     Running     2 (32h ago)   102d    10.233.117.173   ks-k8s-master-0              
    devops-jenkins-56d7d75d9-zj7lh       1/1     Running     0             4m34s   10.233.117.177   ks-k8s-master-0              
    s2ioperator-0                        1/1     Running     2 (32h ago)   102d    10.233.87.33     ks-k8s-master-1              
    

    注意: 启动过程较慢,需要多刷新几次,确保状态 READY 值为 1/1

  • 登录 Jenkins 管理界面

    确保能正常登录系统。

    系统管理里没有明显报错。

    原有的 Jenkins 项目都能查看。

  • 验证原有的流水线任务

    执行原有的流水线任务,检查任务是否能正常执行,并且结果符合预期。

  • 常见问题

    采用默认配置文件时 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 插件管理里存在很多告警。

    由于能力和时间很有限,只能以一个不完美的结果结束本文了,非常抱歉!

    因此,本文仅作为抛砖引玉之作,实战过程不适合在生产环境直接使用。动手能力超强的读者可将文中的思路和操作方法作为参考,继续改造。如果有更加完美的解决办法,请联系我分享给我,我将不胜感激!

    相关文章

    KubeSphere 部署向量数据库 Milvus 实战指南
    探索 Kubernetes 持久化存储之 Longhorn 初窥门径
    征服 Docker 镜像访问限制!KubeSphere v3.4.1 成功部署全攻略
    那些年在 Terraform 上吃到的糖和踩过的坑
    无需 Kubernetes 测试 Kubernetes 网络实现
    Kubernetes v1.31 中的移除和主要变更

    发布评论