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 (예: Docker 또는 shell)와 함께 작동하는 솔루션입니다.

SSH 키 생성 및 사용

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

  1. 로컬에서 ssh-keygen으로 새 SSH 키 쌍 생성합니다.
  2. 개인 키를 파일 유형 CI/CD 변수로 프로젝트에 추가합니다. 변수 값은 줄 바꿈(LF 문자)으로 끝나야 합니다. 줄 바꿈을 추가하려면, CI/CD 설정에 SSH 키를 저장하기 전에 SSH 키의 마지막 줄 끝에서 Enter 또는 Return을 누릅니다.
  3. 작업에서 ssh-agent를 실행하여 개인 키를 로드합니다.
  4. 액세스 권한이 있는 서버에 공용 키를 복사합니다 (일반적으로 ~/.ssh/authorized_keys에). 비공개 GitLab 리포지토리에 접근하는 경우, 공용 키를 deploy key로 추가해야 합니다.

다음 예에서 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 필드에 이전에 생성한 키 쌍의 개인 키 내용을 붙여넣습니다. 파일이 줄 바꿈으로 끝나는지 확인합니다. 줄 바꿈을 추가하려면, SSH 키의 마지막 줄 끝에서 Enter 또는 Return을 누릅니다.
  3. .gitlab-ci.ymlbefore_script 작업으로 수정합니다. 다음 예에서는 Debian 기반 이미지를 가정합니다. 필요에 맞게 수정하세요:

    before_script:  
      ##  
      ## Docker에서 필요하므로 ssh-agent를 설치합니다.  
      ## (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 리포지토리에 접근하는 경우, deploy key로 추가해야 합니다.

그게 다입니다! 이제 빌드 환경에서 비공식 서버 또는 리포지토리에 접근할 수 있습니다.

SSH 키를 사용하는 Shell Executor

Shell executor를 사용하고 Docker를 사용하지 않는 경우, SSH 키를 설정하는 것이 더 쉽습니다.

GitLab Runner가 설치된 머신에서 SSH 키를 생성할 수 있으며, 이 머신에서 실행되는 모든 프로젝트에서 해당 키를 사용할 수 있습니다.

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

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

    sudo su - gitlab-runner
    
  3. SSH 키 생성 지침에 따라 SSH 키 쌍을 생성합니다.
    SSH 키에 암호를 추가하지 마세요. 그렇지 않으면 before_script에서 그에 대한 프롬프트가 표시됩니다.

  4. 마지막 단계로, 이전에 생성한 공개 키를 빌드 환경 내에서 액세스할 수 있는 서비스에 추가합니다.
    개인 GitLab 리포지토리에 접근하는 경우 배포 키로 추가해야 합니다.

키를 생성한 후, 원격 서버에 로그인하여 지문을 수락해 보세요:

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를 “Key”로 하는 새로운 파일 유형 CI/CD 변수를 만들고,
“Value”에 ssh-keyscan의 출력을 추가합니다. 파일이 줄바꿈으로 끝나는지 확인하세요. 줄바꿈을 추가하려면, 저장하기 전에 SSH 키의 마지막 줄 끝에 Enter 또는 Return를 누르세요.

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

참고:

.gitlab-ci.ymlssh-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을 사설 서버의 도메인 이름으로 바꾸세요.  
  ## 연결할 서버가 여러 개 있는 경우 해당 명령을 반복하세요. 
  ## 키 유형을 지정하려면 -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 변수를 사용합니다.

문제 해결

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

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

SSH 키를 파일 형식 CI/CD 변수로 저장할 때, 값은 새 줄(LF 문자)로 끝나야 합니다. 새 줄을 추가하려면, 변수를 저장하기 전에 SSH 키의 -----END OPENSSH PRIVATE KEY----- 행 끝에서 Enter 또는 Return 키를 누르세요.