IAM Policyの作り方に悩む - とりあえずS3 + CloudFront静的サイトを考える -

まとめ

  • AWS の Policy の種類が復習できた
  • AWS の Policy 関連用語と Terraform 用語の Resource, Data Source 用語との紐付けができた
  • 静的サイト向けの Policy に集中して考えた

操作から切り離して概念を整理しやすいのでドキュメントベースになるとありがたい。

AWS S3 の Bucket を読み書きできるポリシーとその適用方法が揺れていた

これまでに存在しているポリシーが以下のようなひどいことになっていた。

  1. S3 の Bucket Policy で Role と Action を割り当てているもの
  2. S3 の読み書きに特化した IAM User を作り、そのインラインポリシー ( IAM User Policy ) 側に Bucket ( arn ) 情報が書かれているもの
  3. IAM User Policy Attachment ( 未適用 )

図にするとこんな感じ。

S3 Bucketの読み書きのPolicy設定方法が複数ある様子

※ 上の図では AWS 用語を枠線で囲んでおいて、Terraform 用語を無地の上にそのまま置いている。そもそもこれまでこの辺の用語の理解が曖昧だったことに今回ほんとに気づかされている。(どうしても触る機会の少ないインフラ周りがおざなりになってしまう。)今回気づいたのは Bucket でも User でもない真ん中の Managed-Policy を aws_iam_policy で管理するようにしたらどうか?という話。

初期は 1 でやっていた。この頃の目的は静的サイト向けの Bucket ではなく、Web アプリの無限ストレージとして使い始めた。まだ AWS 自体がよく分かっておらず、読み書きを割り当てている IAM User の概念もボンヤリしていた。

で、いくつかそういうアプリが増えてきたときに Bucket 作って Policy 開いて、みたいな操作がダルくてイヤになって、Policy だけ別に作って Bucket に適用した方がよいのでは? と思い始めて 2 の形になった。

しかしこれは今にして思うと失敗だった。たぶん当初 3 を意識していたがやはり操作が面倒くさくて 2 の形に流れてしまった。

しかもこの形での指定が妙に複雑になっている部分がある。確か

  • ログイン可能な IAM User が手動で読み書き可能な Bucket を確認できるように
  • Rails + fog で bucket を覗く際になぜか指定が足りないと怒られた

辺りが理由と記憶しているが、これは静的サイトを CI で deploy するようにという今回の目的のためには不要な配慮になるはず。

解決案

静的サイトに限定して考える。

上のポリシーは Web アプリのストレージとしての Bucket のポリシーと混ざっているのがそもそもよくない。

AWS のマネージメントコンソールを手作業でぽちぽちしていくやり方と Terraform を共存(怖いけど)させる場合、恐らく 1 の形に近づけて Policy を Data Source で定義したうえで、せめてコピペせずに Bucket ごとに 個別に割り当ててあると直感的に分かりやすいと思う。(Bucket のプロパティを覗けばどういう状況か分かるので。)

ただ、ちゃんと自動化するなら第4の方式、

  • S3 Bucket
  • IAM User
  • IAM Policy
  • IAM Policy Document

をそれぞれ独立して定義した上で IAM User に IAM Policy をアタッチしておいて、最終的に IAM Policy Document だけをメンテすればよい感じにする方が .tf も .tfstate も diff が小さくなると思う。

少なくとも IAM User Policy の側に Bucket (正確には arn)を列挙してしまっている現状は、手作業での手間は若干減ってはいる(少なくとも bucket ごとに丸ごと policy をコピペしたうえで書き換える必要はない)が、自動化前提ではアホくさい。

User の関心事は 1) シンプルに静的サイトの deploy であり、2) deploy は手作業でなく CI/CD サービス経由であり、3) ログインは不要であるならば、 ユーザーの知っているべき情報は特に変化はない

手作業を捨てるならコードは DRY にして設定ファイルとしての HCL の可読性に寄せる方がスジがよいと思われる。

要確認

そもそも CloudFront 経由でしか publish しない方針なら、実は S3 の Read Only Policy って必要ないのでは?

参考

2016年に設計なんてない、そこそこの量のJavaScriptのエラーを監視して対策し始めました雑感

