KLabGames Tech Blog

KLabは、多くのスマートフォン向けゲームを開発・提供しています。 スマートフォン向けゲームの開発と運用は、Webソーシャルゲームと比べて格段に複雑で、またコンシューマゲーム開発とも異なったノウハウが求められる領域もあります。 このブログでは、KLabのゲーム開発・運用の中で培われた様々な技術や挑戦とそのノウハウについて、広く紹介していきます。

カテゴリ: ツール

KLab Advent Calendar 8日目の記事です。 こんにちは knsh14 です。

KLabではUnityを使って iOS、Android の端末で遊べるようなゲームを開発し、提供しています。 その一方で、それら以外の環境でも遊べるゲームが作れないかということで常に技術検証を行っています。 最近では 「ユニティちゃんのホームランスタジアム」 を Apple TV で提供したりしています。(紹介記事)

その活動の一環として、今回はブラウザで快適に動作する 3D のゲームを作るべく、Unity ではないゲームエンジンを使って開発したのでその紹介をしようと思います。

なぜUnityを使わなかったのか?

ブラウザ動作するためのゲームを開発するにあたって、幾つかの制約がありました。

  1. モバイル、PC のブラウザで動作すること
  2. 容量が小さい(理想は 3MB 以下におさまる)こと

僕らが普段使い慣れている Unity でも WebGL ビルドができ、PC やモバイルのブラウザで遊ぶことができます。ですが、試しに「ユニティちゃんのホームランスタジアム」をビルドしてみたところ、20MB 以上の容量になってしまいました。 これではとてもリリースできないので、Unity を使う選択肢を諦め、別のエンジンを使う道を探し始めました。

色々調べた結果、PlayCanvas というゲームエンジンが海外での利用実績などもあり良さそうだという結論になったので実際に試してみました。

PlayCanvasってなに?

  • 公式サイト
  • WebGL で動作することを主な目的としたゲームエンジンです
    • iOS で動作するように吐き出されるオプションもあります
  • その為吐き出されたゲームのサイズが最小で 10KB 程度と非常に軽いのが特徴です
  • 使用する言語は Javascript です
  • ゲームエンジンが Github で公開されているので、Unity と異なり動作をかなり細かいところまで追いかけることができます
  • エディタ上でチャットすることができ、お互いがその場にいなくてもペアプロのようにして開発することができます。

実際の開発画面

オブジェクトなどをいじるエディタ画面はこのような感じです。

シーンエディタ

だいぶUnityに近い感じで操作できます。

コードエディタ

Ace Editor を利用した感じのエディタになっているのでシンタックスハイライトもありますし、あまり使いにくいことはなさそうです。 このスクリーンショットだとわかりにくいですが、多少のコード補完もしてくれます。

実際にゲームを作ってみる

公式チュートリアル からタップでリフティングして落とさないようにするゲームを作ってみると一通りの使い方などがわかると思います。

PlayCanvas のメリット

開発環境のセットアップが要らない

ブラウザさえあればどこでも開発できるので便利です。

エディタ上で複数バージョンのプロダクトを管理できる

プロダクトを公開するときは、エディタ上から簡単に世界に公開することができます。 また複数バージョンをスタンバイさせておくことができるので、バグが有った場合にも簡単に前のものに差し戻すことができます。

Chrome でデバッグができる

Google Chromeは開発者ツールを使うことでかなり高機能なデバッグができます。 ブレークポイントをはって処理を止めながらデバッグすることができるのはもちろんですし、プロファイラで時間がかかっている処理を調べながら開発することができるので、初期からパフォーマンスを意識しながら開発することができます。

苦労話

PlayCanvas 上でバージョン管理できなかった

PlayCanvas からパブリッシュした成果物は PlayCanvas 上で一覧でき、昔のものを復活させることができます。 ですが、プロジェクトの状態は復活してくれないので、リファクタする時にかなり覚悟が必要でした。 Githubなどとコードを連携する方法 もありますが、Legacy なシステムなのでいつなくなるかわからないのが現状です。 Git でコミットするように成果物を Download しておいて Github で管理するか、Google Drive などに置いておくのが鉄則になりそうです。 どっちの方法でもシーンの状態を戻すことができないのでいい方法を模索中です。

なぜかありえない場所で衝突イベントが走る

物体を動かすために毎フレーム pc.Entity.setLocalPosition() で物体を動かしていました。 ですが、ある日物体が何もない場所でいきなり衝突イベントが走るバグに悩まされていました。 物理演算に任せて動いている場合は何事もないのですが、setLocalPosition() で物を移動させた後おかしくなることがわかりました。

