CodeBuildプロジェクトを使用して、GitHubのリポジトリをダウンロードし、その中のファイルを更新し、再度アップロードする。

記事タイトルとURLをコピーする

こんにちは🐱
カスタマーサクセス部の山本です。

GitHubのリポジトリからファイルをダウンロードし、それを更新して再びアップロードするという作業を、CodeBuildプロジェクトを使ってどのように安全に行うかについて考えました。

CodeBuildプロジェクトを使ってGitHubのリポジトリにあるファイルを操作するには、Github のパーソナルアクセストークン(Personal Access Tokens、PAT)が必要です。 Github のパーソナルアクセストークンは、ユーザー認証を確立するための一種の秘密鍵のようなものです。
GitHubのパーソナルアクセストークンは、GitHub APIに対する認証や、プライベートリポジトリへのアクセスなどを許可します。

パーソナルアクセストークンはパスワードとは異なり、特定のスコープ(権限)を持つことができます。つまり、トークンは許可された特定の操作のみを実行できます。このため、全体のセキュリティを維持しながら、特定のタスクに対するアクセスを柔軟に制御することができます。
トークンは秘密情報です。他人に公開しないようにし、安全な場所に保存します。また、トークンは生成時に一度だけ表示されます。後から表示することはできません。

トークンを発行し、他の人に見られないように CodeBuild プロジェクトに保管する方法について、公式ドキュメント等を参考に調査し検証しました。
画面付きで紹介します。

参考にしたサイト

docs.aws.amazon.com

docs.github.com

Github の Personal Access Token (PAT) を発行

GitHubにログインし、右上の自分のプロフィール写真をクリックして表示されるドロップダウンメニューから「Settings(設定)」を選択します。

左側のメニューから「Developer settings(開発者設定)」を選択します。

「Fine-grained tokens」を選択し、「Generate new token」を選択します。

"Fine-grained personal access tokens"とは、GitHub のパーソナルアクセストークン(Personal Access Tokens, PATs)の一種で、トークンに細かいスコープ(権限)を設定できるようにするものを指します。
GitHubのPATsは、APIに対する認証やリポジトリへのアクセスなどを許可するために使用されます。それぞれのトークンには複数の権限を持たせることができます。
クラシック版の Tokens を使用する場合、例えば「repo」スコープは、プライベートリポジトリを含むすべてのリポジトリに対する読み書きアクセスを許可します。
しかし、「Fine-grained personal access tokens」を使用すると、リポジトリへのアクセス権限をより細かく設定できます。これにより、特定のリポジトリへの読み取り専用アクセスや、特定のアクション(例えば、イシューの作成やプルリクエストのマージ)だけを許可するなどの設定が可能になります。
この機能は、トークンの権限を最小限に制限することで、セキュリティリスクを軽減するためのものです。
"Fine-grained personal access tokens"はベータ版であり、GitHubはこの機能の動作を完全には保証していません。しかし、ユーザーはこの機能を試すことができ、フィードバックを提供することが期待されています。
(説明終わり)

トークンに付ける名前、説明、期限を入れます。

リポジトリを選択します。鍵マークの付いたプライベートリポジトリを選択しました。

AWS の CodeBuild プロジェクト内でGitHubのリポジトリをダウンロードし、その中のファイルを更新し、再度アップロードするため、Permissions は "Contents" を選択し、"Read and Write "を選択しました。

Generate token をクリックしました。

発行されたトークンをクリックしコピーしました。(画面略)

AWS の CodeBuild プロジェクト内でGitHubのリポジトリをダウンロードする

AWS CodeBuild のプロジェクトにPersonal Access Token (PAT) を登録

AWSマネジメントコンソールのCodeBuildサービスに移動します。
「プロジェクトを作成する」を選択し、プロジェクト名を入力します。

「GitHub の個人用アクセストークンで接続する」を選択し、「GitHub の個人用アクセストークン」を入力します。発行したPersonal Access Token (PAT)を入力します。
「トークンの保存」を押します。

