EKSにself-hosted runners(Github Actions)を立ち上げて安全にdigdag pushする


はじめに

現在携わっているサービスではワークフローの実行にDigdagを採用しており、ワークフローのファイルはGithubで管理されています。この構成でGithub Actionsを使ってワークフローのデプロイを自動化したときに発生したセキュリティ課題と、その解決策についてまとめてみました。

前提

  • DigdagのワークフローをGithubで管理している
  • Github ActionsやCircleCIなどの外部からDigdagにPUSHをしたいと考えている。

[構成図]
今回の構成ではDigdagをEKS上で動かしています。

やりたいこと

  • DigdagワークフローをGithub Actionsで自動デプロイすることで楽したい

課題

  • セキュリティ観点からDigdagのエンドポイントは外部に公開したくないが、GithubActionsのIPからDigdagのエンドポイントに接続したい

解決策

Digdagのエンドポイントに接続する案としては2つ検討しました。

案1:RunnerのIPをSecurityGroupで許可

CircleCIではワークアラウンドとして一時的にCircleCIが利用するIPを許可する方法が紹介されています。

GithubもIPアドレスの一覧を取得する方法が紹介されていますが、IPアドレスによる許可はお勧めしないと書かれています。

個人的にも共有されているIPを許可するのはお勧めしたくないかな、、、という印象です。

案2:self-hosted runnersを使う

今回はこちらの方法を採用しました。以下のような構成図になります。

self-hosted runnersを使うメリットは以下のようなところだと思います。

  • 定期的にGithub Actionsにポーリングする仕様になっているため、外部からself-hosted runnersにアクセスできる必要がない(セキュリティ的に有利)
  • EKS上にPodで起動しておけば、外部に接続するときのIPアドレス(NatGatewayIP)が固定できる。
  • DigdagエンドポイントのALB SecurityGroupにNatGatewayIPを登録しておけばself-hosted runnersからアクセスできる。

やってみる

以下の手順については省略しています。

  • Parsonal Access Tokenを取得する
  • Personal Access TokenをSecretsに登録する(External Secretsを利用しています)
  • NatGatewayのIPをALBのSecurityGroupに追加する

Dockerfileを準備する

こちらのサイトを参考にさせていただき、一部書き換えています。
https://sanderknape.com/2020/03/self-hosted-github-actions-runner-kubernetes/

変更点

  • stg環境とprd環境のrunnerをlabelで判定するために環境変数を追加
  • digdagが動くようにベースイメージを変更(azul/zulu-openjdk:8)
  • digdagをインストール
Dockerfile
FROM azul/zulu-openjdk:8

ARG GITHUB_RUNNER_VERSION="2.277.1"

ENV RUNNER_NAME "runner"
ENV GITHUB_PAT ""
ENV GITHUB_OWNER ""
ENV GITHUB_REPOSITORY ""
ENV RUNNER_WORKDIR "_work"
ENV GLOBAL_ENVIRONMENT ""

RUN apt-get update \
    && apt-get install -y \
        curl \
        sudo \
        git \
        jq \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/* \
    && useradd -m github \
    && usermod -aG sudo github \
    && echo "%sudo ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

RUN curl -o /usr/local/bin/digdag --create-dirs -L 'https://dl.digdag.io/digdag-0.10.0' \
    && chmod +x /usr/local/bin/digdag

USER github
WORKDIR /home/github

RUN curl -Ls https://github.com/actions/runner/releases/download/v${GITHUB_RUNNER_VERSION}/actions-runner-linux-x64-${GITHUB_RUNNER_VERSION}.tar.gz | tar xz \
    && sudo ./bin/installdependencies.sh

COPY --chown=github:github entrypoint.sh ./entrypoint.sh
RUN sudo chmod u+x ./entrypoint.sh

ENTRYPOINT ["/home/github/entrypoint.sh"]
entrypoint.sh
#!/bin/sh
registration_url="https://api.github.com/repos/${GITHUB_OWNER}/${GITHUB_REPOSITORY}/actions/runners/registration-token"
echo "Requesting registration URL at '${registration_url}'"

payload=$(curl -sX POST -H "Authorization: token ${GITHUB_PAT}" ${registration_url})
export RUNNER_TOKEN=$(echo $payload | jq .token --raw-output)

./config.sh \
    --labels ${GLOBAL_ENVIRONMENT} \
    --name $(hostname) \
    --token ${RUNNER_TOKEN} \
    --url https://github.com/${GITHUB_OWNER}/${GITHUB_REPOSITORY} \
    --work ${RUNNER_WORKDIR} \
    --unattended \
    --replace

remove() {
    ./config.sh remove --unattended --token "${RUNNER_TOKEN}"
}

trap 'remove; exit 130' INT
trap 'remove; exit 143' TERM

./run.sh "$*" &

wait $!

[注意点]
Parsonal Access Tokenを利用してrunner用のトークンを取得していますが、「Parsonal Access Token」は1年つかわないと削除されるため、1年以上Deployしていないとトークンが有効期限切れになりリリースに失敗する可能性があります。
https://docs.github.com/ja/github/authenticating-to-github/creating-a-personal-access-token

ECRにイメージをPUSHする

今回はAmazonECRを利用するため事前にECRのリソースを作成しておきます。

コマンド例
docker build -t github-runner .
docker tag github-runner:latest xxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/github-runner:latest
docker push xxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/github-runner:latest

デプロイ

Parsonal Access TokenはSecretに登録しておきます。

github-runner.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: github-runner
  labels:
    app: github-runner
spec:
  replicas: 2
  selector:
    matchLabels:
      app: github-runner
  template:
    metadata:
      labels:
        app: github-runner
    spec:
      containers:
      - name: github-runner
        image: xxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/github-runner:latest
        env:
        - name: GITHUB_OWNER
          value: 'xxxxxx' #組織名
        - name: GITHUB_REPOSITORY
          value: 'xxxxxxx' #GHAを動かすrepository
        - name: GLOBAL_ENVIRONMENT
          value: 'xxx' #stg/prdなど
        - name: GITHUB_PAT
          valueFrom:
            secretKeyRef:
              name: github-secret
              key: pat
kubernetesへのデプロイ
kubectl apply -f github-runner.yml

確認

GithubのSettings > ActionsにRunnerが登録されていれば正常に稼働しています。