いろいろ試した結果、pc.Entity.setLocalPosition() では Entitypc.Model は移動しますが、 rigidbody の位置が移動しないことが原因でした。

rigidbody がついた Entity を動かすときは

Sample.prototype.move = function(x, y, z) {
  this.entity.setLocalPosition(x, y, z);
  this.entity.rigidbody.teleport(x, y, z);
};

というメソッドを生やしてこれを使うほうが良さそうです。

まとめ

今回は Unity ではないゲームエンジンで WebGL ゲームを開発してみました。 PlayCanvas はどちらかと言うと個人でささっとプロトタイプを作ってすぐに見せるような場合に非常に便利なのではないかと思いました。 大人数で高品質なゲームを作るには Unity 少人数でとにかくスピード感を重視するような開発では PlayCanvas というように状況に応じて使い分けていけたらと思います。

(本稿はKLab Advent Calendar 2016 の4日目の記事になります)

Travis CIはよく知られたCIサービスの一つです。読者の方々の中にも、個人的なプロジェクトのCIに利用している人は多いのではないでしょうか。一方で、設定ファイル .travis.yml 中に秘密情報を暗号化して記述できることはあまり知られていないかもしれません。

YAML中での暗号化のやり方はTravis CIのドキュメント「Encryption keys」にも書いてあるのですが、 travis encrypt コマンドによりAPIトークンなどの秘密情報を暗号化して .travis.yml 中に記述するような仕組みになっています。この情報はTravis CI側で復号されてCIプロセス中で利用することができます。

今回指摘する内容は、この暗号の強度が多くのプロジェクトにおいて不足しているのではないかという点です。というのも、2015年4月以前に作られたTravis CIプロジェクトではRSA 1024bit鍵による暗号化が利用されているのです。

本稿ではTravis CIの暗号化の仕組みを簡単に説明した上で、どういうときに危険性があるかの詳細と鍵ペア再生成の方法を紹介します。

travisコマンドの概要

まずは travis コマンドを用いた暗号化について簡単に紹介します。 travis コマンドというのは gem install travis でインストールされるRuby製のコマンドで、内部的にTravis CIのAPIを叩いて色々とよしなにやってくれる便利コマンドです。

そのサブコマンドの一つが travis encrypt で、これを使えば任意の文字列を暗号化して .travis.yml 中に記述することができます。たとえば、Travis CI連携しているGitHubプロジェクト直下のディレクトリで下記コマンドを実行してみましょう。

$ travis encrypt 'FOO=secret_information'
Please add the following to your .travis.yml file:

  secure: "BEC97APcjoBsKRRGS4DCcQoLCviHTzK88JxfEq0wDfJ4+kfuLktyXEbHbG6Ct9cP+KLnwxIDBamf0pgOS7iQGLLb5Irn00fn4JEBeHd6kyTXQbyuPSe/NffVceg5vq8RWPT8nlWzVHD3wtjJFWz/Ocm6q5RkqvOtLszwM1Nc0Ig="

上記コマンドで出力された行を .travis.yml 中に書けば FOO=secret_information と書いたのと同じ意味になります。この仕組みにより、APIトークンやメールアドレスなどをYAML中に記述して外部サービスとの連携に使うことができます。

travisコマンドによる暗号化の中身

さて、この暗号化はどのような仕組みなのでしょうか? travis コマンドの中身を見ると、その正体がRSAを利用した公開鍵暗号であるとわかります。具体的には、travis encrypt コマンドが公開鍵で暗号化を行い、暗号文を受け取ったTravis CIが秘密鍵で復号するような仕組みになっています。

この暗号化に用いられるRSA鍵ペアの生成はTravis CI内部で暗黙に行われており、秘密鍵はTravis CIだけが持っています。つまり、公開鍵で暗号化した文字列は暗号化した本人でさえ復号できず、Travis CIだけが復号できるというわけです。

言い換えると、この暗号化を信用するためのポイントは2点だと言えます。

  1. Travis CIが秘密鍵や復号済みデータを流出させるようなことが無い
  2. 公開鍵への攻撃により秘密鍵を求められるようなことが無い

これさえ守られていれば、暗号化された情報は安全だと言えるでしょう。逆に上記のうちどちらかの問題が発生するようだと、秘密情報を .travis.yml に平文で書いたのと同じということになりかねません。本当に大丈夫なのでしょうか?

実は2012年に少数のプロジェクトで1の問題が発生したことがあるようですが、今後は安全だと仮定するしかないでしょう。今回は2の問題について議論していきます。

