概述

在使用 Jenkins 作为 CI 和 CD 工具的时候,我们经常可能需要使用一些保密的信息,比如 Github 的账号密码,或者机器的 SSH Key 之类的,我们经常不希望所有的人都能够看到这些信息,所以我们就会查看 Jenkins 的各种概念,看是否有满足需求的东西。

于是,我们就能发现 Jenkins Credentials,然后就觉得它满足了我们的需求,然后就把保密信息放在 Credentials 里面了。但是,当过了一段时间之后,你就会发现事实并没有那么简单。

Credentials 是保存在本地的

虽然 Credentials 是加密的,但是 Jenkins 也需要保存下来,所以,这些信息无论是放在数据库还是文件,总是有地方存放的。事实上,Jenkins 会将这些信息存放在目录 $JENKINS_HOME/secrets/ 中,例如:

  1. [root@liqiang.io]# sudo ls -al /var/lib/jenkins/secrets
  2. total 40
  3. drwx------ 2 jenkins jenkins 4096 Jun 4 11:35 .
  4. drwxr-xr-x 16 jenkins jenkins 4096 Jun 13 11:32 ..
  5. -rw-r--r-- 1 jenkins jenkins 48 May 29 08:15 hudson.console.ConsoleNote.MAC
  6. -rw-r--r-- 1 jenkins jenkins 32 May 29 08:21 hudson.model.Job.serverCookie
  7. -rw-r--r-- 1 jenkins jenkins 272 May 29 08:07 hudson.util.Secret
  8. -rw-r--r-- 1 jenkins jenkins 32 May 29 07:50 jenkins.model.Jenkins.crumbSalt
  9. -rw-r--r-- 1 jenkins jenkins 256 May 29 07:50 master.key
  10. -rw-r--r-- 1 jenkins jenkins 272 May 29 08:01 org.jenkinsci.main.modules.instance_identity.InstanceIdentity.KEY
  11. -rw-r--r-- 1 jenkins jenkins 272 May 29 08:26 org.jenkinsci.plugins.workflow.log.ConsoleAnnotators.consoleAnnotator
  12. -rw-r--r-- 1 jenkins jenkins 48 Jun 4 11:35 org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices.mac

这些信息是可以复制拷贝的,如果有人可以访问我的 Credentials 文件,那么他们将可以完全访问我整个 Jenkins 实例及其访问的所有内容。

Credentials 是可以打印的

除了本地保存文件泄露之外,实际上,在使用这些 Credentials 的时候,这些信息都是以明文的方式传递的(不然我们的应用要怎么使用呢?),并且以环境变量的传递给应用,例如下面我的一个 Jenkins Pipeline 的运行参数有这个参数:

图 :这个是图片说明

然后再我的 Jenkins 任务配置中可以直接通过环境变量的方式读取这个环境变量:

  1. [root@liqiang.io]# cat Jenkinsfile
  2. ... ...
  3. stage('create vke cluster(terragrunt apply)') {
  4. steps {
  5. dir("/home/jenkins/${ENV}/${CLUSTER_NAME}") {
  6. sh 'TEST_ACCESS_KEY=${ACCESS_KEY} TEST_SECRET_KEY=${SECRET_KEY} terragrunt apply -auto-approve'
  7. ... ...

如果我这里不是一个合法的 Jenkins 任务,而是一个想偷鸡的脚本,那么我将可以这么打印出我想要看到的加密信息:

  1. [root@liqiang.io]# cat Jenkinsfile
  2. ... ...
  3. stage('create vke cluster(terragrunt apply)') {
  4. steps {
  5. dir("/home/jenkins/${ENV}/${CLUSTER_NAME}") {
  6. sh 'echo "ACCESS_KEY = ${ACCESS_KEY}"'
  7. sh 'echo "SECRET_KEY = ${SECRET_KEY}"'
  8. ... ...

所以,从这里也可以看出 Credentials 其实也并不是安全的。

真的安全的做法

那么,既然 Credentials 不是真的安全,那么有真的安全的做法吗?我个人的看法这其实和 Kubernetes 的 Secret 遇到的问题类似,我们可以通过一些额外的方式保证中间传输方式的安全(即避免第一个问题,以及第二个的部分安全问题)。但是,对于恶意应用的问题,我们可以通过应用身份识别的方式来保证授予真正的应用才能够获取到加密的数据。

但是,这些做法我都是根据个人的想法提出来的,并没有真正地去实践过,所以,如果你真的遇到了类似的需求,并且有所不同的意见,欢迎留言交流。

Ref