개요
Credentials이 포함된 Jenkins 파이프라인을 구성해서 사용 중인데, Jenkins 서버를 다른 서버로 이관하고자 한다. Jenkins 디렉터리를 그대로 복사해서 사용하면 좋겠지만, 그렇게 처리하기가 애매하고 작업할 수도 많지 않아 직접 옮기는 작업을 진행하고 있다. 하지만, 복사가 필요한 Credentials 값이 전부 Serect으로 처리되어 있어 실제 값을 알 수 없는 상태다.
Jenkins에서 Credentials의 Secret을 복호화하는 방법을 몇 가지 알아보려고 한다.
hudson.util.Secret.decrypt
Jenkins 스크립트 콘솔에서 hudson.util.Secret.decrypt 함수를 사용하면 암호화된 값을 복호화할 수 있다. 단, 암호화된 값을 알아내야 하는데, 개발자 모드를 사용하면 알아낼 수 있다.
1. 암호문 알아내기
값을 확인할 Credential로 접근한다.
이 페이지에서 Update 버튼을 클릭하면 값을 갱신할 수 있는 페이지로 이동하는데,
보면 값에 해당하는 부분이 Concealed되어 있음을 알 수 있다. 여기서 Change Password 버튼을 클릭하면 아래와 같이 마스킹된 값을 볼 수 있다.
이 상태에서 브라우저의 개발자 모드로 접근해 확인할 요소를 클릭하면 아래와 같이 선택한 요소의 HTML을 찾을 수 있다.
찾은 tag 속성 중 value가 바로 Secret의 암호문에 해당한다.
2. 스크립트 콘솔에서 복호화
이제 Jenkins 스크립트 콘솔로 접근하여 아래 코드를 실행시킨다.
println hudson.util.Secret.decrypt("암호문")
# 예시
println hudson.util.Secret.decrypt("{AQAAABAAAAAQ9Db4FBoIVP6J7HBc2bhBlwjf56/tbk5wtWWQbgD2NC8=}")
평문이 test라는 것을 확인할 수 있다.
+ 참고로 평문을 암호화할 떄는 아래 코드를 사용한다.
println(hudson.util.Secret.fromString("some_text").getEncryptedValue())
모든 Credentials 확인하기
스크립트 콘솔에서 아래 코드를 통해 Jenkins에 저장된 모든 Credentials의 목록과 그 값을 확인할 수도 있다.
import com.cloudbees.plugins.credentials.CredentialsProvider
import com.cloudbees.plugins.credentials.Credentials
import com.cloudbees.plugins.credentials.domains.Domain
import jenkins.model.Jenkins
def indent = { String text, int indentationCount ->
def replacement = "\t" * indentationCount
text.replaceAll("(?m)^", replacement)
}
Jenkins.get().allItems().collectMany{ CredentialsProvider.lookupStores(it).toList()}.unique().forEach { store ->
Map<Domain, List<Credentials>> domainCreds = [:]
store.domains.each { domainCreds.put(it, store.getCredentials(it))}
if (domainCreds.collectMany{ it.value}.empty) {
return
}
def shortenedClassName = store.getClass().name.substring(store.getClass().name.lastIndexOf(".") + 1)
println "Credentials for store context: ${store.contextDisplayName}, of type $shortenedClassName"
domainCreds.forEach { domain , creds ->
println indent("Domain: ${domain.name}", 1)
creds.each { cred ->
cred.properties.each { prop, val ->
println indent("$prop = \"$val\"", 2)
}
println indent("-----------------------", 2)
}
}
}
참고 문서
https://www.codurance.com/publications/2019/05/30/accessing-and-dumping-jenkins-credentials