事情是这样色的,去年春节前夕,A同事说gitlab不太稳定,有时候访问会502,代码不能合并,但是重启或者刷新配置就好了(可能这个时候服务器已经被挖矿了)。大概又过了几天吧,B同事说,安装有gitlab的服务器CPU飙到100%了,进程杀不死,有大流量向外网传输,就如同下面的画面。
纳尼,怎么会这样?这台服务器在内网下,为什么会被挖矿?
服务器鬼使神差的主动连接外网的SSH。
这个时候某服务器异常问题群已经建立起来了,总监已经进群了,顿时警觉了起来,好在经过B同事的不懈的努力,终于定位到了该进程。
git 91607 18.7 0.0 54732 41872 ? Ssl 21:25 0:16 /boot/nptgdg
但是无法将此进程彻底杀死,还是在狂建链接。脑补一下电影中的画面吧,黑客们在疯狂的敲击着键盘...
当然了此时B同事也在疯狂的敲击着键盘,好似黑客攻击大战,你攻我守。费了九牛二虎之力B同事成功定位到这个进程了,就是利用定时任务启动的。此时A同事嘴角泛起一丝微笑,“这台服务器上唯一的定时任务就是gitlab的每日备份了”。经过B同事深挖发现是名称为kthreaddk的程序,百度发现是挖矿的。
最后上了杀毒软件,做了个全盘扫描,发现了106个病毒,都是在/var/opt/gitlab-workhorse/和/usr目录下。
B运维说“这台服务器上重要文件都备份一下吧”。此时我心里犹如乱麻,这台服务器可是我进公司接触的第一台服务器,称它为“老伙计”吧。"老伙计"长期资源利用率不高且杂乱。其实早在一个月之前我就向总监提议要将这台服务器要进行优化,采取专机专用。像比较重要的GitLab、Confluence、DOClever等采用独立部署,增加服务器权限,增加监控策略,增加备份策略(重要文件备份至其它服务器上),这样看来服务器的优化计划要提前了。
大概在晚上7点的时候我们完成了备份。
这个时候总监在群里拽了一篇文章“攻击者利用漏洞发动DDoS攻击,3万台GitLab服务器仍未修补”并@我说“兄弟们,今天必须要整改落实到位啊”,我知道今晚肯定要加班了。
其实早在2021年11月份的时候,谷歌云安全可靠性工程师 Damian Menscher 在推特上指出,根据CVE-2021-22205漏洞利用报告,有攻击者正在利用 GitLab 托管服务器上的安全漏洞来构建僵尸网络,并发起规模惊人的分布式拒绝服务攻击(DDoS)。其中一些攻击的峰值流量,甚至超过了1Tbps。而这个被利用的漏洞,正是GitLab在2021年4月修补的漏洞。谷歌的工程师 Damian Menscher表示,被黑客攻击的服务器是某巨型僵尸网络的一部分,该僵尸网络由"数千个受感染的GitLab实例"组成,并且正在发动大规模的DDoS攻击。
GitLab已提供了超过六个月的补丁服务,然而遗憾的是,针对面向互联网的GitLab实例分析表明,大量实例仍然是脆弱的。Rapid7于周一发布的帖子显示,有超过60,000台GitLab服务器连接到互联网,尽管GitLab已于2021年4月完成了修补工作,但其中大约有30,000台GitLab服务器仍未修补CVE-2021-22205 ExifTool漏洞。
在蜜罐社区,安全威胁情报周报(21.11.13~21.11.19)看到捕获的gitlab漏洞GitLab rce (CVE-2021-22205) 影响的 GitLab版本:11.9 <= GitLab(CE/EE)< 13.8.8 13.9 <= GitLab(CE/EE)< 13.9.6 13.10 <= GitLab(CE/EE)< 13.10.3
我们的版本为13.7.6,正好命中了。
好了,开始加班之旅吧。
一、版本确认
使用内部文件查看当前版本
#通过以下命令来查看GitLab版本 cat /opt/gitlab/embedded/service/gitlab-rails/VERSION
或者使用/help页面确认
查看GitLab的官方博客确定安全版本
GitLab官方博客(https://about.gitlab.com/releases/categories/releases/).可以在这个页面订阅一下GitLab的双周通讯,便于接受一些重要信息。
二、制定升级计划
GitLab升级必须按照官方给定的版本跨度去升级,否则就会出现意想不到的错误。别问我是怎么知道的,因为我曾经被这个版本跨度折磨过,那滋味不好受,你们千万要听劝。
升级路线(https://docs.gitlab.com/ee/update/#upgrade-paths),如下:
三、备份及恢复
备份 GitLab
创建 GitLab 及其所有数据(数据库、存储库、上传、构建、工件、LFS 对象、注册表、页面)的备份。如果升级出现问题,这对于将 GitLab 回滚到工作状态至关重要。
- 创建GitLab 备份。确保根据您的安装方法遵循说明。不要忘记备份机密和配置文件。
- 或者,创建您的实例的快照。如果这是多节点安装,则必须对每个节点进行快照。
根据GitLab 版本进行备份,版本不同备份命令可能不同。
GitLab 12.2 或更高版本(我们公司备份命令):
sudo gitlab-backup create
GitLab 12.1 及更早版本:
gitlab-rake gitlab:backup:create
如果您从源代码安装了 GitLab,请使用以下命令:
sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
如果您在 Docker 容器中运行 GitLab,请根据您安装的 GitLab 版本从主机运行备份。
GitLab 12.2 或更高版本:
docker exec -t <container name> gitlab-backup create
GitLab 12.1 及更早版本:
docker exec -t <container name> gitlab-rake gitlab:backup:create
备份配置文件
- 对于综合(我们公司备份路径):
/etc/gitlab/gitlab-secrets.json /etc/gitlab/gitlab.rb
- 从源安装:
/home/git/gitlab/config/secrets.yml /home/git/gitlab/config/gitlab.yml
对于Docker 安装,您必须备份存储配置文件的卷。如果您根据文档创建了 GitLab 容器,它应该在 /srv/gitlab/config目录中。
恢复 GitLab版本
要恢复 GitLab 备份:
- 在恢复之前,请务必阅读 先决条件,最重要的是,备份的版本和新的 GitLab 实例的版本必须相同。
- 恢复 GitLab,确保根据您的安装方法遵循说明。确认密钥和配置文件也已恢复。
停止 GitLab 并删除当前包,举例:从 13.12.15 到 13.7.6降级.
在主要版本之间降级时,请考虑升级到要降级的主要版本时发生的特定版本更改。这是说有些版本升级的时候进行了一些大的升级,比如调整了配置文件,是需要做相应修改的。
$ sudo gitlab-ctl stop puma #如果此时运行的是puma,要停止。14版本后必须是puma,之前是unicorn ## 停止 sidekiq $ sudo gitlab-ctl stop sidekiq ## 如果在Ubuntu上:移除当前安装包 $ sudo gitlab-ctl uninstall ## 如果在Centos上:删除当前包 $ udo yum remove gitlab-ce $ gitlab-ctl cleanse #保留数据不执行该命令 $ rm -rf /opt/gitlab #保留数据不执行该命令
注:必要时可以直接gitlab-ctl stop停止gitlab来进行降级。
将 GitLab 降级到所需版本
rpm -Uvh gitlab-ce-13.7.6-ce.0.el7.x86_64.rpm
重新配置 GitLab
gitlab-ctl reconfigure gitlab-ctl start
注:若是降级时没有删除数据目录,那么备份恢复就不用操作了。
备份数据恢复
此过程假定:
- 您已安装与创建备份 完全相同的 GitLab Omnibus 版本和类型 (CE/EE) 。
- 你sudo gitlab-ctl reconfigure至少跑过一次。
- GitLab 正在运行。如果没有,请使用sudo gitlab-ctl start.
首先确保您的备份 tar 文件位于 gitlab.rb配置中描述的备份目录中gitlab_rails['backup_path']。默认值为 /var/opt/gitlab/backups. 它需要归git用户所有。
sudo cp 11493107454_2018_04_25_10.6.4-ce_gitlab_backup.tar /var/opt/gitlab/backups/ sudo chown git.git /var/opt/gitlab/backups/11493107454_2018_04_25_10.6.4-ce_gitlab_backup.tar
停止连接到数据库的进程。让 GitLab 的其余部分继续运行:
sudo gitlab-ctl stop puma sudo gitlab-ctl stop sidekiq # Verify sudo gitlab-ctl status
接下来,恢复备份,指定要恢复的备份的时间戳:
# This command will overwrite the contents of your GitLab database! sudo gitlab-backup restore BACKUP=11493107454_2018_04_25_10.6.4-ce
GitLab 12.1 及更早版本的用户应改用该命令gitlab-rake gitlab:backup:restore。
四、版本升级
##升级前先停止unicorn或者puma、sidekiq、nginx gitlab-ctl stop unicorn gitlab-ctl stop sidekiq gitlab-ctl stop nginx #开始升级 rpm -Uvh gitlab-ce-14.6.2-ce.0.el7.x86_64.rpm gitlab-ctl reconfigure #加载配置,执行完此步骤请注意打印的信息,有时候会提示重启redis或postgresql等 #启动 gitlab-ctl start
注:每升级一个版本都要验证是否升级成功,升级大版本时要注意官网的版本更新变化。有时会对一些依赖插件做调整,如postgresql的版本等。
为啥凌晨3点还在升级?
通过官网的升级路线,我制定了以下的升级版本路线:
13.7.6-->13.8.8-->13.12.15-->14.0.11-->14.1.8-->14.2.6-->14.6.2
升级之前我备份了nginx相关的配置文件,如下:
gitlab-health.conf gitlab-http.conf nginx.conf nginx-status.conf
备份了全量代码,如下:
sudo gitlab-backup create
备份了配置文件,如下:
gitlab.rb gitlab-secrets.json
我记忆中其余的文件应该都没有动过,只有gitlab.rb中部分是自定义的,如下:
external_url 'http://192.168.0.181' unicorn['port'] = 80 gitlab_rails['backup_path'] = "/home/gitlab/backups" gitlab_rails['backup_keep_time'] = 604800 git_data_dirs({ "default" => { "path" => "/home/gitlab-data" } })
unicorn['port'] = 80 这行配置为我加班埋下了伏笔,不知是哪个挨千刀的加了这行配置(你们要相信这行绝不是我加的,因为我有证据,后面举证。)
从13.7.6-->13.8.8-->13.12.15都很丝滑,升级成功后访问查看,再进行全量代码备份,再升级。直到13.12.15-->14.0.11的时候,这种大版本的升级我知道肯定有重大的变更,通过官网查看,我们设计到的主要有两项变更:
- 已放弃对 PostgreSQL 11 的支持。确保在更新到 GitLab 14.0 之前将 您的数据库更新到版本 12。
- GitLab 14.0 中删除了对 Unicorn 的支持,转而支持 Puma。Puma 具有多线程架构,与 Unicorn 等多进程应用程序服务器相比,它使用的内存更少。使用 Puma 减少了 40% 的内存消耗。
PostgreSQL 12在升级GitLab 13.8.8时候会自动升级为12,至于Puma需要将配置文件中Unicorn相关的都调整为Puma,如下:
external_url 'http://192.168.0.181' puma['port'] = 80 gitlab_rails['backup_path'] = "/home/gitlab/backups" gitlab_rails['backup_keep_time'] = 604800 git_data_dirs({ "default" => { "path" => "/home/gitlab-data" } })
但是在升级完成的时候访问报502,我以为操作有误,来来回回试了很多遍降级、升级都是502。此时差不多22点了吧(gitlab的备份超级慢,耽误了很多时间),版本停留到了13.12.15,其实此时已经脱离了gitlab漏洞范围了,索性回家洗洗睡吧。
(有没有记流水账的感觉?)
回家躺床上,越想越睡不着,“为什么会这样哩?到底哪里出的问题?”,这股牛劲促使着我,我又起来了,开始查找有关的解决方案,试了几次还是不行,最后我猛然想起来,最开始之前的版本我也有备份的配置文件。因为在这之前我还升级过两次,2020.7.10和2021.2.9都升级过,看吧,我是有证据的,最后的配置文件我是有备份的,虽然我记性很好,但是我还是崇尚“好记性不如烂笔头”。
(王婆卖瓜自卖自夸...)
其中2020.7.10是8.6-->13.0.0,也是跨越了好几个大版本的升级。如下配置:
external_url 'http://192.168.0.181' gitlab_rails['backup_path'] = "/home/gitlab/backups" git_data_dir "/home/gitlab-data"
2021.2.9是13.0.0-->13.7.6,如下配置:
external_url 'http://192.168.0.181' gitlab_rails['backup_path'] = "/home/gitlab/backups" gitlab_rails['backup_keep_time'] = 604800 git_data_dirs({ "default" => { "path" => "/home/gitlab-data" } })
看到了吧,现在的配置文件比原先的时候多了unicorn['port'] = 80,在升级14之前我改为了puma['port'] = 80,这到底是谁加的呢?
其实unicorn默认的端口是8080,我想是因为端口冲突有人添加了这一行配置。理论上这行不通啊,因为gitlab的nginx默认端口也是80,如下:
... server { listen *:80; server_name 192.168.0.181; } ...
两者都是80端口,难道不冲突吗?但是之前确实是可以启动并且正常访问...
升级14之前我改为了puma['port'] = 80,这个时候确实和gitlab的nginx端口冲突了,导致502访问不成功。我将80改成了81,顺利升级到14.0.11,最后经过几个版本的跨越升级到了14.6.2。
此时已经凌晨3点半了,潇洒的在群里拽了上图后就睡了。
再来说说服务器挖矿的事吧,其实挖矿危机并没有完全解决,即使升级了也无法彻底解决,只要gitlab的定时任务开启,挖矿进程就会死灰复燃,最彻底的做法就是重新装系统,好在我们后来对服务器进行了虚拟化,采用专机专用。
我想说“安全无小事,运维靠大家。” 等啥里,赶紧去检查自家gitlab的版本吧,或者提桶跑路也行。