This page contains information related to upcoming products, features, and functionality. It is important to note that the information presented is for informational purposes only. Please do not rely on this information for purchasing or planning purposes. The development, release, and timing of any products, features, or functionality may be subject to change or delay and remain at the sole discretion of GitLab Inc.
Status Authors Coach DRIs Owning Stage Created
proposed @igor.drozdov @ayufan @arturoherrero @sranasinghe devops create 2024-02-29

Git over SSH 요청 라우팅

이 문서는 Git over SSH 라우팅의 설계 목표와 구조를 개요하고 있습니다.

개요

SSH를 통해 Git 작업(git pull/clone/fetch, git push, git archive)이 수행될 때, GitLab Shell은 요청을 처리하고 GitLab Rails에서 요청을 승인하며, Git과 사용자 사이의 양방향 데이터 교환을 위해 Gitaly에 대한 gRPC 요청을 수행합니다.

예: Git pull

sequenceDiagram participant Git on client participant GitLab Shell participant Rails participant Gitaly Note left of Git on client: git clone/fetch Git on client->>+GitLab Shell: ssh git-upload-pack ... GitLab Shell->>+Rails: GET /internal/api/authorized_keys?key=AAAA... Note right of Rails: 키 ID 조회 Rails-->>-GitLab Shell: 200 OK, command="gitlab-shell upload-pack key_id=1" GitLab Shell->>+Rails: POST /internal/api/allowed{action=upload_pack,key_id=1,project=<project>...} Note right of Rails: 인증 확인 Rails-->>-GitLab Shell: 200 OK, { gitaly: ... } GitLab Shell->>+Gitaly: SSHService.SSHUploadPack gRPC 요청 Note over Git on client,Gitaly: Git 클라이언트와 Gitaly 간 양방향 통신 Gitaly -->>-GitLab Shell: SSHService.SSHUploadPack gRPC 응답 GitLab Shell-->>-Git on client: ssh git-upload-pack 응답

Gitaly 서버는 기본적으로 암호화되지 않은 상태로 네트워크 트래픽이 이동되기 때문에 Gitaly 서버는 공개 인터넷에 노출되어서는 안 됩니다. 이 제한으로 인해 SSH 요청을 다른 인스턴스로 리디렉션하는 것이 어려워집니다.

Geo: 보조 노드로의 Git push

보조 노드로 git push가 수행될 때, 해당 요청은 주 노드로 리디렉션되어야 합니다. 주 노드의 Gitaly 서버는 노출되어 있지 않기 때문에 요청을 리디렉션하기 위해 공개 엔드포인트(Git over SSH, Git over HTTP(S))에 액세스해야 합니다. 이에 따라 Git over SSH 요청을 Git over HTTP(S)로 프록시하고, Git HTTP(S) 응답을 SSH 프로토콜과 호환되는 응답으로 변환하여 사용자에게 반환합니다. 최종 구현은 다음 흐름을 따릅니다.

sequenceDiagram participant C as Git on client participant S as GitLab Shell participant I as Workhorse & Rails participant P as Workhorse & Rails Note left of C: git push Note over S,I: 보조 사이트 Note over P: 주 사이트 C->>+S: ssh git receive-pack 요청 S->>I: SSH 키 유효성 검사 (api/v4/internal/authorized_keys?key=..) I-->>S: HTTP/1.1 300 (사용자 정의 작업 상태) with {endpoint, msg, primary_repo, authorization headers} S->>P: POST $PRIMARY/foo/bar.git/info/refs/?service=git-receive-pack P-->>S: HTTP/1.1 200 OK P-->>S: <응답> S-->>C: 주 노드에서의 Git 응답 반환 C-->>S: 전송할 Git 데이터를 스트리밍 S->>P: POST $PRIMARY/foo/bar.git/git-receive-pack P-->>S: HTTP/1.1 200 OK P-->>S: <응답> S-->>-C: gitlab-shell receive-pack 응답

이 해결책은 일반적인 경우를 처리하기에 좋습니다. 그러나 SSH와 HTTP(S) Git 프로토콜 사이의 미묘한 차이로 문제가 발생하며, 이로 인해 해결책이 신뢰성이 없고 Git 업그레이드에 취약해집니다.

Cells: 올바른 셀로의 SSH 요청 라우팅

Cells Architecture의 개발과 Routing Service의 도입으로 유사한 도전에 직면하게 됩니다. SSH 요청이 수행될 때, 해당 요청은 관련 데이터를 포함한 셀로 라우팅되어야 합니다.

이것은 SSH 요청에 대한 지속 가능한 솔루션을 찾아야 하는 또 다른 이유입니다.

목표

  • 일반적인 경우와 특수한 경우를 신뢰할 수 있는 방법으로 처리하는 지속 가능한 솔루션을 찾습니다.
  • Geo 및 Cells 시나리오를 다룰 수 있으며 다른 유사한 경우에 활용할 수 있는 범용적인 솔루션을 찾습니다.

제안

우리는 Gitaly gRPC에 직접 액세스할 수 없지만, 이를 HTTP Workhorse 엔드포인트를 통해 gRPC 데이터를 노출시킬 수 있습니다. gRPC가 양방향 프로토콜이기 때문에, Workhorse는 이 엔드포인트를 통해 HTTP를 통해 양방향 스트리밍을 지원해야 합니다.

  • 이 접근 방식은 Git 프로토콜 번역을 필요로 하지 않아 더욱 신뢰할 수 있습니다.
  • 노출된 Gitaly RPC는 Workhorse에 의해 보호되며 추가 인가 확인이 이루어집니다.