「リポジトリの URL」にプライベートリポジトリのURLを入力します。

「Git のクローンの深さ」 を "Full" にしておきます。

「コンピューティング」に "EC2" を選択し、他はデフォルトでプロジェクトを作成しました。

以上の設定で、プロジェクトはGitHubのプライベートリポジトリをソースとして使用し、ビルドプロジェクトの開始時にリポジトリを自動的にダウンロードします。
ダウンロードは Personal Access Token (PAT) の権限を用いて行います。

CodeBuild プロジェクト内でGitHubのリポジトリをダウンロードする

CodeBuild プロジェクトはデフォルトでは、「ソースコードのルートディレクトリの buildspec.yml を使用」します。

CodeBuild プロジェクトは buildspec.yml の指示に従いビルド処理を行います。
リポジトリを自動的にダウンロードするのか確認するために、buildspec.yml を以下とし、Githubリポジトリのルートディレクトリに配置しました。

version: 0.2
phases:
  pre_build:
    commands:
      - ls -lat
      - cat .git/config

「ビルドを開始」を押します。

GitHubのプライベートリポジトリを自動的にダウンロードしていました。

また、origin が GitHubのプライベートリポジトリになっています。

(失敗)AWS の CodeBuild プロジェクト内でGitHubのリポジトリの中のファイルを更新し、再度アップロードする

GitHubのプライベートリポジトリを自動的にダウンロードした状態で、ファイルを更新し、再度アップロードできるのか確認してみました。
buildspec.yml を以下としました。8 行目以降を追加しています。

version: 0.2
phases:
  pre_build:
    commands:
      - ls -lat
      - cat .git/config
      - git config --global user.name "My name is Yamamoto. Also known as Yamamoto"
      - git config --global user.email "yamamoto.yamamoto@yamamoto.jp.yamamoto"
  build:
    commands:
      - touch "test_file.txt"
      - git add "test_file.txt"
      - git commit -m "add test_file.txt"
  post_build:
    commands:
      - git push origin main

追加した内容を補足します。

  1. pre_buildフェーズ
    • gitのユーザー名とメールアドレスを設定します。
  2. buildフェーズ
    • "test_file.txt"という名前の新しいファイルを作成します。
    • "test_file.txt"をgitに追加します。
    • "test_file.txt"の追加をコミットします。
  3. post_buildフェーズ
    • 変更をmainブランチにプッシュします。

「ビルドを開始」を押します。

エラーが出ました。

[Container] 2024/03/06 03:59:00.338914 Entering phase POST_BUILD [Container] 2024/03/06 03:59:00.339534 Running command git push origin main fatal: could not read Username for 'https://github.com': No such device or address

[Container] 2024/03/06 03:59:00.572109 Command did not exit successfully git push origin main exit status 128 [Container] 2024/03/06 03:59:00.581013 Phase complete: POST_BUILD State: FAILED [Container] 2024/03/06 03:59:00.581031 Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: git push origin main. Reason: exit status 128

Personal Access Token (PAT) を使った認証ができていないようです
公式ドキュメントのタイトルから察するに、CodeBuild のプロジェクトに 登録した Personal Access Token (PAT) は、あくまで "ソースプロバイダーにアクセスする" ためにあるようです。
ソースコードをダウンロードすることはできるものの、宛先としてアップロードする際には、CodeBuild のプロジェクトに 登録した Personal Access Token (PAT) は使えないようです。 残念!!切腹ですね。

(成功)AWS の CodeBuild プロジェクト内でGitHubのリポジトリの中のファイルを更新し、再度アップロードする

Personal Access Token (PAT) を Secret Manager に保存

AWS Secrets Managerは、アプリケーションやサービスなどに必要なログイン情報などの重要なデータを安全に管理するツールです。
CodeBuildと連携して使うことができます。
CodeBuildのプロジェクトでは、Secrets Managerに保存されている情報を、環境変数として取り込むことが可能です。
CodeBuildでプロジェクトを実行する際にPATを環境変数として読み込むことで、安全にGithubへのアップロードを行うことができます。

