본문 바로가기
CI.CD/Jenkins

[Jenkins] Credentials 완벽 가이드 (보안 사고 100% 방어법)

반응형

파이프라인을 구축하다 보면 젠킨스가 다른 시스템(Github, AWS, Docker Hub, 사내 데이터베이스 등)과 통신해야 하는 일이 무수히 발생합니다. 이때 필연적으로 필요한 것이 바로 '비밀번호, API 키, SSH 인증키' 같은 자격 증명(Credentials) 데이터입니다.
만약 이러한 민감한 정보들을 Jenkinsfile 안에 평문(Plain Text)으로 떡하니 적어둔다면, 소스코드를 열람할 수 있는 모든 개발자나 인턴에게 회사의 가장 중요한 마스터 키를 쥐여주는 꼴이 됩니다.

이번 [Jenkins 실무 완벽 가이드] 포스팅에서는 보안 유출 사고를 원천 차단하는 Jenkins Credentials Plugin의 완벽한 활용법과 파이프라인 내에서의 바인딩 노하우를 3,000자 분량으로 아주 치밀하게 딥다이브 해보겠습니다.

🚫 1. 하드코딩(Hardcoding)의 끔찍한 결말

아직도 많은 초보 개발자들이 Github에 AWS Access Key나 데이터베이스 패스워드를 그대로 커밋하는 실수를 저지릅니다. 이런 실수는 단순한 해프닝으로 끝나지 않습니다.

해커들은 전 세계의 Public Github 레포지토리를 24시간 감시하는 자동화 봇(Bot)을 돌리고 있습니다. 만약 AWS_SECRET_KEY = "AKIA..." 라는 문자열이 커밋되는 순간, 봇은 이를 즉시 낚아채어 3분 안에 최고 사양의 EC2 인스턴스를 수백 대 띄워버리고 암호화폐 채굴을 시작합니다. 하루아침에 회사로 수천만 원의 청구서가 날아오게 됩니다.

Private 레포지토리라고 안심할 수 없습니다. 퇴사한 직원이 악의를 품고 코드를 유출하거나, 사내망이 랜섬웨어에 감염되었을 때 가장 먼저 타겟이 되는 것이 바로 평문으로 적힌 Jenkinsfile 내부의 비밀번호들입니다. 절대로, 단 하나의 비밀번호도 코드 저장소에 올려서는 안 됩니다.


🔐 2. Credentials Plugin: 젠킨스의 금고 역할

젠킨스는 이러한 보안 문제를 해결하기 위해 내부에 거대한 '금고'를 제공합니다. 관리자 권한을 가진 사람만이 이 금고에 접근하여 시크릿 데이터를 넣을 수 있으며, 한 번 저장된 데이터는 심지어 관리자 본인조차도 다시 읽어(Decrypt) 볼 수 없도록 단방향에 가까운 강력한 암호화(AES) 처리가 이루어집니다.

금고에 시크릿 데이터 저장하기:

  1. Jenkins 메인 대시보드에서 [Jenkins 관리] -> [Manage Credentials]로 들어갑니다.
  2. (global) 도메인을 클릭하고 좌측의 [Add Credentials]를 누릅니다.
  3. Kind (자격 증명 종류): 저장할 데이터의 타입에 맞게 선택합니다. 가장 많이 쓰이는 3가지는 다음과 같습니다.
    • Username with password: 일반적인 ID/PW 조합 (예: Docker Hub 로그인, DB 접속)
    • Secret text: 단일 문자열 토큰 (예: AWS API 키, Slack 봇 토큰, Github Token)
    • SSH Username with private key: 리눅스 서버 접속이나 Git 클론에 쓰이는 pem 키(.pem)
  4. ID (매우 중요 🌟): 파이프라인(Jenkinsfile)에서 이 자격 증명을 꺼내 쓸 때 호출할 고유한 이름표입니다. 스페이스바 없이 aws-prod-secret-key, docker-hub-credentials 처럼 직관적으로 지어주어야 합니다.
  5. Description: 다른 팀원들이 알아볼 수 있도록 용도를 적어둡니다. (예: "운영서버 배포용 AWS 키")
  6. Create를 눌러 저장합니다.

⚙️ 3. 파이프라인에서 Credentials 안전하게 꺼내 쓰기

금고에 데이터를 안전하게 넣었으니, 이제 Jenkinsfile에서 그 데이터를 꺼내어(바인딩하여) 사용해 볼 차례입니다. 실무에서 쓰이는 2가지 핵심 문법을 소개합니다.

