GitLab Runner TokenをASCPを使ってAWS Secrets Managerから取得してみた(GitLab Runner on Amazon  EKS)

GitLab Runner TokenをASCPを使ってAWS Secrets Managerから取得してみた(GitLab Runner on Amazon EKS)

Clock Icon2025.04.23

GitLab RunnerをHelmでデプロイする際に、GitLabで発行したGitLab Runner Tokenをセットする必要があります。

Helmのvalues.yamlで渡す場合は以下です。

values.yaml
gitlabUrl: https://example.com/
runnerToken: "<GitLab Runner Token>"
rbac:
  create: true
serviceAccount:
  create: true
  name: "gitlab-runner"

values.yamlはVCS上で管理したいため、トークンのような機密情報はファイル中に含めたくありません。

Secrets Manager経由で渡すことでファイル中に含めないようにします。

今回はAWS Secrets Manager and Config Providerを使って実現します。

AWS Secrets Manager and Config Providerとは

AWS Secrets Manager and Config Provider(以降、ASCP)は、Kubernetes Secrets Store Container Storage Interface (CSI) ドライバー用のProviderです。

ASCPを使うことで、PodはSecrets ManagerとSystem Managerパラーメータストアに保存されているシークレットを取得できます。

やってみた

前提

  • EKSクラスターはAutoModeを利用
  • 認証方式はPod Identityを利用する

今回利用するEKSクラスターの詳細は以下をご確認ください。

後述のコード上で省略しているNetwork周りの設定やProvider定義等も以下から確認できます。

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

IAM Role・SecretsManagerの作成

トークン格納用のSecretsManagerとASCP用のIAM Roleを作成します。

今回、GitLab Runnerはgitlab-runnerというServiceAccountを利用します。

ASCPを使うのは、このServiceAccountになります。

ServiceAccountとASCP用のIAM Roleを関連付けて、アクセスエントリを作成します。

cluster/main.tf
# Secrets Manager
resource "aws_secretsmanager_secret" "gitlab_token" {
  name        = "${var.prefix}-gitlab-token-${random_string.suffix.result}"
  description = "GitLab Token for CI/CD"
  tags        = local.tags
}


# GitLab Runner用IAM Role
resource "aws_iam_role" "gitlab_runner" {
  name               = "${var.prefix}-gitlab-runner"
  assume_role_policy = data.aws_iam_policy_document.eks_pod_assume_role.json
  tags               = local.tags
}

data "aws_iam_policy_document" "eks_pod_assume_role" {
  statement {
    actions = [
      "sts:AssumeRole",
      "sts:TagSession"
    ]

    effect = "Allow"

    principals {
      type        = "Service"
      identifiers = ["pods.eks.amazonaws.com"]
    }
  }
}

resource "aws_iam_policy" "ascp" {
  name        = "${var.prefix}-ascp"
  description = "Policy for AWS Secrets and Configuration Provider"
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "secretsmanager:GetSecretValue",
          "secretsmanager:DescribeSecret"
        ]
        Resource = [
          aws_secretsmanager_secret.gitlab_token.arn
        ]
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "ascp" {
  role       = aws_iam_role.gitlab_runner.name
  policy_arn = aws_iam_policy.ascp.arn
}

# GitLab RunnerからSecrets Managerを参照するため
resource "aws_eks_pod_identity_association" "gitlab_runner" {
  cluster_name    = module.eks.cluster_name
  namespace       = "gitlab-runner"
  service_account = "gitlab-runner"
  role_arn        = aws_iam_role.gitlab_runner.arn
}

Secrets ManagerにGitLab Runner Tokenを保存

以下手順で、トークンを取得します。

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

作成したSecrets Managerにトークンをセットします。

aws secretsmanager create-secret \
  --name "gitlab-token-secret" \
  --secret-string '{"token":"<GitLab Runner Token>"}'

Secrets Store CSI DriverとASCPのインストール

EKSクラスターにSecrets Store CSI DriverとASCPをインストールします。

以下のファイルを準備します。

helm/main.tf
resource "helm_release" "secrets_store_csi_driver" {
  name       = "secrets-store-csi-driver"
  repository = "https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts"
  chart      = "secrets-store-csi-driver"
  namespace  = "kube-system"
}

resource "helm_release" "secrets_provider_aws" {
  //helm_release - helm - terraform: https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release
  name       = "secrets-provider-aws"
  repository = "https://aws.github.io/secrets-store-csi-driver-provider-aws"
  chart      = "secrets-store-csi-driver-provider-aws"
  namespace  = "kube-system"
  # GitLab Runnerノードにtaintsを設定しているため、tolerationsを設定
  # https://github.com/aws/secrets-store-csi-driver-provider-aws/issues/266
  values = [<<-EOF
tolerations:
  - operator: Exists
EOF
  ]

  depends_on = [
    helm_release.secrets_store_csi_driver
  ]
}

GitLabとGitLab Runnerのワーカーノードを分離したかったため、GitLab Runnerのワーカーノードにtaintsを設定していました。

https://dev.classmethod.jp/articles/eks-auto-mode-gitlab-runner-separation/

Secrets Store CSI DriverとASCPは、シークレットをマウントするノード上でPodが起動する必要があります。

Secrets Store CSI Driverはデフォルトで、以下のtolerationsが設定されています。

