bauer's diary

凡人の凡人による凡人のための備忘録

GitHubの2段階認証におけるプロトコル最適解を考える

なに?

cloneしたときに選択したプロトコルが、ローカルGit設定の remote url にそのまま設定されるのですが、
そもそもプロトコルは何を選べばいいのか、ベストプラクティスは何かを検討します。

前提

現場では2段階認証が必須となっているので、前提項目とします。
2段階認証にしておけば、パスワードが盗まれても安全なので推奨します。

プロトコルの種類と速さ

まずプロトコルの種類は下記の3つです。

  1. git
  2. https
  3. ssh

そしてcloneの速さは下記の順番です。
git > https >> ssh

これだけ見れば "gitプロトコルでいいのでは?" となるのですが、そうもいかない事情があります。

git プロトコル

gitプロトコルは read-only のため、そのままではpushできません。
また、社内proxyを経由していて gitプロトコルで使う9418ポートがFWなどで制限されている場合は使えないので、その場合は他のプロトコルに変更する必要が出てきます。

尚、gitプロトコルは現在GitHubのヘルプ上では言及されていませんが、利用可能です。

https プロトコル

f:id:kitakitabauer:20170219015533p:plain
httpsプロトコルの場合、通常はpushのたびにユーザ名/PWによる認証が必要になりますが、2段階認証の場合、PWの代わりにGiHubの設定画面から発行するPersonal Access Tokenが必要となります。

Personal Access Tokenの発行手順は公式ヘルプにあるとおりです。
尚、credential helperを導入すればキャッシュしてくれますが、キャッシュが切れたら再度入力する必要があります。

ssh プロトコル

f:id:kitakitabauer:20170219015440p:plain
ssh は鍵認証です。
clone 後のメリットとして、push のときに ssh-agent や pageant が、パスフレーズの入力を代行してくれるので便利ですが、前述したとおり最も遅いプロトコルとなります。


開発上、sshプロトコルが楽ですが、速さも求めたい。
そんなときどうすればよいのでしょうか。

結論

下記手順を踏むことによって、
cloneは最速のgitプロトコルで clone し、
pushではsshプロトコルによってパスフレーズを求められることなくpushできます。


指定したurlに対して他のプロトコルを使うようにgitconfigに定義します。

[url "git@github.com:"]
  pushInsteadOf = git://github.com/
  pushInsteadOf = https://github.com/
[url "git://github.com/"]
  insteadOf = https://github.com/

この設定によって、"https:" や "git:" を使っていても git push のときには ssh 経由になります。

git fetch や git pull の時は "https:" の代わりに "git:" を使用します。
尚、git configでは"pushInsteadOf"の部分が一つずつしか設定できないため、直接ファイルに追記しました。

また、ssh/configに下記設定を追加すれば、sshのcloneが高速化するので、
間違ってsshでcloneしたときのために設定しておくとよいかと思います。

Host github.com
  Compression yes
  Ciphers arcfour128,arcfour,aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc

Ciphersで利用する暗号方式を指定します。左から順に利用を試みます。

検証

それでは設定を検証してみます。

まずgitプロトコルでcloneします。

% git clone git://github.com/kitakitabauer/clone-sample.git
Cloning into 'clone-sample'...
remote: Counting objects: 51, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 51 (delta 0), reused 0 (delta 0), pack-reused 48
Receiving objects: 100% (51/51), 10.82 KiB | 0 bytes/s, done.
Resolving deltas: 100% (6/6), done.

リモートURLを確認すると、"fetch" ではgitプロトコルが、
"push" ではsshプロトコルが設定されていることがわかります。

% git remote -v
origin	git://github.com/kitakitabauer/clone-sample.git (fetch)
origin	git@github.com:kitakitabauer/clone-sample.git (push)

問題なくpull/pushできます。

% git pull -v
Looking up github.com ... done.
Connecting to github.com (port 9418) ... 192.XX.XXX.XXX done.
From git://github.com/kitakitabauer/clone-sample
 = [up to date]      master     -> origin/master
Already up-to-date.

% git push -v
Pushing to git@github.com:kitakitabauer/clone-sample.git
To github.com:kitakitabauer/clone-sample.git
 = [up to date]      master -> master
updating local tracking ref 'refs/remotes/origin/master'
Everything up-to-date

リポジトリ内の .git/config にも反映されています。

[remote "origin"]
	url = https://kitahara-yuki@github.com/kitakitabauer/go-sample.git
	fetch = +refs/heads/*:refs/remotes/origin/*



おしまい