公開されるどこにも記録を残していないような気がするが、2016年の初めからとある事情により JavaScript のエラーをサーバに送りつけて監視サービスに送りつけてエラーの発生を知り、修正する、ということを地味にくり返していた。

そこに至る顛末と今後の分析の予定のお話。

背景

これまで扱ってきたものはそこまで JS ヘビーでないものが多く、また自分で書くものはできるだけユニットテストが動くように書いていた and そもそも監視サービスが入っていなかったので、エラーのログをサーバに送るとか監視するとか、そこまで手をかけていなかった。

しかし今回の案件は初期の設計では考えてもみなかった量のカウボーイスタイル JS がコミットされしまい、要するに非常にイキのいいフレッシュなレガシーコードがてんこ盛りで動いている状態になってしまった。

(あーはい、全部ぼくがコードレビューしてリジェクトすれば防げたんです、すいません。それをやったら別な角度からこっぴどく叱られたのでしょうけど。)

まずは静的解析

CI に乗せるまでも苦労したのだが、CI に乗せたのを機に eslint は動くようにしていた。

その段階ではほぼ致命的な問題は見つからなかったので、ちょっと安心していたのだけれど、やはり自動化されたテストのないコードが増えると厳しい。「なんかうまく動いていない感じがする」「再現性を確認できるレベルの報告は来ないが、何かは起きてるっぽい」という状態であり、またこの状態では積極的にはやりたくないが、どうしても変更はせざるを得ない。(完全無欠で変更不要なコードなんてあり得ない。)

cache busterできていない問題

そもそもの話なんだけど、件のサイトは AssetPipeline 的な仕組みが標準で入っていないので、当然のように JS がキャッシュされて、ブラウザによって動作がマチマチになってしまう問題を抱えていた。Rails 界隈では AssetPipeline 批判がすでに一周回り終わってしまっているが、世間にはまだそのような便利な仕組みがあることさえ知らずに素朴にキャッシュの効く生 JS を書くお仕事もあるわけです。はい。

が、なにせ量が多く、納得のいく形の cache buster まで持っていく時間を捻出できないので、そこは無視することにした。「cache の問題で意図した動作がユーザーの手元で再現できない場合がある」ことを記録するに留めることとした。

ガッデム。1

とにかくwindow.onerrorでサーバに送る

以前ならテストコードのないサーバサイドのアプリもエラーログで追い詰めつつ改修していくというのも割とよくやったが、最近はそういうやんちゃなコード扱ってないし、そもそも JS だとエラーログねーし…と思っていたが、「いや、何かで見たな」と思い返し、考え方を変えて、「まずはよく分からない状態を分かるようにする」ことにした。

大手Webサービスがクライアント側で発生したJavaScriptのエラーをどう収集しているのか まとめ - Qiita

を参考に、いちばんざっくり書けそうなのは

  • window.onerror
  • Ajax(サーバサイドアプリは単独ドメインなので)

の組み合わせで、サーバサイドに送ってサーバ側で NewRelic に送ることかなと考えた2。サーバサイドのエラーはすでに NewRelic に送ることができていたため、サーバ側に来てさえしまえばなんとかなると考えたのだ3

NewRelic なら Error rate が基準(デフォルトでは 5.0%)以上になると通知してくれるので、何かが起きていることは可視化されやすいし、そこには

  • URI
  • ソース上のエラー発生箇所
  • エラーメッセージ

といった基本的な情報が含まれているので、「分からないものが分かるようになる」段階としてはひとまず十分と言えるだろう。

びっくり仰天サーバサイドでJavaScriptリテラルを生成するコードの存在

上の記録をやり始めてから明確にエラーが減り(JS側の動作がおかしくてサーバ側にエラーが起きていたものも含む)、喜んでいたのもつかの間、いちばんショックなコードに出くわした。

ざっくり要約するとサーバ側のテンプレートで

var obj = val1 + {{$val2}};

みたいなことをやっているので、サーバ側で $val2 が null になると JavaScript 実行時には

var obj = val1 + ;

みたいなコードになってしまい、SyntaxError になるというもの。

こ れ は ひ ど い

2015年のコードでこれはないよ。値は HTTP か data-* で渡せよ。eslint 意味ねーだろ!!

泣く泣く

{{}}

の中に条件演算子を埋め込んで回りましたとさ…。

