MIXI DEVELOPERS NOTE
🆙

GitHub Actions から EC2 へ Session Manager を使用してなるべくセキュアにファイルをアップロードする

2023/10/05に公開

概要

とある案件で GitHub Actions から EC2 へファイルをアップロードしたい、ということがありました。
該当の EC2 は、普段は AWS Session Manager を使用してサーバーにアクセスしており、 SSH/SFTP の穴を開けていないサーバーでした。
そのため、 Session Manager 経由でファイルをアップロードできないか試してみたところ、うまくいったという感じです。

要件

今回やりたかったことは以下のような感じです。

  • GitHub Actions から rsync でファイルをアップロード
  • EC2 の SSH ポートは開けたくない
  • SSH でログインする Linux のユーザーはアップロード用に作成したもの

これを受けて、以下のようにしました。

  • AWS Session Manager を使用して、rsync over ssh でファイルをアップロードする
  • GitHub Actions の AWS Session Manager を実行する権限の設定は、 OIDC Provider による IAM Role の委譲で行う
  • Session Manager が使用する SSM Document は、デフォルトのものだと ssm-user 固定なので、新しく作成

これであれば、EC2 に SSH ポートの穴を開けずに、かつ GitHub 常に固定の AWS のクレデンシャルを残さないので、セキュアにできて良いかなーという気持ちです。

実装

というわけで実装していきます。
AWS の設定は terraform を使って構築していきます。

まずは、使いたい Linux ユーザーでログインできるように、新しく SSM Document を作成します。

resource "aws_ssm_document" "github_actions" {
  name          = "SSM-SessionManagerRunShell-Deploy"
  document_type = "Session"
  content = jsonencode({
    schemaVersion = "1.0"
    sessionType   = "Port"
    inputs = {
      runAsEnabled     = true
      runAsDefaultUser = "hoge-user"
    }
    properties = {
      portNumber = "22"
    }
  })
}

hoge-user はアップロードしたい Linux のユーザー名を入れてください。

次に GitHub Actions で AWS の IAM Role を使用できるようにします。

// OIDC provider を作成
resource "aws_iam_openid_connect_provider" "github_actions_oidc_provider" {
  url            = "https://token.actions.githubusercontent.com"
  client_id_list = ["sts.amazonaws.com"]
  thumbprint_list = [
    "6938fd4d98bab03faadb97b34396831e3780aea1",
    "1c58a3a8518e8759bf075b76b750d4f2df264fcd"
  ]
}

// GitHub Actions で使用する Role を作成
data "aws_iam_policy_document" "github_actions_assume_role" {
  statement {
    effect  = "Allow"
    actions = ["sts:AssumeRoleWithWebIdentity"]
    principals {
      identifiers = [aws_iam_openid_connect_provider.github_actions_oidc_provider.arn]
      type        = "Federated"
    }
    condition {
      test     = "StringEquals"
      variable = "token.actions.githubusercontent.com:sub"
      values   = ["repo:${local.repo_name}:ref:refs/heads/main"]
    }
    condition {
      test     = "StringEquals"
      variable = "token.actions.githubusercontent.com:aud"
      values   = ["sts.amazonaws.com"]
    }
  }
}

resource "aws_iam_role" "role" {
  name               = "oidc-role"
  assume_role_policy = data.aws_iam_policy_document.github_actions_assume_role.json
}

data "aws_iam_policy_document" "policy_document" {
  statement {
    effect    = "Allow"
    actions   = ["ssm:StartSession"]
    resources = [
      "arn:aws:ec2:ap-northeast-1:${data.aws_caller_identity.self.account_id}:instance/${module.instance_web.instance_id}",
      aws_ssm_document.github_actions.arn,
    ]
  }
  statement {
    effect    = "Allow"
    actions   = ["ssm:TerminateSession"],
    resources = ["arn:aws:ssm:*:*:session/*"]
    ]
  }
}

resource "aws_iam_role_policy" "role_policy" {
  role   = aws_iam_role.role.id
  policy = data.aws_iam_policy_document.policy_document.json
}

local.repo_name には実行したい GitHub Actions があるリポジトリ名が入ります。org-name/repo-name みたいなやつ。

ここで、作成した SSM Document を使って、ログインできるか確認します。
事前にインスタンスには SSH の公開鍵を登録しておいてください。

ssh hoge-user@ -oProxyCommand='sh -c "aws ssm start-session --target i-1234567880abcdefg --document-name SSM-SessionManagerRunShell-Deploy"'

問題なくログインできれば 🆗

次に、GitHub Actions を設定します。
今回は、 easingthemes/ssh-deploy という Action を使ってみました。

name: deploy

on:
  push:
    branches:
      - main
jobs:
  deploy:
    name: 🚀 deploy
    runs-on: ubuntu-latest
    permissions:
      contents: write
      id-token: write

    steps:
      - name: 🔑 Setup AWS Credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          role-to-assume: arn:aws:iam::1234567890:role/hoge-role
          role-session-name: deploy
          aws-region: ap-northeast-1

      - name: 🚀 Deploy to EC2
        uses: easingthemes/ssh-deploy@main
        env:
          SSH_PRIVATE_KEY: ${{ secrets.EC2_SSH_KEY }}
          REMOTE_USER: ${{ secrets.DEPLOY_USER }}
          REMOTE_HOST: "i-1234567880abcdefg"
          SSH_CMD_ARGS: "-o StrictHostKeyChecking=no, -o ProxyCommand='aws ssm start-session --target %h --document-name SSM-SessionManagerRunShell-Deploy'"
          SOURCE: "dist/"
          TARGET: "/home/${{ secrets.DEPLOY_USER }}/dist"

これで無事に GitHub Actions からセキュアにファイルをアップロードできるようになりました。
便利み🎉

MIXI DEVELOPERS NOTE
MIXI DEVELOPERS NOTE

Discussion