kakakakakku blog

Weekly Tech Blog: Keep on Learning!

LambdaDB の Quickstart を試す

LambdaDB は全文検索とベクトル検索を組み合わせた「ハイブリッド検索」を実現するサーバレスネイティブなサービス💡ウェブサイトには従量課金で使えるため Pinecone と比較してコスト削減ができるよ〜と書いてあったりする.

lambdadb.ai

また LambdaDB ブログに内部アーキテクチャの解説もあって,AWS Lambda / Amazon S3 / Amazon DynamoDB / Amazon EventBridge / Amazon EFS などを活用しているようだった.

“Serverless” Database Is Dead - It’s Time to Evolve から引用

Quickstart

LambdaDB をサクッと入門できる Quickstart があって,試してみた❗️

docs.lambdadb.ai

🚀 Step 1: Install the SDK

まずは LambdaDB SDK をインストールする.現在 Python と TypeScript の SDK が提供されていて,今回は LambdaDB Python SDK を使う.あと Python の仮想環境などは uv を使ってイイ感じに管理する.

$ uv venv
$ uv pip install lambdadb

github.com

🔑 Step 2: Get your API key

次に LambdaDB 検証用の認証情報を取得する.フォームを送信したらすぐにメールが届いた.

認証情報には「API Base URL」「Shared API Key」が含まれている.今回は Asia Pacific (Seoul) リージョンを使う.あくまで検証用の環境なので注意する🚨

📚 Step 3: Create a collection

さっそく LambdaDB に「コレクション」を登録する.コレクションに関してはドキュメントに詳しく書いてある.今回使う text タイプ・keyword タイプ・vector タイプ以外にもいくつかのインデックスタイプがサポートされているようだった.

docs.lambdadb.ai

ちなみに Quickstart のコードだと認証情報(server_urlproject_api_key)を直接 Python コードに入力するようになっていて,今回は dotenv を使って .env を読むように書き換えた👌

$ uv pip install python-dotenv

一箇所 Python コードにシンタックスエラーがあって,修正するプルリクエストを送ったらすぐに merge してもらえた🎉

github.com

Quickstart のコードではサンプルとして10次元(少なめ)のベクトル設定になっていた.

import os
from dotenv import load_dotenv
from lambdadb import LambdaDB, models

load_dotenv()

# Initialize the LambdaDB client
lambda_db = LambdaDB(
    server_url=os.getenv("SERVER_URL"),
    project_api_key=os.getenv("PROJECT_API_KEY"),
)

collection_name = "kakakakakku"

# Create collection with text and vector indexes
res = lambda_db.collections.create(
    collection_name=collection_name,
    index_configs={
        "text": {
            "type": models.TypeText.TEXT,
            "analyzers": [
                models.Analyzer.ENGLISH,  # English text support
                models.Analyzer.KOREAN    # Korean text support
            ],
        },
        "keyword": {
            "type": models.Type.KEYWORD
        },
        "vector": {
            "type": models.TypeVector.VECTOR,
            "dimensions": 10,                        # Vector dimension
            "similarity": models.Similarity.COSINE,  # Cosine similarity metric
        },
    }
)
print(res)

実行結果は以下🐍

collection=CollectionResponse(project_name='playground', collection_name='kakakakakku', index_configs={'text': IndexConfigsText(type=<TypeText.TEXT: 'text'>, analyzers=[<Analyzer.ENGLISH: 'english'>, <Analyzer.KOREAN: 'korean'>]), 'keyword': IndexConfigs(type=<Type.KEYWORD: 'keyword'>), 'vector': IndexConfigsVector(type=<TypeVector.VECTOR: 'vector'>, dimensions=10, similarity=<Similarity.COSINE: 'cosine'>), 'id': IndexConfigs(type=<Type.KEYWORD: 'keyword'>)}, num_docs=0, collection_status=<Status.CREATING: 'CREATING'>, source_project_name=None, source_collection_name=None, source_collection_version_id=None)

📄 Step 4: Add documents

今度は作ったコレクションにドキュメントを追加する.ドキュメントとしては3つ.ベクトルはあくまでサンプル値になっていて,実際にはエンベディングをする必要がある.

LambdaDB Python SDK で呼び出す upsert() などの関数は GitHub にドキュメントがまとまっている📝

github.com

import os
from dotenv import load_dotenv
from lambdadb import LambdaDB

load_dotenv()

# Initialize the LambdaDB client
lambda_db = LambdaDB(
    server_url=os.getenv("SERVER_URL"),
    project_api_key=os.getenv("PROJECT_API_KEY"),
)

collection_name = "kakakakakku"

