Github ActionsでOIDC認証を使ってGoアプリケーションをLambdaにデプロイできるようにした

最近Goを使って小さいアプリケーションを書いていますが、そろそろLambdaにデプロイして動かしてみることにしました。
ちょうど最近AWSからLambdaにデプロイするactionが公開されたようなので、それを使ってみることにしました。

https://dev.classmethod.jp/articles/aws-github-action-support-lambda-deploy/

実際の記述を元に記事用の調整をしているので、そのまま利用した場合に動かない可能性があります。ご容赦ください。

Lambdaの環境構築

簡単にLambdaを構築するための環境を作ります。
Terraformでこんな感じ。

data "aws_iam_policy_document" "assume_role" {
  statement {
    effect = "Allow"

    principals {
      type        = "Service"
      identifiers = ["lambda.amazonaws.com"]
    }

    actions = ["sts:AssumeRole"]
  }
}

resource "aws_iam_role" "lambda_execution_role" {
  name               = "go-lambda-execution-role"
  assume_role_policy = data.aws_iam_policy_document.assume_role.json
}

resource "aws_iam_role_policy_attachment" "lambda_logs" {
  role       = aws_iam_role.lambda_execution_role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

# Package the Go binary into a zip file
data "archive_file" "lambda_zip" {
  type        = "zip"
  source_file = "build/bootstrap"
  output_path = "function.zip"
}

# Lambda function
resource "aws_lambda_function" "go_lambda" {
  filename         = data.archive_file.lambda_zip.output_path
  function_name    = "go-lambda-function"
  role             = aws_iam_role.lambda_execution_role.arn
  handler          = "bootstrap"
  source_code_hash = data.archive_file.lambda_zip.output_base64sha256
  runtime          = "provided.al2023"
}

まだアプリケーションが小さいので、S3は経由せずzipファイルをあげる方式を取っています。
アプリケーションのビルド時に build/bootstrap を出力先にしておくのがポイントです。

GitHub Actions OIDC認証の設定

Github ActionsからAWSにデプロイする際、OIDC認証が必要になるためOIDC認証の設定を追加します。

OIDC プロバイダーの作成

まず、AWSでGitHub Actions用のOIDCプロバイダーを作成します。

# terraform-bootstrap/oidc.tf
resource "aws_iam_openid_connect_provider" "github_actions" {
  url = "https://token.actions.githubusercontent.com"

  client_id_list = [
    "sts.amazonaws.com"
  ]

  # GitHubのOIDC証明書のサムプリント(2024年時点)
  # 最新の値は GitHub公式ドキュメントで確認してください
  thumbprint_list = [
    "6938fd4d98bab03faadb97b34396831e3780aea1",
    "1c58a3a8518e8759bf075b76b750d4f2df264fcd"
  ]
}

サムプリント値は時間の経過とともに変更される可能性があります。実装時は必ずGitHub公式ドキュメントで最新の値を確認してください。

IAMロールとAssumeRoleポリシーの設定

特定のリポジトリとブランチからのみアクセスを許可するポリシーを作成:

data "aws_iam_policy_document" "github_actions_assume_role_policy" {
  statement {
    effect = "Allow"

    principals {
      type        = "Federated"
      identifiers = [aws_iam_openid_connect_provider.github_actions.arn]
    }

    actions = ["sts:AssumeRoleWithWebIdentity"]

    condition {
      test     = "StringEquals"
      variable = "token.actions.githubusercontent.com:aud"
      values   = ["sts.amazonaws.com"]
    }

    condition {
      test     = "StringLike"
      variable = "token.actions.githubusercontent.com:sub"
      values   = [
        "repo:${var.github_org}/${var.github_repo}:*",
        "repo:${var.github_org}/${var.github_repo}:ref:refs/heads/${var.github_branch}"
      ]
    }
  }
}

Lambda デプロイ用の権限設定

data "aws_iam_policy_document" "github_actions_lambda_deploy" {
  # Lambda関数の操作権限
  statement {
    effect = "Allow"
    actions = [
      "lambda:GetFunctionConfiguration",
      "lambda:CreateFunction",
      "lambda:UpdateFunctionCode",
      "lambda:UpdateFunctionConfiguration",
      "lambda:PublishVersion"
    ]
    resources = [
      "arn:aws:lambda:${var.aws_region}:${var.aws_account_id}:function:go-lambda-function"
    ]
  }

  # Lambda実行ロールへのPassRole権限
  statement {
    effect = "Allow"
    actions = [
      "iam:PassRole"
    ]
    resources = [
      "arn:aws:iam::${var.aws_account_id}:role/*lambda*"
    ]
  }
}

GitHub Actions ワークフローの実装

さて、これまでの情報を使ってGithub Actionsのワークフローを用意します。

基本的なワークフロー構成

# .github/workflows/deploy.yml
name: Deploy Lambda Function

on:
  push:
    branches: [ "main" ]
  workflow_dispatch:

env:
  AWS_REGION: us-west-2

permissions:
  id-token: write  # OIDC認証に必要
  contents: read

jobs:
  deploy:
    name: Deploy Lambda Function
    runs-on: ubuntu-latest
    steps:

    # 中略

    - name: Download dependencies
      run: go mod download

    - name: Build Lambda function
      env:
        GOOS: linux
        GOARCH: amd64
        CGO_ENABLED: 0
      run: |
        mkdir -p build
        go build -o build/bootstrap cmd/api/main.go

    - name: Check binary exists
      run: |
        if [ -f build/bootstrap ]; then
          echo "✅ Bootstrap binary built successfully"
          ls -lh build/bootstrap
        else
          echo "❌ Bootstrap binary not found"
          exit 1
        fi

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v4.0.2
      with:
        role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
        aws-region: ${{ env.AWS_REGION }}

    - name: Deploy Lambda Function
      uses: aws-actions/aws-lambda-deploy@v1.0.1
      with:
        function-name: go-lambda-function
        code-artifacts-dir: ./build
        handler: bootstrap
        runtime: provided.al2023

事前にGoの環境の用意、ビルドを行い、AWSの認証を通したうえでLambdaのデプロイを行うという流れです。

まとめ

今回はOIDC認証を使って、GoアプリケーションをLambdaにデプロイする仕組みを構築しました。

小さなGoアプリケーションからスタートして、必要に応じてS3デプロイやマルチ環境対応なども検討していきたいと思います。

今回の実装が、同じような環境を構築する方の参考になれば幸いです。

参考資料