StackdriverでGCP上のサービスを監視してみた

今関わっているサービスは、GCPGoogle App Engine (GAE) とGoogle Container Engine (GKE) を使って開発しています。そのサービスの監視にStackdriver Monitoringを使ってみたときのメモです。

現在の印象としては、かなり面白い機能はあるけど、基本的に思えることがうまくできないことがある、なかなか癖のある監視サービスという感じです。いくつかの機能について思ったことを以下に書いておきます。

Uptime Checks

Uptime ChecksはStackdriverの各種機能の中でも割とちゃんと使える機能だと感じました。

大抵の監視サービスだとUptime Checksのチェック先はURLで指定すると思いますが、StackdriverではGAEのModuleやグループで指定できます。下の図は(ぼかしでやや分かりづらいですが)GAEのModuleを選んでいるところです。

f:id:ks888:20160720210822p:plain

細かな設定として、文字列マッチングによる成否条件の設定や、任意のHTTP Header付与もできます。

f:id:ks888:20160720211011p:plain

デフォルト設定でも6リージョンからチェックしてもらえるのは驚きました。まぁ6リージョンいるかは分かりませんが。笑

f:id:ks888:20160720211324p:plain:w500

Pingdomのような外形監視が売りのサービスに比べるとトランザクショナルな監視がないとかありますが、基本的な機能は揃っており、十分使えるレベルだと思います。

リソースの監視

リソース監視は、最初から色々設定されていて助かりましたが、結構ハマりどころがありました。

ある程度のリソース監視は最初から設定されています。特にGAEについては、結構充実しています。まぁPaaSですしね。例えば以下の項目です。

  • Response Codeごとのカウント
  • Response LatencyのAverageと95th percentile
  • CPU使用量
  • メモリの使用量
  • Datastoreの各種操作回数

また、以下のようなグラフも最初から設定されています。以下はHTTP関連のグラフです。

f:id:ks888:20160720211734p:plain

一方で、最初から設定されているグラフにデータが全く来ない、ドキュメントの手順どおりに操作しても監視エージェントをインストールできないなど、ハマりどころもかなりありました。

特に、GKEが起動・管理するGCEインスタンスに、監視エージェントを自動インストールする方法は今でもよく分かりません。手動ならできるのですが。。そもそも、そこは監視しなくていいということなんでしょうか。。

また、相対値をグラフで見たいときにどうするのか、よくわかりませんでした。例えばメモリ使用量ではなくメモリ使用率を見たい場合とか、HTTPリクエストが5XXを返す割合を見たい場合です。収集した値に対する演算は、合計、平均、95th Percentileなど色々ありますが、相対値を見るための方法は見つかりませんでした。

リソース監視については、機能あるいはドキュメントがやや不足気味で、ちょっと使いにくい部分があると思います。

アラート

アラートは設定が大変だったので、正直あまり使いたくないです。

機能不足なわけではないです。機能に関しては、AWSのCloudWatchとかと比較してもそれほど遜色ないと思っています。アプリケーションのログにフィルターをかけてメトリクスとアラートを作成したり、複数のリソースからの値を集約したりできます。以下のように、結構色々な集約方法を選べます。

f:id:ks888:20160723130931p:plain

また、アラートを鳴らす条件を複数設定できるので、例えば、特定のパスにリクエストが来ているときはアラートを鳴らさない、みたいな設定もできます。まぁあまりこだわった条件にすると、メンテが大変そうですが。

アラートで大変だったのは、アラート作成のAPIが見当たらなかったことと、(全GAE Moduleなどの)グループに対してまとめてアラートを設定する機能がうまく動かなかったことです。その結果、個別のGAE Moduleごとに複数のアラートを手動で設定することになってしまいました。当然、時間がかかりますし、設定ミスもありますし、バージョン管理もできません。

さらに、作成したアラートを保存しようとすると「Failed to Save Policy. Please try again or contact support.」と言われ、何度やっても保存できなくなるバグもありました。諦めて最初からアラートを作りなおすとうまく行きます。

このように設定作業で苦しんだので、アラートは僕の中ではあまり使いたくない機能になっています。こうすると楽だよーみたいなのあれば教えて下さい!

感想

まだβですし、ドキュメントも公開されているノウハウもかなり不足していますし、バグじゃないか?と思える挙動もあります。でも、GAEとの相性はいいし、面白い機能もあるので、余裕があれば使ってみるのもありだと思います。

AWS LambdaでCI環境を作れるOSS「LambCI」試用メモ

これまでそれほど縁がなかったサーバレスですが、LambCIというOSSを使うとAWS LambdaでCI環境が作れるという話を聞き、ちょっと使ってみました。

GitHub - lambci/lambci: A continuous integration system built on AWS Lambda

LambCIとは

LambCIの紹介としては作者がMediumに投稿した記事がわかりやすいです。

Introducing LambCI — a serverless build system – Michael Hart – Medium

LambCI開発の背景部分をかいつまんで書き出すと、以下のような感じです。

  • CircleCIみたいなサービスは、運用は楽なんだけど、結構高い
  • Jenkinsみたいな自前環境は、運用が大変
  • サーバレスアーキテクチャでCIサービスを作れば、運用は楽だし、ビルド処理分だけのお金で済みそう