# Prepare sample documents
docs = [
    {
        "id": "doc1",
        "text": "Serverless computing does not mean no servers are involved. It refers to a cloud computing model where the server management is abstracted away from developers.",
        "keyword": "serverless",
        "vector": [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
    },
    {
        "id": "doc2",
        "text": "Instead, it refers to a cloud computing model where developers can build and run applications without having to manage the underlying infrastructure.",
        "keyword": "cloud",
        "vector": [0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1]
    },
    {
        "id": "doc3",
        "text": "The key aspect is that developers don't need to explicitly provision or manage servers. The cloud provider handles all server management automatically.",
        "keyword": ["serverless", "infrastructure"],  # Multiple keywords supported
        "vector": [0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2]
    }
]

# Upload documents to the collection
res = lambda_db.collections.docs.upsert(
    collection_name=collection_name,
    docs=docs
)
print(res)

実行結果は以下🐍

message='Upsert request is accepted'

さらに追加したドキュメントを取得する.

import os
from dotenv import load_dotenv
from lambdadb import LambdaDB

load_dotenv()

# Initialize the LambdaDB client
lambda_db = LambdaDB(
    server_url=os.getenv("SERVER_URL"),
    project_api_key=os.getenv("PROJECT_API_KEY"),
)

collection_name = "kakakakakku"

# Check collection status and document count
res = lambda_db.collections.get(collection_name=collection_name)
print(res)

実行結果は以下🐍

期待通りに num_docs=3 と出力されている👌ちょっと見にくいけど...

collection=CollectionResponse(project_name='playground', collection_name='kakakakakku', index_configs={'vector': IndexConfigsVector(type=<TypeVector.VECTOR: 'vector'>, dimensions=10, similarity=<Similarity.COSINE: 'cosine'>), 'text': IndexConfigsText(type=<TypeText.TEXT: 'text'>, analyzers=[<Analyzer.ENGLISH: 'english'>, <Analyzer.KOREAN: 'korean'>]), 'id': IndexConfigs(type=<Type.KEYWORD: 'keyword'>), 'keyword': IndexConfigs(type=<Type.KEYWORD: 'keyword'>)}, num_docs=3, collection_status=<Status.ACTIVE: 'ACTIVE'>, source_project_name=None, source_collection_name=None, source_collection_version_id=None)

コレクションとドキュメントの準備が整ったので,まずは「全文検索」をする.今回は text の検索と keyword の一致が条件になっていた.ちなみに Quickstart のコードで検索キーワードが I hate managing servers(私はサーバー管理が嫌い) になっててイイw

import os
from dotenv import load_dotenv
from lambdadb import LambdaDB

load_dotenv()

# Initialize the LambdaDB client
lambda_db = LambdaDB(
    server_url=os.getenv("SERVER_URL"),
    project_api_key=os.getenv("PROJECT_API_KEY"),
)

collection_name = "kakakakakku"

res = lambda_db.collections.query(
    collection_name=collection_name,
    size=10,
    query={
        "bool": [
            {
                "queryString": {
                    "query": "I hate managing servers",  # Main search query
                    "defaultField": "text"               # Search in text field
                }
            },
            {
                "queryString": {
                    "query": "keyword:serverless"       # Filter by keyword
                },
                "occur": "must"
            }
        ]
    },
    consistent_read=True
)

# Display results
print("🔍 Search Results:")
for result in res.docs:
    doc_id = str(result.doc['id'])
    score = f"{result.score:.2f}"
    keyword = str(result.doc['keyword'])
    text = str(result.doc['text'])

    print(f"{doc_id:<5} | {score:<5} | {keyword:<15} | {text}")

クエリ条件の occur は以下のドキュメントに詳しくまとまっていた.

docs.lambdadb.ai

実行結果は以下🐍

2つのドキュメントがヒットして,スコアも確認できた👌

🔍 Search Results:
doc3  | 0.83  | ['serverless', 'infrastructure'] | The key aspect is that developers don't need to explicitly provision or manage servers. The cloud provider handles all server management automatically.
doc1  | 0.80  | serverless      | Serverless computing does not mean no servers are involved. It refers to a cloud computing model where the server management is abstracted away from developers.

次は「ハイブリッド検索」をする.検索条件としては I hate managing servers のベクトル(今回はあくまでサンプル値)を指定してベクトル検索をしているような感じだった.

import os
from dotenv import load_dotenv
from lambdadb import LambdaDB

load_dotenv()

# Initialize the LambdaDB client
lambda_db = LambdaDB(
    server_url=os.getenv("SERVER_URL"),
    project_api_key=os.getenv("PROJECT_API_KEY"),
)

collection_name = "kakakakakku"

res = lambda_db.collections.query(
    collection_name=collection_name,
    size=10,
    query={
        "l2": [  # L2 normalization combines scores
            {
                "queryString": {
                    "query": "I hate managing servers",
                    "defaultField": "text"
                }
            },
            {
                "knn": {  # K-nearest neighbors vector search
                    "field": "vector",
                    "k": 5,
                    "queryVector": [
                        0.9, 0.8, 0.7, 0.6, 0.5,
                        0.4, 0.3, 0.2, 0.1, 1.0
                    ]
                }
            }
        ]
    },
    consistent_read=True
)

# Display hybrid search results
print("🔄 Hybrid Search Results:")
for result in res.docs:
    doc_id = str(result.doc['id'])
    score = f"{result.score:.2f}"
    keyword = str(result.doc['keyword'])
    text = str(result.doc['text'])

    print(f"{doc_id:<5} | {score:<5} | {keyword:<15} | {text}")

実行結果は以下🐍

全文検索ではヒットしなかった doc2 もヒットするようになっていた👌

🔄 Hybrid Search Results:
doc3  | 0.66  | ['serverless', 'infrastructure'] | The key aspect is that developers don't need to explicitly provision or manage servers. The cloud provider handles all server management automatically.
doc1  | 0.62  | serverless      | Serverless computing does not mean no servers are involved. It refers to a cloud computing model where the server management is abstracted away from developers.
doc2  | 0.33  | cloud           | Instead, it refers to a cloud computing model where developers can build and run applications without having to manage the underlying infrastructure.

🧹 Step 7: Clean up

最後はコレクションを削除しておく.ちなみに今回は検証用の環境なので翌日には自動的にコレクションが削除されているような気がした🗑️ブログをまとめながら数回 Quickstart を試していて気付いた.

import os
from dotenv import load_dotenv
from lambdadb import LambdaDB

load_dotenv()

# Initialize the LambdaDB client
lambda_db = LambdaDB(
    server_url=os.getenv("SERVER_URL"),
    project_api_key=os.getenv("PROJECT_API_KEY"),
)

collection_name = "kakakakakku"

lambda_db.collections.delete(collection_name=collection_name)

まとめ

LambdaDB の Quickstart を試してみた❗️まだ新しいプロダクトなので今後もウォッチしていきたいな〜と思う.最近だと Amazon S3 Vectors のプレビューリリースもあったりして,選択肢の幅も増えそう.

aws.amazon.com

GitHub Actions でアクションの SHA 固定を強制できる「Enforce SHA pinning」

2025年8月15日に GitHub Actions で「特定のアクションやバージョンをブロックする機能」「アクションの SHA 固定を強制する機能」がリリースされた💡

github.blog

たとえば GitHub Actions で使っているアクションにバックドア的な脆弱性が組み込まれてしまった場合のリスクを抑制できる.今年だと tj-actions/changed-files の件があったりした.

nvd.nist.gov

個人的に「アクションの SHA 固定を強制する機能 (Enforce SHA pinning)」に興味があってさっそく試してみた❗️今回はサンプルとして actions/checkout を使う.

github.com

👾 .github/workflows/deploy.yml(バージョン固定)

まずは Enforce SHA pinning を有効化せずに actions/checkout@v5.0.0(バージョン固定)を指定すると問題なく実行できる👌

name: sandbox-github-actions-sha-pinning

on:
  workflow_dispatch:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5.0.0
      - name: Run deployment
        run: echo 'Start deployment🚀'

Enforce SHA pinning を有効化する

ちなみに Enforce SHA pinning は「リポジトリレベル」「Organization レベル」で設定できる.今回はリポジトリレベルで設定する.もし仕事で Enforce SHA pinning を有効化するときに最初から Organization レベルで設定してしまうと既存リポジトリへの影響が大きそうではある💨

リポジトリレベルで Enforce SHA pinning を設定する

Organization レベルで Enforce SHA pinning を設定する

Enforce SHA pinning を有効化して実行する

次に Enforce SHA pinning を有効化して実行すると actions/checkout@v5.0.0(バージョン固定)では以下のエラーになった🚨

Error: The action actions/checkout@v5.0.0 is not allowed in kakakakakku/sandbox-github-actions-sha-pinning because all actions must be pinned to a full-length commit SHA.

👾 .github/workflows/deploy.yml(SHA 固定)

今度は actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8(SHA 固定)を指定する✅️

name: sandbox-github-actions-sha-pinning

on:
  workflow_dispatch:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
      - name: Run deployment
        run: echo 'Start deployment🚀'

すると今度は実行できた❗️

まとめ

2025年8月15日にリリースされた GitHub Actions の「アクションの SHA 固定を強制する機能 (Enforce SHA pinning)」を試してみた👌

今回はシンプルなワークフローで試したので,普段使っているもっと複雑なワークフローにも適用してみようと思う.

関連ドキュメント

docs.github.com

docs.github.com

Security Hub で [SSM.7] SSM documents should have the block public sharing setting enabled を修復する

AWS Security Hub の AWS Foundational Security Best Practices (FSBP) で [SSM.7] SSM documents should have the block public sharing setting enabled という警告が出ていた👀

docs.aws.amazon.com

SSM.7 とは

[SSM.7] SSM documents should have the block public sharing setting enabled と書いてある通り,AWS Systems Manager ドキュメントの「パブリック共有設定をブロック」が無効化されていると警告が出る🚨

docs.aws.amazon.com

数ヶ月前にはなかったような気がして確認したところ,2025年7月15日に追加された比較的最近のコントロールだった💡

For the AWS FSBP standard, IDs for the applicable controls are: CloudFront.15, Cognito.2, EC2.180, ELB.18, MSK.4, MSK.5, MSK.6, RDS.45, Redshift.18, S3.25, SSM.6, and SSM.7.

docs.aws.amazon.com

修復する(マネジメントコンソール)

マネジメントコンソールで修復する場合は AWS Systems Manager ドキュメント詳細設定パブリック共有設定をブロック を有効化すれば OK👌

修復する(AWS CLI)

AWS CLI で修復する場合は aws ssm update-service-setting コマンドを実行すれば OK👌

$ aws ssm update-service-setting \
    --setting-id /ssm/documents/console/public-sharing-permission \
    --setting-value Disable \
    --region 'ap-northeast-1'

docs.aws.amazon.com

修復する(Terraform)

Terraform で修復する場合は aws_ssm_service_setting を使えば OK👌

resource "aws_ssm_service_setting" "psp" {
  setting_id    = "/ssm/documents/console/public-sharing-permission"
  setting_value = "Disable"
}

修復する(AWS CloudFormation / AWS CDK)

調べた限りだと,現時点では AWS CloudFormation / AWS CDK ではサポートされていなさそうだった🙅‍♂️AWS CloudFormation Public Coverage Roadmap にも特に issue はなかった.今後アップデートはありそうだし待ってみよう.

github.com

修復確認

AWS Systems Manager ドキュメントの「パブリック共有設定をブロック」を有効化したら [SSM.7] SSM documents should have the block public sharing setting enabledPASSED になった👏

AWS Lambda Deploy GitHub Action: GitHub Actions から Lambda 関数をデプロイしよう

2025年8月7日にリリースされた AWS Lambda Deploy GitHub Action (aws-actions/aws-lambda-deploy) を使うと GitHub Actions から AWS Lambda 関数を直接デプロイできる🎉さっそく試してみた \( 'ω')/

aws.amazon.com

github.com

仕組み

AWS Lambda Deploy GitHub Action は AWS Lambda 関数がなければ作って,既にあったら更新する.

  • CreateFunction
  • UpdateFunctionCode
  • UpdateFunctionConfiguration

そして index.js の実装を確認すると AWS SDK for JavaScript v3 を使った実装になっているため,Terraform や AWS SAM / AWS CloudFormation / AWS CDK のような「状態」を管理する仕組みはなく,AWS SDK で命令型のように管理するイメージになる.あと AWS Lambda 関数を削除する仕組みはなく,不要になった場合は別途マネジメントコンソールなどから削除する必要がある🗑️

準備

AWS Lambda Deploy GitHub Action の管理する範囲は AWS Lambda 関数自体(設定とコード)になるため,たとえば AWS Lambda 関数に設定する IAM Role は自動で作られず,事前に作っておく必要がある.今回は Terraform で IAM Role を作る(最後に試すため AWS X-Ray のポリシーも追加してある).

resource "aws_iam_role" "main" {
  name = "sandbox-aws-lambda-deploy"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "lambda.amazonaws.com"
        }
      }
    ]
  })
}

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

