Private RepositoryのGitLFSとAWS CodeBuildを連携する

Kota Tsuyuzaki
nttlabs
Published in
10 min readJan 14, 2020

こんにちは. NTT研究所の露崎です.先日 Git LFSについて調べてみた という記事を書いたのですが,実際にAWS CodeBuildと連携する際に少しハマったポイントがあったので備忘録としてブログ化します.

AWS CodeBuildでやりたかったこと

Git LFSを導入してやりたかったことはチームの管理するコードのCI,特にAnsibleコードの実行に使うパッケージの管理です.インストールするパッケージを外部に置いておくとAccessibilityなどの問題を起こしやすいためです.例えば,社内にパッケージを置いておくとクラウドのCIから取得できない.一方で,外部のクラウドに置いておくと社内のプロキシなどの制約でダウンロードできない場合がある,などです.このため,コードを置くことを許されたGitHubのPrivate Registryでパッケージも一元管理し,CI上では単にGitのコードごとPullしてくれば必要なパッケージが揃う,というのが理想でした.

CodeBuild上でsmudge処理が実行されていない

実際にGitLFSを有効化してCIでの活用を始めたところAnsibleのCopyモジュールでパッケージの配布を試そうとした時にchecksumの検証で Copied file does not match the expected checksum Transfer failed と言われてしまいました.buildspec.yamlに shasum <target package> のコマンドを入れて値を出力させてみても実際のファイルとSHA1の値が一致していません.そこで対象のパッケージをcatしてみたところGitLFSが管理するポインタ情報が出てきました.イメージとしては以下のようなものです.(以下は公開用の単なる写真の場合のポインタ情報)

$ cat photos/barcelona.png | git-lfs clean
version https://git-lfs.github.com/spec/v1
oid sha256:1c705a8402928de15b40221568eba39b494294ebd501feca70f15c52df5d0334
size 25408556

前の記事で少しだけ紹介しましたがGitLFSはバイナリファイルをS3などの外部ストレージに保存し,そのバージョンやURLをGit上で管理します.つまりCodeBuildでCIジョブが起動した際にはこのポインタの状態のデータしか持たず,実際に実行したいバイナリファイルが取得できていない,ということがわかりました.また実体のファイルを取得するためには明示的にsmudge(smudgeについては詳しくはこちら)もしくはpullの処理を実行する必要があります.

CodeBuild上でPrivate RepositoryをPullする

このGit LFSの実体ファイルをpullする上で課題となったのがGithubのPrivate Repositoryという制約です.Public Repositoryであれば git-lfs pull とでもコマンド一つ入れておけば解決します.一方でPrivate Repositoryでは,そもそもビルドプロジェクトを設定する際に

  • OAuthでgithub認証したアカウントを連携する
  • 認証したアカウントから閲覧可能なgithubのrepositoryを設定する
  • OAuth認証されたgithub repositoryにCodeBuildがWebhookを登録する

という手順を踏む必要があります.また,各ビルドのジョブはCodeBuild側が,そのWebhook経由で提供されるコードをCI環境上に展開するため(*1),CI環境上ではこのOAuth認証を直接利用した操作を実施することができません.このためCIとして実行開始した環境上ではPrivate Repositoryへのアクセスは 404 NotFound になってしまいます.

この問題を解決するために,AWS CodeBuildのパラメータストアとgithubのtokenアクセスを組み合わせることにしました.AWSのパラメータストアはAWSのKMS(Key Management Service)を使ってセキュアなパスワードなど(AWSの公式docsでアクセスキー ID,AWS シークレットアクセスキーなどを保存する場合に使うべき,と記載)を保存し,実行時に環境変数に代入してくれる,という仕組みです.またgithubのtokenはssh鍵以外の手段として事前にユーザアカウントによって生成されたtokenを用いて https://<account name>:<generated token>@github.com/<org>/<repository>というアクセス方法を提供する仕組みです.

実際の設定としては,この辺の記事を参考に,事前にgithub用のtoken(tokenの取得方法はこちら)をAWSのパラメータセットに設定しておけば

# setup git-lfs
- wget https://github.com/git-lfs/git-lfs/releases/download/v2.9.1/git-lfs-linux-amd64-v2.9.1.tar.gz
- tar vzxf git-lfs-linux-amd64-v2.9.1.tar.gz
- ./install.sh
- git remote set-url origin https://<account>:${GENERATED_TOKEN}@github.com/<org>/<repo>
- git-lfs pull

