世界線航跡蔵

Mad web programmerのYuguiが技術ネタや日々のあれこれをお送りします。

2015年06月07日

Automation Accountパターン

コンテキスト

あなたが開発しているサービスはユーザー向けにAPIを提供している。そして、APIを利用するにはユーザーは短寿命の認可情報(たとえばOAuth2トークン)を提示しなければならない。

ユーザーは認可情報が紐付いているアカウントの権限でリソースを読み取ったり、作成したり、所有したり、編集または削除したりする。 ここで、ユーザーは人間(が操作するユーザーエージェント)であることもあるが、人間の手を離れてバックグラウンドで自動実行されるプログラムかもしれない。

また、あなたは悪用目的でアカウントが大量登録されるのを防ぐためにCaptchaを利用したいと思っている。 さらに、課金目的で請求書送付先を登録させたいとも思っているかもしれない。

問題

プログラムが利用するアカウントを安全に管理するのがユーザーにとって困難である。

プログラムは自分でCaptchaを解いたりEメールを受け取るのが苦手だし(そうでないとCaptchaの意味がない)、 また郵便物で請求書を受け取って銀行に振り込みに行くのは更に苦手である。 よって、プログラムが利用するアカウントを作成し、管理し、対応する請求書を処理するのは人間(か、少なくともそれ専用の別のシステム)でなければならない。

ではその人間はどのようにそのプログラムが利用するアカウントを管理すれば良いのか。幾つかの簡単な解決策を思いつくが、いずれも十分とは言えない。

人間のアカウントを使い回す

プログラムを管理しているチームの誰かのアカウントを使う、という解決法。

しかし、個々の人間は自動プログラムを管理ししているチームを離れることがある。このアカウントを所有していた人物がいなくなると、 アカウントの元に所有されていたリソースは消滅したり、アクセスが制限されたりする可能性がある。 最低でも、そのアカウントの認可情報を更新するのは困難となる。

プログラム専用のアカウントを共有する

人間用のアカウントを作るのと同様にして、人間がプログラム専用のアカウントを作成する。そしてそのアカウントをプログラムに利用させる、という解決法。 アカウントは自動プログラムを管理する人間たちによって共有されており、たとえ誰かがチームから居なくなっても 他の者がアカウントの管理、認可情報の更新などを行える。

しかし、これもまた十分とは言えない。人間たちはアカウントを管理するためのパスワードなどの認証情報を共有しなければならないが、 その周知の情報をいつ誰が利用したのか監査記録を付けるのは大きなチームでは難しい。 また大きくなるほど認証情報漏洩のリスクは高まって適時の更新が必要とされるが、大きくなるほど更新したという事実を全員に伝えるのも難しい。 苦労してこれらの問題を解決したところで、誰かが開発用にアカウントを作ったが良いが周知するのを忘れたままチームを去って、結局誰も管理できないアカウントになったりするのもありがちな問題である。

更に、セキュリティ上はプログラム専用アカウントは最小限の権限を持つのが望ましいが、最小化するために権限ごとにアカウントを設定すると 管理すべきアカウントの数が増えて管理にまつわる問題は酷くなっていく。

具体例

1. Github - Travis連携

システム
github
リソース
プライベートリポジトリ
アカウント
githubアカウント
短寿命認可情報
githubのOAuth2 token
管理のための認証情報
githubのパスワード
自動化プログラム
travisによるビルドプロセス

2. クックパッド - AWS

システム
Amazon Web Services
リソース
S3 bucket
アカウント
AWSアカウント
短寿命認可情報
AWSアクセスキー
管理のための認証情報
AWSパスワード
自動化プログラム
料理の画像をアップロードする機能

解決策

自動化プログラム用のアカウント種別(Automation Account)を作って、人間用のアカウントとは区別する。 また、Automation Accountには管理用のパスワードを割り当てず、代わりに「このAutomation Accountを管理できる人間用アカウントのリスト」を対応させておく。

人間たちは自分自身の人間用アカウントでログインするだけで(リストに載っていれば)Automation Accountを管理できる。 このため、Automation Accountのパスワードを共有する必要はない。 それどころか、プログラム用のアカウントはどうせ人間の誰かが自分のアカウントで管理するのだからAutomation Accountにはパスワードがなくても差し支えない。

