..

velero irsa

개요

Velero 설치시 IAM Role for Service Accounts를 구성하는 방법을 정리한 가이드입니다.

IRSA for velero

Velero 시스템을 운영하는 DevOps Engineer, SRE를 대상으로 작성되었습니다.

 

이 게시물이 게시되는 시점에는 service account에 대한 IRSA 또는 IAM 역할을 사용하여 Velero를 설정하는 방법에 대한 공식 문서가 없어서 직접 작성하게 되었습니다.

 

배경지식

Velero 설치 방식

Velero를 설치하는 방법에는 두 가지가 있습니다.

  1. velero CLI: velero install 명령어를 사용해 Velero 파드와 관련 리소스를 쿠버네티스 클러스터에 설치하는 방식입니다.
  2. Helm 설치: Velero Helm 차트를 사용해 설치하는 방식입니다.

이 시나리오에서는 Helm 차트를 사용한 velero 설치 방법을 소개합니다.

 

파드에 IAM 권한부여

  • 쿠버네티스 환경에서 IRSAIAM Role for Service Account나 EKS Pod Identity를 사용하여 Pod 리소스에 IAM 권한을 부여하는 패턴은 일반적으로 권장하는 모범사례입니다.
  • 최근에는 IRSA 대신 EKS Pod Identity를 사용하는 걸 권장하는 추세입니다.
  • 최악의 안티패턴인 파드에 권한을 부여하기 위해 EC2 Worker node role에 직접 권한을 부여하는 행위는 절대하지 않도록 합니다.

 

환경

  • EKS v1.28 (EKS v1.30에서도 동일한 절차로 테스트 완료되었습니다.)
  • Velero v1.14.0 (헬름차트로 배포됨)
    • Velero 플러그인: velero-plugin-for-aws:v1.10.0

 

IRSA 설정 가이드

환경변수 설정

로컬 환경에 환경변수를 설정합니다.

BUCKET_NAME=<YOUR_S3_BUCKET_NAME>
CLUSTER_NAME=<YOUR_CLUSTER_NAME>
OIDC_ENDPOINT="$(aws eks describe-cluster --name "${CLUSTER_NAME}" \
    --query "cluster.identity.oidc.issuer" --output text)"
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' \
    --output text)
NAMESPACE=velero

OIDC Endpoint, Account ID, Namespace 정보가 담긴 환경변수들은 모두 IAM Role, IAM Policy 리소스를 생성할 때 사용됩니다.

 

로컬 환경변수가 잘 설정되어 있는지 검증합니다.

echo $BUCKET_NAME $CLUSTER_NAME $OIDC_ENDPOINT $AWS_ACCOUNT_ID $NAMESPACE

 

IAM json 작성

2개의 IAM 설정파일을 생성합니다.

  • velero-policy.json : IAM Policy의 설정이 담긴 파일입니다.
  • velero-trust-policy.json : IAM Role의 Trust Relationship 설정이 담긴 파일입니다.
cat > velero-policy.json <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ec2:DescribeVolumes",
                "ec2:DescribeSnapshots",
                "ec2:CreateTags",
                "ec2:CreateVolume",
                "ec2:CreateSnapshot",
                "ec2:DeleteSnapshot"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:DeleteObject",
                "s3:PutObject",
                "s3:AbortMultipartUpload",
                "s3:ListMultipartUploadParts"
            ],
            "Resource": [
                "arn:aws:s3:::${BUCKET_NAME}/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::${BUCKET_NAME}"
            ]
        }
    ]
}
EOF

스냅샷 백업, 쿠버네티스 리소스 백업을 수행하기 위한 EBS, S3 권한들입니다.

 

IAM Role 생성

IAM Role을 생성합니다. 이 IAM Role을 velero-server 서비스 어카운트가 사용하게 됩니다.

먼저 velero 파드가 IRSAIAM Role for Service Account를 통해 IAM Role에 접근할 수 있게 신뢰관계부터 생성합니다.

