Github ARC Runners sur EKS - Assume roles
Tags: aws, eks, github
Published: 2024-04-25 08:45:46

Récemment, nous avons migré nos runners Github en "self-hosted" sur Kubernetes (EKS) via l'opérateur ARC.

L'installation est assez aisée (même si la doc est un peu succincte).

Une fois avoir installé l'opérateur ARC, on installe des CRD AutoScalingRunnerSet avec Helm dont voici un exemple fichier de values.

```
githubConfigUrl: "https://github.com/<myorganisation>"
githubConfigSecret: "pre-defined-secret"
maxRunners: 100
runnerScaleSetName: "arc-runner-set-arm"

template:
  metadata:
    annotations:
      karpenter.sh/do-not-disrupt: "true"
  spec:
    nodeSelector:
      kubernetes.io/arch: "arm64"
    serviceAccountName: arc-runner-base-role
    tolerations:
    - key: github/arm
      value: "true"
      effect: NoSchedule
    initContainers:
    - name: init-dind-externals
      image: ghcr.io/actions/actions-runner:latest
      command: ["cp", "-r", "-v", "/home/runner/externals/.", "/home/runner/tmpDir/"]
      volumeMounts:
        - name: dind-externals
          mountPath: /home/runner/tmpDir
    containers:
    - name: runner
      image: ghcr.io/actions/actions-runner:latest
      command: ["/home/runner/run.sh"]
      env:
        - name: DOCKER_HOST
          value: unix:///run/docker/docker.sock
      resources:
        requests:
          cpu: 1
      volumeMounts:
        - name: work
          mountPath: /home/runner/_work
        - name: dind-sock
          mountPath: /run/docker
          readOnly: true

    - name: dind
      image: public.ecr.aws/docker/library/docker:dind
      args:
        - dockerd
        - --host=unix:///run/docker/docker.sock
        - --group=$(DOCKER_GROUP_GID)
      env:
        - name: DOCKER_GROUP_GID
          value: "123"
      securityContext:
        privileged: true
      volumeMounts:
        - name: work
          mountPath: /home/runner/_work
        - name: dind-sock
          mountPath: /run/docker
        - name: dind-externals
          mountPath: /home/runner/externals
    volumes:
    - name: work
      emptyDir: {}
    - name: dind-sock
      emptyDir: {}
    - name: dind-externals
      emptyDir: {}

controllerServiceAccount:
  name: arc-gha-rs-controller
  namespace: arc-systems
```

La partie importante pour les droits va être de renseigner un `spec.serviceAccountName` qui sera utilisé par tous les runners qui vont être créés.

Avec AWS CDK, j'ai auparavant créé un serviceAccount et un rôle associé

```
        const arcBaseRole = kubernetesCluster.addServiceAccount('arc-base-role', {
            name: 'arc-runner-base-role',
            namespace: 'arc-systems',
        });
        // Allow to assumeRole in the account starting with arc-runner-*
        arcBaseRole.role.attachInlinePolicy(
            new Policy(this, 'arc-base-role-policy', {
                statements: [
                    new PolicyStatement({
                        actions: ['sts:AssumeRole', 'sts:TagSession'],
                        resources: ['arn:aws:iam::'+ this.account + ':role/arc-runner-*'],
                    }),
                ],
            })
        );

```
Ainsi qu'un rôle à assumer pour ce runner (ici la possibilité de push sur le dépôt ECR.)

```
const pusherRole = new Role(this, 'arc-ecr-image-pusher-role', {
    assumedBy: new AccountPrincipal(this.account),
    roleName: 'arc-runner-ecr-image-pusher-role',
});

pusherRoleI.attachInlinePolicy(
    new Policy(this, 'arc-ecr-image-pusher-policy-base', {
        statements: [
            new PolicyStatement({
                actions: [
                    'ecr:GetAuthorizationToken',
                    'ecr:BatchCheckLayerAvailability',
                    'ecr:GetDownloadUrlForLayer',
                    'ecr:BatchGetImage',
                    'ecr:InitiateLayerUpload',
                    'ecr:UploadLayerPart',
                    'ecr:CompleteLayerUpload',
                    'ecr:PutImage',
                ],
                resources: ['*'],
            })
        ]
        })
);
```

Ensuite dans mon job github, plus qu'à préciser le rôle à assumer et voila !


```yaml
- uses: aws-actions/configure-aws-credentials@v4
  with:
    aws-region: eu-central-1
    role-to-assume: arn:aws:iam::${{ secrets.ECR_AWS_ACCOUNT_ID }}:role/arc-runner-ecr-image-pusher-role
    role-session-name: ${{ github.workflow }}_${{ github.run_number }}_${{ github.job }}
    role-skip-session-tagging: true
```

Pourquoi j'en ai fait un post ?
Parce que ça n'a pas marché tout de suite, notamment à cause du paramètre : `role-skip-session-tagging: true` qu'il faut rajouter sous peine de voir le runner répéter le même message en boucle :)