Jenkins Security Auditing, Accessing Credential in Jenkins

jaclyn·2021년 2월 27일
1

Jenkins Security Test

목록 보기
2/2

개요

Jenkins 내에서는 중요 정보를 관리해주는 Credential Management 기능이 존재합니다.
여기에 저장된 데이터들을 Jenkins Job에 가져다 쓸 경우, 혹시나 Build Log에 유출될 수 있는 민감정보를 마스킹 처리해서 보여줍니다. 또한 Jenkins 내부에 암호화되어 저장되기 때문에 일반적으로는 안전한 것처럼 보일 수 있습니다.
하지만 공격자에게 Job을 생성 후 실행할 권한 혹은 그 이상의 권한이 있다면 몇 가지의 방법으로 이를 우회해 저장되어 있는 Credential을 알아낼 수 있습니다.
이번에는 그 우회할 수 있는 방법과 해결방안에 대해 알아보도록 하겠습니다.

환경 구성(Envrionment Configuration)

1) Jenkins Docker 이미지를 사용해 Jenkins 설치

> docker run -p 8080:8080 -p 50000:50000 -v jenkins_home:/var/jenkins_home jenkins/jenkins:lts

2) docker 기본 설정 후 Credential 생성

3) Credential을 Jenkins PipeLine에서 사용(일반적)

groovy script

withCredentials([usernamePassword(credentialsId: 'account_admin', passwordVariable: 'admin_pw', usernameVariable: 'admin_id')]) {
    // some block
    print 'id :' + admin_id
    print 'pw :' + admin_pw
}

4) Build Log에 마스킹 되어있는 것 확인

Jenkins Job을 통한 Credential 획득 방법(Accessing Credential without Encryption using Jenkins Job)

1) Jenkins Job(Pipeline) 생성 후 pipeline에 아래 groovy script 입력 후 저장

Groovy Script

withCredentials([usernamePassword(credentialsId: 'account_admin', passwordVariable: 'admin_pw', usernameVariable: 'admin_id')]) {
    
    print 'id : ' + admin_id + 'pw : ' + admin_pw
    
    print 'admin_id.collect { it } =' + admin_id.collect { it }
    print 'admin_pw.collect { it } =' + admin_pw.collect { it }
}

2) Job Build 실행 후 Console Output 확인

job 이름이 jenkins_credential_jop으로 되어있는건 다시 스크린샷 찍기 귀찮아서 그냥.. 올렸습니다

Extra comment

groovy script 에서 string.collect { var } 하게 되면 string 값들을 배열 형태로 출력해 주는데 여기서 credential의 마스킹 처리가 풀리면서 그대로 console output에 credential이 평문으로 노출됨

Jenkins Credential id 리스팅(list all of credential id in jenkins)

1) Jenkins Job(Pipeline) 생성 후 pipeline에 아래 groovy script 입력 후 저장

Groovy Script

pipeline{
    agent any
    stages {
        stage('list credentials ids') {
          steps {
            script {
              sh 'cat $JENKINS_HOME/credentials.xml | grep "<id>"'
            }
          }
        }
    }
}

2) Job Build 실행 후 Console Output 확인

Jenkins Console을 통한 System Credential 획득(Accessing System Credential using jenkins console)

Background

System Credential vs Global Credential
System Credential : Jenkins Plug-in 환경 설정 등에서만 접근 가능한 Credential, Jenkins Job에서는 접근 불가
Global Credential : Jenkins Plug-in 환경 설정 및 Jenkins Job에서 접근 가능한 Credential

즉, System Credential은 Jenkins Job에서 접근이 불가하기 때문에 획득하려면 다른 방법이 필요하다!

1) Jenkins > Credentials > Update > change password 클릭
아래와 같이 패스워드가 마스킹 처리되는 것을 볼 수 있다

Jenkins는 한번 저장한 Credential 정보를 다시 보여주지 않는다

2) 개발자 도구(F12)를 이용해 AES 방식으로 암호화된 암호문 획득

예제 : AQAAABAAAAAQy51W6BsZpM/KaF1aFlgrVCwtBvFiJKVfVo9E/nNIQt0=

3) Jenkins Script Console 이용해 AES 복호화 (https://jenkins_domain/script)

스크립트 콘솔에서는 Jenkins 서버 안에 있는 AES 암호화 키를 이용할 수 있기 때문에 복호화가 가능하다

Groovy Script

println hudson.util.Secret.decrypt("{암호문}")

위와 같이 암호화 해독이 가능하긴 하지만 위 방법이 성공하려면 아래 두 가지 조건을 만족해야 한다.
1) 스크립트 콘솔에 접근하기 위한 관리자 권한
2) Credential에 대한 Update 권한

위 두가지가 충족된다는 건 이미 다 털렸다는 걸 의미한다고 볼 수 있기 때문에 발생 가능성이 좀 낮다고 볼 수 있다.
Jenkins 권한 관리만 잘 이루어진다면 성립이 어려운 방법이라는 생각이 든다.

해결 방안(Mitigation)

1) Vault, AWS Secrets Manager와 같은 Third Party Credential Management Tool을 쓴뒤 Jenkins 에 있는 Plug-in으로 가져다 쓴다

2) 권한 관리를 잘한다

  • Jenkins > Configuration > Global Security Management > Authorization

Reference

https://www.codurance.com/publications/2019/05/30/accessing-and-dumping-jenkins-credentials

profile
DevSecOps

0개의 댓글