cat > velero-trust-policy.json <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "IRSAforVeleroServerPod",
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider/${OIDC_ENDPOINT#*//}"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "${OIDC_ENDPOINT#*//}:aud": "sts.amazonaws.com",
          "${OIDC_ENDPOINT#*//}:sub": "system:serviceaccount:${NAMESPACE}:velero-server"
        }
      }
    }
  ]
}
EOF

 

IAM Role을 생성하고 이전 과정에서 작성한 신뢰관계를 적용합니다.

ROLE_NAME=${CLUSTER_NAME}-velero-server-irsa-role
aws iam create-role \
  --role-name ${ROLE_NAME} \
  --assume-role-policy-document file://./velero-trust-policy.json

 

aws iam create-role 명령어를 실행 결과가 다음과 같이 출력되면 IAM Role이 정상적으로 생성되었다고 판단할 수 있습니다.

{
    "Role": {
        "Path": "/",
        "RoleName": "<YOUR_CLUSTER_NAME>-velero-server-irsa-role",
        "RoleId": "ARO...REDACTED...LSP",
        "Arn": "arn:aws:iam::<AWS_ACCOUNT_ID>:role/<YOUR_CLUSTER_NAME>-velero-server-irsa-role",
        "CreateDate": "2024-07-29T02:43:44+00:00",
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Sid": "IRSAforVeleroServerPod",
                    "Effect": "Allow",
                    "Principal": {
                        "Federated": "arn:aws:iam::<AWS_ACCOUNT_ID>:oidc-provider/oidc.eks.ap-northeast-2.amazonaws.com/id/<OIDC_ENDPOINT>"
                    },
                    "Action": "sts:AssumeRoleWithWebIdentity",
                    "Condition": {
                        "StringEquals": {
                            "oidc.eks.ap-northeast-2.amazonaws.com/id/<OIDC_ENDPOINT>:aud": "sts.amazonaws.com",
                            "oidc.eks.ap-northeast-2.amazonaws.com/id/<OIDC_ENDPOINT>:sub": "system:serviceaccount:velero:velero-server"
                        }
                    }
                }
            ]
        }
    }
}

 

Customer inline policy를 IAM Role에 붙입니다.

aws iam put-role-policy \
  --role-name "${ROLE_NAME}" \
  --policy-name "${CLUSTER_NAME}-velero-server-s3-backup-irsa-policy" \
  --policy-document file://./velero-policy.json

 

velero 헬름 차트 설정

IRSA를 사용하려면 velero의 AWS 플러그인velero-plugin-for-aws을 사용해야 합니다. Velero에서 이러한 플러그인들은 initContainers 형태로 적용, 관리됩니다.

# charts/velero/values.yaml
# Init containers to add to the Velero deployment's pod spec. At least one plugin provider image is required.
# If the value is a string then it is evaluated as a template.
initContainers:
  # - name: velero-plugin-for-aws
  #   image: velero/velero-plugin-for-aws:v1.10.0
  #   imagePullPolicy: IfNotPresent
  #   volumeMounts:
  #     - mountPath: /target
  #       name: plugins

 

아래와 같이 initContainers에 AWS plugin을 새롭게 추가합니다.

# charts/velero/values.yaml
initContainers:
  - name: velero-plugin-for-aws
    image: velero/velero-plugin-for-aws:v1.10.0
    imagePullPolicy: IfNotPresent
    volumeMounts:
      - mountPath: /target
        name: plugins

serviceAccount에 다음과 같이 eks.amazonaws.com/role-arn Annotation을 추가합니다.

# charts/velero/values.yaml
serviceAccount:
  server:
    create: true
    name:
    annotations:
      eks.amazonaws.com/role-arn: arn:aws:iam::<AWS_ACCOUNT_ID>:role/<YOUR_CLUSTER_NAME>-velero-server-irsa-role
    labels:
    imagePullSecrets: []

 

credentials.useSecrettrue에서 false로 변경해서, IAM Key가 아닌 IRSA를 assumeRole 해서 S3 버킷에 접근하도록 차트 설정을 변경합니다.

