[ArgoCD]Cross Account EKS Cluster 연동 방법(Declarative Setup)

2025. 5. 31. 21:37·DevOps
반응형

배경 상황

EKS 클러스터를 테스트용으로 사용할 때나 아주 작은 규모에서 운영할 경우를 제외하고 대부분의 서비스 운영에서는 여러 개의 클러스터를 이용하는 경우가 대부분이다. 이 때 ArgoCD를 각 클러스터에 배포할수도 있지만, 관리의 편의성을 위해 ArgoCD에 여러 개의 클러스터를 연결하기도 하게 된다. 특히 지금 회사에서는 환경별로 별도의 ArgoCD 서버를 운영한다고 하더라도 서로 다른 계정에 배포된 EKS 클러스터를 ArgoCD에 등록할 필요가 있어 아래 구성을 진행하게 되었다.

 

Cross Account EKS Cluster 연동 방법

연동 구성을 간단하게 도식화 하면 아래와 같다.

ArgoCD 공식문서를 확인해보면 클러스터의 선언적 구성 방법이 나와있는데, 요약해보면

  • ArgoCD가 운영되는 계정에서 IAM Role을 생성하고(아래 그림 상 argocd-management-role), argocd-server, argocd-applicationset-controller, argocd-application-controller 세 개 SA에 연결
  • 연결하고자 하는 EKS 클러스터가 배포된 계정에서 IAM Role을 생성(service-cluster-role)하고 Access Entry를 이용해 EKS 클러스터에 대한 접근 권한을 부여
  • argocd-management-role에서 service-cluster-role로 assume 할 수 있도록 신뢰 관계를 구성
  • argocd management 클러스터에서 Secret을 생성해 ArgoCD에 등록할 EKS 클러스터 정보를 작성

 

그럼 단계별로 연동 작업을 진행해보도록 하자(아래 예제에서 AWS 리소스는 Terraform으로 생성했다).

 

 

1. [ArgoCD Management 계정] IRSA를 구성하기위해서 테라폼 모듈로 IAM Role을 생성한다. 먼저 IAM Role에 연결할 IAM Policy를 구성해 argo-management-role이 Service 계정의 service-cluster-role을 assume할 수 있도록 한다.

module "iam_policy_argo_management" {
  source  = "terraform-aws-modules/iam/aws//modules/iam-policy"
  version = "5.55.0"

  name        = format("%s-argo-mgmt-policy", local.namespace)
  description = format("%s-argo-mgmt-policy", local.namespace)

  policy = data.aws_iam_policy_document.argo_mgmt_iam_policy.json
}

data "aws_iam_policy_document" "argo_mgmt_iam_policy" {
  statement {
    sid    = "stsAssumeRole"
    effect = "Allow"
    actions = [
      "sts:AssumeRole",
    ]
    resources = [
      "arn:aws:iam::<SERVICE_ACCOUNT_ID>:role/service-cluster-role",
    ]
  }
}

 

 

2. [ArgoCD Management 계정] IRSA 구성을 위해 Trust policy document를 작성해준다. 이 정책을 적용하면 argocd 네임스페이스의 세 개 serviceaccount에서 argo-management-role을 assume할 수 있게 된다. 참고로 OIDC 정보를 연결할 때에는 OIDC Issuer URL과 ARN 정보가 둘 다 필요하기 때문에 output에서 미리 정의해놓고 가져다 사용한다.

# Trust Policy에서 OIDC 정보를 불러오기 위한 설정
output "cluster_oidc_issuer_url" {
  description = "OIDC issuer URL"
  value       = module.eks.cluster_oidc_issuer_url
}

output "cluster_oidc_provider_arn" {
  description = "OIDC provider ARN"
  value       = module.eks.oidc_provider_arn
}

# OIDC Issuer URL의 https:// prefix를 제거
locals {
  cluster_oidc_issuer_url_no_prefix = replace(module.eks.cluster_oidc_issuer_url, "https://", "")
}

