GitLab CI/CD에서 SSH 키 사용하기

Tier: Free, Premium, Ultimate Offering: GitLab.com, Self-managed, GitLab Dedicated

GitLab은 현재 빌드 환경(여기서는 GitLab Runner가 실행됨)에서 SSH 키를 관리하는 기본 지원이 없습니다.

다음과 같은 경우에 SSH 키를 사용합니다.

  • 내부 서브모듈을 확인합니다.
  • 패키지 관리자를 사용하여 개인 패키지를 다운로드합니다. 예: Bundler.
  • 애플리케이션을 자체 서버 또는 Heroku와 같은 곳에 배포합니다.
  • 빌드 환경에서 원격 서버로 SSH 명령을 실행합니다.
  • 빌드 환경에서 파일을 원격 서버로 Rsync합니다.

위 중 어느 하나라도 해당된다면 SSH 키가 필요할 확률이 높습니다.

가장 널리 지원되는 방법은 .gitlab-ci.yml을 확장하여 빌드 환경에 SSH 키를 주입하는 것이며, 이 방법은 executor(예: 도커 또는 쉘)의 유형에 관계없이 작동합니다.

SSH 키 생성 및 사용

GitLab CI/CD에서 SSH 키를 생성하고 사용하려면:

  1. ssh-keygen을 사용하여 로컬에서 새 SSH 키 쌍을 생성합니다.
  2. 생성된 개인 키를 프로젝트에 파일 형식의 CI/CD 변수로 추가합니다. 변수 값은 개행(라인 피드)으로 끝나야 합니다. 개행을 추가하려면 SSH 키의 마지막 줄 뒤에 Enter 키를 누르고 저장하세요.
  3. 작업 중에 ssh-agent를 실행하여 개인 키를 로드합니다.
  4. 접근하려는 서버에 공개 키를 복사합니다(보통 ~/.ssh/authorized_keys에) 또는 배포 키로 추가합니다. 이 과정은 프라이빗 GitLab 저장소에 접근하는 경우 필요합니다.

아래 예에서 ssh-add - 명령어는 작업 로그에 $SSH_PRIVATE_KEY 값을 표시하지 않지만, 디버그 로깅을 가능케 한다면 노출될 수 있습니다. 또한 파이프라인의 가시성을 확인하는 것이 좋습니다.

Docker executor 사용 시 SSH 키

CI/CD 작업이 Docker 컨테이너 내에서 실행되는 경우(즉, 환경이 격리된 경우)에 코드를 프라이빗 서버에 배포하려면 SSH 키 쌍이 필요합니다.

  1. 먼저 SSH 키 쌍을 생성해야 합니다. 자세한 내용은 SSH 키 생성 지침을 따르세요. SSH 키에 패스프레이즈를 추가하지 마세요. 그렇게 하면 before_script에서 패스프레이즈를 요청합니다.

  2. 파일 형식 CI/CD 변수를 생성하세요.
    • (Key) 필드에 SSH_PRIVATE_KEY 입력
    • (Value) 필드에 이전에 생성한 키 쌍의 개인 키 내용을 붙여넣습니다. 파일이 개행으로 끝나는지 확인하세요. 개행을 추가하려면 Enter 키를 누르고 변경 사항을 저장하기 전에 마지막 줄에.
  3. .gitlab-ci.ymlbefore_script를 추가하세요. 아래 예에서는 Debian 기반 이미지를 가정하고 있습니다. 필요에 맞게 수정하세요:

    before_script:
      ##
      ## apt-get을 사용하여 ssh-agent가 설치되어 있지 않으면 설치합니다 (RPM 기반 이미지인 경우 yum으로 변경)
      ##
      - 'command -v ssh-agent >/dev/null || ( apt-get update -y && apt-get install openssh-client -y )'
    
      ##
      ## ssh-agent 실행 (빌드 환경 내부에서)
      ##
      - eval $(ssh-agent -s)
    
      ##
      ## 올바른 권한 부여, 그렇지 않으면 ssh-add가 파일을 추가하지 않습니다.
      ## SSH_PRIVATE_KEY 파일 형식 CI/CD 변수에 저장된 SSH 키를 에이전트 저장소에 추가합니다
      ##
      - chmod 400 "$SSH_PRIVATE_KEY"
      - ssh-add "$SSH_PRIVATE_KEY"
    
      ##
      ## SSH 디렉토리 생성 및 올바른 권한 부여
      ##
      - mkdir -p ~/.ssh
      - chmod 700 ~/.ssh
    
      ##
      ## 필요한 경우 Git 명령을 사용하려면 사용자 이름 및 이메일 설정
      ##
      # - git config --global user.email "user@example.com"
      # - git config --global user.name "User name"
    

    before_script는 기본값으로 설정하거나 작업별로 설정할 수 있습니다.

  4. 프라이빗 서버의 SSH 호스트 키가 확인되었는지 확인하세요.

  5. 마지막으로, 첫 번째 단계에서 생성한 공개 키를 빌드 환경 내부에서 접근하려는 서비스에 추가합니다. 프라이빗 GitLab 저장소에 접근하는 경우 배포 키로 추가해야 합니다.