LambCIの主な構成要素としては、以下のような感じです。ほとんどの構成要素は、CloudFormationで数分で作成できます。

ビルド処理は、レポジトリ内の.lambci.jsonあるいは.lambci.jsというファイルに書きます。以下は.lambci.jsonの例で、Pythonのtoxでテストを実行しています。

{
  "cmd": "pip install --user tox && tox"
}

実際にビルドしてみると、以下のような画面でビルド結果を確認できます。この画面はS3内にhtmlファイルとして保存されています。

f:id:ks888:20160710164510p:plain

AWS Lambda内の処理について

Lambda Function内の処理はNode.jsで記述されています。Node.jsが、.lambci.jsonで指定されたコマンドをbash経由で実行します。

実行できる処理

Lambda Functionの実行環境内でできる処理はなんでもできますが、足りないバイナリやライブラリは自分で用意する必要があります。例えばGoツールは含まれていないので、go testとかしたい場合は、Goツールをダウンロードする必要があります。

そのほか、Lambda Functionの実行環境については、以下の記事に書かれています。

AWS Lambdaをいろいろ暴く - Qiita

ちなみにPythonはやや特別扱いされています。PythonはLambdaの実行環境に元々含まれている上に、LambCIがpipをバンドルしてくれているので、いきなりpipを使用できます。

ビルドの並列化と実行時間制限

TravisやCircleCIだと、設定ファイルを読んでビルドの並列化をしてくれますが、LambCIにはまだそういう機能はまだありません。これに、Lambda Functionの最大実行時間5分という制限が加わると、ちょっと厄介です。ビルドを並列化なしで5分で済ませないといけません。

LambCIとしては、ビルドをAmazon ECS(EC2 Container Service)上で実行することで、この制限を超える方法を用意しています。Dockerコンテナの中でさらにDockerコンテナを動かす仕組みになっていて、内側のDockerコンテナでビルド処理が動きます。このECSを使った方法ですが、避けたはずの「運用」の二文字が再び見え隠れしてきて、個人的にはイヤな感じがします。

まぁビルドの並列化についてはv1.0へのロードマップにも出ているので、そのうち実装されると思います。

感想

これまでCI環境を用意するとなると、それなりの運用コストを払って自前環境を作るか、お金を払ってCircleCIとか使うか、という選択肢だった気がします。LambCIはここに、運用コストを大幅に抑えつつ自前環境を作る、という選択肢をもたらすかも、と思いました。現状はまだ最低限の機能しかありませんが、v1.0が出る頃にはかなり使えるモノになっている気がします。

個人的には、LambCIに対するCircleCIとかの反応が気になります。例えば、課金モデルはどうなるでしょうか。CircleCIとかは、並列度を上げたいならもっとお金を払ってね、というモデルです。対してLambCIは、どれだけ並列度を上げてもAWSに払う金額は変わりません。あくまで合計ビルド時間に応じた料金が発生するだけです。

ユーザは、最初はCircleCIを使っていたとしても、並列実行するために高いお金を払うぐらいならLambCIに移行しようと考えそうです。そんな感じでユーザーが離れていくと、並列度に対して課金するモデルは成立しなくなり、合計ビルド時間に対して課金するモデルとかに移行せざるを得なくなるのでは、とか妄想しています。

追記: LambCIと似たコンセプトで、LambStatusというOSSを作っています。サービスの稼働状況をユーザに伝えるステータスページ(例:GitHubのステータスページTravis CIのステータスページ)を、サーバレスに実現するOSSです。よかったら見てみてください

各EC2インスタンスに配置したSnortのアラートをELK (ElasticSearch, Logstash, Kibana) で監視する

EC2でネットワークのパケット監視をしたい場合、どうするのがいいんでしょうか。商用だとDeep SecurityとかAlert Logicとかありそうですが、値段もそれなりにします。なんとかOSSでできないかということで、ネットワーク型IDS/IPSであるSnortと、ELK (ElasticSearch, Logstash, Kibana)の組み合わせを試してみました。

f:id:ks888:20160607131820p:plain

構成

Snortを使う場合、監視用のサーバにSnortを入れて、そのサーバにネットワークを流れるパケットを監視させる形がふつうなようです。ただEC2でこの形を実現するのは大変そうなので、今回は各EC2インスタンスSnortを入れる形にしてみます。各インスタンスは自分のところに来たパケットだけを監視します。

また、これだけだとSnortの出すアラートが各インスタンスに散らばってしまいます。そこで、アラートをlogstashで集めて、Amazon Elasticsearch Serviceに送るようにします。Snortに対応したネットワーク監視WebアプリとしてSnorbyというのもあるようですが、こういうログもKibanaから見たいなーと思ってElasticsearch Serviceにしてみました。

Snortの設定

Snortの設定はまじめにやると面倒そうです。こちらの記事等に手順はまとまってますが、かなり長いです。