Automation Accountの図解

実現例

1. Google Cloud Platform (GCP)のサービスアカウント

GCPのAPIが提供するほとんどのリソースは「プロジェクト」という単位に所属する。

ユーザーアカウントはプロジェクトとは独立したアカウント(GmailアカウントまたはGoogle Apps for Workアカウント)で、 任意の数のプロジェクトに読み取り専用、書き込み可、またはオーナーとして参加できる。

これに対してサービスアカウントはプログラム専用のアカウントで、ただ1つのプロジェクトに一意に属し、プロジェクトが削除されると他のリソースと同様サービスアカウントも削除される。

サービスアカウントはログイン用のパスワードを持たないためWebページのログインには利用できず、OAuth2トークンを用いてプログラムからAPIを呼ぶためにしか利用できない。 サービスアカウントを管理するには、そのプロジェクトのオーナーになっている人間のアカウントを利用する。

課金先情報はプロジェクトごとに登録管理される。サービスアカウントであれ一般のユーザーアカウントであれ、プロジェクト内のリソースに対する操作はプロジェクトに対して課金される。

Service Accountの図解

2. AWS Identity and Access Management (IAM)

APIが提供するリソースは特定のAWSユーザーアカウント(rootアカウント)に属する。

権限を分割するために、ユーザーアカウント内に任意個のIAMアカウントを作成できる。 IAMアカウントはパスワードを設定して人間に割り振ることもできるし、パスワードを与えないでおいてプログラムに利用させることもできる。 プログラム用のIAMアカウントを管理するためにwebコンソールにアクセスする場合は、パスワードを割り振られた人間用のIAMアカウントまたはrootアカウントを利用する。

課金情報はrootアカウントごとに登録管理される。IAMアカウントが利用したリソースはその属するrootアカウントに対して課金される。

IAMの図解

2つの実現例を比べてみよう。

GCPのアプローチは一個人が趣味で開発しているような小規模開発においても、開発者のアカウントの他にプロジェクトという単位を作成する必要があるのでやや煩雑である。 一方AWSのアプローチは個人の小規模開発であれば人間用にはIAMアカウントを発行せず、rootアカウントだけですべてを済ませることも可能なので単純である。

大規模な場合に目を移すと、AWSのアプローチはrootアカウントそれ自体がユーザー名とパスワードを持つアカウントであるため、守るべき対象が1つ多い分だけほんの少しセキュアでない。 またそもそもこのrootアカウントのパスワードをどう管理するかという点において上記と類似の問題が残されたままである。 これに対してGCPでは、この通常使われることのない余分な認証情報はそもそも存在しないのでセキュアである。

トラックバック

http://yugui.jp/articles/891/ping

現在のところトラックバックはありません

コメント閲覧/投稿

2015年05月04日

grpc-gateway更新

先日公開したgrpc-gatewayだが、gRPCのメーリングリストで宣伝したらGoogleからフィードバックがあったので対応した。

実はGoogleは社内にgrpc-gatewayに似た仕組みを持っていて、RESTful APIとgRPCの変換にはそれを使っている。 んで、今回Googleはその変換の設定に使っているスキーマを<URL:https://github.com/google/googleapis/tree/master/google/api>に公開してくれたのだ。

