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 확인

블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,