resource "aws_iam_role_policy_attachment" "xray" {
  role       = aws_iam_role.main.name
  policy_arn = "arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess"
}

よって,AWS Lambda Deploy GitHub Action はインフラとアプリケーション(と区別するべきかどうかは別として)で言うと「アプリケーション」に特化したツールと言えそう.もしくは「ライフサイクル」という観点だと「頻繁にデプロイするコードの管理」を GitHub Actions で実現するためのツールと表現することもできそう👀

サンプル

GitHub リポジトリに deploy-lambda-example.yml という GitHub Actions ワークフローのサンプルがあって,シュッと試すならこのワークフローにある環境変数を書き換えれば OK👌

github.com

デプロイ

今回は Python x uv で requests を使って外部 API (Dog API) にアクセスするコードをデプロイする🐍🐕️

ディレクトリ構造

.
├── .github
│   └── workflows
│       └── deploy.yml
├── application
│   ├── pyproject.toml
│   └── src
│       └── app.py
├── infrastructure
│   └── iam.tf
└── README.md

👾 application/src/app.py

import requests


def lambda_handler(event, context):
    print('Hello aws-actions/aws-lambda-deploy😀')

    response = requests.get('https://dog.ceo/api/breeds/image/random')
    print(response.json()['message'])

👾 application/pyproject.toml