公開鍵への攻撃の可能性

今回指摘したいのは、RSA公開鍵への攻撃の可能性についてです。

まずはTravis CIの公開鍵にアクセスしてみましょう。リポジトリに紐付く公開鍵は下記のようにAPI経由で取得できます(参照:「Travis CI - API Reference - Repository Keys」)。URL中の hnw/php-build というのがユーザー名/リポジトリ名になっています。

$ curl -s https://api.travis-ci.org/repos/hnw/php-build/key | jq -r '.key'
-----BEGIN RSA PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOQb++oR7aBL6TfjSZbo/ssNrE
sV9FJmOn5TZktfAgLFv7T5c93Iot1k6ha7OO0FaZyf67bR+5Nou4Vd4SaiFpvb38
NMj4Pz9Smdwi3pWisqcgZaQOOpe9IB0nTAGhzZp8+2EPC1syRUi30FXOD03xnL0q
X8rhgIkuD6415tGP3QIDAQAB
-----END RSA PUBLIC KEY-----
$

ところで、この公開鍵は短そうに見えますよね。実はこれが1024bit鍵です。RSA 1024bit鍵の素因数分解は現代のスパコンでもかなり手強い計算ではありますが、コンピュータの性能向上により5年後なり10年後なりには現実的に攻撃可能になると考えられています。「暗号の2010年問題」の頃に2048bit以上の鍵への移行が叫ばれたことを考えても、1024bit鍵の寿命が近いのは間違いないと言えるでしょう。

ちなみに、鍵ペアが1024bitになっているのは一定以上古いプロジェクトだけです。最近のプロジェクトでは4096bit鍵が利用されていますので、今後プロジェクトを作る分にはこの問題はありません。正確な時期はわかりませんが、2015年4月頃に4096bit鍵に切り替わったように推測しています。

ご自分のプロジェクトの鍵ペアの鍵長を確認したい場合、上のようにAPIから公開鍵を確認すればわかります。公開鍵がASCIIで210文字くらいだったら1024bit鍵、730文字くらいだったら4096bit鍵ということになります。わざわざ鍵を確認しなくても、 travis encrypt の結果の長さも鍵長と同じサイズになるので、そこからも判断できます。

鍵の中身を正確に把握したい場合は openssl asn1parsedumpasn1 などを試してみてください。

鍵ペアを再生成する手順

もしかすると短い鍵ペアを使っているプロジェクトが見つかったかもしれませんね。もしそうだとしても、鍵ペアを再生成するAPIが提供されていますので安心してください。ちなみに、現時点ではAPIを直接叩く以外の方法は提供されていません。

鍵ペアの再生成APIを利用するにはAPIトークンが必要です。これは travis login コマンドでログインした後で travis token コマンドを実行することで取得できます。このAPIトークンを下記のように Authorization: ヘッダから送信すればAPIの認証が成功します。ただし、下記の hnw/php-timecop はユーザー名およびプロジェクト名です。

$ curl -d '' -H 'Authorization: token abcdefghijkl1234567890' -s https://api.travis-ci.org/repos/hnw/php-timecop/key

API呼び出しに成功すると新たな鍵ペアが生成されます。失敗した場合はおそらくトークンの指定が間違っています(ヘッダ中の token は消してはいけません)。元の鍵ペアが1024bitだった場合でも再生成すれば4096bit鍵になりますので、あと20年くらいは安心だといえそうです。

もちろん、鍵ペアを再生成した場合は改めて秘密情報の暗号化を行う必要があります。また、古い暗号文を遠い将来第三者が解読する可能性まで考えれば、暗号化対象のパスワード変更やAPIトークン再発行なども合わせて行うのが良いでしょう。

まとめ

  • Travis CIのtravis encryptによる暗号化にはRSAが使われている
  • そのRSA鍵の鍵長が1024bitのことがあるので要確認
  • 1024bitでは暗号強度の観点から中長期的に不安
  • 2015年4月頃までにTravis CI上に作られたプロジェクトが該当
  • API経由で鍵ペアの再生成ができる
  • 再生成すると4096bit鍵になる

本題とはズレますが、RSAを署名ではなく暗号化に使っている事例は比較的珍しい気がするので、その観点でも面白い話題といえるかもしれません。


@hnw

このエントリーは、KLab Advent Calendar 2015 の20日目の記事です。

まえおき

高田といいます。ふだんはゲームのデータなどを集計し、統一的に管理するデータ収集・分析のためのシステムを開発しています。

私のチームではインフラにはAWSを活用し、自分たちで運用しています。