※ サーバサイドの View で JavaScript を書くのをそもそも禁止すれば少しはマシになりそうな気がするんだけど、これを静的解析で見つけることは可能なのかなぁ? 人間がダメ出しすることはできても機械的に弾けないとやはり不安は残る。

無視すべきエラーとGoogle Analyticsへの記録

最近あった、ちょっと困ったパターン。

  • Chrome 55 で実装された PointerEvents がバグっててエラー急増
  • Babel を使って書いてる部分があって、IE 8 以下でエラーを吐く
  • iOS の Google Search App が(恐らくZoomイベントに)バグを抱えていてエラーを吐く

こいつらはブラウザ側の問題でかつサポート外か、警告は出るが動作はするというものなので、無視する(サーバに送らない)ことにした。

※ Google Search App だとググってからでないとサイトを訪れることができないので、ほぼ production 環境以外ではデバッグできないわけだけど、みんなこんなもんどうやって相手してんの?

無視するだけだと怖いのでGoogle Analyticsに記録することにした

もしかしたら Chrome 56 で修正されるかもしれないし、闇雲に無視してしまうのは本来拾えるはずの情報を捨てることであり、なかなか怖い。ということでアプリが動いているサーバには送らないが Google Analytics には送ることとした。これなら通知はされないがあとで記録を見返すことはできる。

Google AnalyticsでJavaScriptエラーをトラッキングする

ただし、記録、閲覧できる情報量に不満があるので、もしかしたらイベントの方がよいかもしれない。

Google Analyticsを利用してクライアントサイドのエラーのレポーティングを行う - Thousand Years

とは言え、だいたい普通はイベントに関しては「何らかの効果の捕捉」に使うもので、利用回数に制限のあるイベントトラッキングを、何かの拍子に爆発しかねないエラーの記録に使うのはややリスキーだよね。

Google Analytics は分析目的の詳細な情報の記録ではなく、あくまで数の参考に留めておくのがよいのかもしれない。

まだ改善は続く

自分以外の人間が書くコードに対して、自分の得意なテストコードベースの手法だけを適用していこうとするのはやはり無理がある。一朝一夕には TDD はできるようにならないし、自社に十分な人数のデキるエンジニアが揃っていない場合は理想だけを追っても意味はない。

ということもあって、エラーログを単に「現在エラーが起きている」ことを知るためだけに使うのではなく、エラー発生率の変化など、指標として可視化してふり返りや分析にも利用できるようにしたらどうだろう、そしてたぶんこれは単独のサイトで考えるのではなく、会社全体としてログ分析基盤の一環として考えるべきなのではないかと思い始めている。

NewRelic以外のログ分析の基盤を用意したい

と考えると、単なる尻拭い案件ではなくなり、急に面白みが増してきた。

ERRORログが多すぎるWebアプリに出会ったら | GMOインターネット 次世代システム研究室

なんて話もあるが、現在我々には

Amazon Athena – サーバーレスのインタラクティブなクエリサービス – AWS

があるので、ログを S3 に放り込んで Athena で分析するのはアリだなと考えている。

NewRelic はエラーの通知とグラフィカルな可視化にはよいが、そもそも NewRelic のサイトの応答が重く、Error も Similar なもので畳まれて追いにくくなるので、もっと分析に特化したものは用意した方がよいように感じている。NewRelic はすぐに対応するにはよいが、長いスパンで見たい場合にはあまり向いていないなーと思っていたが、似たようなことを感じている人がいた。

※ export も自分で API を叩くコードを書かなきゃいけないし。

なぜ私たちはSumo Logicを捨ててBigQueryを選んだのか - tech.guitarrapc.cóm

この記事では BigQuery に入れることにしたようだが、自分には基盤整備の時間が十分にあるわけでもないので、「とにかくなんでも後回し」で考えると S3 + Athena かなという気がしている。幸い、ログを S3 に保存するのは自動化できている。

※ ところでバックトレースは複数行にまたがってしまうのに行に対して検索を掛ける SQL ベースの分析基盤はエラーログ分析には実は向いていないような気がしないでもないのですが、すでに基盤を構築済みの皆さんはどうしてるんですか? トレースを改行のない状態に畳み込んでから記録してる? そうするとロガーに手を加える必要がありますよね?

