まーぽんって誰がつけたの?

iOS→Scala→インフラなおじさん技術メモ

fluentdのS3 output pluginでは権限に注意しよう

現象

fluentdが集めてきたログをS3にputしていたつもりが、全体のうちの1/3ぐらいしかputされずそれ以外がロストしていたという話です。

調べてみると・・エラー吐いてた

fluentdのヘルスチェックとかは確認していて、fluentdが死んでいる様子はない。 S3にもログ自体は吐かれている、冗長化している片方のインスタンスが死んでいるわけでもない。 ということですぐに気づけませんでした。

fluentdがエラーを吐いてたので見てみるとS3の権限っぽいエラーが。

2017-04-21 12:50:46 +0000 [warn]: temporarily failed to flush the buffer. next_retry=2017-04-21 12:50:48 +0000 error_class="Aws::S3::Errors::Forbi
dden" error="" plugin_id="object:2b1bacaec3f4"
  2017-04-21 12:50:46 +0000 [warn]: suppressed same stacktrace

Aws::S3::Errors::Forbiddenというエラー内容からIAMとかBucket Policyだとピンときて確認してみるも、PutObject権限はきちんとついていて路頭に迷うことに。

Aws::S3::Errors::Forbiddenでググりまくると・・

https://groups.google.com/forum/#!topic/fluentd/Vvok7FTVuq4 このページの真ん中あたりのこの部分がヒントになった。

If an IAM user has permissions to the bucket but doesn't have !AM permissions to s3 that user can write files but @bucket.objects[s3path].exists? will fail with 'Permission Denied' when true but not when false (Weird).

fluentdがs3にbufferをs3にwriteしに行く際に、ある特定の区切りの時間のオブジェクトはまだ存在しないので書き込みできる。

で、そのあと同じs3のファイルに対して一度existsを確認してから追記しにいくんだろうけど、このexistsで失敗していると思われる。

実際に、現状のIAMロールはs3:*に対してAllowされてるけど、bucket policyはs3:PutObjectのみになっていた!!!!

fluent-pluginの該当コード部分

pluginのこの該当コード https://github.com/fluent/fluent-plugin-s3/blob/master/lib/fluent/plugin/out_s3.rb#L237 のwhile条件を抜けてしまう。

        end while @bucket.object(s3path).exists?

なので、1回目は書き込みにいけるが、その後追記しにいくときに失敗する。

1/3ぐらいしか残っていないというのも、残ってるのは特定の時間で新規でwriteした分で、本来であれば残りのログもそのobjectに対してwirteしにいけたが、bucketのポリシーが足りないためexists確認ができずに、失敗してしまったと思われる。

対応

バージョンによるみたいですがv0.8.0からはcheck_bucketcheck_objectのオプションが追加されていて、それだとs3:PutObjectだけでいけるみたいです。

Example when check_bucket=false and check_object=false When the mentioned configuration will be made, fluentd will work with the minimum IAM poilcy, like: "Statement": [{ "Effect": "Allow", "Action": "s3:PutObject", "Resource": ["*"] }] https://github.com/fluent/fluent-plugin-s3

Release 0.8.0 - 2016/12/20

まとめ

最初動いたからといって油断してはいけない