# charts/velero/values.yaml
credentials:
  # Whether a secret should be used. Set to false if, for examples:
  # - using kube2iam or kiam to provide AWS IAM credentials instead of providing the key file. (AWS only)
  # - using workload identity instead of providing the key file. (Azure/GCP only)
- useSecret: true
+ useSecret: false

 

velero 헬름 차트에서 사용하는 쿠버네티스 커스텀 리소스인 backupStorageLocation, volumeSnapshotLocation을 설정합니다.

  • bucket에는 자신이 백업 저장소로 사용할 S3 버킷 이름을 선언해주세요.
  • region에는 S3 버킷이 위치한 리전을 선언합니다. 이 시나리오에서는 서울 리전을 사용합니다.
# charts/velero/values.yaml
configuration:
  # Parameters for the BackupStorageLocation(s). Configure multiple by adding other element(s) to the backupStorageLocation slice.
  # See https://velero.io/docs/v1.6/api-types/backupstoragelocation/
  backupStorageLocation:
    # name is the name of the backup storage location where backups should be stored. If a name is not provided,
    # a backup storage location will be created with the name "default". Optional.
  - name: velero-s3-bsl
    # provider is the name for the backup storage location provider.
    provider: velero.io/aws
    # bucket is the name of the bucket to store backups in. Required.
    bucket: <YOUR_BUCKET_NAME>
    # caCert defines a base64 encoded CA bundle to use when verifying TLS connections to the provider. Optional.
    caCert:
    # prefix is the directory under which all Velero data should be stored within the bucket. Optional.
    prefix:
    # default indicates this location is the default backup storage location. Optional.
    default: true
    # validationFrequency defines how frequently Velero should validate the object storage. Optional.
    validationFrequency:
    # accessMode determines if velero can write to this backup storage location. Optional.
    # default to ReadWrite, ReadOnly is used during migrations and restores.
    accessMode: ReadWrite
    credential:
      # name of the secret used by this backupStorageLocation.
      name:
      # name of key that contains the secret data to be used.
      key:
    # Additional provider-specific configuration. See link above
    # for details of required/optional fields for your provider.
    config:
      region: ap-northeast-2
    #  s3ForcePathStyle:
    #  s3Url:
    #  kmsKeyId:
    #  resourceGroup:
    #  The ID of the subscription containing the storage account, if different from the cluster’s subscription. (Azure only)
    #  subscriptionId:
    #  storageAccount:
    #  publicUrl:
    #  Name of the GCP service account to use for this backup storage location. Specify the
    #  service account here if you want to use workload identity instead of providing the key file.(GCP only)
    #  serviceAccount:
    #  Option to skip certificate validation or not if insecureSkipTLSVerify is set to be true, the client side should set the
    #  flag. For Velero client Command like velero backup describe, velero backup logs needs to add the flag --insecure-skip-tls-verify
    #  insecureSkipTLSVerify:

    # annotations allows adding arbitrary annotations to this BackupStorageLocation resource. Optional.
    annotations: {}

  # Parameters for the VolumeSnapshotLocation(s). Configure multiple by adding other element(s) to the volumeSnapshotLocation slice.
  # See https://velero.io/docs/v1.6/api-types/volumesnapshotlocation/
  volumeSnapshotLocation:
    # name is the name of the volume snapshot location where snapshots are being taken. Required.
  - name: velero-s3-dsl
    # provider is the name for the volume snapshot provider.
    provider: velero.io/aws
    credential:
      # name of the secret used by this volumeSnapshotLocation.
      name:
      # name of key that contains the secret data to be used.
      key:
    # Additional provider-specific configuration. See link above
    # for details of required/optional fields for your provider.
    config:
      region: ap-northeast-2
  #    region:
  #    apiTimeout:
  #    resourceGroup:
  #    The ID of the subscription where volume snapshots should be stored, if different from the cluster’s subscription. If specified, also requires `configuration.volumeSnapshotLocation.config.resourceGroup`to be set. (Azure only)
  #    subscriptionId:
  #    incremental:
  #    snapshotLocation:
  #    project:

 

