GitLab Runner는 GitLab CI/CD 파이프라인에서 작업(Job)을 실행하는 중요한 구성 요소입니다.
Helm Chart를 이용해 GitLab Runner를 Kubernetes 환경에서 배포하면, Runner가 Job을 처리할 새로운 Pod를 생성하여 파이프라인을 실행하는 방식으로 동작합니다.
이를 Kubernetes 환경에서 효율적으로 관리하기 위해 Helm Chart를 활용하여 GitLab Runner를 배포할 수 있습니다.
특히 AWS 환경에서 IAM Role for Service Account(IRSA) 를 적용하면, GitLab Runner가 AWS의 다양한 서비스(ECR, S3 등)에 접근할 수 있도록 안전하게 권한을 부여할 수 있습니다. IRSA를 사용하면 인스턴스 전체에 IAM 권한을 부여하는 대신, Kubernetes의 ServiceAccount에 필요한 최소 권한만을 부여하여 보안성을 높일 수 있습니다.
이번 글에서는 Helm Chart를 활용하여 GitLab Runner를 EKS에 배포하는 과정과 함께 IRSA를 적용하여 AWS 리소스와의 연동을 설정하는 방법을 설명합니다. 이를 통해 다음과 같은 활용이 가능해집니다.
- ECR에 빌드된 컨테이너 이미지 저장 및 가져오기
- S3를 활용한 GitLab Runner 캐시 저장소 구성
1. GitLab Runner IRSA 사전 준비 작업
- GitLab Runner가 AWS 리소스에 안전하게 접근하기 위해 IAM 역할을 생성하고 필요한 권한을 부여해야 합니다.
- S3, ECR 이 사전에 필요하며, 적용하고자 하는 최소 권한 생성이 사전에 필요합니다.
1-1) GitLab Runner에서 IRSA가 적용될 신뢰 관계 정책(Trust Policy)
AWS의 IAM Role for Service Account(IRSA) 를 활용하면, GitLab Runner가 AWS 리소스에 접근할 때 EC2 인스턴스에 IAM 역할을 부여하는 기존 방식 대신, Kubernetes 서비스 계정(ServiceAccount)에 IAM 역할을 연결하여 보다 안전하고 최소 권한 원칙(Least Privilege)에 맞는 접근 제어를 수행할 수 있습니다.
- IAM Trust Policy 설정
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::{AWS_ACCOUNT_ID}:oidc-provider/oidc.eks.ap-northeast-2.amazonaws.com/id/{OIDC_ID}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.ap-northeast-2.amazonaws.com/id/{OIDC_ID}:aud": "sts.amazonaws.com",
"oidc.eks.ap-northeast-2.amazonaws.com/id/{OIDC_ID}:sub": "system:serviceaccount:gitlab-runner:gitlab-runner"
}
}
}
]
}
- Principal (신뢰할 주체)
- AWS IAM 역할이 특정 OIDC 프로바이더(OpenID Connect Provider) 를 통해 페더레이션(Federation) 인증을 허용하도록 설정합니다.
- {AWS_ACCOUNT_ID}: 현재 AWS 계정 ID를 입력합니다.
- {OIDC_ID}: 해당 EKS 클러스터에서 사용 중인 OIDC Provider의 ID입니다.
- 이를 통해 AWS는 특정 OIDC 프로바이더(=EKS의 OIDC 엔드포인트)를 신뢰하고, 해당 프로바이더를 통해 인증된 Kubernetes 서비스 계정에게 역할을 부여할 수 있도록 합니다.
- Action (허용할 작업)
- GitLab Runner가 웹 ID를 사용하여 IAM 역할을 Assume할 수 있도록 합니다.
- 즉, GitLab Runner가 EKS 내에서 실행될 때, OIDC를 통해 AWS IAM 역할을 Assume할 수 있도록 허용합니다.
- Condition (적용 조건)
- GitLab Runner Pod가 특정 Kubernetes ServiceAccount를 사용할 때만 역할 Assume을 허용하는 조건을 정의합니다.
- aud (Audience): OIDC 토큰의 대상(Audience)이 sts.amazonaws.com 이어야 함을 명시합니다.
- sub (Subject): 특정 네임스페이스와 서비스 계정(ServiceAccount) 에서만 IAM 역할을 Assume할 수 있도록 제한합니다.
- system:serviceaccount:gitlab-runner:gitlab-runner
- Namespace: gitlab-runner
- ServiceAccount: gitlab-runner
- system:serviceaccount:gitlab-runner:gitlab-runner
⚠️ GitLab Runner가 gitlab-runner 네임스페이스 내에서 실행되는 gitlab-runner 라는 Service Account를 사용할 때만, 해당 IAM 역할을 Assume할 수 있음을 보장합니다.
⚠️ 추후 Service Account 를 생성할 때 gitlab-runner 라는 이름으로 생성!! 하지 않는다면 신뢰 관계 정책에서 Service Account 이름 변경이 필요하게 됩니다.
1-2) S3 및 ECR 권한 부여 방식
GitLab Runner가 S3와 ECR에 접근하는 방법은 두 가지가 있습니다.
- 별도의 IAM 역할을 생성하여 필요한 리소스(ECR, S3 등)에 대한 권한을 정의하고, 해당 역할을 Assume하도록 설정
- GitLab Runner에 부여한 IAM 역할에 직접 S3 및 ECR 접근 권한을 추가하여 사용
첫번 째 방식으로 IAM Role을 따로 만들어 AssumeRole 방식으로 접근하면, 역할(IAM Role) 별 최소 권한을 유지할 수 있고, GitLab Runner가 다양한 AWS 리소스를 관리해야 할 때 보다 세분화된 제어가 가능합니다.
두번 째 방식으로 IAM Role을 하나만 생성하고 직접 권한을 추가하면, 설정이 간단하지만, 모든 권한을 하나의 역할에서 관리해야 하기 때문에 보안상 리스크가 발생할 가능성이 있습니다.
💡 운영 환경에서는 AssumeRole 방식을 활용하여 각 AWS 리소스에 대한 역할을 따로 생성하는 것이 권장됩니다.
필자의 경우 첫번 째 방식으로 구축하였으나, 필요에 따라 간단한 테스트 환경에서는 GitLab Runner의 역할에 S3 및 ECR 접근 권한을 직접 추가하여 빠르게 적용할 수도 있습니다.
2. GitLab Runner의 동작 방식과 RBAC 설정 (Role & RoleBinding)
- GitLab Runner는 GitLab CI/CD 파이프라인을 실행하는 핵심 구성 요소입니다.
- GitLab에서 .gitlab-ci.yaml 파일을 작성 후 CI/CD 작업을 실행할 때마다 새로운 Pod를 동적으로 생성하여 Job을 수행합니다.
- 이때 Kubernetes 내에서 Pod를 생성하고, 로그를 조회하고, 실행 중인 Pod 내에서 명령을 실행할 수 있도록 권한 RBAC(Role-Based Access Control) 을 설정해야 정상적으로 동작할 수 있습니다.
2-1) GitLab Runner의 기본 워크플로우
GitLab Runner가 파이프라인을 실행하는 과정은 다음과 같습니다.
- .gitlab-ci.yml 파일에 정의된 CI/CD 파이프라인이 GitLab에서 실행
- GitLab은 Runner에 API 요청을 보내 특정 Job을 할당함
- Kubernetes 클러스터에서 GitLab Runner는 Job을 실행할 새로운 Pod를 동적으로 생성
- CI/CD 작업(빌드, 테스트, 배포 등)을 수행
- 작업이 완료되면 GitLab Runner는 결과를 GitLab에 전송하고, Pod를 자동 삭제하여 클러스터 리소스를 정리
2-2) GitLab Runner의 RBAC 설정 (Role & RoleBinding)
- GitLab Runner가 새로운 Pod를 생성하고 실행 결과를 확인하려면 Kubernetes 리소스에 대한 접근 권한이 필요합니다.
- Pod 생성(Create), 조회(Get), 삭제(Delete)
- Pod 내부 명령 실행(Exec) 및 로그 조회(Log)
- 이러한 작업을 수행하려면 Kubernetes의 RBAC(Role-Based Access Control)를 설정하여 GitLab Runner에 적절한 권한을 부여해야 합니다.
- (1) Role 설정: GitLab Runner가 필요한 권한 정의
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: gitlab-runner
name: gitlab-runner-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["list", "get", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
- GitLab Runner가 Kubernetes에서 새로운 Pod를 생성하고, 실행 중인 Pod의 상태를 조회 및 삭제할 수 있도록 권한을 부여
- pods/exec 권한을 추가하여 CI/CD 작업 중 컨테이너 내부에서 명령을 실행할 수 있도록 설정
- pods/log 권한을 부여하여 실행된 Job의 로그를 확인 가능
- (2) RoleBinding 설정: GitLab Runner 서비스 계정과 Role 연결
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
namespace: gitlab-runner
name: gitlab-runner-rolebinding
subjects:
- kind: ServiceAccount
name: gitlab-runner
namespace: gitlab-runner
roleRef:
kind: Role
name: gitlab-runner-role
apiGroup: rbac.authorization.k8s.io
- RoleBinding을 통해 gitlab-runner 서비스 계정이 gitlab-runner-role 권한을 사용할 수 있도록 설정
- GitLab Runner가 gitlab-runner 네임스페이스 내에서 정의된 권한을 적용받아 CI/CD 작업을 수행하는 Pod를 제어할 수 있도록 허용
RBAC를 올바르게 설정하면 Runner가 Kubernetes 내에서 안전하게 Pod를 생성하고 관리할 수 있으며, 필요하지 않은 권한을 부여하지 않음으로써 보안성도 강화할 수 있습니다.
- (3) Role, RoleBinding 생성
kubectl create ns gitlab-runner
kubectl apply -f ./runner-role.yaml -n gitlab-runner
kubectl apply -f ./runner-rolebinding.yaml -n gitlab-runner
3. GitLab Runner Token 발급 및 Secret을 생성
- GitLab UI에 접속하여 New Runner를 생성하여 새로운 runnerToken을 생성한 후 Token을 보관합니다.
3-1) runnerToken을 위한 Kubernetes Secret 생성
- GitLab Runner를 Kubernetes 환경에서 배포할 때 runnerToken을 Helm Chart의 values.yaml에 직접 입력하는 방법도 있지만, Kubernetes Secret을 사용하여 Token을 관리하는 것이 더 안전하고 효율적인 방법입니다.
- 필자의 경우, ArgoCD를 통해 Helm Chart를 대부분 배포하기 때문에 values.yaml 파일에 직접 Token을 입력하면 Git 저장소에 저장되어 보안에 취약하여 Secret을 사용하였습니다.
apiVersion: v1
kind: Secret
metadata:
name: gitlab-runner-token-secret
namespace: gitlab-runner
type: Opaque
stringData:
runner-token: "glrt-xxxxxxxxxxxx" # GitLab에서 발급받은 runnerToken을 입력
runner-registration-token: "" # 예전 Token등록 방식이지만 빈값이라도 입력이 필요!
- Secret data에 runner-registration-token: "" 을 포함하지 않으면 다음과 같은 에러가 발생하게 됩니다.
MountVolume.SetUp failed for volume "projected-secrets" : references non-existent secret key: runner-registration-token
4. GitLab Runner Helm Chart 배포
- GitLab Runner를 Kubernetes 환경에서 배포하기 위해 Helm Chart를 사용하면 보다 쉽고 체계적으로 관리할 수 있습니다.
- Helm을 이용해 GitLab Runner의 Helm Chart를 다운로드하고, 원하는 버전을 선택하여 배포할 수 있습니다.
4-1) GitLab Runner Helm Chart 저장소 추가 및 특정 버전 다운로드
# GitLab Runner Helm Chart 저장소 추가
helm repo add gitlab https://charts.gitlab.io/
# 등록한 저장소의 최신 버전을 가져오기 위해 Helm 저장소를 업데이트
helm repo update
# GitLab Runner Helm Chart 버전 조회
helm search repo gitlab/gitlab-runner --versions
NAME CHART VERSION APP VERSION DESCRIPTION
gitlab/gitlab-runner 0.74.0 17.9.0 GitLab Runner
gitlab/gitlab-runner 0.73.3 17.8.3 GitLab Runner
gitlab/gitlab-runner 0.73.2 17.8.2 GitLab Runner
gitlab/gitlab-runner 0.73.1 17.8.1 GitLab Runner
gitlab/gitlab-runner 0.73.0 17.8.0 GitLab Runner
gitlab/gitlab-runner 0.72.1 17.7.1 GitLab Runner
gitlab/gitlab-runner 0.72.0 17.7.0 GitLab Runner
gitlab/gitlab-runner 0.71.0 17.6.0 GitLab Runner
gitlab/gitlab-runner 0.70.5 17.5.5 GitLab Runner
gitlab/gitlab-runner 0.70.4 17.5.4 GitLab Runner
# 특정 버전의 Helm Chart 다운로드
helm pull gitlab/gitlab-runner --version 0.72.0 --untar
4-2) override-vaules.yaml 준비
GitLab Runner를 Helm Chart를 통해 배포할 때, 기본 values.yaml을 그대로 사용하는 것이 아니라, 환경에 맞춰 설정을 재정의할 수 있도록 override-values.yaml을 작성해야 합니다.
해당 URL을 참고하시어 필요한 옵션을 추가하여 사용할 수 있습니다.
gitlabUrl: "https://gitlab.mzc-devops.site"
serviceAccount:
create: true
name: gitlab-runner
annotations:
eks.amazonaws.com/role-arn: "{GitLab Runner가 사용할 IAM Role ARN}"
rbac:
create: true
concurrent: 5
runners:
secret: gitlab-runner-token-secret
name: eks-runner
config: |
[[runners]]
executor = "kubernetes"
shell = "bash"
[runners.kubernetes]
privileged = true
image = "{GitLab Runner 컨테이너에서 사용할 기본 이미지 지정}"
pull_policy = ["if-not-present", "always"]
...
...
[runners.cache]
Type = "s3"
Shared = true
MaxUploadedArchiveSize = 0
[runners.cache.s3]
...
...
...
4-3) GitLab Runner Helm Chart 배포
GitLab Runner의 설정을 마쳤다면, 이제 Helm을 사용하여 Kubernetes 클러스터에 배포할 수 있습니다.
앞서 작성한 override-values.yaml을 활용하여 Helm Chart를 배포하면, 원하는 환경에 맞게 GitLab Runner가 설정됩니다.
helm upgrade --install gitlab-runner -f override-values.yaml . -n gitlab-runner
- 배포 후 상태 확인
❯ kubectl get all -n gitlab-runner
NAME READY STATUS RESTARTS AGE
pod/gitlab-runner-7fc66c46b-pqpsh 1/1 Running 0 92s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/gitlab-runner 1/1 1 1 18m
NAME DESIRED CURRENT READY AGE
replicaset.apps/gitlab-runner-7fc66c46b 1 1 0 93s
replicaset.apps/gitlab-runner-ff5f5fdcf 0 0 0 18m
4-4) 파이프라인 동작 확인
파이프라인의 특정 Stage도 eks-runner를 통해 돌았으며, ECR에서 기본 이미지 또한 잘 pull 받아와서 실행되는 모습 확인이 가능합니다!
개인 정리
GitLab Runner를 Kubernetes 환경에서 배포하는 과정에서, Helm Chart를 활용하여 보다 체계적이고 확장성 있는 방식으로 Runner를 관리할 수 있음을 확인...했다
Runner Token을 Secret으로 저장하여 보안성을 강화하는 접근 방식을 적용하였고, IAM Role for Service Account(IRSA)를 활용하여 AWS 리소스(ECR, S3) 접근 권한을 부여하였고, ECR에 대한 권한은 GitLab 파이프라인 동작을 통해 Pull, Push 권한 등이 정상인 것을 확인하였으나, S3의 캐싱 기능은 추후 테스트를 마저 해봐야 함!!!!
GitLab Runner 최신 버전에서는 배포 과정에서 runner-registration-token을 필요로 하지 않음에도 Helm Chart가 이를 참조하려는 이슈가 발생하였으며, 이를 해결하기 위해 runner-registration-token 값을 비워 Secret에 추가하는 방식을 적용하여 해결...
이번 과정을 통해 GitLab Runner를 Helm Chart로 배포할 때 고려해야 할 사항과 문제 해결 방법을 정리할 수 있었으며,
향후에는 HashiCorp Vault와 연동하여 GitLab Runner의 인증 정보를 안전하게 관리하는 방법도 테스트해보면 좋을 것 같다!!!
'GitLab' 카테고리의 다른 글
[GitLab] Helm Chart - Backup 설정하기 (0) | 2025.03.08 |
---|---|
[GitLab] Keycloak OIDC - 그룹 기반 인증 연동 설정 (w. terraform) (2) | 2024.10.13 |
[GitLab] Okta SAML연동을 통한 SSO(Single Sign-On) 설정하기 (0) | 2024.06.23 |