ログの情報量アップ

これまでは window.onerror に標準で渡ってくる情報を頼りに、トレースを取らずにそのままサーバに送っていたが、さすがにつらくなってきたので、

JavaScriptエラーログ収集に役立つツール・ライブラリ・手法まとめ - WPJ

を参考に

StackTrace.JS - Framework-agnostic, micro-library for getting stack traces in all web browsers

csnover/TraceKit: Attempts to create stack traces for unhandled JavaScript exceptions in all major browsers.

を使ってバックトレースは欲しいと思っているところ。

全体的な目標としては

JavaScript 祭で発表してきました - 若き JavaScripter の悩み

こんな感じですよね。よくまとまっていて分かりやすい資料をありがとうございます。

バグを防ぐ、デバッグという意味では本稼動してるアプリのログはやはり後手に回っているので、本来は前行程で防ぎたい。でも今は便利なツールが揃っているし、後手に回ったなら回ったなりにできることはいろいろあるし、これに慣れてくると、ちゃんとログ残したり監視できていないサイトはデプロイするの怖いという気もしてきそう。

エンジニアは怠惰で贅沢な生きものだもの。

  1. ま、でもあれです。ぶっちゃけ地方には JS 専門の人なんてほぼ皆無で、みんなこんなもんすよ。と思ってないと平静を保てません。全部自分で書けるわけじゃないのが現実です。 

  2. この1年半ほどでようやく NewRelic の恩恵に与かりまくっている。 

  3. 実際には試しに入れた Rails のサイトでは目的の機能はさっくり実現できたのだが、本命のサイトは PHP でできていてかつグローバルにエラーを拾ってゴニョゴニョするという悪魔のような機能が動いていて、そこで四苦八苦することになるのだがそれは今回のテーマではないので割愛。 

Rinari+RhtmlでRailsのコードを書くことにした

いつものことながらすごく今さらな話。

ずっと ruby-mode.el 一本でやってきたのだけど、Rails のコードはどうも読みにくいし、なんかそう言えば rails.el って聞いたことあったなぁと思い出して調べてみた。結果、

  • rails.el は 2007年で止まっていて事実上の discontinued 状態
  • Rinari という minor mode があるらしい

minor mode で大丈夫なんかいなと思ったけれど、心配無用でした。1

Rinari

Rinari: Ruby on Rails Minor Mode for Emacs

インストールの注意点

git clone を使って install する際は submodule を要求する。default では git protocol で取得しようとするので git protocol の通らない環境ではインストールに失敗する。

..gitmodules を編集してから submodule を取得しにいけばいいのかもしれないけど、やってみてないのでよく分からない。

Rinari がやってくれること

Introduction - Rinari: Ruby on Rails Minor Mode for Emacs

  • navigation ( MVC や migration 間の行き来 )
  • Web server 立ち上げたり
  • 適切な sql-mode を起動したり
  • テストを支援してくれたり

など。あれ、「読みにくい」という問題は解決しないような。

Rhtml-mode を追加

「読みにくい」のが始まりなので追求。

Add Ons - Rinari: Ruby on Rails Minor Mode for Emacs

んーでも YAML も CSS も JavaScript も困っていないので、追加するとしたら Rhtml かな。

あと yasnippet-rails を入れておいた。(yasnippet はインストール済み)

rhtml-mode の色づけがちょっと気に入らなかったので

M-x customize-group

erb-faces

からちょっといじった。

