Kubernetes 통합 개발 지침

이 문서는 GitLab Kubernetes 통합을 개발할 때 여러 지침을 제공합니다.

개발

아키텍처

일부 Kubernetes 작업, 예를 들어 제한된 프로젝트 네임스페이스 생성 등은 GitLab Rails 애플리케이션에서 수행됩니다. 이러한 작업은 클라이언트 라이브러리를 사용하여 수행되며, 일정 수준의 위험을 내포하고 있습니다. 이러한 작업은 GitLab Rails 애플리케이션을 실행하는 동일한 사용자로 실행됩니다. 자세한 내용은 아래의 보안 섹션을 참조하세요.

일부 Kubernetes 작업, 예를 들어 클러스터 애플리케이션 설치는 Kubernetes 클러스터 자체의 일회성 팟에서 수행됩니다. 이 설치 팟은 install-<application_name>로 명명되며 gitlab-managed-apps 네임스페이스 내에서 생성됩니다.

코드 구성 측면에서 우리는 일반적으로 Kubernetes 리소스를 나타내는 객체를 lib/gitlab/kubernetes에 추가합니다.

클라이언트 라이브러리

우리는 Kubernetes API 호출을 수행하기 위해 kubeclient 젬을 사용합니다. kubeclient 젬은 단일 클라이언트에서 다양한 API 그룹(예: apis/rbac.authorization.k8s.io)을 지원하지 않기 때문에, 우리는 이를 달성하도록 하는 Gitlab::Kubernetes::KubeClient 래퍼 클래스를 생성했습니다.

선택한 Kubernetes API 그룹은 지원됩니다. 필요한 경우 새로운 API 그룹이나 메소드를 사용해야 할 경우에는 해당 그룹에 대한 내부 클라이언트를 만들어 주는 방식으로 Gitlab::Kubernetes::KubeClient에 지원을 추가하세요. 새로운 메소드는 관련 내부 클라이언트로 위임되어야 합니다.

성능 고려 사항

Kubernetes API로의 모든 호출은 백그라운드 프로세스에서 이루어져야 합니다. 웹 요청 내에서 Kubernetes API 호출을 수행하지 마세요. 이렇게 하면 웹 서버가 차단되어 Kubernetes 클러스터 응답 시간이 우리의 통제 범위를 벗어나기 때문에 GitLab에 서비스 거부(Denial of Service, DoS) 공격을 유발할 수 있습니다.

호출이 백그라운드 프로세스에서 수행되도록 하는 가장 쉬운 방법은 해당 작업을 Sidekiq worker로 위임하는 것입니다.

Kubernetes에 호출을 수행하고 응답을 반환하려는 경우에는 백그라운드 워커가 적합하지 않을 수 있습니다. 이때 반응형 캐시를 사용하는 것을 고려해보세요. 예를 들어:

  def calculate_reactive_cache!
    { pods: cluster.platform_kubernetes.kubeclient.get_pods }
  end

  def pods
    with_reactive_cache do |data|
      data[:pods]
    end
  end

테스트

우리는 당신의 테스트에서 Kubernetes API 호출을 목업하는 데 도움이 되는 KubernetesHelpers에 일부 WebMock 스텁을 가지고 있습니다.

Amazon EKS 통합

이 섹션은 GitLab 인스턴스가 EKS 클러스터를 생성할 수 있도록 허용하는 프로세스를 개요로 설명합니다.

다음 사전 조건이 필요합니다:

  • 고객 AWS 계정. EKS 클러스터가 이 계정에 생성됩니다. 다음 리소스가 있어야 합니다:
    • 클러스터 및 관련 리소스를 생성할 권한을 가진 프로비저닝 역할. GitLab AWS 계정을 신뢰하는 엔터티로 목록에 표시되어야 합니다.
    • 클러스터에서 사용할 VPC, 관리 역할, 보안 그룹 및 서브넷.
  • GitLab AWS 계정. 이 계정은 프로비저닝 작업을 수행합니다. 다음 리소스가 있어야 합니다:
    • 고객 계정의 프로비저닝 역할을 가정할 권한을 가진 서비스 계정.
    • gitlab.ymlkubernetes 섹션을 통해 GitLab에 구성된 이 서비스 계정의 자격 증명.

클러스터를 생성하는 프로세스는 다음과 같습니다:

  1. :provision_role_arn으로 제공된 역할을 GitLab이 가정하고, 임시 자격 증명을 공급 엔터티 레코드에 저장합니다. 기본적으로 이러한 자격 증명은 한 시간 동안 유효합니다.
  2. AWS CloudFormation EKS 템플릿을 바탕으로 CloudFormation 스택이 생성됩니다. 이는 EKS 클러스터에 필요한 모든 리소스의 생성을 트리거합니다.
  3. GitLab은 대부분의 경우 10분에서 15분 사이에 걸쳐 대부분의 경우에 준비될 때까지 스택의 상태를 폴링합니다.
  4. 스택이 준비되면, GitLab은 클러스터 세부 정보를 저장하고, 이번에는 kubeclient를 통해 클러스터에 연결할 수 있도록 또 다른 일회용 자격 증명을 생성합니다. 이러한 자격 증명은 1분 동안 유효합니다.
  5. GitLab은 워커 노드를 구성하여 클러스터에 인증할 수 있도록하고, 미래 작업을 위해 자체를 위한 서비스 계정을 생성합니다.
  6. 더 이상 필요하지 않은 자격 증명이 제거됩니다. 이로써 다음과 같은 속성이 삭제됩니다:
    • access_key_id
    • secret_access_key
    • session_token

보안

서버 측 요청 위조(SSRF) 공격

Kubernetes 클러스터의 URL은 사용자가 제어하기 때문에 서버 측 요청 위조(SSRF) 공격에 쉽게 노출될 수 있습니다. 클러스터에 더 많은 API 호출을 추가하는 경우, 대처 전략을 이해해야 합니다.

대처 전략은 다음과 같습니다:

  1. 공격자 컨트롤러 리소스로의 리디렉션 허용하지 않기: Kubeclient::KubeClienthttp_max_redirects: 0 옵션을 전달하여 모든 리디렉션을 방지하도록 구성할 수 있습니다.
  2. 오류 메시지 노출 금지: 이를 통해, 우리는 공격자가 오류를 유발하여 공격자가 제어하는 요청으로부터 결과를 노출하는 것을 막습니다. 예를 들어, 우리는 (또는 저장하지 않는) 원시 오류 메시지를 노출하지 않습니다:

    rescue Kubernetes::HttpError => e
      # bad
      # app.make_errored!("Kubernetes error: #{e.message}")
    
      # good
      app.make_errored!("Kubernetes error: #{e.error_code}")
    

Kubernetes 통합 디버깅

Kubernetes 통합과 관련된 로그는 kubernetes.log에서 찾을 수 있습니다. 로컬 GDK 설치에서는 이러한 로그가 log/kubernetes.log에 있습니다.

또한 설치 문제를 디버깅하기 위해 설치 로그를 따를 수 있습니다. 설치/업그레이드가 진행 중일 때, 파드가 생성되기를 기다린 다음, 다음을 실행하여 빈 포드가 쓰여지는 대로 해당 파드 로그를 얻을 수 있습니다:

kubectl logs <pod_name> --follow -n gitlab-managed-apps