[project]
name = "sandbox-aws-lambda-deploy"
version = "0.1.0"
description = "sandbox-aws-lambda-deploy"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
    "requests==2.32.4",
]

👾 .github/workflows/deploy.yml

GitHub Actions ワークフローのサンプル deploy-lambda-example.yml を参考に Python x uv のステップを追加した👌

name: Deploy to AWS Lambda

on:
  push:
    branches:
      - main

env:
  AWS_REGION: ap-northeast-1
  AWS_ROLE_TO_ASSUME: arn:aws:iam::000000000000:role/xxx
  LAMBDA_FUNCTION_NAME: sandbox-aws-lambda-deploy
  LAMBDA_CODE_ARTIFACTS_DIR: application/dist
  LAMBDA_HANDLER: app.lambda_handler
  LAMBDA_RUNTIME: python3.13
  LAMBDA_EXECUTION_ROLE: arn:aws:iam::000000000000:role/sandbox-aws-lambda-deploy

permissions:
  id-token: write
  contents: read

jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-latest

    steps:
    - name: Checkout
      uses: actions/checkout@v4

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

    - name: Install uv
      uses: astral-sh/setup-uv@v6

    - name: Install Python 3.13
      run: uv python install 3.13

    - name: Build using uv
      working-directory: application
      run: uv pip install . --python 3.13 --target ./dist

    - name: Deploy Lambda Function
      uses: aws-actions/aws-lambda-deploy@v1
      with:
        function-name: ${{ env.LAMBDA_FUNCTION_NAME }}
        code-artifacts-dir: ${{ env.LAMBDA_CODE_ARTIFACTS_DIR }}
        handler: ${{ env.LAMBDA_HANDLER }}
        runtime: ${{ env.LAMBDA_RUNTIME }}
        role: ${{ env.LAMBDA_EXECUTION_ROLE }}

