kazasiki's blog

プログラミングとかVRゲームとか

AWS Codecommit の認証どうする問題

最近は仕事で AWS CodecommitというAWSのGitリポジトリのサービスを使っています。正直Githubのほうが便利だと思うのですが、お金とかセキュリティとか色々大人の事情があるので仕方ないですね。

で、今回はそのCodecommitへの認証方法の話です。Codecommitの方法は概ね4つあります。

  1. SSH
  2. HTTPS
  3. git-remote-codecommit
  4. aws cli の credential-helper

1と2はgithubなどでもあるので見慣れたものだと思います。特に難しいこともありません。問題は3と4でこいつらが曲者です。

先に結論を書いておくと3はお勧めしません。4をお勧めしますが、公式ドキュメントには罠があるのでその回避方法をお伝えします。

git-remote-codecommitの場合

docs.aws.amazon.com

公式ドキュメントには以下の記述があります。

ルートアカウント、フェデレーティッドアクセス、または一時的な認証情報を使用して CodeCommit に接続する場合は、git-remote-codecommit を使用してアクセスを設定する必要があります。

AWSではユーザ管理用のAWSアカウントのユーザから特定の案件/サービスのAWSアカウントにswitch roleして使うというのがよくあるパターンです。そういった仕組みの上でCodecommitの権限を利用する場合は、git-remote-codecommitが必要になります。

これはgitのcredentials.helperの機能を利用しています。ざっくりいうとgitリポジトリにアクセスする際の認証時に、通常の認証をする代わりに特定のインターフェースのコマンドを実行する機能です。

大体の使い方は↑に貼った公式Documentにも書いてありますが

  1. 予めgit-remote-codecommitというpythonで書かれたコマンドをローカルにインストールします。
    pip install git-remote-codecommit
  2. 次に、git clone時にURLを指定するときのプロトコルの部分をcodecommitとしています。
    git clone codecommit://MyDemoRepo my-demo-repo

これだけです。

もうちょっと書くと、リポジトリのURLのプロトコル部分がcodecommitになっている場合、gitコマンドはgit-remote-codecommitコマンドを探しに行きます。で、git-remote-codecommitはAWS CLIと同じように~/aws/configを読んで、一時的な認証情報の取得を済ませてくれます。

とても親切な機能に見えますが、落とし穴があります。

pythonおよびpip installしたライブラリを実行しているということです。CUIのターミナルからgitを扱うときは(多分)問題ないですが、エディタの拡張機能GUIツールから使う場合は、環境変数などによってどのgitおよびpythonが動くのかわかりづらい場合があります。GUIツールによっては環境変数周りが把握/変更出来ない場合もあります。(そもそもGUIツールを使っている人たちにそこまで求めるのが酷な場合もあります。)

pythonを普段から使っている場合でもそうでない場合でも、このツールためにpythonの環境を弄るのはちょっと面倒です。

aws cli の credential-helper の場合

docs.aws.amazon.com

公式ドキュメントには以下の記述があります。

ただし、ルートアカウント、フェデレーテッドアクセス、または一時的な認証情報を使用して CodeCommit に接続する場合は、AWS CLI に含まれている認証情報ヘルパーを使用できます。

というわけで、こちらもgit-remote-codecommitと必要になるケースは同じです。私はこちらの方法を推します。

とはいえ、↑の公式ドキュメントではちょっとイケてない記述があります。以下です。

git config --global credential.helper '!aws codecommit credential-helper $@'
git config --global credential.UseHttpPath true

気軽にGitのglobal設定を変更させるんじゃない!

Codecommit以外のgitも一緒に使っている人がいたら問題が起きること請け合いです。

自分は以下の設定をおすすめします。リュージョンはap-northeast-1以外なら適宜書き換えてください。

  1. ローカルのgitで以下を実行。codecommitにつなぐときにhttpPathを使うようにする。
    git config --global credential."https://git-codecommit.ap-northeast-1.amazonaws.com".UseHttpPath true
  2. git cloneするときに以下を実行。
    git clone -c credential.helper= -c credential.helper='!aws --profile XXXXX codecommit credential-helper $@' https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/my-demo-repo

UseHttpPathをGlobalのConfigにしていますが、ホストを指定しているので他のGitリポジトリにはほぼ影響はないでしょう。気になるならこれも個別のリポジトリの.git/configに書いてください。で、各リポジトリのcloneするときにprofileを含めてcredential.helperを指定します。いろんなAWSアカウントがあるならプロファイル名も異なるでしょう。これでcloneすればリポジトリの.git/configのcredential.helperにも書き込まれるので後から変更する必要はありません。

GUIツールからgit pullなどをする場合も.git/configを読み込んでちゃんと動きます。ツールによってAWS CLIが見つけられない場合もあるので、その場合は、 !aws ではなく絶対パスを指定してください。

ちなみに、git-remote-codecommit sourcetree とかでググると、「git-remote-codecommitをつかってcloneして、SourceTreeからpull出来ない場合は.git/configに↑で挙げたような内容を書く」というのがちらほら引っかかりますが、なんというか普通に二度手間な気がします。

.gitconfig周りがわかっていればなんでもないことですが、意外に苦労するところでもあるのでメモ程度に書き残しておきました。誰かの参考になれば幸いです。

追記&修正 (2021/11/02)

記事中のgit cloneの例を修正しました。一言でいうと、 -c credential.helper= を追加しました。

  • 修正前
    git clone -c credential.helper='!aws --profile XXXXX codecommit credential-helper $@' https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/my-demo-repo
  • 修正後
    git clone -c credential.helper= -c credential.helper='!aws --profile XXXXX codecommit credential-helper $@' https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/my-demo-repo

説明を以下に追記します。

Macの場合はgitのデフォルトの認証手段にKeychainが設定されていて、パスワードがexpireして403になるらしいので以下の対応が必要な場合があります。

docs.aws.amazon.com

OS X および macOS でリリースされているデフォルトバージョンの Git では、Keychain Access ユーティリティを使用して、生成された認証情報を保存します。セキュリティ上の理由により、CodeCommit リポジトリへのアクセス用に生成されるパスワードは一時的なものであり、約 15 分後にキーチェーンに保存されている認証情報は機能しなくなります。

Macのデフォルトのgitだと、 ~/.gitconfig (globalのgitconfig)に以下の記述があります。

[credential]
    helper = osxkeychain

gitの挙動としては、

  • ~/.gitconfig にホスト名が指定されてないcredential.helperの設定が書いてある
  • 個別リポジトリの .git/config にホスト名が指定されたcredential.helperの設定が書いてある

という状態だと、前者のほうが優先されるようです。正確には前者で認証の取得を試して、それに失敗した場合は後者を試すようです。403で落ちるということは認証的には失敗しているのですが、認証情報の取得自体は成功しているので前者だけで処理が終わってしまいます。

その辺りの細かい仕様はgitドキュメントをご参照ください

上で示したAWSのドキュメントでは3つの解決策が提示されています。

  1. credential(ホスト名なし)にosxkeychainが設定されているのを消す
  2. 消しはしないが、具体的なgithubなどのホスト名を指定して、codecommitアクセス時に動作しないようにする。
  3. codecommit用のcredential(ホスト名あり)のところで、空文字のヘルパーを設定する

私のオススメは3番です。

1と2についての解説は不要だと思います。3について補足すると、gitは空文字のhelperを指定された場合、ヘルパーの候補リストを一旦消すという挙動を取ります。なので、個別リポジトリの方からヘルパー設定を上書きしたい場合はこの対応が一番順当です。

記事中の修正もそのように行いました。