(custom-set-faces
...
 '(erb-delim-face ((t (:foreground "blue" :weight bold))))
 '(erb-exec-face ((t (:inherit erb-face :underline t))))
 '(erb-face ((((class color) (min-colors 8)) (:underline "black"))))
 '(erb-out-delim-face ((((background dark)) (:foreground "blue" :weight bold))))
...

こんな感じ。

結局 Rails のコードは読みにくいまま

..html.erb は編集しやすくなったし、コード間の移動もやりやすくなった。しかし Ruby のコードは読みやすくならなかった。

Rails のコードはなんていうか helper 以外は宣言的(?)過ぎて、普通のコードのようにメソッドのカタマリを目が認識できない。そのせいかどこで何をやっているのかよく分からない感じになってしまう。少なくとも古い Ruby コードにしか馴染みのない人間にはいささかつらいものがある。もしかするとこれが DSL と騒がれた片鱗なのかもしれないが。

とりあえず何かのツールで劇的に読みやすくなるということはなさそうなので、少しずつ目を慣らしていくしかないみたい。

とは言え Rinari は便利。収穫アリ。

  1. ほんとの最先端は Rinari じゃないらしいんだけど、ほとんどのツールで先端を追ってない自分にはまったく問題ない。 

Webby で静的サイト作成

Rake の練習課題として以前調べておいた

Welcome! - Rote

を試そうかと思っていたんだけど、ちょっと調べたら

Webby :: Webby

を見つけた。こっちの方がいいかもしんない。

rote は

  • Textile などで書かれたコンテンツファイル
  • メタデータを記述する rb ファイル

が分離していたんだけど、webby ではこれが一つのファイルにまとまっている。フォーマットはこんな感じ。

---
RFC822 風のメタデータ
---
Textile などで書かれたコンテンツ

コンテンツの処理は filter で指定する。filter には Textile などの書式の他に erb も指定できるので、コンテンツの中に Ruby で扱える変数や処理を自由に埋め込むことができる。これは便利だ。

使い方

Rails のように webby-gen コマンドでサイトのひな形を作る。このとき指定できるのは 0.9.3 で

  • blog
  • presenation
  • tumblog
  • website

の4種類。それぞれ適した task が利用できるようになる。

blog

試しに blog を作ると task に

blog:post

ができて、これを呼ぶと呼んだ当日の年月のディレクトリを

YYYY/MM

で掘る。blog:post 時に path の入力を求められるが、これを入れて

YYYY/MM/path

なエントリになる。Type Pad 風というか海外の blog ツールで最もポピュラーな URL かな。

website

これが website になると

create:page

になる。

deploy

Capistrano ではないけれど rsync などを使った deploy も行える。ただし ftp では行えない。うーん、もったいない。ftp に対応すれば使えるシーンはたくさんありそうなのに。ま、output したものを sitecopy などで mirroring すればいいっちゃいいんだけど。

autobuild

面白い機能として最後に autobuild を紹介しておく。このタスクを実行するとファイルの更新を監視して自動的に HTML の出力を行ってくれ、なおかつ WEBrick で serve してくれる。

正直、このツールに興味を持つ人は自分で Web サーバくらい立てられる気もするが、そうでない人でもこの autobuild を利用すればサイトの検証を行いやすい。

印刷業界と Web

※ コメントを読んでもらうと分かりますが、以下の文書は今のところリンク先の文書とかけ離れた話になってしまっています。削除してしまうのが簡単なのですが、なんかそれもどうかなと思い、リンク先の文書とは切り離して残そうと思っているところです。ということで、この文書はとりあえずリンク先の文書とは切り離してお読みください。あーあ。やっちまった。

メディアは「道具」なんだから、変って当然

otsune さんのブックマークより。

時代の流れに沿って印刷、出版業界も仕事のやり方や提案の仕方変えなきゃね、というだけの内容なのに、中途半端に聞きかじった知識で本論よりも紙幅を割いて Web やネットを批判しないとやってられないのかな、と心配してしまう書き方になってますな。

まぁネット界隈というか Web 界隈のビジネスや試みでは、激しく動いてはいるが商業的に失敗してる試みも多く、そういう意味では「何やってんだこいつらは」的な印象を、紙を含め、ネット以外のメディアの人は抱きやすいだろうなとは思う。でもそこは成熟しちゃったメディア業界と違うのは当たり前だし、また、Web 系のビジネスは小さい初期投資で始められるものもあるという特徴もあるのだから、今の時点では失敗したときの痛手も既存のメディア業界と全然違うと言っていいと思う。つまり、従前のメディア業界の人たちの感覚では Web 界隈の人のアクションを批判しない方がいいですよ、と思うんだけどどうだろう。1

もっとも、「いずれ取って代わられる」的な発言が鼻につくのは事実で、売り言葉に買い言葉的な、脊髄反射的な反応が生まれる下地を Web やネット界隈の人たちが作っちゃってる部分はあるので、それ以外のメディア関係の人たちのそういう反応を見ても差し引いてあげないとダメかもしんないけど。

  1. 印刷、出版関係は放送業界と違って下手に自分たちもコンピュータを使ってる人たちって意識がある分(?)謹慎憎悪みたいな状況に陥っているように見えるフシが多々あるんだよな。 

trac って日本語通るんかな?

shugo さんとこ 経由で trac

いいかも。でも Subversion 使ってないし、Wiki とか日本語通るんでしょか? まったく新規に起こすならこれよさげだなーと思うんですが。

何がいいって Repository の Web インターフェイスもあるけど reStructuredText. このフォーマットが唯一メールなどのプレーンテキストにそのまま使い回せるフォーマットだと信じているので。いわゆる Wiki フォーマットは書くのは速いけどそのままメールにコピペできないのがつらい。そら技術的にはできるけど、それを読むのはやだ。

まー普段の作業と再利用とどっちの優先度が高いかって言ったら前者かなぁとは思いますが、使い回すときって「メールで確認とかって事態で、何度も再利用するのが容易に想像される」ので、そのままコピペしたいのですよ。

参考。

PHP で使える PCRE のバージョン

昨日のメモ書きを眺めていてふと PCRE のバージョンが気になった。手元の環境では

PHPPCRE
4.2.4-dev3.4
4.3.104.5

になっている。PCRE の ChangeLog によると

  • 3.3 で utf-8 サポート開始
  • 3.8 で

The experimental UTF-8 code was completely screwed up. It was packing the bytes in the wrong order. How dumb can you get?

PHP のマニュアルによると Unix 版は 4.1.0 から、Win32版は 4.2.3 から utf-8 サポートが有効になっているらしい。

PHP の ChangeLog によると

PHPPCRE
4.3.54.5
4.3.34.3
4.3.03.9
4.2.3Win32 で utf-8 対応を有効に
4.0.53.4

ということなので、4.3.0 以降は preg で utf-8 使って大丈夫と判断していいかな?

SheepShaver

http://member.nifty.ne.jp/poseidon/emu/sheepshaver1.html

from スラドの http://slashdot.jp/comments.pl?sid=144358&cid=462976

へぇ。PPC エミュレータ。要 Mac のシステム ROM。

8.6 までの MacOS が動くそうで。十分じゃないですか。動かしてみてないのでスピードなどの使い勝手は分かりませんが、PPC で 8.6 ならけっこういろんなアプリが動くし、スピードはプロセッサメーカーがある程度勝手に問題を解決してくれるので、これはかなりいいかもしんない。

もちろん OS X に移行できる環境ならそれがいちばんいいですが、古い環境を残しておかなければいけない、でも機械は古いし遅いし、そのくせ場所取るし、、、という状況には向いているでしょう。(かなり限定される気もするけど。)もちろん遊びにも向いているし、Web なんかのマルチプラットフォームを常に意識する状況にも向いているなぁ。(古い PCI Mac なんかけっこうお手頃価格で手に入るだろうし。)

PHP の OO を(自分流に)少し洗練させてみる

Perl が今のところネイティブな言語である自分には、PHP はイマイチ自由が利かないとやはり感じてしまう部分がある。

その一つはコンストラクタが値を返せないこと。これができないとインスタンスの生成について失敗を示す偽を返すことができない。でもこれが OO の基本的なスタンスなのであれば仕方がないので別な方法を考えた。

これはたぶんさらに異なる言語を扱う機会が出てきても通用する。Perl 脱却へのさらなる一歩でもあるわけだ。

忘年会とかなんとか

面白い時期に今の会社に入ったものだと思う。もちろん社員全員やる気があってこれから伸びるぞ、などというあほな意味ではないが、価値観のギャップを埋め込むにはいいタイミングかもしれない。暗躍は得意ではないが、そうも言っていられない。潜行するには自分の価値観を早く固めてそれが熱く語るようなシロモノではないくらいに自分の中で消化する必要がある。年内にビジョンは固めておくか。

認識違ってました。

先日の飲み会で小便器のことを「朝顔」と呼んだところ、誰にも通じなかった。そこで調べてみた。

http://www.lint.ne.jp/~takuya/wc/wc111.htm

うーん、普通に見かける小便器は朝顔ではないらしい。

っつーかそういう話じゃないんだけども。通じなかったことのショックがことのほか大きかったです(笑)

About

例によって個人のなんちゃらです