さようなら ImageMagick

こんにちは、アプリケーション基盤チームの青木(@a_o_k_i_n_g)です。

一般的な Web アプリケーションがそうであるように、サイボウズのグループウェアにも画像をサムネイルで表示する機能があります。サイボウズでは日々数万件やそれ以上のサムネイルを生成しており、それらは全て ImageMagick によって生成されていました。

そこで得た知見はこちらの記事で公開されています。
blog.cybozu.io

しかし現在、サイボウズから ImageMagick は消え去りました。その理由と、我々が取った代替手段について紹介します。

ImageMagick を外した理由

言うまでもなく ImageMagick は優秀なツールで、画像変換に関する何らかのサービスやツールを作る場合には採用の第一候補になることでしょう。あらゆる画像フォーマットに対応し、出力画像をきめ細かに制御できる膨大なオプションがあるからです。

しかし一方で、 ImageMagick には脆弱性が大量に存在します。2017 年に報告された ImageMagick の脆弱性は 236 件 でした。大量にある上にリモートコード実行級の脆弱性もあり、安全性という観点ではかなり厳しい評価をしなければなりません。こちらに ImageMagick の脆弱性情報があり、その多さが伺えると思います。
Imagemagick : Security Vulnerabilities

もちろん、我々は AppArmor による厳重なアクセス制御やサムネイル作成専用の環境を使うなどの策は施しています。しかしそれでもこれだけ多数の脆弱性があるとなると、 ユーザーに安心安全なクラウドサービスを提供できているか? という点で疑問がありました。

また、脆弱性報告が来るたびにサイボウズに影響が無いか調査しており、そのコストが無視できないほど大きくなりました。脆弱性報告が来た際は否応無しに調査に時間を取られますし、意図しないタイミングでバージョンアップを迫られることもあります。スムーズな運用のためにも ImageMagick を採用し続けるのは得策ではないだろうという意見が出ていました。

検討を重ねた結果、我々は ImageMagick を捨てる決意をしました。

ImageMagick の代わりに

代替として使えそうなツールがいくつかありましたが、サイボウズのサムネイル事情は少々仕様が凝っている部分があり、自作することにしました。そして調査の結果、Go 言語と imaging パッケージが良さそうということでこれを用いて実装することにしました。

結論から言えば、ImageMagick に依存しないサムネイル作成ツールを実装し、移行も終えています。いくつか判明した点について記します。

PNG の変換画像が僅かに暗くなるケースがある

Go 版サムネイル生成ツールと ImageMagick では、PNG を変換した際に Go 版の方がわずかに色が暗くなるケースがあることが判明しました。

Wikipedia の PNG のページ にある PNG 画像を例に取って説明します。一枚目が ImageMagick で変換した画像、二枚目が Go 版サムネイル生成ツールで変換した画像です。

f:id:cybozuinsideout:20180817180448p:plain
ImageMagick で変換した画像
f:id:cybozuinsideout:20180817180534p:plain
Go 版で変換した画像
・・・というわけで、肉眼ではわかりませんね。ImageMagick の compare コマンドで画像の差分を出力すると差分が浮かび上がります。

f:id:cybozuinsideout:20180817175457p:plain

稀に肉眼でわかる程度の差が出る画像もあるにはありますが、実用では問題無いと判断しました。

変換できない画像がある

ImageMagick で変換出来ても Go 版サムネイル生成ツールでは変換出来ない画像があります。

まず、Go 版では BMP の一部は変換出来ません。BMP にはいくつか種類があり、その種類を表す値は Bitmap Information Header というヘッダ部分で指定されます。ここで指定される値と種類は下記の通りです。

値 意味
40 Windows V3
108 Windows V4
124 Windows V5
12 OS/2 V1
64 OS/2 V2

しかし Go の image パッケージの当該部分を見ると 40 という値が来ることを前提としており、Windows V3 以外の BMP のバージョンは未サポートでした。
https://github.com/golang/image/blob/c73c2afc3b812cdd6385de5a50616511c4a3d458/bmp/reader.go#L151

ImageMagick では Windows V3 以外の BMP も変換可能で、この点では Go 化して劣化した部分と言えます。とはいえ近年は BMP ファイルがアップロードされる回数はさほど多くなく、大きな問題には至ってません。

他にも、ImageMagick は壊れた画像も変換できる という謎機能があり、もちろん壊れ方にも依るのですが、Go 版では変換に失敗する画像でも ImageMagick だと変換できることがあります。なおそういったケースは全体から見れば極僅かなのでこのケースも実用では問題無いでしょう。

運用後

ImageMagick を廃止し Go 版サムネイル生成ツールを運用してからしばらく経ちましたが、大きな問題は出ていません。我々はサムネイル作成の成功率をモニタリングしており、 成功率は 99.9% 付近を保っています。巨大画像や壊れた画像が来るケースを考慮すると十分な成功率と言えるでしょう。

これで以前より一歩安全なクラウドサービスに近づけたかと思います。「現状動いているからそれでいい」というような安易な運用ではなく、安全性を確保するためなら作りなおしも厭わないという姿勢はサイボウズの誇れるところだと思います。

また、脆弱性対応の工数を減らせるという点でも目的を達成できました。脆弱性対応は工数だけでなく精神力も消耗するものなので、こういった部分の改善はサービスの安定運用に繋がると思います。もちろん Go 化したからといって脆弱性が無くなるわけではなく、関連する脆弱性情報は引き続き注視していきます。

サムネイル機能というものはあって当然で、あまり目立たない地味な機能かも知れません。でもその裏では様々な画像を変換してくれる賢いツールが活躍してくれているのです。ImageMagick は長期間にわたりサイボウズのサムネイル事情を支えてくれました。さようなら ImageMagick、いままでサムネイルをありがとう。