IANA 시간대를 이후 스케줄 백업에 사용하기 위해 extraEnvVars 설정을 헬름 차트에 추가합니다.

# charts/velero/YOUR_VALUES_FILE.yaml
configuration:
  extraEnvVars:
    TZ: Asia/Seoul

Velero v1.6.0 버전 이상에서만 TZ 환경변수를 사용할 수 있습니다. 관련 이슈는 #2061입니다.

 

나중에 헬름 차트에 설정한 extraEnvVars 설정은 다음과 같이 파드 환경변수에 적용됩니다.

kubectl get pod -n velero -o yaml
# velero pod's yaml
spec:
  containers:
  - args:
    - server
    - --uploader-type=kopia
    - --keep-latest-maintenance-jobs=3
    command:
    - /velero
    env:
    - name: TZ
      value: Asia/Seoul

 

새로운 설정을 적용하기 위해 velero 차트를 업그레이드합니다. 아래 명령어는 최초 설치 시에도 사용할 수 있습니다. helm upgrade --install 명령어는 차트가 설치되어 있지 않을 경우 새로운 설치를 진행하며, 이미 설치되어 있는 경우에는 차트를 업그레이드합니다. 따라서 초기 설치와 차트 업그레이드를 동일한 명령어로 처리할 수 있습니다.

helm upgrade \
  --install \
  --namespace velero \
  --create-namespace \
  velero . \
  --values <your-values-file>.yaml \
  --wait

 

velero-server라는 이름의 serviceAccount가 새로 생성됩니다. velero 파드는 velero-server serviceAccount 리소스를 통해 IAM Role에 연결됩니다.

kubectl get serviceaccount velero-server -n velero -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::<REDACTED>:role/<REDACTED>
  labels:
    app.kubernetes.io/instance: velero
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: velero
    argocd.argoproj.io/instance: velero
    helm.sh/chart: velero-7.1.3
  name: velero-server
  namespace: velero

 

S3 연결상태 확인

Velero 서버는 백업 스토리지로 S3 버킷을 사용합니다. 이 때 Velero는 백업 스토리지 위치를 지정하는 backupStorageLocationbsl 커스텀 리소스를 사용해서 S3 버킷에 연결됩니다.

bsl

bsl의 Phase가 Available로 변경되면 정상적으로 S3로부터 백업, 복구를 수행할 수 있게 연결된 상태라는 의미입니다.

# In short `kubectl get bsl -n velero`
$ kubectl get backupstoragelocation -n velero
NAME            PHASE       LAST VALIDATED   AGE   DEFAULT
velero-s3-bsl   Available   54s              23d   true

 

velero 파드가 IAM Role for Service Account 구성에서 정상적으로 백업을 하는지 테스트하기 위해, 테스트 백업을 수행합니다.

$ velero backup-location get
NAME            PROVIDER        BUCKET/PREFIX            PHASE       LAST VALIDATED                  ACCESS MODE   DEFAULT
velero-s3-bsl   velero.io/aws   velero-backup-s3   Available   2024-08-27 09:34:02 +0900 KST   ReadWrite     true
$ velero create backup test-backup
Backup request "test-backup" submitted successfully.
Run `velero backup describe test-backup` or `velero backup logs test-backup` for more details
$ velero backup get
NAME          STATUS      ERRORS   WARNINGS   CREATED                         EXPIRES   STORAGE LOCATION   SELECTOR
test-backup   Completed   0        0          2024-08-27 09:33:16 +0900 KST   29d       velero-s3-bsl      <none>

잠시 기다리면 백업 상태가 완료Completed로 바뀝니다.

 

이후 backup 리소스를 삭제합니다. backup 리소스를 삭제하면 S3에 저장된 데이터와 PV를 백업해서 생성된 EBS Snapshot이 모두 삭제됩니다.

velero delete backup test-backup

 

이제 Access Key를 직접 Velero 차트에 넣는 대신, IAM Role for Service Account 방식을 사용해서 좀 더 안전한 파드 권한을 구성했습니다.

 

관련자료

Blog article for velero IRSA:

AWS IRSA:

AWS EKS Pod Identity: