Crossplane과 워크로드 아이덴티티
Crossplane과 워크로드 아이덴티티 (Workload Identity)
관리형 Kubernetes 클러스터(EKS, AKS, GKE)에서 Crossplane을 실행할 때, Kubernetes 워크로드 아이덴티티(Workload Identity)를 사용해 Crossplane이 프라이빗 클라우드 컨테이너 레지스트리에서 패키지를 가져올 수 있게 할 수 있습니다. 이를 통해 정적 자격 증명을 관리하지 않고도 AWS ECR, Azure ACR, Google Artifact Registry 같은 레지스트리에서 providers, functions, configurations를 설치할 수 있어요.
출처: 문서
본문
⚠️ 중요: 이 가이드는 Crossplane 패키지 매니저가 프라이빗 레지스트리에서 패키지를 가져오도록 구성합니다. 패키지는 별도의 파드(providers와 functions)로 실행되는 컨테이너 이미지를 참조해요.
두 단계 이미지 가져오기 과정:
- Crossplane 패키지 매니저가 패키지를 가져와 패키지 내용(CRDs, XRDs)을 추출하고 배포를 생성합니다.
- Kubernetes 노드가 provider/function 파드를 만들 때 런타임 컨테이너 이미지를 가져옵니다.
이 가이드는 1단계를 다룹니다. 2단계를 위해서는 Kubernetes 노드가 프라이빗 레지스트리에서 이미지를 가져올 권한이 있는지 확인하세요. 보통 클러스터 수준에서 구성됩니다.
- AWS EKS: ECR pull 권한이 있는 노드 IAM 역할
- Azure AKS: AcrPull 역할이 있는 Kubelet 관리 아이덴티티
- GCP GKE: Artifact Registry reader 역할이 있는 노드 서비스 계정
노드 수준 접근 권한이 없으면 패키지 설치는 성공하지만 파드는 ImagePullBackOff로 실패합니다.
소개 (Introduction)
Crossplane 패키지 매니저가 프라이빗 레지스트리에 접근할 수 있게 하려면 설치 중에 서비스 계정 어노테이션을 구성하세요. crossplane-system 네임스페이스의 crossplane 서비스 계정에는 각 클라우드 제공자별 특정 어노테이션이 필요합니다.
- AWS EKS: IAM Roles for Service Accounts (IRSA)
- Azure AKS: Azure Workload Identity
- Google Cloud GKE: GKE Workload Identity
클라우드 제공자 설정 (Cloud provider setup)
아래에서 자세한 설정 지침을 위한 클라우드 제공자를 선택하세요.
- AWS EKS
- Azure AKS
- Google Cloud GKE
AWS에서 워크로드 아이덴티티 구성하기 (Configure workload identity on AWS)
IAM Roles for Service Accounts (IRSA)를 사용해 Amazon ECR에서 패키지를 가져오도록 Crossplane을 구성합니다.
사전 요구 사항
- OIDC provider가 활성화된 Amazon EKS 클러스터
- 설치 및 구성된 AWS CLI
- EKS 클러스터에 접근하도록 구성된 kubectl
- IAM 역할과 정책을 만들 권한
OIDC provider 활성화
EKS 클러스터에 OIDC provider가 없으면 활성화하세요.
$ eksctl utils associate-iam-oidc-provider \
--cluster=<your-cluster-name> \
--approve
OIDC provider를 확인하세요.
$ aws eks describe-cluster \
--name <your-cluster-name> \
--query "cluster.identity.oidc.issuer" \
--output text
ECR 접근용 IAM 정책 만들기
ECR에서 이미지를 가져올 권한을 부여하는 IAM 정책을 만드세요.
$ cat > crossplane-ecr-policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ecr:GetAuthorizationToken"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage"
],
"Resource": "arn:aws:ecr:<REGION>:<ACCOUNT_ID>:repository/*"
}
]
}
EOF
$ aws iam create-policy \
--policy-name CrossplaneECRPolicy \
--policy-document file://crossplane-ecr-policy.json
📝 참고:
<REGION>과<ACCOUNT_ID>를 AWS 리전과 계정 ID로 바꾸세요. 필요하면Resource를 특정 리포지토리로 제한할 수 있어요.
신뢰 정책을 가진 IAM 역할 만들기
Crossplane 서비스 계정이 맡을 수 있는 IAM 역할을 만드세요.
$ export CLUSTER_NAME=<your-cluster-name>
$ export AWS_REGION=<your-aws-region>
$ export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
$ export OIDC_PROVIDER=$(aws eks describe-cluster --name $CLUSTER_NAME --region $AWS_REGION --query "cluster.identity.oidc.issuer" --output text | sed -e "s/^https:\/\///")
$ cat > trust-policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider/${OIDC_PROVIDER}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"${OIDC_PROVIDER}:sub": "system:serviceaccount:crossplane-system:crossplane",
"${OIDC_PROVIDER}:aud": "sts.amazonaws.com"
}
}
}
]
}
EOF
$ aws iam create-role \
--role-name CrossplaneECRRole \
--assume-role-policy-document file://trust-policy.json
역할에 정책 연결하기
ECR 정책을 IAM 역할에 연결하세요.
$ aws iam attach-role-policy \
--role-name CrossplaneECRRole \
--policy-arn arn:aws:iam::${AWS_ACCOUNT_ID}:policy/CrossplaneECRPolicy
IRSA 어노테이션으로 Crossplane 설치하기
서비스 계정 어노테이션으로 Crossplane을 설치하세요.
$ helm upgrade --install crossplane \
crossplane-stable/crossplane \
--namespace crossplane-system \
--create-namespace \
--set "serviceAccount.customAnnotations.eks\.amazonaws\.com/role-arn=arn:aws:iam::${AWS_ACCOUNT_ID}:role/CrossplaneECRRole"
구성 검증하기
서비스 계정에 올바른 어노테이션이 있는지 확인하세요.
$ kubectl get sa crossplane -n crossplane-system -o yaml
예상 출력에는 다음이 포함되어야 합니다.
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/CrossplaneECRRole
name: crossplane
namespace: crossplane-system
ECR에서 패키지 설치 테스트하기
구성이 완료되면 ECR 레지스트리에서 Crossplane 패키지(Providers, Functions, Configurations)를 설치할 수 있습니다. Provider를 사용한 예입니다.
$ kubectl apply -f - <<EOF
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws-s3
spec:
package: ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/crossplane/provider-aws-s3:v1.2.0
EOF
Provider 설치 상태를 확인하세요.
$ kubectl get provider provider-aws-s3
$ kubectl describe provider provider-aws-s3
트러블슈팅
인증 토큰 가져오기 실패
오류:
failed to get authorization token: AccessDeniedException
해결 방법:
- IAM 역할에
ecr:GetAuthorizationToken권한이 있는지 확인. - 신뢰 정책이 서비스 계정이 역할을 맡을 수 있게 하는지 확인.
- 서비스 계정 어노테이션이 IAM 역할 ARN과 일치하는지 확인.
잘못된 아이덴티티 토큰
오류:
An error occurred (InvalidIdentityToken) when calling the AssumeRoleWithWebIdentity operation
해결 방법:
- EKS 클러스터에서 OIDC provider가 활성화되어 있는지 확인.
- 신뢰 정책 조건이 클러스터의 OIDC provider와 일치하는지 확인.
- 조건의 서비스 계정 네임스페이스와 이름이 올바른지 확인.
ECR 리포지토리 접근 거부
오류:
denied: User: arn:aws:sts::123456789012:assumed-role/CrossplaneECRRole is not authorized to perform: ecr:BatchGetImage
해결 방법:
- IAM 정책에
ecr:BatchGetImage,ecr:BatchCheckLayerAvailability,ecr:GetDownloadUrlForLayer가 포함되는지 확인. - 정책의
Resource에 ECR 리포지토리 ARN이 포함되는지 확인. - IAM 역할에 정책이 연결되어 있는지 확인.
서비스 계정 어노테이션 미적용
설치 후 서비스 계정에 어노테이션이 없으면:
# Update via Helm
$ helm upgrade crossplane \
crossplane-stable/crossplane \
--namespace crossplane-system \
--reuse-values \
--set "serviceAccount.customAnnotations.eks\.amazonaws\.com/role-arn=arn:aws:iam::${AWS_ACCOUNT_ID}:role/CrossplaneECRRole"
# Restart Crossplane
$ kubectl rollout restart deployment/crossplane -n crossplane-system
Crossplane 로그 확인하기
인증 문제에 대한 로그를 확인하세요.
$ kubectl logs -n crossplane-system deployment/crossplane --all-containers -f
다음 항목을 찾아보세요.
- AWS 자격 증명 오류
- ECR 인증 실패
- 특정 리포지토리 경로가 있는 이미지 가져오기 오류
더 알아보기
Azure에서 워크로드 아이덴티티 구성하기 (Configure workload identity on Azure)
Azure Workload Identity를 사용해 Azure Container Registry (ACR)에서 패키지를 가져오도록 Crossplane을 구성합니다.
사전 요구 사항
- Workload Identity가 활성화된 AKS 클러스터
- 설치 및 구성된 Azure CLI
- AKS 클러스터에 접근하도록 구성된 kubectl
- Azure 관리 아이덴티티와 역할 할당을 만들 권한
AKS에서 워크로드 아이덴티티 활성화
AKS 클러스터에 Workload Identity가 활성화되어 있지 않으면 업데이트하세요.
$ export RESOURCE_GROUP=<your-resource-group>
$ export CLUSTER_NAME=<your-cluster-name>
$ az aks update \
--resource-group $RESOURCE_GROUP \
--name $CLUSTER_NAME \
--enable-oidc-issuer \
--enable-workload-identity
OIDC issuer URL을 가져오세요.
$ export AKS_OIDC_ISSUER=$(az aks show \
--resource-group $RESOURCE_GROUP \
--name $CLUSTER_NAME \
--query "oidcIssuerProfile.issuerUrl" \
--output tsv)
$ echo $AKS_OIDC_ISSUER
Azure 관리 아이덴티티 만들기
Crossplane용 관리 아이덴티티를 만드세요.
$ export IDENTITY_NAME=crossplane-acr-identity
$ az identity create \
--name $IDENTITY_NAME \
--resource-group $RESOURCE_GROUP
$ export USER_ASSIGNED_CLIENT_ID=$(az identity show \
--name $IDENTITY_NAME \
--resource-group $RESOURCE_GROUP \
--query 'clientId' \
--output tsv)
$ export USER_ASSIGNED_OBJECT_ID=$(az identity show \
--name $IDENTITY_NAME \
--resource-group $RESOURCE_GROUP \
--query 'principalId' \
--output tsv)
$ echo "Client ID: $USER_ASSIGNED_CLIENT_ID"
$ echo "Object ID: $USER_ASSIGNED_OBJECT_ID"
ACR pull 역할 할당하기
관리 아이덴티티에 ACR에서 가져올 권한을 부여하세요.
$ export ACR_NAME=<your-acr-name>
$ export ACR_ID=$(az acr show \
--name $ACR_NAME \
--query 'id' \
--output tsv)
$ az role assignment create \
--assignee-object-id $USER_ASSIGNED_OBJECT_ID \
--assignee-principal-type ServicePrincipal \
--role AcrPull \
--scope $ACR_ID
페더레이션 아이덴티티 자격 증명 만들기
관리 아이덴티티와 Kubernetes 서비스 계정 사이의 신뢰를 설정하는 페더레이션 아이덴티티 자격 증명을 만드세요.
$ az identity federated-credential create \
--name crossplane-federated-credential \
--identity-name $IDENTITY_NAME \
--resource-group $RESOURCE_GROUP \
--issuer $AKS_OIDC_ISSUER \
--subject system:serviceaccount:crossplane-system:crossplane \
--audience api://AzureADTokenExchange
워크로드 아이덴티티 구성으로 Crossplane 설치하기
테넌트 ID를 가져오세요.
$ export AZURE_TENANT_ID=$(az account show --query tenantId --output tsv)
워크로드 아이덴티티 어노테이션과 라벨로 Crossplane을 설치하세요.
$ helm upgrade --install crossplane \
crossplane-stable/crossplane \
--namespace crossplane-system \
--create-namespace \
--set "serviceAccount.customAnnotations.azure\.workload\.identity/client-id=$USER_ASSIGNED_CLIENT_ID" \
--set "serviceAccount.customAnnotations.azure\.workload\.identity/tenant-id=$AZURE_TENANT_ID" \
--set-string 'customLabels.azure\.workload\.identity/use=true'
📝 참고: Azure Workload Identity에는 다음이 필요합니다.
- 클라이언트 ID와 테넌트 ID용 서비스 계정 어노테이션
- 파드에
azure.workload.identity/use: "true"라벨 (customLabels를 통한 적용)
customLabels 설정은 모든 Crossplane 리소스에 라벨을 적용합니다. Azure Workload Identity webhook은 파드의 이 라벨을 사용해 환경 변수와 토큰 볼륨을 주입합니다. 값을 부울이 아니라 문자열로 처리하려면 --set-string을 사용하세요.
구성 검증하기
서비스 계정에 올바른 어노테이션이 있는지 확인하세요.
$ kubectl get sa crossplane -n crossplane-system -o yaml
예상 출력에는 다음이 포함되어야 합니다.
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
azure.workload.identity/client-id: <your-client-id>
azure.workload.identity/tenant-id: <your-tenant-id>
name: crossplane
namespace: crossplane-system
배포에 필요한 라벨이 있는지 확인하세요.
$ kubectl get deployment crossplane -n crossplane-system -o yaml
예상 출력에는 다음이 포함되어야 합니다.
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
azure.workload.identity/use: "true"
name: crossplane
namespace: crossplane-system
spec:
template:
metadata:
labels:
azure.workload.identity/use: "true"
ACR에서 패키지 설치 테스트하기
구성이 완료되면 ACR에서 Crossplane 패키지(Providers, Functions, Configurations)를 설치할 수 있습니다. Provider를 사용한 예입니다.
$ kubectl apply -f - <<EOF
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-azure-storage
spec:
package: ${ACR_NAME}.azurecr.io/crossplane/provider-azure-storage:v1.2.0
EOF
Provider 설치 상태를 확인하세요.
$ kubectl get provider provider-azure-storage
$ kubectl describe provider provider-azure-storage
트러블슈팅
인증 필요 오류
오류:
unauthorized: authentication required
해결 방법:
- 관리 아이덴티티에 ACR의 AcrPull 역할이 있는지 확인.
- 페더레이션 자격 증명 구성을 확인.
- 서비스 계정 어노테이션이 관리 아이덴티티 클라이언트 ID와 테넌트 ID와 일치하는지 확인.
참조 해결 실패
오류:
failed to resolve reference: failed to fetch oauth token
해결 방법:
- AKS 클러스터에서 워크로드 아이덴티티가 활성화되어 있는지 확인.
- 페더레이션 자격 증명의 OIDC issuer URL이 클러스터 OIDC issuer와 일치하는지 확인.
- 페더레이션 자격 증명의 subject가
system:serviceaccount:crossplane-system:crossplane과 일치하는지 확인.
잘못된 페더레이션 토큰
오류:
invalid federated token
해결 방법:
- 페더레이션 자격 증명 audience가
api://AzureADTokenExchange를 사용하는지 확인. - OIDC issuer URL이 올바른지 확인.
- 서비스 계정 네임스페이스와 이름이 페더레이션 자격 증명 subject와 일치하는지 확인.
서비스 계정 어노테이션 미적용
설치 후 서비스 계정에 어노테이션이 없으면:
# Update via Helm
$ helm upgrade crossplane \
crossplane-stable/crossplane \
--namespace crossplane-system \
--reuse-values \
--set "serviceAccount.customAnnotations.azure\.workload\.identity/client-id=$USER_ASSIGNED_CLIENT_ID" \
--set "serviceAccount.customAnnotations.azure\.workload\.identity/tenant-id=$AZURE_TENANT_ID"
# Restart Crossplane
$ kubectl rollout restart deployment/crossplane -n crossplane-system
Crossplane 로그 확인하기
인증 문제에 대한 로그를 확인하세요.
$ kubectl logs -n crossplane-system deployment/crossplane --all-containers -f
다음 항목을 찾아보세요.
- Azure 인증 오류
- ACR 인증 실패
- 특정 리포지토리 경로가 있는 이미지 가져오기 오류
더 알아보기
- Azure Workload Identity Documentation
- AKS Workload Identity Overview
- Azure Container Registry Authentication
GCP에서 워크로드 아이덴티티 구성하기 (Configure workload identity on GCP)
GKE Workload Identity를 사용해 Google Artifact Registry에서 패키지를 가져오도록 Crossplane을 구성합니다.
사전 요구 사항
- Workload Identity가 활성화된 GKE 클러스터
- 설치 및 구성된 gcloud CLI
- GKE 클러스터에 접근하도록 구성된 kubectl
- 서비스 계정과 IAM 바인딩을 만들 권한
GKE에서 워크로드 아이덴티티 활성화
GKE 클러스터에 Workload Identity가 활성화되어 있지 않으면 새 클러스터를 만들거나 기존 클러스터를 업데이트하세요.
새 클러스터:
$ export PROJECT_ID=<your-project-id>
$ export CLUSTER_NAME=<your-cluster-name>
$ export REGION=<your-region>
$ gcloud container clusters create $CLUSTER_NAME \
--region=$REGION \
--workload-pool=${PROJECT_ID}.svc.id.goog
기존 클러스터:
$ gcloud container clusters update $CLUSTER_NAME \
--region=$REGION \
--workload-pool=${PROJECT_ID}.svc.id.goog
Google 서비스 계정 만들기
Crossplane용 Google Cloud 서비스 계정을 만드세요.
$ export GSA_NAME=crossplane-gar-sa
$ gcloud iam service-accounts create $GSA_NAME \
--display-name="Crossplane Artifact Registry Service Account" \
--project=$PROJECT_ID
전체 서비스 계정 이메일을 가져오세요.
$ export GSA_EMAIL=${GSA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com
$ echo $GSA_EMAIL
Artifact Registry 권한 부여하기
서비스 계정에 Artifact Registry에서 읽을 권한을 부여하세요.
$ gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:${GSA_EMAIL}" \
--role="roles/artifactregistry.reader"
특정 리포지토리 접근에는 다음을 사용하세요.
$ export REPOSITORY=<your-repository>
$ export REPOSITORY_LOCATION=<your-repository-location>
$ gcloud artifacts repositories add-iam-policy-binding $REPOSITORY \
--location=$REPOSITORY_LOCATION \
--member="serviceAccount:${GSA_EMAIL}" \
--role="roles/artifactregistry.reader"
IAM 정책 바인딩 만들기
Google 서비스 계정과 Kubernetes 서비스 계정 사이에 IAM 정책 바인딩을 만드세요.
$ gcloud iam service-accounts add-iam-policy-binding $GSA_EMAIL \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:${PROJECT_ID}.svc.id.goog[crossplane-system/crossplane]"
워크로드 아이덴티티 어노테이션으로 Crossplane 설치하기
서비스 계정 어노테이션으로 Crossplane을 설치하세요.
$ helm upgrade --install crossplane \
crossplane-stable/crossplane \
--namespace crossplane-system \
--create-namespace \
--set "serviceAccount.customAnnotations.iam\.gke\.io/gcp-service-account=$GSA_EMAIL"
구성 검증하기
서비스 계정에 올바른 어노테이션이 있는지 확인하세요.
$ kubectl get sa crossplane -n crossplane-system -o yaml
예상 출력에는 다음이 포함되어야 합니다.
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
iam.gke.io/gcp-service-account: [email protected]
name: crossplane
namespace: crossplane-system
Artifact Registry에서 패키지 설치 테스트하기
구성이 완료되면 Artifact Registry에서 Crossplane 패키지(Providers, Functions, Configurations)를 설치할 수 있습니다. Provider를 사용한 예입니다.
$ kubectl apply -f - <<EOF
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-gcp-storage
spec:
package: us-docker.pkg.dev/${PROJECT_ID}/crossplane/provider-gcp-storage:v1.2.0
EOF
Provider 설치 상태를 확인하세요.
$ kubectl get provider provider-gcp-storage
$ kubectl describe provider provider-gcp-storage
트러블슈팅
권한 거부
오류:
PERMISSION_DENIED: Permission denied on resource
해결 방법:
- Google 서비스 계정에
roles/artifactregistry.reader역할이 있는지 확인. - Google 서비스 계정과 Kubernetes 서비스 계정 사이에 IAM 정책 바인딩이 있는지 확인.
- 서비스 계정 어노테이션이 Google 서비스 계정 이메일과 일치하는지 확인.
OAuth 토큰 가져오기 실패
오류:
failed to fetch oauth token
해결 방법:
- GKE 클러스터에서 워크로드 아이덴티티가 활성화되어 있는지 확인.
- IAM 정책 바인딩이 Kubernetes 서비스 계정이 Google 서비스 계정을 대신할 수 있게 하는지 확인.
- 워크로드 풀이 프로젝트
${PROJECT_ID}.svc.id.goog와 일치하는지 확인.
잘못된 아이덴티티 토큰
오류:
invalid identity token
해결 방법:
- IAM 정책 바인딩 멤버 형식이
serviceAccount:${PROJECT_ID}.svc.id.goog[crossplane-system/crossplane]인지 확인. - 노드 풀에서 워크로드 아이덴티티가 활성화되어 있는지 확인.
- 서비스 계정 어노테이션이 올바른지 확인.
서비스 계정 어노테이션 미적용
설치 후 서비스 계정에 어노테이션이 없으면:
# Update via Helm
$ helm upgrade crossplane \
crossplane-stable/crossplane \
--namespace crossplane-system \
--reuse-values \
--set "serviceAccount.customAnnotations.iam\.gke\.io/gcp-service-account=$GSA_EMAIL"
# Restart Crossplane
$ kubectl rollout restart deployment/crossplane -n crossplane-system
워크로드 아이덴티티 구성 검증하기
워크로드 아이덴티티 구성을 테스트하세요.
# Check if workload identity is enabled on the cluster
$ gcloud container clusters describe $CLUSTER_NAME \
--region=$REGION \
--format="value(workloadIdentityConfig.workloadPool)"
# Verify IAM policy binding
$ gcloud iam service-accounts get-iam-policy $GSA_EMAIL
Crossplane 로그 확인하기
인증 문제에 대한 로그를 확인하세요.
$ kubectl logs -n crossplane-system deployment/crossplane --all-containers -f
다음 항목을 찾아보세요.
- Google Cloud 인증 오류
- Artifact Registry 인증 실패
- 특정 리포지토리 경로가 있는 이미지 가져오기 오류
더 알아보기
- GKE Workload Identity Documentation
- Artifact Registry Authentication
- IAM Service Account Permissions
설치 후 구성하기 (Configure after installation)
Crossplane이 이미 설치되어 있다면, 클라우드 제공자 탭에 표시된 적절한 --set 플래그로 Helm upgrade를 사용해 서비스 계정 어노테이션을 업데이트할 수 있습니다. 업데이트 후 Crossplane 배포를 재시작하세요.
$ kubectl rollout restart deployment/crossplane -n crossplane-system
더 알아보기 (Learn more)
- Crossplane 설치 - Helm 차트로 Crossplane 설치하기
- Provider 패키지 - Provider 설치와 관리