CI/CD 构建中能保护好 SSHKEY吗?

news2024/11/24 16:22:50

目录

背景

方案

编码存储

逐行存储

合并存储

打马赛克

结论


背景


使用极狐GitLab CI/CD,在部署方面,主要有两种方式:

部署到K8S集群

  • Push模式:流水线通过kubectl执行命令部署,这需要把K8S的权限给流水线,存在安全风险

  • Pull模式:使用极狐GitLab Agent for Kubernetes 或ArgoCD,通过GitOps的方式“监听”极狐GitLab的变化,触发部署

图片

部署到服务器

目前仍有不少企业因为行业性质或者场景所限,没有使用K8S等云原生技术,还在采用传统的服务器方式进行部署。一般使用ssh、scp、rsync等命令部署到服务器。极狐GitLab也提供了基于SSH keys的部署。详见:Using SSH keys with JiHu GitLab CI/CD。

需要说明的是,如果是使用专用的编译机进行编译构建,然后部署到指定的服务器,只需要实现编译机和部署服务器的免密SSH登陆即可,相对简单。但如果使用容器进行编译构建,然后部署到服务器,就需要按照上面文档中提到的,配合极狐GitLab CI/CD环境变量,将SSH_PRIVATE_KEY等变量存储到极狐GitLab Project、Group或Instance中,实现复用。且可以通过极狐GitLab CI/CD环境变量的Mask设置,掩藏这些变量在CI/CD日志中的显示。详见:极狐GitLab CI/CD variables。

但遗憾的是Mask功能目前是有限制的,对于SSH_PRIVATE_KEY这种多行的变量无法直接使用Mask功能。这样开发人员就可以在.gitlab-cti.yml文件的脚本中执行echo $SSH_PRIVATE_KEY,在流水线的日志中输出SSH Keys,存在密钥泄露风险。

The value of the variable must:

  • Be a single line.

  • Be 8 characters or longer, consisting only of:

Characters from the Base64 alphabet (RFC4648).

The @ and : characters (In GitLab 12.2 and later).

The . character (In GitLab 12.10 and later).

The ~ character (In GitLab 13.12 and later).

  • Not match the name of an existing predefined or custom CI/CD variable.

图片

图片

这个问题在极狐GitLab的Issue上挂了有一年多 ,看样子短时间没法解决。有没有其他方式Mask SSH_PRIVATE_KEY?于是开始了各种折腾。

方案


编码存储

SSH Keys不能直接Mask,但Mask的要求里面是支持Base64的。所以把SSH Keys先用Base64编码,存到CI/CD环境变量中,这样就可以Mask了,然后在.gitlab-ci.yml中解码,就可以在不影响功能的前提下实现效果。看看操作步骤:

  • Base64编码SSH_PRIVATE_KEY

# 输入示例   
echo "-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAsWchpjSe6HW8dS/DdmokMqET2+eCvD8ysOeju3Ur3cbXtZF1
*****
pbPfj6i+faMGc1wbP+Svh8P5bcWTJZvZcP87D/HRmSFz6xcT014=
-----END RSA PRIVATE KEY-----" | base64 
# 输出示例:Base64编码
LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb2dJQkFBS0NBUUVBc1djaHBqU2U2SFc4ZFMvRG
*****
cjRzNmVjY25ZRUZxb1NSTGVNU2xMb1ZreU5VZEpQUjJRa1djQzRkVDVQZwpwYlBmajZpK2ZhTUdjMXdiUCtTdmg4UDViY1dUSlp2WmNQODdEL0hSbVNGejZ4Y1QwMTQ9Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==
  • 将输出的Base64编码作为SSH_PRIVATE_KEY存储在极狐GitLab CI/CD环境变量,并Mask

图片

  • 修改.gitlab-ci.yml

before_script:
    - 'command -v ssh-agent >/dev/null || ( apt-get update -y && apt-get install openssh-client -y )'
    - eval $(ssh-agent -s)
    # - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
    - echo "$SSH_PRIVATE_KEY" | base64 -d | ssh-add -
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - echo "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts
    - chmod 644 ~/.ssh/known_hosts
  • 运行测试,大功告成

这看上去是个不错的方案,但真的保证了SSH_PRIVATE_KEY安全么?我们本着Geek(作死)精神,测试一下:

  • 修改.gitlab-ci.yml,通过各种方式看看能不能打印出SSH_PRIVATE_KEY

before_script:
    - 'command -v ssh-agent >/dev/null || ( apt-get update -y && apt-get install openssh-client -y )'
    - eval $(ssh-agent -s)
    # --- test begin ---
    - echo "$SSH_PRIVATE_KEY" 
    - echo "$SSH_PRIVATE_KEY" >> output.txt
    - cat output.txt
    - echo "$SSH_PRIVATE_KEY" | base64 -d
    # --- test end ---
    - echo "$SSH_PRIVATE_KEY" | base64 -d | ssh-add -
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - echo "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts
    - chmod 644 ~/.ssh/known_hosts
  • 运行测试

