1. CICD 서버에 저장해두고 사용하는 방식의 단점
k8s 로 배포하는 구성을 Jenkins 로 진행하는 경우, Jenkins가 설치된 CICD 서버에서 아래 두가지 스테이지를 진행하게 된다.
- 빌드된 이미지를 container registry 에 push(docker push)
- k8s 클러스터에 오브젝트들을 배포(helm upgrade --install 또는 kubectl apply)
docker push 를 위해서는 CICD 서버에서 docker hub에 로그인이 되어 있어야 한다. 아래와 같은 경로에 계정 정보가 base64 인코딩 되어있다.
$ cat ~/.docker/config.json
{
"auths": {
"https://index.docker.io/v1/": {
"auth": "<base64 인코딩 된 id:password 값>"
}
}
}
<id>:<passowrd> 평문을 base64 인코딩 한 값이라서, 이 값을 알게 되면 누구나 실제 id, password 값을 쉽게 알 수 있다.
또한 k8s 클러스터의 관리자 인증서는 아래와 같은 경로에 존재한다.
$ cat /var/lib/jenkins/.kube/config
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: ...
server: ...
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: ...
client-key-data: ...
이 인증서 정보를 알게되면 관리자 권한으로 k8s 클러스터에 명령어를 보낼 수 있게 되어 매우 위험하다. 이러한 중요한 기밀정보를 CICD 서버에 영구 저장해두고 사용하는 방식은 바람직하지 않다.
2. Jenkins 의 Credentials 으로 생성하기
따라서 이러한 중요한 데이터를 암호화하여 관리하기 위해 Jenkins 의 Credentials 을 사용할 수 있다.
아래와 같은 경로로 이동한다.
Jenkins 관리 > Credentials > System > Global > Add Credentials




여기서 먼저 Username with password 를 선택해서 Docker hub 계정정보를 credentials 로 생성해준다.


다음으로 아래 이미지처럼 k8s 인증서를 Secret file 로 등록한다. 인증서는 미리 CICD 서버에서 로컬 컴퓨터로 복사해두고 업로드한다.


3. CICD 서버에서 인증정보 삭제하기
아래 명령어로 docker logout 하여 도커 허브 인증정보를 삭제한다.
$ docker logout
Removing login credentials for https://index.docker.io/v1/
// 인증정보가 삭제됨을 확인
$ cat ~/.docker/config.json
{
"auths": {}
}
아래 명령어로 쿠버네티스 인증서 파일을 삭제한다.
$ rm -rf ~/.kube/config
// kubectl 명령어를 날려 권한 없음 확인
$ kubectl get pods -A
E0526 23:17:54.778287 22685 memcache.go:265] couldn't get current server API group list: <html><head><meta http-equiv='refresh' content='1;url=/login?from=%2Fapi%3Ftimeout%3D32s'/><script id='redirect' data-redirect-url='/login?from=%2Fapi%3Ftimeout%3D32s' src='/static/8c86e82d/scripts/redirect.js'></script></head><body style='background-color:white; color:white;'>
Authentication required
<!--
-->
</body></html>
4. Jenkinsfile 에서 credentials 사용하기
아래와 같이 컨테이너 업로드가 포함된 스텝에서 withCredentials 와 usernamePassword 를 이용해 docker hub 계정정보를 취득하여 사용한다. credentialsId 의 값으로 사용할 credentials 의 id 를 지정해야 한다.
stage('이미지 빌드 및 업로드') {
steps {
...
script{
// credentials 에서 가져온 계정정보로 도커 로그인
withCredentials([usernamePassword(credentialsId: 'docker_username_password', passwordVariable: 'PASSWORD', usernameVariable: 'USERNAME')]) {
sh "echo " + '${PASSWORD}' + " | docker login -u " + '${USERNAME}' + " --password-stdin"
}
...
}
}
post {
always {
// 도커 로그아웃하여 config.json 파일을 정리해줌
sh "docker logout"
}
}
}
쿠버네티스 인증서는 파일로 생성했기 때문에 아래와 같이 withCredentials 와 file 을 이용해 취득한다. 마찬가지로 credentialsId 의 값으로는 사용할 credentials 의 id 를 지정한다. helm upgrade 명령어의 옵션으로 --kubeconfig ${KUBECONFIG} 를 넘겨 인증서를 사용할 수 있게 한다.(그 이외의 변수는 신경쓰지 말자)
stage('헬름 배포') {
steps {
// 클러스터 인증서 정보를 가져와 KUBECONFIG 변수에 담아 사용
withCredentials([file(credentialsId: 'k8s_admin_config', variable: 'KUBECONFIG')]) {
sh "helm upgrade sample-api ./sample-api -f ./sample-api/values-${params.PROFILE}.yaml" +
" -n sample-ns --install --kubeconfig " + '${KUBECONFIG}' +
" --wait --timeout=10m" +
" --set image.tag=${TAG}" +
" --set image.repository=${DOCKERHUB_USERNAME}/sample-api"
}
}
}
5. Jenkins pipeline 에서 credentials 사용 확인
docker_username_password 확인

k8s_admin_config 확인

