Amazon EKSにデプロイしたGitLabのオブジェクトストレージをS3に変更する(EKS Pod Identity)

Amazon EKSにデプロイしたGitLabのオブジェクトストレージをS3に変更する(EKS Pod Identity)

Clock Icon2025.02.19

以下の記事の認証方法をEKS Pod Identityを利用したバージョンです。

作成するS3バケット等の情報に関しては、以下の記事に記載しましたので割愛します。

https://dev.classmethod.jp/articles/eks-gitlab-objectstorage-s3/

EKS Pod Identityの概要や嬉しいポイントは以下の記事をご確認ください。

https://dev.classmethod.jp/articles/eks-pod-identity-terraform-blue-green-upgrade/

前提

  • EKSにHelmを使ってGitLabを構築済みであること

https://dev.classmethod.jp/articles/gitlab-eks-helm-tutorial/

Amazon EKS Pod Identity Agentアドオンをインストールする

以下のコマンドでアドオンをインストールします。

aws eks create-addon --cluster-name gitlab-cluster-blog --addon-name eks-pod-identity-agent

EKS Pod Identity Agent用のPodsが起動しているか確認します。

kubectl get pods -n kube-system | grep 'eks-pod-identity-agent'

以下のようにPodsが稼働していれば、問題ありません。

出力例
eks-pod-identity-agent-lh22n                    1/1     Running   0          4m26s
eks-pod-identity-agent-vwshp                    1/1     Running   0          4m26s

Amazon EKS Pod Identity エージェントのセットアップ - アマゾン EKS

ServiceAccountの作成

PodsからS3バケットにアクセスするために、ServiceAccountを用意します。

kubectl create serviceaccount gitlab-global -n gitlab

S3バケットとIAM Roleの作成

S3バケットとPodからS3バケットにアクセスするためのIAM Roleを作成します。

Terraformコードは以下です。

main.tf
terraform {
  required_version = "~> 1.10.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 5.82.0"
    }
  }
}

provider "aws" {
  region = var.region
}

variable "name_prefix" {}
variable "region" {
  default = "ap-northeast-1"
}

locals {
  buckets_names = [
    "registry",
    "lfs",
    "artifacts",
    "uploads",
    "packages",
    "backups",
    "tmp"
  ]
  oidc_provider = element(split("/id/", var.oidc_provider_arn), 1)
}

data "aws_kms_key" "aws_s3" {
  key_id = "alias/aws/s3"
}

resource "aws_s3_bucket" "gitlab" {
  for_each      = toset(local.buckets_names)
  bucket        = "${var.name_prefix}-${each.key}"
  force_destroy = true
}

resource "aws_s3_bucket_versioning" "gitlab" {
  for_each = aws_s3_bucket.gitlab

  bucket = each.value.id

  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_s3_bucket_server_side_encryption_configuration" "gitlab" {
  for_each = aws_s3_bucket.gitlab

  bucket = each.value.id

  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm     = "aws:kms"
      kms_master_key_id = data.aws_kms_key.aws_s3.arn
    }
  }
}

resource "aws_s3_bucket_public_access_block" "gitlab" {
  for_each = aws_s3_bucket.gitlab

  bucket = each.value.id

  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

## S3 access policy for all buckets except registry and backups (covered by separate policies)
resource "aws_iam_policy" "gitlab_s3_policy" {
  name = "${var.name_prefix}-s3-policy"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "s3:PutObject",
          "s3:GetObject",
          "s3:DeleteObject",
        ]
        Effect   = "Allow"
        Resource = [for k, v in aws_s3_bucket.gitlab : "${v.arn}/*" if !contains(["registry", "backups"], k)]
      },
      # Backup Utility and Geo Replication
      {
        Action = [
          "s3:ListBucket",
        ]
        Effect   = "Allow"
        Resource = [for k, v in aws_s3_bucket.gitlab : v.arn if !contains(["registry", "backups"], k)]
      },
    ]
  })
}

resource "aws_iam_policy" "gitlab_s3_backups_policy" {
  name = "${var.name_prefix}-s3-backups-policy"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "s3:PutObject",
          "s3:GetObject",
          "s3:DeleteObject",
        ]
        Effect   = "Allow"
        Resource = ["${aws_s3_bucket.gitlab["backups"].arn}/*"]
      }
    ]
  })
}

## S3 access policy for registry bucket
resource "aws_iam_policy" "gitlab_s3_registry_policy" {
  name = "${var.name_prefix}-s3-registry-policy"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      # Docker Registry S3 bucket requires specific permissions
      # https://docs.docker.com/registry/storage-drivers/s3/#s3-permission-scopes
      {
        Action = [
          "s3:ListBucket",
          "s3:GetBucketLocation",
          "s3:ListBucketMultipartUploads",
        ]
        Effect   = "Allow"
        Resource = aws_s3_bucket.gitlab["registry"].arn
      },
      {
        Action = [
          "s3:PutObject",
          "s3:GetObject",
          "s3:DeleteObject",
          "s3:ListMultipartUploadParts",
          "s3:AbortMultipartUpload"
        ]
        Effect   = "Allow"
        Resource = "${aws_s3_bucket.gitlab["registry"].arn}/*"
      },
    ]
  })
}

