[小ネタ] AWS SAMのGoアプリケーションビルド時に -trimpath オプションを付ける方法

2023.09.13

しばたです。

前回の記事でAWS SAMでGo言語アプリケーションをビルドする際に「条件により -trimpath パラメーターが付くこともある」旨を記載しました。

その手順自体はシンプルなのですが、どうも公式にドキュメント化されてない様なので本記事で軽く紹介しようと思います。

AWS SAMにおけるGoアプリケーションのビルド基本

AWS SAMではランタイム毎にアプリケーションのビルド方法が定められており、その実装はAWS Lambda Buildersにあります。
Go言語の場合はAWS::Serverless::Functionリソースで2パターンの指定方法があります。

  1. Runtimeプロパティをgo1.xに指定する : go1.xランタイムの場合
  2. メタデータのBuildMethodプロパティにgo1.xを指定する : カスタムランタイムの場合

template.yaml

# go1.x ランタイムの場合
Resources:
  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: TestFunction
      CodeUri: function/
      Handler: main
      Runtime: go1.x

# カスタムランタイムの場合
Resources:
  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: TestFunction
      CodeUri: function/
      Handler: bootstrap
      Runtime: provided.al2
    Metadata:
      BuildMethod: go1.x

どちらの場合もsam buildコマンド時に内部でgo buildコマンドを実行します。

# sam build内で呼ばれるビルドイメージ
export GOOS=linux 
export GOARCH=Architecturesで指定されたアーキテクチャ
go build -o "Handlerパラメーターで指定された値" "CodeUriで指定されたパス"

ビルド時に-trimpathオプションを付ける方法

go build時のオプションを開発者が自由に設定することはできません。
ただ、-trimpathオプションに関しては利用者からのIssue起票 *1もあり設定可能となっています。

設定方法は簡単でAWS::Serverless::FunctionリソースのメタデータのBuildPropertiesプロパティ内でTrimGoPath: Trueを設定してやればOKです。
これでAWS Lambda Builders側で-trimpathオプションを付けたビルドをしてくれます。

template.yaml

# BuildPropertiesを設定することでgo buildに介入可能
Resources:
  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: TestFunction
      CodeUri: function/
      Handler: bootstrap
      Runtime: provided.al2
    Metadata:
      BuildMethod: go1.x
      BuildProperties:
        TrimGoPath: True

この場合のビルドイメージはこんな感じです。

# TrimGoPathプロパティを指定した際のビルドイメージ
export GOOS=linux 
export GOARCH=Architecturesで指定されたアーキテクチャ
go build -trimpath -o "Handlerパラメーターで指定された値" "CodeUriで指定されたパス"

その他のオプションを設定したい場合

AWS Lambda Buildersのソースを見る限り-trimpath以外のオプションは指定できない感じでした。
(ローカルデバッグ時は別途専用のオプションが付く)

このため他のオプションも指定したい場合はMakefileを使ったビルドを選び、自分でgo buildのコマンドラインをカスタマイズしてやる必要があります。
具体的な内容については前回の記事の「補足 : Makefileビルドする場合」を参照してください。

余談1 : GOFLAGS環境変数も使えた、が...

Go言語ではグローバルな環境変数GOFLAGSが存在し既定のオプションを設定することができます。

このGOFLAGS環境変数を使ってAWS SAMの設定を無視してgo build時のオプションを指定することができました。

# PowerShell環境での実行例

# GOFLAGS環境変数を設定して既定のオプションを指定
$env:GOFLAGS="-trimpath -tags=lambda.norpc"
sam build

一応動作したのですが、このためだけにグローバルな設定を変えてしまうよりは前述のMakefileビルドを選ぶ方が良いでしょう。

余談2 : 他言語での BuildProperties

Go言語だけでなく他の言語で使えるBuildPropertiesを調べたところざっくり以下のプロパティを見つけることができました。
Node.jsについてはドキュメントも見つけたので細かい点はこちらを見ると良いでしょう。

言語 プロパティ名 内容 設定値
Go TrimGoPath go build時に-trimpathオプションを設定 True or False (デフォルトFalse)
Node.js (npm) UseNpmCi npm ciを使うか否か True or False (デフォルトFalse)
Node.js (esbuild) EntryPoint アプリケーションのエントリポイント 値で指定
Node.js (esbuild) External ビルドから除外するパッケージ名 値で指定
Node.js (esbuild) Format ビルド時の出力フォーマット 値で指定
Node.js (esbuild) Loader esbuild --loaderパラメーターに設定する値を指定するっぽい 値で指定
Node.js (esbuild) MainFields package.jsonのメインフィールド 値で指定 (デフォルトmain,module)
Node.js (esbuild) Minify 出力コードをminifyするか否か True or False (デフォルトTrue)
Node.js (esbuild) OutExtension 出力ファイルの拡張子 値で指定
Node.js (esbuild) Sourcemap ソースマップを出力するか否か True or False (デフォルトFalse)
Node.js (esbuild) SourcesContent ソースマップにソースコードを含むか否か True or False (デフォルトTrue)
Node.js (esbuild) Target ECMAScriptのバージョン 値で指定 (デフォルトes2020)
Rust (cargo-lambda) Binary 複数関数ある場合にビルド対象を指定 値で指定

たぶんこれ以外にもプロパティはあると思うので気が向いたら追記します。

最後に

簡単ですが以上となります。

メタデータに関する設定のためあまり厳密にドキュメント化されていない様です。
個人的には「-trimpathはデフォルトで付けてしまっても良かったのでは?」と思いますが、現状オプション設定ですので原則設定する様にしておくと良いでしょう。

脚注

  1. 一般的に-trimpathオプションはセキュリティの文脈で語られることが多いと思いますが、このIssueではバイナリの同一性を担保したい点が発端になっています