デプロイ確認

AWS Lambda Deploy GitHub Action で AWS Lambda 関数をデプロイできた👏 実行結果も期待通りだった.

GitHub Actions のログを抜粋すると以下のように出力されていた📝

1回目だから Creating new Lambda function も出力されていた.

Creating new Lambda function: sandbox-aws-lambda-deploy
Lambda function created successfully
(中略)
Getting current configuration for function sandbox-aws-lambda-deploy
Updating function configuration for sandbox-aws-lambda-deploy
Waiting for function update to complete. Will wait for 5 minutes
Function update completed successfully
Lambda function deployment completed successfully

デプロイ2回目

今度はコードを書き換えて(v2 のところ)もう一度デプロイして,同じく期待通りだった.

import requests


def lambda_handler(event, context):
    print('Hello aws-actions/aws-lambda-deploy😀v2')

    response = requests.get('https://dog.ceo/api/breeds/image/random')
    print(response.json()['message'])

GitHub Actions のログを抜粋すると以下のように出力されていた📝

2回目だから Creating new Lambda function は出力されていなかった.

Getting current configuration for function sandbox-aws-lambda-deploy
Updating function configuration for sandbox-aws-lambda-deploy
Waiting for function update to complete. Will wait for 5 minutes
Function update completed successfully
Lambda function deployment completed successfully

デプロイ3回目

今度は AWS Lambda 関数の設定を変更する.メモリ (memory-size) とトレーシング (tracing-config) を追加で設定した👌

name: Deploy to AWS Lambda

on:
  push:
    branches:
      - main

env:
  AWS_REGION: ap-northeast-1
  AWS_ROLE_TO_ASSUME: arn:aws:iam::000000000000:role/xxx
  LAMBDA_FUNCTION_NAME: sandbox-aws-lambda-deploy
  LAMBDA_CODE_ARTIFACTS_DIR: application/dist
  LAMBDA_HANDLER: app.lambda_handler
  LAMBDA_RUNTIME: python3.13
  LAMBDA_EXECUTION_ROLE: arn:aws:iam::000000000000:role/sandbox-aws-lambda-deploy
  LAMBDA_MEMORY_SIZE: 256
  LAMBDA_TRACING_CONFIG: Active

permissions:
  id-token: write
  contents: read

jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-latest

    steps:
    - name: Checkout
      uses: actions/checkout@v4

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

    - name: Install uv
      uses: astral-sh/setup-uv@v6

    - name: Install Python 3.13
      run: uv python install 3.13

    - name: Build using uv
      working-directory: application
      run: uv pip install . --python 3.13 --target ./dist

    - name: Deploy Lambda Function
      uses: aws-actions/aws-lambda-deploy@v1
      with:
        function-name: ${{ env.LAMBDA_FUNCTION_NAME }}
        code-artifacts-dir: ${{ env.LAMBDA_CODE_ARTIFACTS_DIR }}
        handler: ${{ env.LAMBDA_HANDLER }}
        runtime: ${{ env.LAMBDA_RUNTIME }}
        role: ${{ env.LAMBDA_EXECUTION_ROLE }}
        memory-size: ${{ env.LAMBDA_MEMORY_SIZE }}
        tracing-config: '{"Mode": "${{ env.LAMBDA_TRACING_CONFIG }}"}'

もう一度デプロイすると期待通りに AWS Lambda 関数の設定が更新されていた❗️