resource "aws_iam_policy" "gitlab_s3_kms_policy" {
  name = "${var.name_prefix}-s3-kms-policy"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "kms:Decrypt",
          "kms:GenerateDataKey"
        ]
        Effect = "Allow"
        Condition = {
          "StringLike" = {
            "kms:EncryptionContext:aws:s3:arn" = [
              for key, values in aws_s3_bucket.gitlab : values.arn
            ]
          }
        },
        Resource = data.aws_kms_key.aws_s3.arn
      }
    ]
  })
}

resource "aws_iam_role" "gitlab_eks_global" {
  name = "${var.prefix}-eks-global"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action    = ["sts:AssumeRole", "sts:TagSession"]
        Effect    = "Allow"
        Principal = { "Service" = "pods.eks.amazonaws.com" }
      },
    ]
  })
}

resource "aws_iam_role_policy_attachment" "gitlab_s3_policy" {
  policy_arn = aws_iam_policy.gitlab_s3_policy.arn
  role       = aws_iam_role.gitlab_eks_global.name
}
resource "aws_iam_role_policy_attachment" "gitlab_s3_backups_policy" {
  policy_arn = aws_iam_policy.gitlab_s3_backups_policy.arn
  role       = aws_iam_role.gitlab_eks_global.name
}
resource "aws_iam_role_policy_attachment" "gitlab_s3_registry_policy" {
  policy_arn = aws_iam_policy.gitlab_s3_registry_policy.arn
  role       = aws_iam_role.gitlab_eks_global.name
}
resource "aws_iam_role_policy_attachment" "gitlab_s3_kms_policy" {
  policy_arn = aws_iam_policy.gitlab_s3_kms_policy.arn
  role       = aws_iam_role.gitlab_eks_global.name
}

output "gitlab_eks_global_role" {
  value = aws_iam_role.gitlab_eks_global.arn
}

terraform.tfvarsで任意の値を渡して、リソースを作成します。

terraform.tfvars
name_prefix = "" # Example: example-gitlab-eks
region = "" # Example: us-east-1

Terraformを実行して、リソースを作成します。

terraform init
terraform plan
terraform apply

IAM Role ARNが出力されますので、これを控えておきます。

TerraformコードやIAMポリシーは以下を参考にしました。

terraform/modules/gitlab_ref_arch_aws/storage.tf · main · GitLab.org / GitLab Environment Toolkit · GitLab

Pod Identityの関連付けを作成

Pod Identityの関連付けを作成して、IAMロールをKubernetesサービスアカウントに割り当てます。

<IAMロールARN>はTerraformで作成したIAMロールを利用します。

aws eks create-pod-identity-association \
    --cluster-name gitlab-cluster-blog --role-arn <IAMロールARN> \
    --namespace gitlab --service-account gitlab-global

Secretsの作成・values.yamlの準備・Helmリリースの更新・動作確認

以下の記事の該当箇所をご確認ください。

https://dev.classmethod.jp/articles/eks-gitlab-objectstorage-s3/

動作確認の補足

Podにサービスアカウントトークンのファイルがマウントされていることは以下のコマンドで確認できます。

webservice等のpodが置き換わりますので、podにはwebserviceのpodを指定して確認します。

Pod名(gitlab-webservice-default-57d7598f89-ffjxq)部分は各自の環境に合わせて置き換えてください。

kubectl describe pod gitlab-webservice-default-57d7598f89-ffjxq -n gitlab | grep AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE:
出力例
AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE:  /var/run/secrets/pods.eks.amazonaws.com/serviceaccount/eks-pod-identity-token

サービスアカウントを使用して AWS サービスにアクセスするように pods を設定する - アマゾン EKS

(オプション)IRSAからPod Identityに切り替える場合

すでにIRSAでS3アクセスが可能な状態で、切り替える際は再起動が必要な場合があります。

サービスアカウントトークンのファイルがマウントされない場合は、以下の操作をお試しください。

# Deploymentの再起動
kubectl rollout restart deployment -n gitlab

# StatefulSetの再起動
kubectl rollout restart statefulset -n gitlab

おわりに

IRSAと比較して以下の点が楽でした。

  • EKS用のIDプロバイダー作成が不要
  • ServiceAccountのIAMロール関連付け用のアノテーション作成が不要
  • IAMロールのassume_role_policyがシンプル(IDプロバイダーのプロバイダー情報が不要)

代わりに以下の作業を行う必要がありました。

  • EKS Pod Identity Agent用のアドオンインストール
  • Pod Identityの関連付け

今回のケースでは、EKS Pod Identityを使ったほうが作業量が少なかったです。

以上、AWS事業本部の佐藤(@chari7311)でした。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.