これらのタスクをbuildspec.yamlに追加すると,実体ファイルをpullできるようになります.(account , GENERATED_TOKEN, org, repo はご自身の環境に合わせて読み替えてください)

セキュリティ関連でのあれこれ

Outside Collaboratorsの設定画面

この設定でPrivate RepositoryをPullできるようになったものの,残念ながらGithubのTokenは“アカウントに紐づく”ためTokenの設定者の権限が強い(Ownerや色々なリポジトリの権限を持つなど)場合にTokenが漏洩した場合リスクが生じます.その対策として,

  • CI専用のGithubアカウントを作成する
  • CI専用のアカウントで必要な権限のみを有するTokenを発行する
  • Private repositoryにはCI専用のアカウントをRead権限のみのCollaboratorsとして追加する

という設定を実施しています.これらの設定で権限を絞っておくことで

  • CI専用のアカウントが乗っ取られた場合,Collaboratorsから外す
  • CI専用のTokenが漏れた場合,Tokenの再取得をする

などケースに応じていくつかの対策を取ることができます.また実際に問題が起こった場合のリスクを想定しても一つのRepositoryへの参照権限しか与えていないためアカウントにアクセス可能になった第三者が実施可能なことは

  • CIで利用していたRepositoryをcloneできる

という程度であり他のRepositoryを参照されたり,設定を書き換えられるリスクを抑えることができます.

余談

今回紹介したいくつかの手法の組み合わせでようやくGitLFSをCIと連携させて活用できるようになりました.一方で,どちらが良かったかの判断は難しいですが,事情が許せばAWS S3などを利用しても良かったかもという思いはあります.S3を使う場合にも考えるべき点はあり,例えばGitLFSが担保してくれている認証系の情報(取得できるIP制限やpre-signed URLの仕組みなどで取得を制限するなど)を別途AWS上で試行錯誤しなければならないという点は存在します.こうした運用やセキュリティに関する対策というのは組織や運用者の方針によって違うと思いますが今回の情報共有があとで運用を考える方々の知見になればと思います.

また後になってみて気づいたこととして,githubにおけるGitLFSを利用した時のOutboundの無料枠が思ったより小さかった,ということがあります.githubのGitLFSの無料枠は転送量1GB/月,保存容量1GB/月です.保存容量としては小さいパッケージであれば十分かと思いますが例えばパッケージのサイズがトータル20MBの場合,CIでのpullを50回実行すると月の転送上限を超えてしまいます.$5/月の課金で転送量、保存容量に+50GBされるのでトータルサイズやPullの回数がよっぽど多くなければ比較的安いコストで済ませることはできそうですが,S3に置いておけばAWS内転送になり,コストがCIの回数に依らない(が,外部で利用しようとした時はS3のOutbound Feeはかかる)という面があるので,この辺もS3とどっちが良かったか迷うポイントではあります.

まとめ

GitLFSとGithubのPrivate Repository,AWS CodeBuildを組み合わせる場合のポイントとして

  • GitLFSを利用する場合は実体の取得(smudge, pull)が必要
  • CodeBuildからPrivate RepositoryをPullする場合にTokenアクセスとParameter Storeの組み合わせで実行できる
  • GithubのTokenアクセスを利用する際のセキュリティ対策あれこれ

といった点を紹介しました。

おわりに

私たちNTTは、オープンソースコミュニティで共に活動する仲間を募集しています。ぜひ弊社 ソフトウェアイノベーションセンタ紹介ページ及び、採用情報ページをご覧ください。

参考リンク一覧

Ansible Copy Module: https://docs.ansible.com/ansible/latest/modules/copy_module.html

GitLFS ポインタの例: https://github.com/bloodeagle40234/play-with-git-lfs/blob/master/photos/barcelona.png

GitLFSをちょっと詳しく: https://qiita.com/ikmski/items/5cc8b8832336b8d85429

AWS Codebuild Docs: https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/run-build.html

[CodeBuild]buildspec.ymlでの環境変数指定方法あれこれまとめ: https://dev.classmethod.jp/cloud/codebuild-env/

コマンドライン用の個人アクセストークンを作成する(github help): https://help.github.com/ja/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line

*1: ドキュメントに明示的な挙動の記述は見つからず、見えてる動作からの推測です

--

--

Kota Tsuyuzaki
nttlabs
Writer for

Research Engineer at Nippon Telegraph and Telephone Corporation (NTT). OpenStack Swift core team member, OpenStack Storlets Project Team Lead.