では、Personal Access Token (PAT) を Secret Manager に保存します。
「新しいシークレットを保存する」を選択します。

「その他のシークレットのタイプ」を選択します。
任意のキー名を付与し、値にPAT を登録します。

「シークレットの名前」を記入し、シークレットを作成します。
「/CodeBuild/」から始まる名前を使うと、CodeBuildのプロジェクトを作る際に自動生成されるサービスロールから、そのシークレットを参照することができます。検証のため、本記事のCodeBuild のプロジェクトでは自動生成のサービスロールを使用しています。

「シークレットの ARN」と「シークレットキー」を確認します。

「シークレットの ARN」と「シークレットキー」を「:」で繋ぐ形でメモしてください。

<シークレットの ARN>:<シークレットキー>
例:
arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:/CodeBuild/Test/GITHUB_PAT_Terraform-o7iZKr:GITHUB_PAT_Terraform

Secret Manager に保存した PAT を CodeBuild プロジェクトの環境変数に設定する

CodeBuild プロジェクトの「環境」セクションを「編集」します。

「環境変数」の「名前」に環境変数名を記入し、「値」にはメモした「<シークレットの ARN>:<シークレットキー>」を記入します。
「タイプ」は「Secrets Manager」とします。

CodeBuild プロジェクトの環境変数を buildspec.yml で参照し、GitHubのリポジトリにアップロードを行う

buildspec.yml を以下としました。

version: 0.2
phases:
  pre_build:
    commands:
      - ls -lat
      - cat .git/config
      - git config --global user.name "My name is Yamamoto. Also known as Yamamoto"
      - git config --global user.email "yamamoto.yamamoto@yamamoto.jp.yamamoto"
  build:
    commands:
      - touch "test_file.txt"
      - git add "test_file.txt"
      - git commit -m "add test_file.txt"
  post_build:
    commands:
      - git push https://${GITHUB_PAT_Terraform}@github.com/yamazoon0207/test-terraform.git main:main

内容を補足します。

  1. pre_buildフェーズ
    • gitのユーザー名とメールアドレスを設定します。
  2. buildフェーズ
    • "test_file.txt"という名前の新しいファイルを作成します。
    • "test_file.txt"をgitに追加します。
    • "test_file.txt"の追加をコミットします。
  3. post_buildフェーズ
    • 変更をmainブランチにプッシュします。

16 行目でCodeBuild プロジェクトの環境変数を ${GITHUB_PAT_Terraform} という記述で参照しています。
https://${GITHUB_PAT_Terraform}@github.com/ユーザー名/リポジトリ名.git という形式の URL を用いて、PAT の認証情報を使用して Github にアップロードしています。

結果、 Github にアップロードが成功しました。

【補足1】buildspec.yml ファイル内で AWS Secrets Managerに保存されている秘密の情報を取得し、環境変数として利用する

CodeBuild プロジェクトの環境変数を設定せずに、buildspec.yml ファイル内で環境変数を設定することもできます。
2〜4 行目で環境変数 PAT を定義し、20 行目で ${PAT} という記述で参照しています。

version: 0.2
env:
  secrets-manager:
    PAT: /CodeBuild/Test/GITHUB_PAT_Terraform:GITHUB_PAT_Terraform
phases:
  pre_build:
    commands:
      - ls -lat
      - cat .git/config
      - git config --global user.name "My name is Yamamoto. Also known as Yamamoto"
      - git config --global user.email "yamamoto.yamamoto@yamamoto.jp.yamamoto"
  build:
    commands:
      - touch "test_file2.txt"
      - git add "test_file2.txt"
      - git commit -m "add test_file2.txt"
  post_build:
    commands:
      # - git push https://${GITHUB_PAT_Terraform}@github.com/yamazoon0207/test-terraform.git main:main
      - git push https://${PAT}@github.com/yamazoon0207/test-terraform.git main:main