图片

直接输出SSH_PRIVATE_KEY是被Mask了,但执行echo "$SSH_PRIVATE_KEY" | base64 -d,居然把SSH_PRIVATE_KEY打印了出来,所以这个方法还是存在一定的问题。

逐行存储

SSH Keys头部和尾部的-----BEGIN RSA PRIVATE KEY-----、-----END RSA PRIVATE KEY-----不能Mask,但里面的内容,每一行可以单独作为一个环境变量存储并Mask,使用的时候再进行拼接,看看操作步骤:

  • 将SSH_PRIVATE_KEY每一行拆分成一个变量,进行存储,有多少行就要存多少变量,为了偷懒,此处只列了3行,实际上我这个SSH_PRIVATE_KEY除去头尾,有26行……

图片

图片

  • 修改.gitlab-ci.yml,并加入一些测试

before_script:
    - 'command -v ssh-agent >/dev/null || ( apt-get update -y && apt-get install openssh-client -y )'
    - eval $(ssh-agent -s)
    # 拼接SSH_PRIVATE_KEY
    - |
      SSH_PRIVATE_KEY=$'-----BEGIN RSA PRIVATE KEY-----\n'
      SSH_PRIVATE_KEY=$SSH_PRIVATE_KEY$SSH_PRIVATE_KEY1$'\n'
      SSH_PRIVATE_KEY=$SSH_PRIVATE_KEY$SSH_PRIVATE_KEY2$'\n'
      SSH_PRIVATE_KEY=$SSH_PRIVATE_KEY$SSH_PRIVATE_KEY3$'\n'
      SSH_PRIVATE_KEY=$SSH_PRIVATE_KEY$'-----END RSA PRIVATE KEY-----'
    # --- test begin ---
    - echo "$SSH_PRIVATE_KEY" 
    - echo "$SSH_PRIVATE_KEY" >> output.txt
    - cat output.txt
    # --- test end ---
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - echo "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts
    - chmod 644 ~/.ssh/known_hosts
  • 运行测试

图片

方案行是行,实际操作起来要存26个变量然后还要拼起来,实在是太土了,能不能减少行数,存一行。

合并存储

Mask不支持空格,只支持@:.~,那我们尝试把SSH_PRIVATE_KEY除了头尾的部分合并成一行,把换行符替换成支持的符号,如.,然后再与头尾进行拼接。操作步骤如下:

  • 合并SSH_PRIVATE_KEY

# 输入示例
echo "-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAsWchpjSe6HW8dS/DdmokMqET2+eCvD8ysOeju3Ur3cbXtZF1
*****
pbPfj6i+faMGc1wbP+Svh8P5bcWTJZvZcP87D/HRmSFz6xcT014=
-----END RSA PRIVATE KEY-----" | tr -d '\r' | tr "\n" "."

#输出示例
-----BEGIN RSA PRIVATE KEY-----.MIIEogIBAAKCAQEAsWchpjSe6HW8dS/DdmokMqET2+eCvD8ysOeju3Ur3cbXtZF1.LMb2Rq68/FPXsteLr4Y1ECKoy/YhFpyDw1h3cLm2WBUtRjt/Tq0ASbQCWAVkDsmx.uy28WofwfEKktzy3FmDSCXbvcOQgjChAmMbALWyH****=.-----END RSA PRIVATE KEY-----.
  • 将除头尾部分存入环境变量并Mask

图片

  • 修改.gitlab-ci.yml

before_script:
    - 'command -v ssh-agent >/dev/null || ( apt-get update -y && apt-get install openssh-client -y )'
    - eval $(ssh-agent -s)
    # 拼接SSH_PRIVATE_KEY
    - SSH_PRIVATE_KEY=$'-----BEGIN RSA PRIVATE KEY-----\n'$SSH_PRIVATE_KEY$'\n-----END RSA PRIVATE KEY-----'
    # --- test begin ---
    - echo "$SSH_PRIVATE_KEY" 
    - echo "$SSH_PRIVATE_KEY" >> output.txt
    - cat output.txt
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | tr "." "\n" 
    # --- test end ---
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | tr "." "\n" | ssh-add -
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - echo "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts
    - chmod 644 ~/.ssh/known_hosts
  • 运行测试

图片

和“编码存储”的方案一样,跑的通,但依旧可以通过对应的方式,打印出SSH_PRIVATE_KEY。