GitHub Actions のログを抜粋すると以下のように出力されていた📝

今度は Configuration difference detected と出力されていて,既存の設定と差分がある箇所をちゃんと検出できていた.

Getting current configuration for function sandbox-aws-lambda-deploy
Configuration difference detected in MemorySize: 128 -> 256
Configuration difference detected in TracingConfig
Updating function configuration for sandbox-aws-lambda-deploy
Waiting for function update to complete. Will wait for 5 minutes
Function update completed successfully
Lambda function deployment completed successfully

README 修正

AWS Lambda Deploy GitHub Action を試しながら README に1箇所誤りがあることに気付いて修正しておいた✅️

github.com

まとめ

AWS Lambda Deploy GitHub Action を試してみた❗️GitHub Actions から簡単に AWS Lambda 関数をデプロイできて,既存の GitHub Actions ワークフローにすぐ組み込めるのもメリットだと思う.

あくまで個人的な感想だけど,ツールセットを増やしたくなくて,シンプルな AWS Lambda を管理したいという要件であれば選択肢になると思う.逆に Amazon SQS / Amazon EventBridge Scheduler などのトリガー設定も組み合わせたサーバレスアーキテクチャを構築するのであれば AWS SAM / AWS CDK / Terraform を GitHub Actions から実行するような仕組みを最初から選択するかな〜と思ったりもした💡

あとは Terraform で AWS Lambda 関数を "リソースとして" デプロイしつつ,AWS Lambda 関数のコードは AWS Lambda Deploy GitHub Action でデプロイするっていう分割パターンも考えたけど...どうだろう🤔そこまでメリットがあるようには感じないかなぁ.もうちょっと考えてみよう \( 'ω')/

関連ポスト

DuckDB で CloudTrail 証跡をクエリする

AWS CloudTrail 証跡をアドホックにサクッと分析したいな〜という場面があって DuckDB を使ってみた🦆

もちろん AWS CloudTrail LakeAmazon Athena を使う選択肢もあるけど,せっかく Amazon S3 にデータ (.json.gz) があるんだし,もっと気軽にクエリできても良いのでは❗️と思って DuckDB を選んだ.

$ duckdb --version
v1.3.2 (Ossivalis) 0b83e5d2f6

シークレットを登録する

まずは DuckDB を起動して,CREATE SECRET コマンド(もしくは CREATE OR REPLACE SECRET コマンド)で Amazon S3 にアクセスするためのシークレットを登録しておく.

⚫◗ CREATE OR REPLACE SECRET secret (
    TYPE s3,
    PROVIDER credential_chain,
    CHAIN config,
    PROFILE 'xxxxx'
);
┌─────────┐
│ Success │
│ boolean │
├─────────┤
│ true    │
└─────────┘

duckdb.org

テーブルを作る

次に CREATE TABLE AS SELECT (CTAS) コマンドで AWS CloudTrail 証跡テーブル events を作る.今回はプレフィックスで範囲を限定して「2025年7月」のみにした📅 取得するフィールドはドキュメントを参考に代表的なものを選んだ.

docs.aws.amazon.com

docs.aws.amazon.com

⚫◗ CREATE TABLE events AS
    SELECT
        record.eventTime::TIMESTAMP AS eventTime,
        record.eventSource,
        record.eventName,
        record.awsRegion,
        record.userIdentity,
        record.eventType,
        record.requestParameters
    FROM (
        SELECT unnest(Records) as record
        FROM read_json('s3://aws-cloudtrail-logs-000000000000-xxxxxxxx/AWSLogs/000000000000/CloudTrail/ap-northeast-1/2025/07/*/000000000000_CloudTrail_ap-northeast-1_*.json.gz', ignore_errors=true)
    );

duckdb.org

クエリを実行する

あとは自由にクエリを実行する❗️

eventSource 別カウント

ちょうど7月に ECS Blue/Green デプロイの検証ecspresso x ECS Blue/Green デプロイの検証 をしていて elasticloadbalancing.amazonaws.comecs.amazonaws.com のカウントが増えている📈

⚫◗ SELECT eventSource, awsRegion, COUNT(*) AS COUNT
    FROM events
    GROUP BY eventSource, awsRegion
    ORDER BY COUNT DESC;