4 行目にあるように、AWS Secrets Managerで管理しているシークレットは、「<シークレットの名前>:<シークレットキー>」という形式で参照できます。
ただし、これは同じAWSアカウント内のシークレットの場合のみです。
異なるAWSアカウントのシークレットを参照する場合には、そのシークレットのARN(Amazon Resource Name)が必要になります。
ただし、ARNを buildspec.ymlに直接書くと、そのファイル内にAWSアカウントIDなどの情報が含まれてしまいます。そのため、セキュリティ上の観点からは、ARNをCodeBuildのプロジェクト設定の環境変数として設定する方がより安全です。
さらに、buildspec.ymlファイル内にシークレットの参照設定を書くと、そのファイルを見るだけでAWS Secrets Managerを使用して情報を管理していることが分かってしまいます。このことがセキュリティ上問題となる可能性もあるため、多少の注意が必要です。しかし、公式の資料では特に非推奨にはなってはいません。

【参考】環境変数の優先順位

CodeBuildのプロジェクトに設定する環境変数と、buildspec.yml ファイル内での環境変数では優先順位が異なります。 そのため、競合しないように気をつける必要があります。 以下の優先順位となります。

  1. ビルドプロジェクトの開始時に設定する環境変数
  2. ビルドプロジェクトにあらかじめ設定する環境変数
  3. buildspec内の環境変数

ご参考:CodeBuild のビルド仕様に関するリファレンス

ビルド開始オペレーション呼び出しの値が最も優先順位が高くなります。ビルドの作成時に環境変数を追加または上書きできます。詳細については、「AWS CodeBuild でのビルドの実行」を参照してください。

ビルドプロジェクト定義の値が次に優先されます。プロジェクトを作成または編集するときに、プロジェクトレベルで環境変数を追加できます。詳細については、「 でのビルドプロジェクトの作成AWS CodeBuild」および「AWS CodeBuild でのビルドプロジェクトの設定の変更」を参照してください。

ビルド仕様宣言の値の優先順位が最も低くなります。

【補足2】CodeBuildプロジェクトを実行した際の出力やログに、Secrets Manager から取得した環境変数の内容が表示されるのではないか?➡️されません!

echo をしても *** と表示されます。

printenv は ステータスコード 1 のエラーになります。

Systems Manager パラメータストアとAWS Secrets Managerから取得した値は非表示になるようです。

ご参考:AWS CodeBuild でのデータ保護 - AWS CodeBuild

機密情報を保護するために、ログでは以下が非表示になっています CodeBuild 。

CodeBuild プロジェクト環境変数の Parameter Store または buildspec env/parameter-storeセクションを使用して指定された文字列。詳細については、Amazon EC2 Systems Managerユーザーガイドの「Systems Manager パラメータストア」および「Systems Manager パラメータストアコンソールのチュートリアル」を参照してください。

CodeBuild プロジェクト環境変数または buildspec env/secrets-managerセクションAWS Secrets Managerで を使用して指定された文字列。詳細については、「キー管理」を参照してください。

【補足3】CodeBuildのプロジェクトを作る際に自動生成されるサービスロール

CodeBuildのプロジェクトを作る際に自動生成されるサービスロールでは、「/CodeBuild/」から始まる名前を使う Secrets Manager のシークレットを参照することができます。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "secretsmanager:GetSecretValue"
            ],
            "Resource": [
                "arn:aws:secretsmanager:<CodeBuildプロジェクトの存在するリージョン>:<CodeBuildプロジェクトの存在するAWSアカウント番号>:secret:/CodeBuild/*"
            ]
        }
    ]
}

最小限の権限を付与する場合には、Resource セクションを変更すると良いでしょう。

まとめ

CodeBuildプロジェクトを使用して、GitHubのリポジトリをダウンロードし、その中のファイルを更新し、再度アップロードする方法を紹介しました。

余談

2 月の終わりから 3 月の初めにかけて、大量の降雪があり、富士山が綺麗です。
西伊豆の達磨山より。

山本 哲也 (記事一覧)

カスタマーサクセス部のエンジニア(一応)

好きなサービス:ECS、ALB

趣味:トレラン、登山(たまに)