GitHub ActionsからKubernetes(EKS)のJobを実行する

## はじめに

GitHub ActionsからKubernetes(EKS)のJobを実行したいというケースがあったので、それについてまとめます。jobの実行には`kube-job`を用います。

https://github.com/h3poteto/kube-job

## 外部からEKSにアクセスする仕組み

クラスターを操作する権限をAWSユーザーやロールに付与するには、EKSの `aws-auth` というConfigMapを編集する必要があります。 仕組みは以下のようになっており、Kubernetesの認証Webhookという機能が用いられているみたいです。つまり、認証は`AWSのIAM`で行い、認可は`KubernetesのRole Based Access Control(RBAC)`によって決まります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295942/58fcfa96-ff3f-c5d4-c316-3cc4a0046c9c.png)

Ref: https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/cluster-auth.html

## IAM Roleの作成

GitHub ActionsにてAWS認証しなければならないのでOpenID Connect (OIDC)認証可能なIAM Roleを作成し、認可として`EKSクラスターへの参照権限`のポリシーをアタッチします

https://docs.github.com/ja/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services

```tf:oidc.tf
resource "aws_iam_openid_connect_provider" "github_actions" {
  url = "https://token.actions.githubusercontent.com"

  client_id_list = ["sts.amazonaws.com"]

  thumbprint_list = ["6938fd4d98bab03faadb97b34396831e3780aea1"]
}

resource "aws_iam_role" "github_actions_oidc" {
  name = "GitHubActionsOIDC"

  # 信頼関係
  assume_role_policy = jsonencode({
    "Version" : "2012-10-17",
    "Statement" : [
      {
        "Effect" : "Allow",
        "Principal" : {
          "Federated" : aws_iam_openid_connect_provider.github_actions.arn
        },
        "Action" : "sts:AssumeRoleWithWebIdentity",
        "Condition" : {
          "StringEquals" : {
            "token.actions.githubusercontent.com:aud" : "sts.amazonaws.com"
          },
          "StringLike" : {
            "token.actions.githubusercontent.com:sub" : "repo:<my-user-id>/<my-repository>:*"
          },
        }
      }
    ]
  })
}

resource "aws_iam_policy" "github_actions_oidc" {
  name = "github_actions_oidc"
  policy = jsonencode({
    "Version" : "2012-10-17",
    "Statement" : [
      {
        "Effect" : "Allow",
        "Action" : "eks:DescribeCluster",
        "Resource" : "*"
      }
    ]
  })
}

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

```

## RBACの設定

ありがたいことに、kube-jobのREADME.mdに必要なロールが記述されていました。

```yaml:rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: job-exec-role
  namespace: default
rules:
- apiGroups: ["batch"]
  resources: ["jobs", "jobs/status"]
  verbs: ["create", "get", "delete"]
- apiGroups: [""]
  resources: ["pods", "pods/log"]
  verbs: ["get", "list", "delete", "deletecollection"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: job-exec-group
  # namespace「default」に対して許可する
  namespace: default
subjects:
- kind: Group
  name: job-exec-group
  apiGroup: rbac.authorization.k8s.io
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: job-exec-role

```

## aws-authの設定

EKSは以下のTerraform moduleで構築しており、aws-authの設定ができます。

https://registry.terraform.io/modules/terraform-aws-modules/eks/aws/latest

```tf:eks.tf

module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  # -- 省略 -- 

  manage_aws_auth_configmap = true

  aws_auth_roles = [
    {
      rolearn  = "arn:aws:iam::0123456789012:role/${aws_iam_role.github_actions_oidc.name}"
      username = "github-actions-k8s-access"
      groups   = ["job-exec-group"]
    },
  ]
```

## JobのManifest

KubernetesでJobを実行するためのマニフェストを記述すればOKです。

```yaml:job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: migration
  namespace: default
spec:
  backoffLimit: 0
  template:
    spec:
      containers:
        - name: migration
          image: 0123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/migration:latest
          command: ["bundle", "exec", "rails", "db:migrate"]
      restartPolicy: Never
```

## GitHub Actions workflow

`aws eks update-kubeconfig --name eks` でkubeconfigファイルを生成し、次のJob実行に渡します。以上でGitHub ActionsでKubernetesのJobが実行できます。

```yaml:migration.yaml
# -- 省略 -- 

- name: Configure AWS Credentials
  uses: aws-actions/configure-aws-credentials@v1
  with:
    aws-region: ap-northeast-1
    role-to-assume: arn:aws:iam::0123456789012:role/GitHubActionsOIDC

- name: Configure EKS
  run: |
    aws eks update-kubeconfig --name eks

- name: Run db migration
  run: |
    wget https://github.com/h3poteto/kube-job/releases/download/v0.2.0/kube-job_0.2.0_linux_amd64.zip
    unzip kube-job_0.2.0_linux_amd64.zip
    ./kube-job run --config=$HOME/.kube/config \
      --template-file=job.yaml \
      --container="migration"
```

## まとめ

今回は、GitHub ActionsからKubernetes(EKS)のJobを実行しました。また、GitHub ActionsにはSelf-hosted Runnersといって自分自身が用意した環境でJobを実行することもできるので今後試してみたいなと思いました。

## 参考文献

https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/add-user-role.html

https://zenn.dev/take4s5i/articles/aws-eks-authentication

https://zenn.dev/nameless_gyoza/articles/eks-authentication-authorization-20210211

https://qiita.com/sonots/items/96984e349debc33057c5

https://qiita.com/taishin/items/dfb9a5620f37ffb74fe9

https://kubernetes.io/ja/docs/reference/access-authn-authz/rbac

## その他

OIDC ID認証(EKS)もできるみたい

https://aws.amazon.com/jp/blogs/containers/introducing-oidc-identity-provider-authentication-amazon-eks/

https://tech.isid.co.jp/entry/2021/12/16/Amazon_EKS%E3%81%AE%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%BF%E3%83%BC%E8%AA%8D%E8%A8%BC%E3%83%BB%E8%AA%8D%E5%8F%AF%E3%82%92%E7%90%86%E8%A7%A3%E3%81%99%E3%82%8B#Amazon-EKS%E3%81%AE%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%BF%E3%83%BC%E8%AA%8D%E8%A8%BC%E8%AA%8D%E5%8F%AF%E3%81%AE%E6%A6%82%E8%A6%81%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6