Article:

2023/01/16 記事中でGithubActions用にシークレットを発行していましたが、GithubActionsがOIDCに対応したことによりこれが不要になりました。これについて追記を行っています。


タイトルの通りです。

cdk等使わずにできるだけシンプルでいきます。

すでに作成済みのLambda関数のコードをGitのpushイベントをトリガーに最新のものに更新するだけで、Actions側でロールなどの設定は行わないケースを想定しています。

この記事ではLambda関数のランタイムはPythonを前提に進めますが、GithubActionsでコンパイル等も行えるので基本的に何でも応用できると思います(未検証)。

GithubActions側から更新したいLambda関数の「リージョン」と「名前」をキーにして更新します。

Lambda関数はもうすでに作成済みであることを前提条件にします。

GithubActionsについて

Github純正のCI/CDです。神サービスです。

コミットやプルリクなどをイベントにして、ワンタイムの仮想環境上で任意のコード・コマンドを実行できます。

使いみちとしてはコードをコンパイルしてテストしたり、その結果をSlackに通知したりと何でもです。

今回はGithubActionsの仮想環境上でレポジトリの内容をzipにまとめて、aws-cliをインストールして、それでデプロイするコマンドを叩くといった感じで使います。

Secrets

なにかスクリプトを走らせるに当たり、例えばデプロイ先のサーバーの認証情報だったり、通知するSlackのWebhookエンドポイントだったり、他の人に見られるとマズい情報っていうのはありますよね。

それをレポジトリごとに名前をつけて安全に保管し、Actions側で呼び出せる機能がActions Secretsです。今回はAWSのIAMのログイン情報をこれをつかって保管します。

IAMユーザーの作成とSecretsの設定

2023/01/16追記

この記事ではGithubActions用のアクセスID及びシークレットを発行していますが、GithubがOIDCに対応したことにより認証情報をGithubに保管しなくても、 Githubのユーザー名やレポジトリ名を用いたアクセス制限を行うことが可能となりました。

GithubActions + TerraformでAWS開発ではこのOIDCを用いた認証を行っているので、こちらを参考にOIDC用のロールを作成し、 workflow.ymlでawsコマンドを叩く直前に以下のタスクで認証情報を取得します。

workflow.yml (抜粋)
1
2
3
4
5
    - name: Configure AWS credentials from IAM Role
      uses: aws-actions/configure-aws-credentials@v1
      with:
        role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
        aws-region: ${{ secrets.AWS_REGION }}

これを行っておくだけで、aws系の操作がここで指定したroleにassumeして実行してくれます。最高!

追記ここまで


ではまず最初にGithubActionsを開いて…と言いたいところなのですが、先にActions用のアカウントをAWSに作成するところから始めます。

IAMを開いて左のカラムからユーザーを選択。「ユーザーを追加」を選択します。

STEP1: ユーザー名を決めて「プログラムによるアクセス」を選択します。

僕はだいたいユーザー名は「GithubActions-<Lambda関数名>」って命名にしてます。

STEP2: アクセス許可は後で設定するので何も選択せずに次のステップに進みます。

STEP3: タグもとくに管理基準がなければなにも入力せずに次のステップに進みます。

STEP4: アクセス権限がないと警告が出ますが無視して次に進みます。

STEP5: ここで出てくるアクセスキーIDシークレットアクセスキーをGithubに入力します。

(このクレデンシャルはこのページを閉じると二度と見れなくなり、紛失するとアカウントを作り直しになるので注意です。)

GithubのLambdaを管理したいレポジトリを開きます(まだ作ってなければ空でいいので作成してください)。

そしてレポジトリのSettings>Secretsを開きます。

右上のNew repository secretボタンを押してシークレットを作成します。

ここではアクセスキーIDをAWS_ACCESS_KEY_IDという名前で、シークレットアクセスキーをAWS_SECRET_ACCESS_KEYという名前で保管することにします。

終わったら完了ボタンを押して閉じてしまって大丈夫です。

そしたらIAMのユーザー一覧の画面に戻ると思いますが、そこで先程作成したアカウントを再度選択し、概要のアクセス権限タブの中の +インラインポリシーの追加 を選択します。

JSONタブを開いて次を入力します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "lambda:UpdateFunctionCode"
            ],
            "Resource": "arn:aws:lambda:ap-northeast-1:<12桁のアカウントID>:function:<Lambda関数名>"
        }
    ]
}

Resourceにはarnを入力します。該当Lambdaのページからコピペしたほうが手っ取り早く確実ですが、どこに書いてあるかわからなければ上の<>内を書き換えても作れます。

入力したらポリシーの確認をクリックして次へ。

名前を適当に入力(ぼくはUpdateFunctionCodePolicy)してポリシーの作成をします。

AWS上の作業はこれで完了です。

workflowの作成

Githubの該当レポジトリの上部タブからActionsを選択

小さくてわかりにくいですが「GetStartedWithGithubActions」というデカい文字の下にset up a workflow yourself→のリンクがあるのでそれをクリックします。

そうするとコードエディタが開くので次のコードに書き換えます。割と雰囲気で「なるほどそういうことね〜」というのはわかると思うのでとくに解説は書かないことにしますが、ちょっとだけ書くと"steps"の項目が上から実行されるコマンドになっていて、“uses"がgithubで公開してある外部の手続きの呼び出しを行っていて、“run"がシェル上でのコマンドを表しています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
name: deploy

on:
  push:
    branches:
      - master
  workflow_dispatch:
    branches:
      - master
jobs:
  lambda-cd:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@master
      - uses: actions/setup-python@v1
        with:
          python-version: 3.8
      - run: zip -r package.zip ./*
      - run: pip3 install awscli
      - run: aws lambda update-function-code --function-name <Lambda関数名> --zip-file fileb://package.zip --publish
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_DEFAULT_REGION: ap-northeast-1

<Lambda関数名>の部分を適用したい関数名に書き換えます。

そしたら右上のStart commitを押してコミットします。

これで完成です!masterにコミットされると自動的にGithubActionsが走りLambdaにコードが反映されるはずです。

ちなみに、pythonだとpipでライブラリをグローバルでインストールしそれを使うことが多いと思いますが、Lambdaにデプロイするにはローカルでインストールする必要があります。でも、ライブラリをまるごと全部Gitに追加するのは気が引けますよね。

GithubActionsなら、自由にコマンドを実行できるので、例えば上のスクリプトの zip -r [package.zip](http://package.zip) ./* を実行している直前に - run: pip3 install <好きなパッケージ> -t ./ の行を追加すれば、レポジトリを汚さずにライブラリをインストールした上でデプロイすることができます。これは便利ですね。

ちなみに

Github Actions Secretはレポジトリ単位ではなくてOrganization単位で設定することもできます。ので、ポリシーを特定arnではなくワイルドカードにしたアカウントを作成して複数レポジトリで同じクレデンシャルを使い回すってことが可能です。これはサクっとかんたんなlambdaをポイポイ立てたいときに便利ですよね。でも、「個人アカウントの共有Secret」というのは存在しないので、個人所有のレポジトリではこういうことはできないんですよね〜〜〜。毎回アカウントつくるのちょっとめんどいんでそのへんも自動化したいですね。