Cells

Cells 아키텍처의 경우, GitLab Shell은 라우터 역할을 하고 Global Service와 통신하여 올바른 셀로 요청을 다시 라우팅합니다.

sequenceDiagram participant C as Git on client participant S as GitLab Shell (Global) participant GS as Global Service participant WR as Workhorse & Rails (Local) participant G as Gitaly (Local) Note left of C: git clone/fetch C->>+S: ssh git-upload-pack ... S->>+GS: gRPC 요청을 분류하여 셀 정보 가져오기 GS-->>-S: ClassifyResponse{CellInfo{Address: <cell-address>, ...}} S->>+WR: GET /internal/api/authorized_keys?key=AAAA... Note right of WR: 키 ID 조회 WR-->>-S: 200 OK, command="gitlab-shell upload-pack key_id=1" S->>+GS: gRPC 요청을 분류하여 셀 정보 가져오기 GS-->>-S: ClassifyResponse{CellInfo{Address: <cell-address>, ...}} S->>+WR: POST <cell-address>/internal/api/allowed{action=upload_pack,key_id=1,project=<project>...} Note right of WR: 인가 확인 WR-->>-S: 200 OK, { project_url_prefix: <project-url>, authorization_token: ... } S->>+WR: <project-url>/ssh-upload-pack 요청 WR->>+G: SSHService.SSHUploadPack gRPC 요청 Note over C,G: Git 클라이언트와 Gitaly 간 양방향 통신 G-->>-WR: SSHService.SSHUploadPack gRPC 응답 WR-->>-S: <project-url>/ssh-upload-pack 응답 S-->>-C: ssh git-upload-pack 응답

Geo

Geo 아키텍처의 경우, 보조 GitLab Shell은 주 노드로의 요청을 다시 라우팅하기 위해 보조 Rails와 통신합니다.

sequenceDiagram participant C as Git on client participant S as GitLab Shell participant I as Workhorse & Rails participant P as Workhorse & Rails Note left of C: git push Note over S,I: 보조 사이트 Note over P: 주 사이트 C->>+S: ssh git receive-pack 요청 S->>I: SSH 키 유효성 검사 (api/v4/internal/authorized_keys?key=..) I-->>S: HTTP/1.1 300 (custom action status) with {endpoint, msg, primary_repo, authorization headers} S->>+P: POST $PRIMARY/<project-url>/ssh-upload-pack 요청 P-->>S: HTTP/1.1 200 OK Note over C,P: Git 클라이언트와 Gitaly 간 양방향 통신 P-->>S: <응답> S-->>-C: gitlab-shell receive-pack 응답

컨셉 증명

다음 MR에서는 설명된 아키텍처를 사용하여 git clone을 구현하는 방법을 보여주기 위해 최소한의 변경 사항을 도입합니다. 주요 목적은 GitLab Shell이 Workhorse와 양방향 통신을 HTTP로 설정할 수 있는지 확인하는 것입니다:

인증

현재 Geo는 주 노드에 대한 액세스에 사용되는 토큰을 생성합니다:

  • GitLab Rails는 이 토큰을 /allowed 응답에서 반환합니다.
  • 토큰은 Git을 통해 HTTP(S) 요청을 통해 주 노드에 전송됩니다.
  • 주 노드는 토큰을 인식하고 요청을 승인합니다.

제안된 솔루션에도 유사한 접근 방식을 적용할 수 있습니다:

  • GitLab Rails는 /allowed 응답에서 토큰을 반환합니다.
  • 헤더로 토큰을 Workhorse의 ssh- HTTP 엔드포인트에 전송합니다.
  • Workhorse는 토큰을 GitLab Rails로 전파하여 인식하고 요청을 승인합니다.

언급된 PoC는 이러한 접근 방식이 어떻게 구현될 수 있는지 예를 제공합니다:

  • GitLab Shell은 Shell과 Rails 간의 공유된 시크릿을 사용하여 생성된 JWT 토큰을 Rails에 보냅니다.
  • GitLab Rails는 이 토큰을 git_rpc_auth_header 필드에 다시 전송하여 Geo 시크릿으로도 사용할 수 있습니다.
  • GitLab Shell은 이 토큰을 Workhorse -> GitLab Rails로 전파합니다.
  • GitLab Rails는 이 토큰을 다시 인식하고 요청을 승인합니다.

JWT 생성에는 공유된 시크릿의 지식이 필요하기 때문에 사용자는 일반적으로이 토큰을 생성하거나 가로챌 수 없습니다.

양방향 스트리밍

Git 프로토콜은 Git 서버와 Git 클라이언트 간의 양방향 통신을 함의합니다. HTTP/1.1은 기본적으로 양방향 스트리밍을 지원하지 않으므로 다음 중 하나를 선택해야 합니다:

  • HTTP/1.1에 대한 양방향 스트리밍 실험. PoC는 Go 서버의 EnableFullDuplex 옵션을 사용하여 작동 버전을 가지고 있습니다.
  • 연결을 업그레이드하고 프로토콜을 전환합니다.
  • Workhorse에서 HTTP/2 프로토콜을 지원합니다.

인프라 관점에서 가장 실행 가능한 옵션을 선택해야 합니다.