到这里,可以隐约猜到Mask变量的原理是简单做了一个是否包含字符串的判断。如果与环境变量的值匹配就显示[MASKED],如果不匹配就直接将变量显示出来。这也是为什么目前只允许值是单行且没有太多特殊符号的环境变量才可以MASK的原因。

打马赛克

为了验证上一步留下来的猜想,我设计了一个实验:

  • 恢复环境变量中的SSH_PRIVATE_KEY为原始内容,并且不做Mask,当然也无法Mask

图片

  • 新建一个环境变量,值为SSH_PRIVATE_KEY的一部分内容,这里设置的是SSH_PRIVATE_KEY内容的第一行,然后设置为Mask

图片

  • 恢复.gitlab-ci.yml文件,需要注意的是这里面没有任何关于MOSAIC环境变量的使用

before_script:
    - 'command -v ssh-agent >/dev/null || ( apt-get update -y && apt-get install openssh-client -y )'
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" 
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r'| ssh-add -
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - echo "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts
    - chmod 644 ~/.ssh/known_hosts
  • 运行测试

图片

正如猜想一样,即便没有使用MOSAIC环境变量,但它依然作为判断是否包含字符串而被执行了。

利用这个特性,我们可以通过设置几个马赛克变量,给SSH_PRIVATE_KEY的部分内容打码,就可以一定程度上防止SSH_PRIVATE_KEY的泄露。

结论


作为一般场景下使用,上面的四种方式任意选一个都可以实现基本的安全防护,正所谓防君子不防小人。如果要进一步提高安全性,还是如官方所说,上专业的密钥管理工具,如Vault,或者期待下极狐GitLab在管理密钥这块功能的完善。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1265551.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【python程序】把小于10的数值都变成1

【python程序】把小于10的数值都变成1 import numpy as np import xarray as xra xr.DataArray(np.arange(25).reshape(5, 5)) a[np.where(a < 10)] 1 print(a)

微信小程序+中草药分类+爬虫+torch

1 介绍 本项目提供中草药数据集&#xff0c;使用gpu、cpu版本的torch版本进行训练&#xff0c;将模型部署到后端flask&#xff0c;最后使用微信小程序进行展示出来。 数据爬虫可以参考&#xff1a;http://t.csdnimg.cn/7Olus 项目中的爬虫代码&#xff0c;并且本项目提供相同的…

拆解按摩器:有意思的按键与LED控制电路,学习借鉴一下!

拆解 外观和配色个人感觉还行,比较青春 拉开拉链&#xff0c;拆开外面的布面&#xff0c;里面还有一层纱面 按键部分使用魔术贴固定 拆开纱面后&#xff0c;看到里面的结构&#xff0c;整体是一个海绵 可以看到如下&#xff0c;电池&#xff0c;按键板&#xff0c;充电线的三条…

匿名内部类(内部类) - Java

匿名内部类 1、理解2、语法3、使用&#xff08;1&#xff09;基于接口的内部类&#xff08;2&#xff09;基于类的内部类&#xff08;3&#xff09;基于抽象类的匿名内部类 4、细节&注意事项5、最佳应用场景&#xff08;1&#xff09;当作实参直接传递&#xff0c;简洁高效…

Alibaba Java诊断工具Arthas查看Dubbo动态代理类

原创/朱季谦 阅读Dubbo源码过程中&#xff0c;会发现&#xff0c;Dubbo消费端在做远程调用时&#xff0c;默认通过 Javassist 框架为服务接口生成动态代理类&#xff0c;调用javassist框架下的JavassistProxyFactory类的getProxy(Invoker invoker, Class<?>[] interfac…

GO 集成Prometheus

一、Prometheus介绍 Prometheus&#xff08;普罗米修斯&#xff09;是一套开源的监控&报警&时间序列数据库的组合&#xff0c;起始是由SoundCloud公司开发的。随着发展&#xff0c;越来越多公司和组织接受采用Prometheus&#xff0c;社会也十分活跃&#xff0c;他们便…

GAN:GAN论文学习

论文&#xff1a;https://arxiv.org/pdf/1406.2661.pdf 发表&#xff1a;2014 一、GAN简介&#xff1a;Generative Adversarial Network GAN是由Ian Goodfellow于2014年提出&#xff0c;GAN&#xff1a;全名叫做生成对抗网络。GAN的目的就是无中生有&#xff0c;以假乱真。 …

day64 django中间件的复习使用