これを受けてgrpc-gateway独自のカスタムオプションを捨ててGoogleが公開したオプションを使うことにした(grpc-gateway#12)。これには幾つか理由がある。

  • Googleの長年の経験を踏まえて設計された語彙のほうが、私がとりあえずプロトタイプとして適当に設計した語彙より拡張性と十分性において信頼に足る
    • 実際、Googleのカスタムオプションのほうが表現できる幅は広い
  • 似たようなスキーマがいくつもあるとユーザーとっては不便であるから統一した方が良い。
    • Googleの既存資産を変更させて統一するよりは、こっちのプロトタイプ段階のgatewayを変更した方が早く確実に統一できる。

なお、古い独自オプションのサポートはバッサリ切り捨てた。

それから、HTTP Request pathのテンプレートの文法もちょっと複雑になって従来のgojiのルーティング設定に頼る方式では限界が来たので、 独自にtemplate parserと実行時にマッチするためのスタックマシンを書いた。 ASTそのままでInterpreterパターンすれば十分かとも思ったのだが、よく考えたらparseするのはgatewayのコードを生成するときで、パターン照合が走るのはgatewayのコードが実行される時だ。 よってparse結果を何らかの形でgatewayのソースコードとして保存しなければならないのだが、ASTを表すGoの式を生成しつつ将来の拡張もできる符号化とかも考えると面倒になってきたので スタックマシンのopcodeとして符号化することにしてしまった。 Railsの経験からもルーティングはボトルネックになりがちなので、この意味でもASTを再帰的に辿るよりはopcodeでloop + switchのほうが良いかもしれぬ。

トラックバック

http://yugui.jp/articles/890/ping

現在のところトラックバックはありません

コメント閲覧/投稿

2015年04月07日

gRPC-JSON proxy

grpc-gatewayというgRPCからJSON APIへの変換プロキシ生成機を書いた。 これを使えばシステム内部ののmicroservicesはgRPCで通信しつつ公開APIはJSON APIで提供する、みたいなことが簡単になる。

なお、gRPCそのものについてはmattnさんの記事が参考になる。

背景

gRPCの良い点はいくつもある。

  • データはデフォルトでprotocol buffersで直列化される。ベストではないにせよ十分にコンパクト且つ高速だし、サイズで言えばJSONとは比べるべくもない。
  • 簡単に複数の言語でサーバーのテンプレートやクライアントを生成できる。通信の詳細はgRPCにまかせて開発者はサーバーロジックの実装に注力できる。
  • design by Googleという安心感。

gRPCの素晴らしさは認めるものの、一方では欠点もある。まず、クライアントライブラリの多くはCで書かれたバイナリ拡張を含む。 これはRuby界ではあまり歓迎されていないし、多くのユーザーにAPIを使ってもらうということを考えればどうしたってクライアントは利用言語ネイティブで書かれていた方が良い。 また、そもそもgRPCはまだそんなに普及していない。gRPCがサポートしていない言語だってなくはない。

だからコントロールの効く範囲のシステム内部の通信にgRPCを使うのは極めて妥当な選択だが、現時点で公開APIをgRPCだけで提供するっていう決断はAPI提供者としてはなかなか勇気が要る。

だったら公開APIはJSONのままでいきたいというのは自然な発想だ。 gRPCのJSONシリアライゼーション機能を使っても良いのだけど、それでもHTTP 2.0必須だし、呼び出しパスもちょっと独特なのでちょっとまだ敷居が高い。

そこで、コモディティとしての従来型のRESTful JSON API over HTTP 1.xがやっぱり必要なわけだ。grpc-gatewayはgRPCで書いたサービスを簡単にそうしたRESTful JSON APIに変換してくれる。

実装

grpc-gatewayはgRPCそのものと同じく、protoc (protocol buffers compiler)のプラグインとして実装されている。 gRPCサービスを定義してある.protoファイルに専用のカスタムオプションでちょっとだけ情報を足すと、protoc-gen-grpc-gatewayプラグインがgRPCとJSON APIを仲立ちするreverse proxyを生成してくれるようになる。

カスタムオプションには次のような情報を指定できる

  • path: このメソッド呼び出しをマッピングするHTTP requestのpath
  • method: 同じくHTTP method
  • description: 備考

生成されるproxyはgolangだが、バックエンドのgRPCサービスとはgRPCで通信さえ出来れば良い。よってgRPCサービスのほうは普段通り好きな言語で書けば良い。

現時点ではgRPCのstreaming機能はサポートしていないが、これはすぐにサポートする予定だ。サポートした

そのほかにもREADME.mdに書いてあるようないくつかの機能をサポートしていきたいと思っている。 中でもSwagger API definitionの出力は是非対応したいポイントだ。protoからAPI definitionは作るからあとはJSON API clientはswaggerで勝手に作れ、という風にしたい。

トラックバック

http://yugui.jp/articles/889/ping

現在のところトラックバックはありません

コメント閲覧/投稿

ご案内

最近の記事

タグ一覧

過去ログ

  1. 2015年06月
  2. 2015年05月
  3. 2015年04月
  4. 2015年03月
  5. 過去ログ一覧

フィード

フィードとは

その他

Powered by "rhianolethe" the blog system