방법 1: withCredentials 블록 사용 (특정 단계에서만 잠깐 쓰기)

특정 steps 안에서만 잠깐 보안 토큰을 쓰고 즉시 메모리에서 날려버리고 싶을 때 사용합니다. 보안성이 가장 뛰어난 방법입니다.

pipeline {
    agent any
    stages {
        stage('Deploy to Server') {
            steps {
                // 젠킨스 금고에서 'ssh-prod-key'라는 ID를 찾아 SSH_KEY 변수에 잠깐 담아둡니다.
                withCredentials([sshUserPrivateKey(credentialsId: 'ssh-prod-key', keyFileVariable: 'SSH_KEY', usernameVariable: 'SSH_USER')]) {
                    sh 'echo "서버 접속 중..."'
                    // 변수를 사용해 서버에 접속하는 쉘 스크립트 실행
                    sh 'ssh -i ${SSH_KEY} ${SSH_USER}@192.168.0.100 "pm2 restart app"'
                }
                // 블록을 벗어나는 순간 SSH_KEY 변수는 증발하여 안전해집니다.
            }
        }
    }
}

방법 2: environment 블록 사용 (실무 99% 권장 방식)

매번 withCredentials 블록으로 감싸면 파이프라인 코드가 뚱뚱해지고 가독성이 떨어집니다. 따라서 파이프라인 최상단의 환경변수 블록에서 credentials() 내장 헬퍼 함수를 통해 깔끔하게 끌어다 쓰는 방식을 훨씬 선호합니다.

pipeline {
    agent any
    environment {
        // 1. Secret text 타입 가져오기
        AWS_ACCESS_KEY = credentials('aws-access-key-id')
        
        // 2. Username with password 타입 가져오기 (매우 편리함!)
        // 'docker-login-id'를 가져와 DOCKER_CREDS 변수에 담으면, 젠킨스가 알아서 뒤에 _USR, _PSW를 붙인 2개의 변수를 추가로 생성해 줍니다.
        DOCKER_CREDS = credentials('docker-login-id')
    }
    stages {
        stage('Docker Push') {
            steps {
                // 평문 비밀번호가 노출되지 않고 안전하게 로그인됩니다.
                sh 'docker login -u ${DOCKER_CREDS_USR} -p ${DOCKER_CREDS_PSW}'
                sh 'docker push my-app:latest'
            }
        }
    }
}

🛡️ 4. 완벽한 방어: 콘솔 로그 마스킹 (Masking)

이렇게 변수에 담아서 썼을 때, 혹시라도 개발자가 콘솔 로그에 비밀번호를 출력(echo)해보려 시도하면 어떻게 될까요?

steps {
    // 호기심 많은 신입 개발자가 비밀번호를 로그에 찍어봄
    sh 'echo "DB Password is: ${DOCKER_CREDS_PSW}"'
}

젠킨스는 빌드를 실행하면서 콘솔 출력 버퍼를 실시간으로 스니핑(감시)합니다. 만약 credentials()를 통해 불려 나온 값이 로그에 출력되려고 하면, 그 값을 즉시 별표(*****)로 마스킹(Masking) 처리해 버립니다. 즉, 화면에는 DB Password is: **** 라고만 찍히게 되어, 내부 개발자의 악의적인 시도까지도 완벽하게 방어해 냅니다.


🎯 5. 마무리 및 다음 단계

지금까지 사내 인프라의 마스터 키를 하드코딩의 위험에서 구출해내는 완벽한 Credentials Plugin 설정과 파이프라인 바인딩 전략에 대해 3,000자 분량으로 밀도 있게 살펴보았습니다. 이제 여러분의 Jenkinsfile은 Github Public 저장소에 전체 공개로 올려놓아도 보안상 아무런 타격이 없는 무결점 코드가 되었습니다.

자격 증명을 다루면서 자연스럽게 environment 블록을 맛보셨을 것입니다. 파이프라인에서 변수를 적절하게 활용하는 것은 코드를 재사용 가능하고(Reusable) 우아하게 만드는 핵심 기술입니다. 이어지는 11단계 포스팅에서는 빌드 번호, 브랜치명 같은 젠킨스의 내장 환경변수들과 사용자 정의 변수들을 활용하여 다이내믹(Dynamic) 파이프라인을 구축하는 고급 노하우에 대해 아주 치밀하게 파헤쳐 보겠습니다!

반응형