今回はお試しということで、こちらのシェルスクリプトを実行すると、aptでのインストール+必要な設定がされるようにしました。OSはUbuntu 14.04です。スクリプト内では、以下の設定をしています。

  • 監視範囲のネットワークを絞る(自ホストだけ監視するようにする)
  • アラートのフォーマットをlogstashから扱いやすいものにする
  • checksumモードの変更。デフォルトのモードだと、Snortルールのuricontentという記法がうまく機能しなかったため。
  • logstashから読めるように、ファイルとディレクトリのパーミッションを変更。

Amazon Elasticsearch Serviceの設定

AWSのコンソールからぽちぽちやって、Elasticsearch+Kibanaを構築しました。ほぼデフォルトのままですが、Access Policyは、Snortを入れたEC2インスタンスのパブリックIPアドレスと、Kibanaでログを見るマシンのIPアドレスからアクセスできるように設定しました。Elasticsearchのエンドポイントは後で使うのでメモしておいて下さい。

構築できたら、次のようなリクエストを出して、snort-alertというインデックスを作成します。stringタイプのフィールドの値をindex化するとき、値を勝手に変更しないように設定しています。これをしないと、a-bという値が、abに分割されたりします。また、SrcGeo.locationというプロパティの型も指定しています。これは後で位置情報を使ったグラフを作るときに役立ちます。

curl -XPUT [Elasticsearchのエンドポイント]/snort-alert -d '{
  "mappings": {
    "logs": {
      "dynamic_templates": [
        {
          "notanalyzed": {
            "match": "*",
            "match_mapping_type": "string",
            "mapping": {
              "type": "string",
              "index": "not_analyzed"
            }
          }
        }
      ],
      "properties": {
        "SrcGeo": {
          "properties": {
            "location": {
              "type": "geo_point"
            }
          }
        }
      }
    }
  }
}'

Logstashの設定

Logstashは、こちらのシェルスクリプトを実行すると、elastic社のレポジトリからlogstashをインストール+必要な設定をするようにしました。スクリプト内では、Snort/var/log/snort/alertというファイルに出したアラートを、Elasticsearchに投げる設定をしています。ENDPOINT変数は、Elasticsearchのエンドポイントを入れて下さい。

擬似的な攻撃をしてみる

では、Snortを入れたサーバに攻撃してみて、Kibanaからログを確認できるか試してみます。と言いたいところですが、EC2インスタンスに攻撃する場合は、事前申請が必要です。

申請して許可を待つのも時間がかかるので、今回は擬似的な攻撃と、擬似的な攻撃に反応してアラートを出すSnortルールを作成します。擬似的な攻撃として、pseudo_web_attackあるいはpseudo_dos_attackという文字列をHTTPリクエストのURIに含める攻撃がある、とします。この攻撃に反応するSnortルールとして、次のようなルールを作成します。

alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"Pseudo WEB-ATTACKS"; flow:to_server,established; uricontent:"pseudo_web_attack"; nocase; classtype:web-application-attack; sid:1000001; rev:1;)
alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"Pseudo DoS attack"; flow:to_server,established; uricontent:"pseudo_dos_attack"; nocase; classtype:attempted-dos; sid:1000002; rev:1;)

パッと見はややこしそうですが、実際は、HTTPリクエストのURIに特定の文字列が含まれていないか見ているだけです。このルールは、Snortを入れたサーバの/etc/snort/rules/local.rulesに追記して下さい。追記したらSnortを再起動します。

準備ができたら、http://[Snortを入れたサーバのIPアドレス]/pseudo_dos_attack、あるいはhttp://[Snortを入れたサーバのIPアドレス]/pseudo_web_attackにアクセスします。

成功していれば、KibanaのDiscover画面から、Snortのアラートログが確認できると思います。例えば次のような画面です。

f:id:ks888:20160531184953p:plain

攻撃の様子をグラフで表示する

せっかくKibanaにログを集めたので、色々なグラフを出してみます。まずは直近の攻撃回数の折れ線グラフです。攻撃の種類ごとに線の色を分けてみました。

f:id:ks888:20160531182035p:plain

Web Application Attack(緑色の線)とAttempted Denial of Service(濃い青色の線)は、擬似的な攻撃によるものです。残りは何もしていないのに出ているアラートです。False Positiveなアラートだと思うので、Snortルールのチューニングが必要そうです。

次も直近の攻撃回数の折れ線グラフですが、ホストごとに線の色を分けています。よく攻撃されているホストがわかります。

f:id:ks888:20160607131754p:plain

最後は攻撃元の位置情報を世界地図上にマップした図です。円の色の濃さで攻撃回数の大小がわかります。

f:id:ks888:20160531182322p:plain

まとめて、ダッシュボード化してみました。

f:id:ks888:20160607131820p:plain

まとめ

Snort+ELKでネットワークのパケット監視をやってみました。今回はSnortの設定をかなり省略しましたが、実際はルールの更新とかルールのチューニングが必要そうです。また、Snortを各サーバに入れる形だと、Snortがサーバ本来の処理を阻害しないか不安です。そもそも実際の環境だと、全サーバにSnortを入れるより、入り口付近のサーバにだけ入れれば十分な気がします。このあたりはまた調べたいなーと思います。