┌──────────────────────────────────────────┬────────────────┬───────┐
│               eventSource                │   awsRegion    │ COUNT │
│                 varcharvarchar     │ int64 │
├──────────────────────────────────────────┼────────────────┼───────┤
│ kms.amazonaws.com                        │ ap-northeast-114847 │
│ elasticloadbalancing.amazonaws.com       │ ap-northeast-111297 │
│ ecs.amazonaws.com                        │ ap-northeast-15109 │
│ ec2.amazonaws.com                        │ ap-northeast-13013 │
│ sts.amazonaws.com                        │ ap-northeast-12559 │
│ arc-zonal-shift.amazonaws.com            │ ap-northeast-12398 │
│ s3.amazonaws.com                         │ ap-northeast-12235 │
│ lambda.amazonaws.com                     │ ap-northeast-11488 │
│ autoscaling.amazonaws.com                │ ap-northeast-1407 │
│ cloudformation.amazonaws.com             │ ap-northeast-1396 │
│ logs.amazonaws.com                       │ ap-northeast-1382 │
│ notifications.amazonaws.com              │ ap-northeast-1279 │
│ tagging.amazonaws.com                    │ ap-northeast-1154 │
│ apigateway.amazonaws.com                 │ ap-northeast-159 │
│ schemas.amazonaws.com                    │ ap-northeast-133 │
│ iotsecuredtunneling.amazonaws.com        │ ap-northeast-124 │
│ cloudtrail.amazonaws.com                 │ ap-northeast-118 │
│ servicecatalog-appregistry.amazonaws.com │ ap-northeast-116 │
│ monitoring.amazonaws.com                 │ ap-northeast-116 │
│ sns.amazonaws.com                        │ ap-northeast-112 │
│ ecr.amazonaws.com                        │ ap-northeast-112 │
│ securityhub.amazonaws.com                │ ap-northeast-111 │
│ resource-explorer-2.amazonaws.com        │ ap-northeast-110 │
│ events.amazonaws.com                     │ ap-northeast-19 │
│ servicediscovery.amazonaws.com           │ ap-northeast-17 │
│ compute-optimizer.amazonaws.com          │ ap-northeast-16 │
│ bedrock.amazonaws.com                    │ ap-northeast-16 │
│ codepipeline.amazonaws.com               │ ap-northeast-15 │
│ acm.amazonaws.com                        │ ap-northeast-15 │
│ config.amazonaws.com                     │ ap-northeast-15 │
│ signin.amazonaws.com                     │ ap-northeast-14 │
│ acm-pca.amazonaws.com                    │ ap-northeast-12 │
│ sqs.amazonaws.com                        │ ap-northeast-12 │
│ access-analyzer.amazonaws.com            │ ap-northeast-11 │
│ route53resolver.amazonaws.com            │ ap-northeast-11 │
├──────────────────────────────────────────┴────────────────┴───────┤
│ 35 rows                                                 3 columns │
└───────────────────────────────────────────────────────────────────┘

Amazon ECS 関連の eventName 別カウント

eventSourceecs.amazonaws.com に限定した eventName のカウントも確認できた📈

⚫◗ SELECT eventName, awsRegion, COUNT(*) AS COUNT
    FROM events
    WHERE eventSource = 'ecs.amazonaws.com'
    GROUP BY eventName, awsRegion
    ORDER BY COUNT DESC;
┌────────────────────────────┬────────────────┬───────┐
│         eventName          │   awsRegion    │ COUNT │
│          varcharvarchar     │ int64 │
├────────────────────────────┼────────────────┼───────┤
│ DescribeServices           │ ap-northeast-11653 │
│ DescribeClusters           │ ap-northeast-1704 │
│ DescribeServiceRevisions   │ ap-northeast-1421 │
│ ListContainerInstances     │ ap-northeast-1383 │
│ DescribeTaskDefinition     │ ap-northeast-1373 │
│ DescribeServiceDeployments │ ap-northeast-1299 │
│ ListTasks                  │ ap-northeast-1292 │
│ ListServiceDeployments     │ ap-northeast-1288 │
│ DescribeCapacityProviders  │ ap-northeast-1183 │
│ DescribeTasks              │ ap-northeast-1146 │
│ ListServices               │ ap-northeast-163 │
│ ListTaskDefinitions        │ ap-northeast-160 │
│ UpdateService              │ ap-northeast-156 │
│ ListTaskDefinitionFamilies │ ap-northeast-145 │
│ GetTaskProtection          │ ap-northeast-142 │
│ ListAccountSettings        │ ap-northeast-134 │
│ RegisterTaskDefinition     │ ap-northeast-123 │
│ ListClusters               │ ap-northeast-112 │
│ DeregisterTaskDefinition   │ ap-northeast-19 │
│ DeleteService              │ ap-northeast-19 │
│ CreateService              │ ap-northeast-16 │
│ DeleteCluster              │ ap-northeast-13 │
│ ListTagsForResource        │ ap-northeast-13 │
│ CreateCluster              │ ap-northeast-12 │
├────────────────────────────┴────────────────┴───────┤
│ 24 rows                                   3 columns │
└─────────────────────────────────────────────────────┘

Amazon S3 関連の eventName 別カウント

同じように eventSources3.amazonaws.com に限定した eventName のカウントも確認できた📈

⚫◗ SELECT eventName, awsRegion, COUNT(*) AS COUNT
    FROM events
    WHERE eventSource = 's3.amazonaws.com'
    GROUP BY eventName, awsRegion
    ORDER BY COUNT DESC;
┌──────────────────────────────────┬────────────────┬───────┐
│            eventName             │   awsRegion    │ COUNT │
│             varcharvarchar     │ int64 │
├──────────────────────────────────┼────────────────┼───────┤
│ GetBucketAcl                     │ ap-northeast-12085 │
│ ListObjectVersions               │ ap-northeast-168 │
│ HeadBucket                       │ ap-northeast-121 │
│ GetBucketVersioning              │ ap-northeast-117 │
│ ListObjects                      │ ap-northeast-111 │
│ GetBucketOwnershipControls       │ ap-northeast-17 │
│ GetBucketObjectLockConfiguration │ ap-northeast-16 │
│ GetBucketLifecycle               │ ap-northeast-14 │
│ DeleteBucketLifecycle            │ ap-northeast-12 │
│ GetBucketPublicAccessBlock       │ ap-northeast-12 │
│ GetBucketReplication             │ ap-northeast-11 │
│ GetAccelerateConfiguration       │ ap-northeast-11 │
│ GetBucketTagging                 │ ap-northeast-11 │
│ DeleteBucket                     │ ap-northeast-11 │
│ GetBucketWebsite                 │ ap-northeast-11 │
│ GetBucketEncryption              │ ap-northeast-11 │
│ GetBucketPolicy                  │ ap-northeast-11 │
│ PutBucketVersioning              │ ap-northeast-11 │
│ GetBucketCors                    │ ap-northeast-11 │
│ GetBucketLogging                 │ ap-northeast-11 │
│ DeleteBucketPublicAccessBlock    │ ap-northeast-11 │
│ GetBucketRequestPayment          │ ap-northeast-11 │
├──────────────────────────────────┴────────────────┴───────┤
│ 22 rows                                         3 columns │
└───────────────────────────────────────────────────────────┘

AWS Lambda 関連の eventName 別カウント

eventSourcelambda.amazonaws.com に限定した eventName のカウントも確認できた📈

GetFunction20150331v2GetFunctionConfiguration20150331v2 など AWS Lambda 関連の eventName には日付やバージョン表記が含まれているんだな〜という発見もあった👀

⚫◗ SELECT eventName, awsRegion, COUNT(*) AS COUNT
    FROM events
    WHERE eventSource = 'lambda.amazonaws.com'
    GROUP BY eventName, awsRegion
    ORDER BY COUNT DESC;
┌───────────────────────────────────────┬────────────────┬───────┐
│               eventName               │   awsRegion    │ COUNT │
│                varcharvarchar     │ int64 │
├───────────────────────────────────────┼────────────────┼───────┤
│ GetFunction20150331v2                 │ ap-northeast-1488 │
│ GetFunctionConfiguration20150331v2    │ ap-northeast-1157 │
│ GetAccountSettings20160819            │ ap-northeast-1145 │
│ ListEventSourceMappings20150331       │ ap-northeast-1104 │
│ ListVersionsByFunction20150331        │ ap-northeast-172 │
│ ListTags20170331                      │ ap-northeast-171 │
│ ListFunctions20150331                 │ ap-northeast-142 │
│ GetRuntimeManagementConfig            │ ap-northeast-138 │
│ GetFunctionCodeSigningConfig          │ ap-northeast-138 │
│ ListFunctionUrlConfigs                │ ap-northeast-135 │
│ ListLayers20181031                    │ ap-northeast-135 │
│ GetFunctionEventInvokeConfig          │ ap-northeast-135 │
│ GetPolicy20150331                     │ ap-northeast-135 │
│ ListAliases20150331                   │ ap-northeast-135 │
│ ListProvisionedConcurrencyConfigs     │ ap-northeast-134 │
│ GetFunctionRecursionConfig            │ ap-northeast-134 │
│ UpdateFunctionConfiguration20150331v2 │ ap-northeast-124 │
│ GetEventSourceMapping20150331         │ ap-northeast-117 │
│ DeleteFunction20150331                │ ap-northeast-113 │
│ PublishVersion20150331                │ ap-northeast-112 │
│ GetPolicy20150331v2                   │ ap-northeast-18 │
│ CreateFunction20150331                │ ap-northeast-15 │
│ UpdateFunctionCode20150331v2          │ ap-northeast-13 │
│ RemovePermission20150331v2            │ ap-northeast-12 │
│ AddPermission20150331v2               │ ap-northeast-12 │
│ GetLayerVersionByArn20181031          │ ap-northeast-12 │
│ DeleteEventSourceMapping20150331      │ ap-northeast-11 │
│ CreateEventSourceMapping20150331      │ ap-northeast-11 │
├───────────────────────────────────────┴────────────────┴───────┤
│ 28 rows                                              3 columns │
└────────────────────────────────────────────────────────────────┘

まとめ

普段から DuckDB を使う機会が多いけど,今後は AWS CloudTrail 証跡のアドホックな分析にも DuckDB を使っていこうと思う🦆

関連記事

kakakakakku.hatenablog.com