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 키를 삽입하는 것이며, Docker 또는 shell과 같은 executor와 호환되는 해결책입니다.

SSH 키 생성 및 사용

GitLab CI/CD에서 SSH 키를 생성하고 사용하려면 다음을 수행합니다:

  1. 로컬에서 ssh-keygen을 사용하여 새 SSH 키 쌍을 생성합니다.
  2. 프로젝트에 파일 형식 CI/CD 변수로 비공개 키를 추가합니다. 변수 값은 개행(LF 문자)으로 끝나야 합니다. 개행을 추가하려면 마지막 줄 다음에 Enter 또는 Return을 누릅니다.
  3. 작업에서 (ssh-agent)를 실행하여 비공개 키를 로드합니다.
  4. 서버에 공개 키를 복사하여(일반적으로 ~/.ssh/authorized_keys에 저장) 또는 배포 키로 추가합니다(비공개 GitLab 리포지터리에 액세스하는 경우).

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

Docker executor를 사용하는 경우의 SSH 키

CI/CD 작업이 도커 컨테이너 내에서 실행되는 경우(즉, 환경이 캡슐화됨)에 코드를 프라이빗 서버에 배포하려면 액세스할 수 있는 방법이 필요합니다. 이 경우 SSH 키 쌍을 사용할 수 있습니다.

  1. 먼저 SSH 키 쌍을 생성해야 합니다. 자세한 정보는 SSH 키 생성 지침을 따르세요.
    • SSH 키에 암호를 추가하지 마십시오, 그렇지 않으면 before_script에서 암호를 요구합니다.
  2. 파일 형식 CI/CD 변수를 생성합니다.
    • Key 필드에 SSH_PRIVATE_KEY를 입력합니다.
    • Value 필드에 이전에 생성한 키 쌍의 비공개 키 내용을 붙여넣습니다. 파일이 개행으로 끝나도록 합니다. 개행을 추가하려면 Enter 또는 Return을 눌러 마지막 줄 다음에 커서를 위치시킨 후 변경 사항을 저장합니다.
  3. .gitlab-ci.yml을 수정하여 before_script 작업을 추가합니다. 다음 예에서는 Debian 기반 이미지를 가정합니다. 필요에 맞게 수정하십시오:

    before_script:
      ##
      ## apt-get을 사용하여 ssh-agent가 이미 설치되어 있지 않으면 설치합니다(Docker에서 필요함).
      ## (RPM 기반 이미지를 사용하는 경우 apt-get을 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 리포지터리에 액세스하는 경우 배포 키로 추가해야 합니다.

이것으로 빌드 환경에서 프라이빗 서버 또는 리포지터리에 액세스할 수 있게 되었습니다.

Shell executor를 사용하는 경우의 SSH 키

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

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

  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-agent) 명령을 실행합니다(이상적으로는 프라이빗 서버 자체에서):

## 도메인 이름을 사용합니다
ssh-keyscan example.com

## 또는 IP를 사용합니다
ssh-keyscan 10.0.2.2

SSH_KNOWN_HOSTS를 “Key”로 하고 ssh-keyscan의 출력을 “Value”로 사용하여 파일 형식 CI/CD 변수를 생성하십시오. 파일이 개행으로 끝나도록 합니다. 개행을 추가하려면 Enter 또는 Return을 눌러 마지막 줄 다음에 커서를 위치시킨 후 변경 사항을 저장합니다.

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

note
ssh-keyscan.gitlab-ci.yml 내에서 직접 사용하는 대신 파일 형식 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
  
  ##
  ## 다른 방법으로, 프라이빗 서버의 키를 스캔하는 경우가 있습니다.
  ## example.com을 프라이빗 서버의 도메인 이름으로 변경하십시오. 여러 서버에 연결해야 하는 경우 그 명령을 반복하고 키 유형을 지정하기 위해 -t 플래그를 포함하십시오.
  ##
  # - ssh-keyscan -t rsa,ed25519 example.com >> ~/.ssh/known_hosts
  # - chmod 644 ~/.ssh/known_hosts
  
  ##
  ## 호스트 키 확인을 선택적으로 비활성화할 수 있습니다. 여기에 추가하면 중간에서 가로채는 공격의 취약점에 노출될 수 있음에 유의하십시오.
  ## 경고: Docker executor에서만 사용하십시오, shell에서 사용하면 사용자의 SSH 구성을 덮어쓰게 됩니다.
  ##
  # - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" >> ~/.ssh/config'

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

파일 유형 CI/CD 변수를 사용하고 싶지 않다면, 예제 SSH 프로젝트에서 대체 방법을 확인할 수 있습니다. 이 방법은 권장된 파일 유형 변수 대신 일반적인 CI/CD 변수를 사용합니다.

문제 해결

"/builds/path/SSH_PRIVATE_KEY" 키 로드 오류: libcrypto 오류 메시지

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

파일 유형 CI/CD 변수로 SSH 키를 저장할 때, 값은 개행 (LF 문자)으로 끝나야 합니다. 개행을 추가하려면 SSH 키의 -----END OPENSSH PRIVATE KEY----- 줄의 끝에 Enter 또는 Return을 누른 후 변수를 저장하십시오.