django中间件 django中间件是django的门户 1.请求来的时候需要先经过中间件才能达到真正的django后端 2.响应走的时候也需要经过中间件 ​ djangp自带七个中间件MIDDLEWARE [django.middleware.security.SecurityMiddleware,django.contrib.sessions.middleware.SessionMiddle…

java开发需要掌握的maven相关知识和Junit单元测试

maven简介 什么是maven&#xff1a; maven是一款管理和构建java项目的工具&#xff0c;是apache旗下的一个开源项目。 maven的作用&#xff1a; 依赖管理&#xff1a; 方便快捷的管理项目依赖的资源&#xff08;jar包&#xff09;。 项目构建&#xff1a; 标准化的跨平台&#…

MacBook如何远程控制华为手机?

将手机屏幕投影到电脑上可以提供更大的屏幕空间&#xff0c;方便观看电影、浏览照片、阅读文档等。然而&#xff0c;除了想将手机投屏到电脑&#xff0c;还想要在电脑上直接操作手机&#xff0c;有方法可以实现吗&#xff1f; 现在使用AirDroid Cast的远程控制手机功能就可以实…

【数据结构】树与二叉树(廿五):树搜索给定结点的父亲(算法FindFather)

文章目录 5.3.1 树的存储结构5. 左儿子右兄弟链接结构 5.3.2 获取结点的算法1. 获取大儿子、大兄弟结点2. 搜索给定结点的父亲a. 算法FindFatherb. 算法解析c. 代码实现 3. 代码整合 5.3.1 树的存储结构 5. 左儿子右兄弟链接结构 【数据结构】树与二叉树&#xff08;十九&…

Linux dig指令的十三种用法

文章目录 dig指令有哪些作用dig 具体用法推荐阅读 dig指令有哪些作用 DIG命令(Domain Information Groper命令)是一个网络工具&#xff0c;具有基本的命令行接口&#xff0c;用于进行不同的DNS(域名系统)查询。您可以使用DIG命令: 诊断您的域名服务器。检查所有这些服务器或每…

《数据结构与测绘程序设计》试题详细解析(仅供参考)

一. 选择题&#xff08;每空2分&#xff0c;本题共30分&#xff09; &#xff08;1&#xff09;在一个单链表中&#xff0c;已知q所指结点是p所指结点的前驱结点&#xff0c;若在q和p之间插入结点s&#xff0c;则执行( B )。 A. s->nextp->next; p->nexts; …

Qt路径和Anaconda中QT路径冲突(ubuntu系统)

最近做一个项目需要配置QT库&#xff0c;本项目配置环境如下&#xff1a; Qt version 5 Operating system, version and so on ubuntu 20.04 Description 之前使用过anaconda环境安装过QT5&#xff0c;所以在项目中CMakeLists文件中使用find_package时候&#xff0c;默认使用An…

C#,数值计算——插值和外推,径向基函数插值(RBF_inversemultiquadric)的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { public class RBF_inversemultiquadric : RBF_fn { private double r02 { get; set; } public RBF_inversemultiquadric(double scale 1.0) { this.r02 Globals.SQR(scale); …

Spring Boot实现图片上传和展示

Spring Boot实现图片上传和展示 本文将介绍如何使用Spring Boot框架搭建后端服务&#xff0c;实现接收前端上传的图片并保存到resources/images目录下。同时&#xff0c;我们还将展示如何在前端编写一个HTML页面&#xff0c;实现上传图片和从resources/images目录下获取图片并…

PHP+vue+elementui高校学生社团信息管理系统o7q4a

社团是由高校用户依据兴趣爱好自愿组成&#xff0c;按照章程自主开展活动的用户组织。高校社团是实施素质教育的重要途径和有效方式&#xff0c;在加强校园文化建设、提高用户综合素质、引导用户适应社会、促进用户交流等方面发挥着重要作用&#xff0c;是新形势下有效凝聚用户…

[Python入门系列之十一]在windows上安装OpenCV

1-安装OpenCV 如果是python3.7–python3.9(已测试)&#xff0c;直接安装即可 注&#xff1a;conda需要先激活虚拟环境后再安装 pip install opencv-python如果安装速度慢&#xff0c;使用下面的指令&#xff1a; pip install opencv-python -i https://pypi.tuna.tsinghua.e…

AIGC-文生视频

stable diffusion&#xff1a; stable diffusion原理解读通俗易懂&#xff0c;史诗级万字爆肝长文&#xff0c;喂到你嘴里 - 知乎个人网站一、前言&#xff08;可跳过&#xff09;hello&#xff0c;大家好我是 Tian-Feng&#xff0c;今天介绍一些stable diffusion的原理&#…

Micropython STM32F4外部中断实验

Micropython STM32F4外部中断实验 &#x1f4cc;固件刷可参考前面一篇《STM32刷Micropython固件参考指南》&#x1f33f; 相关篇《Micropython STM32F4入门点灯》&#x1f4cd;固件下载&#xff1a;https://micropython.org/download/?mcustm32f4&#x1f516;本例程基于STM32…