その際非常にめんどうなのがセキュリティグループの管理です。セキュリティグループとは、AWS上の仮想マシンに対するトラフィックを制御する仮想ファイアウォールです。

詳しくはamazonさんの公式のドキュメントを参照してください。

私たちのチームの場合、提供するサービスは社内向けのものが多いので、例えば80ポートや443ポートは社内のIPアドレスのみに開放するといった設定を利用することが多いです。

こちらをAWSのコンソール画面で設定していくのですが、数が増えていくと、どれがどれだったかわからなくなるというパターンが増えていきます。

例えば、192.168.0.12に22ポートを開放すると設定してあったとしても、「これはどこのアドレスだったかな……? あ、大阪事業所だ」といちいち確認する手間も増えます。ひどいときは、「おそらくいらない設定だと思うけど、消して動かなくなると恐いから消さない」ということになり、どんどん誰も手がつけられない負債が増えていきます。

特に、設定をまちがえると必要なユーザーがまったくアクセスできない、あるいはデータベースへのアクセスが遮断されるなど、悲惨な障害につながりかねないため、この手の設定は恐いですね。

経験上、セキュリティグループの管理には、以下のような問題が生じやすいようです。

  1. どの設定が何のためのものかわからなくなる。
  2. 誰がいつ何のために設定したのかがわからなくなる。
  3. 設定ミスは障害につながる。いざというときには、過去の状態に戻せるようにしたい。

githubで管理する

上記の問題をふりかえると、ソースコードなどと同様に、githubのワークフローに載せてやれば、問題点はおおむね解決できそうです。

  1. どの設定が何のためのものかわからない。→ コメントをつける。記録に残す。
  2. 誰がいつ何のために設定したのかがわからない。→ 修正点を共有し、レビューできる。
  3. いざというときには、過去の状態に戻せるようにしたい。→バージョン管理。

具体的には以下のような運用になります。

  • 現状の設定にはコメントをつけ、何のための設定なのか明示化する。
  • 修正時は、プルリクエストし、修正内容をレビューしてから更新する(これによって更新履歴も残る)。
  • すべての修正はgithubに残し、何かあれば過去のバージョンに戻す。

これはよさそうですね。しかしこれを実現するためには、何とかして、セキュリティグループの設定をgithubで管理できるようにする必要があります。

管理スクリプトをつくった

上記のような管理フローを実現するため、セキュリティグループの設定をcsvで取得し、csvから反映できるスクリプトを作成しました。sgという名前です。

(名前は特に思いつかなかったので Security Group 略して sg としました)。

pypiにも登録済みです。なおpythonのバージョンは2.7.9および3.4.3でテストしました。

pip install sg

使い方: 初期化

管理用のディレクトリを作成し、そこで init コマンドを実行します。regionとawsのキーを聞かれます。

(キーはローカルに保存するだけです)。

$ cd yourpath
$ sgsg.py init
enter your region[us-east-1]:
us-west-2
save to sg.cfg
enter your aws_access_key_id:
xxx
enter your aws_secret_access_key:
xxx
save to aws_key

使い方: 保存

リモートのセキュリティグループの設定を保存するには fetch コマンドを利用します。

グループ別に設定がcsvとして保存されます。

ダウンロードされたcsvファイルにはコメントなどを追加することができます。エクセルなどで編集してください。なお、新たなリモート設定が追加された場合もfetchで取得できます。更新時もコメントなどを消すことはありません。

csvは以下のような形となります。(セキュリティグループ名).csvというファイル名で保存されます。

security_groups/somegroup.csv

tcp,80,80,192.168.0.1/32,,東京本社オフィスからのHTTP接続
tcp,22,22,192.168.0.2/32,,東京本社オフィスからのSSH接続
tcp,22,22,192.168.10.1/32,,大阪事業所からのSSH接続
tcp,22,22,othergroup,,別のセキュリティグループからのSSH接続

github上では以下のように表示されます。

csv_screen_shot

使い方: 更新

このcsvファイルにコメントをつけ、gitで管理していきます。

なお更新をAWS側に反映するには commit コマンドを使用します。

csvに追加、または削除を行なったあと、以下のコマンドを実行します。差分が表示されるので確認後yを選択してください。

sgsg.py commit security_groups/somegroup.csv
GROUP: somegroup
post this setting?[y/N]
+tcp    80      80      192.168.0.1

現状sgツールからセキュリティグループの追加や削除には対応していません。(コンソール上で追加したグループは fetch 時に反映されます)。

以上です。活用いただければありがたいです。

↑このページのトップヘ