2017-04-17

GitHub/BitbucketからAccess Tokenを使ってdeployする

あるいはサーバ上で private package を bundle(npm) install したい。

課題

今回の課題はこれ。

private な repos をサーバ上で clone したい

もう少し詳しく書くと直接の git clone もそうだし、bundle install や npm install で private repos から package を install したいが、もちろん

秘密情報は repos に入れたくない

というものである。

※ Access Tokenが使えれば他のサービスでもサーバでもよい。

解決方法

  1. 環境変数と.netrcを使う
  2. 環境変数と動的なURL書き換えを使う

1. 環境変数と.netrcを使う

この方法を知ったきっかけはこれ。

timshadel/heroku-buildpack-github-netrc: Heroku buildpack to access private Github repos over HTTPS without storing user/pass in your files.

やってることは、

  • 環境変数にトークンを保存
  • build 時に環境変数から ~/.netrc に保存し、git の機能で ~/.netrc の情報で認証を通す

これで確かにリポジトリに認証情報を残さずに private repos から clone できる。

もちろん token の権限設定は必要最小限にしておこう。

サーバ上の環境変数設定を簡単に行える環境ならこれが楽だと思う。

2. 環境変数と動的なURL書き換えを使う

Capistrano で clone することで deploy する際には上とは異なる方法を利用することにした。

Easier builds and deployments using Git over HTTPS and OAuth

の情報をもとに Capistrano を叩く環境に変数でトークンを保存したうえで URL を

set :repository, "https://#{fetch(:github_auth_token)}:x-oauth-basic@github.com/{user}/{repos}"

と、cap を叩く時に書き換える。Gemfile や package.json がないならこの方法も使える。

※ Gemfile や package.json がある場合は頑張って上の buildpack と同じようなことをしてあげることになると思う。

手元の環境からも deploy したい場合は dotenv のようなものを使うか、.netrc に情報を保存するのもアリ。Capistrano 側のコードはこんな感じになる。

set :github_auth_token, ENV['GITHUB_AUTH_TOKEN'] || Netrc.read['github.com']['login']

..netrc を読み書きできる便利 gem はこれ。

heroku/netrc: Reads and writes netrc files.

なぜ他の方法ではないのか?

ここから先はちなみに情報。

Git 自体が対応している認証情報の保存方法がいくつかある。最近では自分で手で作業する場合はこのうちのいずれかを利用しているケースが多いと思う。

Git - 認証情報の保存

によると

  • cache (15分だけメモリに保存)
  • store (永続的にファイルに保存)
  • osxkeychain (macのkeychainアプリにパスワードを保存)
  • wincred (Windowsのkeychainのようなもの)

の4つに対応している。

ただしこれらは、人間がパスワードを入力しその認証情報を保存する、という流れを想定しており、Coutinuous Deployment で利用するにはイマイチである。

Git でパスワードを入力せずに push / pull するということでロートルがすぐに思いつくのはパスフレーズなし鍵認証の ssh を使う方法である1が、今回行おうとしているのは

サーバ上で git clone や bundle install や npm install したい

ということであり、サーバ上に余計なものは入れたくないし、まして Heroku などの PaaS 上では採用できない方法である。(deploy用の公開鍵を保存する機能はあっても秘密鍵を保存する機能が存在しなかったりする。)

なぜ.netrcで可能なのか?

最後になるけど、なんか普通に .netrc って言ってるけど、そもそもこれ何?って話。

  • git は http での転送の際に cURL を利用している
  • cURL は .netrc に対応している

..netrc って古の ftp ですよね?ってぼくは思っていたのですが、cURL 力不足ということのようでした。(実は cURL あまり好きじゃなかった)

cf.

Man page of NETRC

  1. なぜなら Git で http での push / pull が使いものになるのは 1.6.6 で登場した Smart HTTP が使えるようになる 2009年以降の話であり、それまでは CVS や Subversion でもおなじみだった ssh と組み合わせる方法の方がポピュラーだったのだ。 

About

例によって個人のなんちゃらです