# Trust Policy 정책 정의
data "aws_iam_policy_document" "argo_mgmt_trust_policy" {
  statement {
    actions = ["sts:AssumeRoleWithWebIdentity"]
    effect  = "Allow"
    principals {
      type        = "Federated"
      identifiers = [module.eks.oidc_provider_arn]
    }
    condition {
      test     = "StringEquals"
      variable = "${local.cluster_oidc_issuer_url_no_prefix}:sub"
      values = [
        "system:serviceaccount:argocd:argocd-application-controller",
        "system:serviceaccount:argocd:argocd-applicationset-controller",
        "system:serviceaccount:argocd:argocd-server"
      ]
    }
    condition {
      test     = "StringEquals"
      variable = "${local.cluster_oidc_issuer_url_no_prefix}:aud"
      variable = "${module.eks.oidc_provider_arn}:sub"
      values = [
        "system:serviceaccount:argocd:argocd-application-controller",
        "system:serviceaccount:argocd:argocd-applicationset-controller",
        "system:serviceaccount:argocd:argocd-server"
      ]
    }
  }
  statement {
    sid    = "ExplicitSelfRoleAssumption"
    effect = "Allow"
    principals {
      type        = "AWS"
      identifiers = ["*"]
    }
    actions = [
      "sts:AssumeRole",
    ]
    condition {
      test     = "ArnLike"
      variable = "aws:PrincipalArn"
      values   = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/argo-management-role"]
    }
  }
}

 

3. [ArgoCD Management 계정] 위에서 생성한 권한들을 가진 argo-management-role이라는 이름의 IAM role을 생성한다. 

module "argo-management-role" {
  source  = "terraform-aws-modules/iam/aws//modules/iam-assumable-role"
  version = "5.55.0"

  create_role = true

  role_name                       = "argo-management-role"
  create_custom_role_trust_policy = true
  custom_role_trust_policy        = data.aws_iam_policy_document.argo_mgmt_trust_policy.json

  custom_role_policy_arns = [
    module.iam_policy_argo_admin.arn
  ]

  tags = merge(local.common_tags, {
    "Name" = "argo-management-role"
  })
}

 

그리고 service 계정에서 생성할 IAM Role에 신뢰관계를 구성하기 위해 output으로 생성한 argo-management-role에 대한 정보를 뽑아준다.

output "argo_management_role_arn" {
  description = "ARN of ArgoCD management role"
  value       = module.argo-management-role.iam_role_arn
}

 

 

4. [Service Cluster 계정] service-eks 클러스터의 어드민 권한을 가진 IAM Role(service-cluster-role)을 생성해야 한다(IRSA 아님). 먼저 위에서 생성한 argo-management-role이 service-cluster-role을 assume할 수 있도록 iam policy document를 생성한다.

data "aws_iam_policy_document" "cluster_role_trust_policy" {
  statement {
    sid    = "ArgoCDClusterRoleAssumption"
    effect = "Allow"
    principals {
      type        = "AWS"
      identifiers = [local.devops_eks_outputs.argo_management_role_arn]
    }
    actions = [
      "sts:AssumeRole",
    ]
  }
}

 

 

5. [Service Cluster 계정] 위에서 작성한 policy document를 기반으로 IAM Role을 생성해준다.

module "eks-cluster-role" {
  source  = "terraform-aws-modules/iam/aws//modules/iam-assumable-role"
  version = "5.55.0"

  create_role = true

  role_name                       = "service-cluster-role"
  create_custom_role_trust_policy = true
  custom_role_trust_policy        = data.aws_iam_policy_document.cluster_role_trust_policy.json

  tags = merge(local.common_tags, {
    "Name" = "service-cluster-role"
  })
}

 

 

6. [Service Cluster 계정] ArgoCD가 서비스 클러스터의 엔드포인트를 호출해서 매니페스트 파일을 배포하고 업데이트할 수 있게 해야하기 때문에 service-eks 클러스터에 Access Entry를 생성해서 클러스터 접근권한을 부여해준다(IAM Policy 아님).

  • 이전 버전의 EKS 클러스터에서는 aws-auth ConfigMap을 수정해야했지만 지금은 Access Entry라는 AWS API를 통해서 EKS 클러스터 권한을 부여/삭제할 수 있게 되었기 때문에 테라폼으로도 권한 부여를 할 수 있다. 참고로 Access Entry는 EKS 클러스터에서 authenticationMode이 API(혹은 API & Config Map)로 설정되어있어야 사용 가능하다. Access Entry에 연결할 Policy는 arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy로 설정한다.
module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "20.36.0"
  
  cluster_name = "service-eks"

  # 기타 설정 생략

  access_entries = {
    cluster-role = {
      principal_arn = module.eks-cluster-role.iam_role_arn
      policy_associations = {
        cluster-admin-policy = {
          policy_arn = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy"
          access_scope = {
            type = "cluster"
          }
        }
      }
    }
  }
}

 

 

7. [ArgoCD Management 계정] 마지막으로 argocd.argoproj.io/secret-type: cluster 레이블이 붙어있는 Secret을 생성해주면 되는데, 연결할 service-eks 클러스터의 CA(Certificate Authority) 데이터 등이 들어가기 때문에 External Secrets으로 생성해준다. 나는 이번에도 Parameter Store에 데이터를 저장 후 불러오는 구성으로 진행했다(External Secrets 설치 방법에 대해서는 링크를 참조). ClusterSecretStore는 이미 생성했다고 가정하고 아래와 같이 설정을 진행하면 클러스터가 ArgoCD 클러스터에 등록된다.

 

