GitLab Runner TokenをASCPを使ってAWS Secrets Managerから取得してみた(GitLab Runner on Amazon EKS)
GitLab RunnerをHelmでデプロイする際に、GitLabで発行したGitLab Runner Tokenをセットする必要があります。
Helmの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パラーメータストアに保存されているシークレットを取得できます。
- kubernetes-sigs/secrets-store-csi-driver: Secrets Store CSI driver for Kubernetes secrets - Integrates secrets stores with Kubernetes via a CSI volume.
- aws/secrets-store-csi-driver-provider-aws: The AWS provider for the Secrets Store CSI Driver allows you to fetch secrets from AWS Secrets Manager and AWS Systems Manager Parameter Store, and mount them into Kubernetes pods.
やってみた
前提
- EKSクラスターはAutoModeを利用
- 認証方式はPod Identityを利用する
今回利用するEKSクラスターの詳細は以下をご確認ください。
後述のコード上で省略しているNetwork周りの設定やProvider定義等も以下から確認できます。
IAM Role・SecretsManagerの作成
トークン格納用のSecretsManagerとASCP用のIAM Roleを作成します。
今回、GitLab Runnerはgitlab-runner
というServiceAccountを利用します。
ASCPを使うのは、このServiceAccountになります。
ServiceAccountとASCP用のIAM Roleを関連付けて、アクセスエントリを作成します。
# 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を保存
以下手順で、トークンを取得します。
作成した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をインストールします。
以下のファイルを準備します。
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を設定していました。
Secrets Store CSI DriverとASCPは、シークレットをマウントするノード上でPodが起動する必要があります。
Secrets Store CSI Driverはデフォルトで、以下のtolerations
が設定されています。
tolerations:
- operator: Exists
これはすべてのtaintを許容するため、デフォルトでどのノードでもPodが稼働します。
一方、ASCPはデフォルトでこの設定が入っていないため、values
の部分で設定を追加しています。
Secret Provider Classの定義
以下のファイルを用意します。
Secret Provider Classは、シークレットの取得を設定するカスタムリソースです。
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"
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
からトークンを取得します。
ファイル名を合わせるために、spec.parameters.objects.jmesPath.objectAlias
をrunner-token
としています。
GitLab Runner用のvalues.yamlを修正
Secretsをマウントするために、Volumesを定義します。
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(全量)
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
STATUS
がRunning
になっていれば正常です。
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ジョブの動作を確認したい場合は、以下が参考になるかと思います。
おわりに
ASCPを使ってSecrets ManagerからGitLab Runner Tokenを取得してみました。
他にもExternalSecretsを使う方法もあるかと思うので、後ほど試してみたいと思います。
参考