tolerations:
  - operator: Exists

これはすべてのtaintを許容するため、デフォルトでどのノードでもPodが稼働します。

一方、ASCPはデフォルトでこの設定が入っていないため、valuesの部分で設定を追加しています。

Secret Provider Classの定義

以下のファイルを用意します。

Secret Provider Classは、シークレットの取得を設定するカスタムリソースです。

kube/templates/secret_provider_class.yaml
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: gitlab-runner-secret-provider
  namespace: gitlab-runner
spec:
  provider: aws
  parameters:
    objects: |
      - objectName: "${secret_name}"  # AWS Secrets Managerに保存されているシークレットの名前
        objectType: "secretsmanager"
        jmesPath:
          - path: "token"
            objectAlias: "runner-token"  # ポッドにマウントするファイル名、GitLab Runner Helmチャートの仕様でrunner-tokenというファイル名にする必要がある
    usePodIdentity: "true"
kube/main.tf
resource "kubernetes_manifest" "gitlab_runner_token_secret_provider_class" {
  manifest = yamldecode(templatefile("${path.module}/templates/manifest/secret_provider_class.yaml", {
    secret_name = data.tfe_outputs.cluster.values.gitlab_token_secrets_name
  }))

  depends_on = [
    helm_release.secrets_provider_aws
  ]
}

GitLab Runnerは/secrets/runner-tokenからトークンを取得します。

GitLab Runner Chart 参考箇所

ファイル名を合わせるために、spec.parameters.objects.jmesPath.objectAliasrunner-tokenとしています。

GitLab Runner用のvalues.yamlを修正

Secretsをマウントするために、Volumesを定義します。

values.yaml
gitlabUrl: https://gitlab.satomasaki.classmethod.info/
- runnerToken:
rbac:
  create: true
serviceAccount:
  create: true
  name: "gitlab-runner"
# 省略
+volumes:
+  - name: secrets-store-inline
+    csi:
+      driver: secrets-store.csi.k8s.io
+      readOnly: true
+      volumeAttributes:
+        secretProviderClass: "gitlab-runner-secret-provider"

+volumeMounts:
+  - name: secrets-store-inline
+    mountPath: "/secrets"
+    readOnly: true
values.yaml(全量)
values.yaml
gitlabUrl: https://gitlab.satomasaki.classmethod.info/
rbac:
  create: true
serviceAccount:
  create: true
  name: "gitlab-runner"

affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: workload
          operator: In
          values:
          - gitlab-runner

tolerations:
  - key: "workload"
    operator: "Equal"
    value: "gitlab-runner"
    effect: "NoSchedule"

runners:
  # tpl: https://helm.sh/docs/howto/charts_tips_and_tricks/#using-the-tpl-function
  # runner configuration: https://docs.gitlab.com/runner/configuration/advanced-configuration.html
  # kubernetes executor: https://docs.gitlab.com/runner/executors/kubernetes/
  config: |
    [[runners]]
      [runners.kubernetes]
        [runners.kubernetes.affinity]
          [runners.kubernetes.affinity.node_affinity]
            [runners.kubernetes.affinity.node_affinity.required_during_scheduling_ignored_during_execution]
              [[runners.kubernetes.affinity.node_affinity.required_during_scheduling_ignored_during_execution.node_selector_terms]]
                [[runners.kubernetes.affinity.node_affinity.required_during_scheduling_ignored_during_execution.node_selector_terms.match_expressions]]
                  key = "workload"
                  operator = "In"
                  values = ["gitlab-runner"]
        [runners.kubernetes.node_tolerations]
          "workload=gitlab-runner" = "NoSchedule"

volumes:
  - name: secrets-store-inline
    csi:
      driver: secrets-store.csi.k8s.io
      readOnly: true
      volumeAttributes:
        secretProviderClass: "gitlab-runner-secret-provider"

volumeMounts:
  - name: secrets-store-inline
    mountPath: "/secrets"
    readOnly: true

Helmコマンドを実行してリソースを更新します。

helm upgrade gitlab/gitlab-runner gitlab-runenr -n gitlab-runner -f values.yaml

動作確認

まずはGitLab Runner管理用のPodが起動できているか確認します。

kubectl get pods

STATUSRunningになっていれば正常です。

出力結果
NAME                             READY   STATUS    RESTARTS   AGE
gitlab-runner-587597c865-9tjgt   1/1     Running   0          84m

Secretsファイルがマウントされていることを確認します。

kubectl exec -it <Pod名> -- cat /secrets/runner-token

Secrets Managerに登録したトークンが確認できれば、正常です。

出力例
<GitLab Runner Token>

その他CI/CDジョブの動作を確認したい場合は、以下が参考になるかと思います。

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

おわりに

ASCPを使ってSecrets ManagerからGitLab Runner Tokenを取得してみました。

他にもExternalSecretsを使う方法もあるかと思うので、後ほど試してみたいと思います。

参考

https://aws.amazon.com/jp/blogs/security/announcing-ascp-integration-with-pod-identity-enhanced-security-for-secrets-management-in-amazon-eks/
https://docs.aws.amazon.com/ja_jp/secretsmanager/latest/userguide/ascp-examples.html
https://docs.aws.amazon.com/eks/latest/best-practices/data-encryption-and-secrets-management.html

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.