여기까지입니다! 이제 빌드 환경에서 프라이빗 서버나 저장소에 접근할 수 있습니다.

SSH 키를 사용할 때 Shell 실행기 사용

만약 Docker가 아닌 Shell 실행기를 사용하는 경우 SSH 키를 설정하는 것이 더 쉽습니다.

GitLab Runner가 설치된 기기에서 SSH 키를 생성하고, 이 키를 이 기기에서 실행되는 모든 프로젝트에 사용할 수 있습니다.

  1. 먼저 작업을 실행하는 서버에 로그인합니다.

  2. 그런 다음 터미널에서 gitlab-runner 사용자로 로그인합니다:

    sudo su - gitlab-runner
    
  3. SSH 키를 생성하는 지침에 설명된 대로 SSH 키 쌍을 생성합니다. SSH 키에 암호를 추가하지 마세요. 그렇지 않으면 before_script에서 암호를 물어봅니다.

  4. 마지막 단계로, 이전에 생성한 공개 키를 빌드 환경 내부에서 액세스하고자 하는 서비스에 추가합니다. 만약 비공개 GitLab 저장소에 액세스하는 경우, 배포 키로 추가해야 합니다.

키를 생성한 후, 원격 서버에 로그인하여 fingerprint를 확인해보세요:

ssh example.com

GitLab.com의 저장소에 액세스하려면 git@gitlab.com을 사용합니다.

SSH 호스트 키 확인

개인 서버의 공개 키를 확인하여 중간자 공격을 당하고 있는지 확인하는 것은 좋은 관행입니다. 의심스러운 일이 발생하면 작업이 실패함으로써 알 수 있습니다 (공개 키가 일치하지 않으면 SSH 연결이 실패합니다).

서버의 호스트 키를 확인하려면 신뢰할 수 있는 네트워크(이상적으로 개인 서버 자체)에서 ssh-keyscan 명령을 실행합니다:

## 도메인 이름 사용
ssh-keyscan example.com

## 또는 IP 사용
ssh-keyscan 10.0.2.2

SSH_KNOWN_HOSTS를 “키”로, ssh-keyscan의 출력을 “값”으로 사용하여 새로운 파일 형식 CI/CD 변수를 만듭니다. 파일은 개행으로 끝나도록 해야 합니다. 개행을 추가하려면 변경 내용을 저장하기 전에 Enter 키나 Return 키를 누르세요.

여러 서버에 연결해야 하는 경우, 모든 서버 호스트 키를 변수의 에 한 줄에 하나씩 수집해야 합니다.

참고: .gitlab-ci.yml 내부에서 ssh-keyscan을 직접 사용하는 대신 파일 형식 CI/CD 변수를 사용하는 것은, 호스트 도메인 이름이 어떤 이유로든 변경되더라도 .gitlab-ci.yml을 바꿀 필요가 없다는 이점이 있습니다. 또한 값은 미리 정의된 것이므로, 호스트 키가 갑자기 변경되더라도 CI/CD 작업이 실패하지 않으며, 서버나 네트워크에 문제가 있는 것을 알 수 있습니다.

이제 SSH_KNOWN_HOSTS 변수가 만들어졌으므로, .gitlab-ci.yml의 내용에 추가해야 합니다:

before_script:
  ##
  ## `SSH_KNOWN_HOSTS` 파일 형식 CI/CD 변수를 만들었다고 가정하고, 다음 두 줄의 주석을 제거하세요.
  ##
  - cp "$SSH_KNOWN_HOSTS" ~/.ssh/known_hosts
  - chmod 644 ~/.ssh/known_hosts

  ##
  ## 대신, 개인 서버의 키를 스캔하기 위해 ssh-keyscan을 사용할 수도 있습니다.
  ## example.com을 개인 서버의 도메인 이름으로 바꿔주세요. 여러 서버에 연결해야 하는 경우
  ## 해당 명령을 반복하세요.
  ##
  # - ssh-keyscan example.com >> ~/.ssh/known_hosts
  # - chmod 644 ~/.ssh/known_hosts

  ##
  ## 선택적으로 호스트 키 확인을 비활성화할 수 있습니다. 이를 추가하면 중간자 공격을 당할 수 있음에 유의하세요.
  ## 경고: Docker 실행기에서만 사용하세요. Shell을 사용하면 사용자의 SSH 구성을 덮어씁니다.
  ##
  # - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" >> ~/.ssh/config'

파일 형식 CI/CD 변수 없이 SSH 키 사용

만약 파일 형식 CI/CD 변수를 사용하지 않고 싶다면, 예제 SSH 프로젝트에서 추천된 파일 형식 변수 대신 일반적인 CI/CD 변수를 사용하는 대체 방법을 보여줍니다.

문제 해결

Error loading key "/builds/path/SSH_PRIVATE_KEY": error in libcrypto 메시지

이 메시지는 SSH 키에 서식 오류가 있는 경우 반환될 수 있습니다.

파일 형식 CI/CD 변수로 SSH 키를 저장할 때 값은 반드시 개행으로 끝나야 합니다 (LF 문자). 개행을 추가하려면 SSH 키의 -----END OPENSSH PRIVATE KEY----- 라인의 끝에 Enter 키나 Return 키를 누릅니다.