GitHubのprivate repositoryを含んだ場合のGo Modules管理
tl;dr
- CI/CD環境から複数のGitHubのprivate repositoryにアクセスさせたい場合にはmachine account(machine user)を使うと良い
- SSH KeyでもAPI tokenでもどちらでも良いけどSSH方式がGo公式repoでも紹介されている
- CircleCIだとSSH Keyの設定(User Key)が簡単でその他の設定がほとんど不要
本題
Goに限った話ではありませんが、プロジェクトで使っているprivate repositoryからまた別のprivate repositoryを参照している場合、CI/CDなどの外部環境からどのようにそれらにアクセスさせるか困ることがあります。
例えば、git submoduleを使っている場合や、Goの場合ですとGo Modulesで指定しているパッケージがprivate repositoryである場合などがあるでしょう。
なぜ困るのかと言うと、GitHubの場合、CI/CD環境からprivate repositoryのリソースにアクセスさせる場合、repositoryにRead-only deploy keyを設定して使う方法が個人にも依存せず、アクセス権限を絞る上でも望ましく、一般的に利用されますが、このDeploy Keyを複数のrepositoryで共有することができないという仕様上の制約があるため、複数のprivate repositoryをcloneしようとすると途端に困ってしまうからです。
どうするか
Deploy Keyが使えない以上、個人ユーザーのSSH Keyか、API tokenを利用するしかありません。しかし、個人のものを使ってしまうと、個人に依存してしまいますし、自分の全てのprivate repositoryにアクセス可能になってしまいます。これでは困る。
ここでも、前回の記事でも取り上げた、"machine account"を活用します。
そういった用途に関して、GitHubのDeveloper Guideにも"Machine users"という項でドンピシャで説明されています。ここでは、accountではなくusersになっています。
ref. https://developer.github.com/v3/guides/managing-deploy-keys/#machine-users
Machine userを作成し、最小限必要なrepositoryのみにREAD権限を与えることで権限を絞ることができます。そのアカウントを複数人で管理すれば個人に依存することもありません。
Goの場合
GoのModulesの場合、対象のpackage repositoryをhttpsスキームのURLで取得しようとするため、取得時にそれを insteadOf で書き換えてやるのが基本戦略になります。
SSHを利用する場合
% git config --global url."ssh://git@github.com/<myorg>/".insteadOf "https://github.com/<myorg>/"
personal access tokenを使う場合
% git config --global url."https://${user}:${token}@github.com/<myorg>/".insteadOf "https://github.com/<myorg>/"
SSHかaccess tokenか
CI/CD上で利用する時、tokenの設定をする方法だと、うっかり画面の実行ログ上でtokenが見えてしまうリスクがあるかも知れません。またSSHを使う方法のほうが、GitHub固有の設定にもならないため、SSH KeyをCI/CD環境上に安全に設定する方法があるのであれば、そちらのほうが良さそうです。
Go公式の以下のissueでも特定のソースホスティングサービス用の設定を持たせられるようにできないか議論されていますが、やはり、sshでinsteadOfを使う方法が現状の対応案として紹介されています。Russ Cox氏もコメントしていますね。
https://github.com/golang/go/issues/26134
CircleCIだとSSH方式がより簡単
CiecleCIは標準でprivate repositoryにDeploy Keyを自動登録することで、repositoryのリソースアクセスを実現しています。
これでは冒頭に述べたように、単一private repositoryのリソースしか取得できないため、CircleCIにはそれを回避するために"User Key"を簡単に設定する機能が備えられています。公式ドキュメントの "Controlling Access Via a Machine User" という項にそれが書かれています。
ref. https://circleci.com/docs/2.0/gh-bb-integration/#controlling-access-via-a-machine-user
これはCircleCIがOAuth経由でGitHubユーザーにSSH Keyを自動的に登録する方法で、CircleCIはそのSSH Keyを使って、repositoryのリソースにアクセスするようになります。
これは少し怖いので、やはり、個人ではなくMachine userでやるべきでしょう。 一度、SSH Keyが登録されたあとは、その認可は念の為revokeしておいた方が良いでしょう。GitHubの個人設定のApplications -> Authorized OAuth Apps からrevokeできます。 revokeするとSSHキーも根こそぎ消えるみたいで駄目でした。セキュリティ的には正しい挙動…。
Go Modulesの依存取得
ここまでくればあとは簡単です。checkoutディレクティブを使えば、repositoryを取得できますが、この時、前項のSSH Keyを自動的に使い、insteadOfの設定も以下のように暗黙的にやってくれています。
% git config --global url."ssh://git@github.com".insteadOf "https://github.com"
あとは、private repositoryはmachine userの権限の範囲で取得できますし、Go Modulesの依存取得もinsteadOfの設定がされているため、go mod download
とかでうまいことやってくれます。
まとめ
ということで、GitHubのMachine userとCircleCIのSSHのUser Keyを利用すれば、複数のprivate repositoryの取得が容易になり、privateなGoパッケージの取得も同様に簡単になります。