Gitlab 利用Server端Hook来锁定文件不被修改

1、背景

研发gitlab CI/CD时,需要编辑一个整个代码仓库统一的CI/CD流程,用于流程与权限的控制。众所周知,Gitlab的CI/CD流程是通过.gitlab-ci.yml文件配置的。通常,如果用户拉出自己的开发分支,那么该yaml文件也会被用户修改,也就是说用户可以完全不用当前的CI/CD流程而重新自定义自己的流程,越权部署代码,存在极大的安全风险。

2、适用场景

需要利用Gitlab的CI/CD功能,保护.gitlab-ci.yml不被普通用户修改;保护其他CI/CD调用到的相关文件不被用户修改。或推广到保护代码仓库中任意文件。

3、方法论

Gitlab目前并没有直接提供锁定或者保护文件相关的功能,经过充分思考与研究后,采用通过配置服务端钩子(Hook onServer),来检查特定文件是否被修改,如有发生,就拒绝接受用户推到远端的代码以保护文件。

4、开发与实践

  • 代码仓库位置
    可能位置1:/home/git/repositories//.git
    可能位置2:/var/opt/gitlab/git-data/repositories//.git
    注意: 代码仓库名称与路径可能被哈希处理了,例如当前测试的gitlab机器上就是这种情况,需要进入@hashed目录,
sh-4.2$ pwd
/var/opt/gitlab/git-data/repositories
sh-4.2$ ls
+gitaly  @hashed
sh-4.2$ cd \@hashed/
sh-4.2$ tree
`-- d4
    `-- 73
        |-- d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35.git
        |   |-- branches
        |   |-- config
        |   |-- custom_hooks
        |   |   `-- pre-receive
        |   |-- description
        |   |-- HEAD
        |   |-- hooks
        |   |   |-- applypatch-msg.sample
        |   |   |-- commit-msg.sample
        |   |   |-- fsmonitor-watchman.sample
        |   |   |-- post-update.sample
        |   |   |-- pre-applypatch.sample
        |   |   |-- pre-commit.sample
        |   |   |-- pre-merge-commit.sample
        |   |   |-- prepare-commit-msg.sample
        |   |   |-- pre-push.sample
        |   |   |-- pre-rebase.sample
        |   |   |-- pre-receive.sample
        |   |   `-- update.sample
        |   |-- info
        |   |   |-- exclude
        |   |   `-- refs
        |   |-- language-stats.cache
        |   |-- objects
        |   |   |-- 47
        |   |   |   `-- 81462ff2e83f3130effecea404514a8ef7382
        |   |   |-- info
        |   |   |   `-- packs
        |   |   `-- pack
        |   |       |-- pack-00634d576da38a59c654603dbb72a9e12d647124.bitmap
        |   |       |-- pack-00634d576da38a59c654603dbb72a9e12d647124.idx
        |   |       |-- pack-00634d576da38a59c654603dbb72a9e12d647124.pac
        |   |-- packed-refs
        |   `-- refs
        |       |-- heads
        |       |   `-- daliang_test_branch
        |       |-- keep-around
        |       |   `-- f37f13e889088502c18715e974299e3aafe0ff7a
        |       |-- merge-requests
        |       `-- pipelines

找到要配置的代码仓库,上图同时也展示仓库的目录与文件结构。

  • 配置服务端钩子

服务器端的钩子主要为:
pre-receive:
在有人用git push向仓库推送代码时被执行
post-receive:
post-receive钩子在成功推送后被调用,适合用于发送通知。对很多工作流来说,这是一个比post-commit更好的发送通知的地方,因为这些更改在公共的服务器而不是用户的本地机器上。给其他开发者发送邮件或者触发一个持续集成系统都是post-receive常用的操作。这个脚本没有参数,但和pre-receive一样通过标准输入读取
update:
update钩子在pre-receive之后被调用,用法也差不多。它也是在实际更新前被调用的,但它可以分别被每个推送上来的引用分别调用。也就是说如果用户尝试推送到4个分支,update会被执行4次。和pre-receive不一样,这个钩子不需要读取标准输入。
事实上,它接受三个参数:
更新的引用名称
引用中存放的旧的对象名称
引用中存放的新的对象名称

因此,我们这里用pre-receive。

sh-4.2$ cd \@hashed/d4/73/d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35.git/
sh-4.2$ mkdir custom_hooks
vim pre-receive

该文件为:

#!/bin/bash
echo "I'm a hooked file on server"
z40=0000000000000000000000000000000000000000
echo $GL_USERNAME
while read oldrev newrev refname; do

 if [ $oldrev == $z40 ]; then
   # Commit being pushed is for a new branch
   oldrev=4b825dc642cb6eb9a060e54bf8d69288fbee4904
 fi
 yaml_file_name=".gitlab-ci.yml"
 approval_user="root"
 file_name=$(git diff --name-only $oldrev $newrev)
 if [ "$yaml_file_name" == "$file_name" ] && [ $GL_USERNAME != "$approval_user" ]; then
         echo "No permission to modify ${yaml_file_name}"
         exit 1
 fi
done
echo "I'm a hooked file on server"
  • 测试结果
    当时用户修改.gitlab-ci.yml之后push,会被服务端拒绝,从而保护了该文件及CI/CD流程不被篡改。
17:41:54.577: [b2c-airflow-poc] git -c credential.helper= -c core.quotepath=false -c log.showSignature=false push --progress --porcelain origin refs/heads/daliang_test_branch:daliang_test_branch
Authenticated to 3.86.51.69 ([3.86.51.69]:22).
Enumerating objects: 5, done.
Delta compression using up to 12 threads
Total 3 (delta 2), reused 0 (delta 0)
remote: I'm a hooked file on server        
remote: No permission to modify .gitlab-ci.yml        
Transferred: sent 3368, received 3948 bytes, in 1.2 seconds
Bytes per second: sent 2789.3, received 3269.7
error: failed to push some refs to 'git@3.86.51.69:root/b2c-airflow-poc.git'
To 3.86.51.69:root/b2c-airflow-poc.git
!	refs/heads/daliang_test_branch:refs/heads/daliang_test_branch	[remote rejected] (pre-receive hook declined)
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值