[Kubernetes]External Secrets란? 설치 및 구성방법 (GitOps 도입 시 크레덴셜 정보 안전하게 저장하기)

배경 상황쿠버네티스 환경에서 깃옵스(GitOps)를 하려고 하면 k8s 매니페스트 파일을 깃헙이나 깃랩같은 코드 저장소에 저장하게 된다. 이렇게 ArgoCD를 이용해서 애플리케이션 부트스트래핑 구성

canaryrelease.tistory.com

apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
  name: eso-service-cluster-secret
  namespace: argocd
spec:
  secretStoreRef:
    name: aws-parameter-store
    kind: ClusterSecretStore
  target:
    name: eso-service-cluster-secret
    creationPolicy: Owner
    template:
      metadata:
        labels:
          argocd.argoproj.io/secret-type: cluster
      data:
      # 정적 값
        name: "service-eks"
      # 동적 값
        server: "{{ .clusterEndpoint }}"
        config: |
          {
            "awsAuthConfig": {
              "clusterName": "lbox-service-stg-eks",
              "roleARN": "arn:aws:iam::<SERVICE ACCOUNT ID>:role/service-cluster-role"
            },
            "tlsClientConfig": {
              "insecure": false,
              "caData": "{{ .clusterCa }}"
            }
          }
  data:
    - secretKey: clusterEndpoint
      remoteRef:
        key: /parameter-store-경로/cluster-endpoint
    - secretKey: clusterCa
      remoteRef:
        key: /parameter-store-경로/cluster-ca

 

 

 

사실 한 번 만들고 나면 별 거 아닌데 번거롭고 손으로 작업하면 실수할 구간들이 꽤 있어서 테라폼으로 만들어놓고 사용하니까 확실히 편하고 실수가 덜해서 좋다(라고 써놓고 테라폼 작성할 때 실수해서 삽질한 건 비밀).

저작자표시 비영리 동일조건 (새창열림)

'DevOps' 카테고리의 다른 글

[cert-manager]error instantiating route53 challenge solver: unable to construct route53 provider: empty credentials; perhaps you meant to enable ambient credentials?" 에러 해결 방법  (1) 2025.07.12
[AWS]DMS로 스테이징 환경 DB 구성하기(Aurora MySQL)  (2) 2025.06.10
[ArgoCD]Grafana, Istio등 Application의 Out of Sync 해결(ArgoCD Diffing custom)  (0) 2025.05.29
[Cisco]Meraki란?  (2) 2025.05.28
[ArgoCD]Github 저장소 선언적으로 등록하고 관리하기(Feat. External Secrets)  (0) 2025.05.27
'DevOps' 카테고리의 다른 글
  • [cert-manager]error instantiating route53 challenge solver: unable to construct route53 provider: empty credentials; perhaps you meant to enable ambient credentials?" 에러 해결 방법
  • [AWS]DMS로 스테이징 환경 DB 구성하기(Aurora MySQL)
  • [ArgoCD]Grafana, Istio등 Application의 Out of Sync 해결(ArgoCD Diffing custom)
  • [Cisco]Meraki란?
Canary_카나리아
Canary_카나리아
어쩌다 데브옵스 엔지니어가 된 문과생의 기록용 블로그
    반응형
  • Canary_카나리아
    release: canary
    Canary_카나리아
  • 전체
    오늘
    어제
    • 분류 전체보기 (120)
      • DevOps (67)
      • Programming (28)
      • Certifications (3)
      • ETC (20)
  • 블로그 메뉴

    • 홈
    • 태그
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    클라우드자격증
    그라파나예제
    spring
    데브옵스엔지니어
    Java
    백엔드개발
    kops사용법
    클라우드엔지니어자격증
    프로메테우스
    백엔드공부
    네이버클라우드자격증
    Prometheus
    제로베이스
    프로메테우스예제
    자바개념
    한빛출판네트워크
    java개념
    NCPprofessional자격증
    ncp서비스
    그라파나
    terraform
    백엔드
    Grafana
    kops란
    개발자
    argocd
    NCP자격증
    백엔드스쿨
    네이버클라우드서비스
    NCPassociate자격증
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.2
Canary_카나리아
[ArgoCD]Cross Account EKS Cluster 연동 방법(Declarative Setup)
상단으로

티스토리툴바