AC、オンプレミスとクラウドのアプリを統合できるiPaaSを提供

接続可能なアプリケーションコネクターは300を超え、SalesforceやGoogle、Microsoft Azure、AWS(アマゾン ウェブ サービス)、NetSuite、Workday、ServiceNow、Box、Dropbox、Marketo、Slack、Zendesk、Jira、Concurなどのクラウドサービスに対応済みだ。 Excelの関数や簡単なマクロを扱える程度の能力があれば、 … 続きを読む

ZendeskのチケットデータをAmazon Elasticsearch Serviceへ自動的にアップロードする | Developers.IO

Amazon Elasticsearch ServiceはAmazon VPCプライベートサブネットに作成; Amazon API Gateway経由でAWS Lambdaを実行させる; Zendeskの自動化とwebhookでAmazon Elasticsearch Serviceへデータを入れるまでを自動化する; Amazon Elasticsearch Serviceへ入れるデータスキーマ … 続きを読む

AMIMOTO AMI の WordPress に同報されているプラグイン

https://ja.amimoto-ami.com/technology/

AMIMOTO AMI の WordPress に同報されているプラグインがどんなものなのか紹介。
なお、記事執筆時点のものなので注意。
AMIMOTOの場合、AMIにWordPress及び追加プラグインが含まれているわけではなく、インスタンス起動時(あるいは wp-setup 実行時)に走るシェルスクリプトによってWordPressの最新版とシェルスクリプト内で指定したプラグインがインストールされるので、変更される可能性があります。

パフォーマンス

Nginx Cache Controller

https://wordpress.org/plugins/nginx-champuru/

Nginx リバースプロキシキャッシュの制御。AMIMOTOなら必ず有効化しておくこと。
逆に AMIMOTO なら他のキャッシュ系プラグインは不要

参照:https://amimoto-ami.zendesk.com/hc/ja/articles/216467137

C3 Cloudfront Cache Controller

https://ja.wordpress.org/plugins/c3-cloudfront-clear-cache/

AWS CloudFront のキャッシュを消すプラグイン。
CloudFrontを使わない構成なら不要。

参照:http://wp-kyoto.net/c3-cloudfront-clear-cache/

Nephila clavata

https://wordpress.org/plugins/nephila-clavata/

WordPressのメディアをS3に移して運用できる。元データはEC2インスタンス内部にも残るので、プラグインをオフにしてもメディアが消えることはない。

参照:https://ja.amimoto-ami.com/2016/04/06/store-wordpress-media-folder-amazon-s3/

開発者向け

Debug Bar 他

パフォーマンスやエラー内容、ボトルネック探し、など。
公開中のサイトにより開発時に使う。

セキュリティ

Login LockDown

https://wordpress.org/plugins/login-lockdown/

ログイン試行制御。指定した回数ログインを失敗したIPアドレスを記録して、そのIPアドレスからは一定時間ログインを不能にする。
参照:https://amimoto-ami.zendesk.com/hc/ja/articles/216466727

Rublon Account Security: Two-Factor Auth+

https://wordpress.org/plugins/rublon/

多要素認証。
参照:https://plasticdreams.org/2015/12/04/are-you-tired-of-mfa/

その他

AMIMOTO Dashboard

https://wordpress.org/plugins/amimoto-dashboard/

Nginx Cache Controller / C3 CloudFront Cache Controller / Nephila clavataの管理を一括でできるプラグインです。

Nginx Mobile Theme

https://wordpress.org/plugins/nginx-mobile-theme/

Nginx リバースプロキシ環境下でユーザーエージェントによってPC用・モバイル用のテーマ切り替え。
同様のプラグインは複数ありますが、AMIMOTOではこちらを使いましょう。

Contact Form 7

https://wordpress.org/plugins/contact-form-7/

言わずと知れたお問い合わせフォームプラグイン。

Flamingo

https://wordpress.org/plugins/flamingo/

Contact Form 7 で送信されたメッセージを DB に保存。ダッシュボードから確認。

参照:http://contactform7.com/ja/save-submitted-messages-with-flamingo/

Simple GA Ranking

https://wordpress.org/plugins/simple-ga-ranking/

Google Analyticsのデータと同期してランキングを表示。
WordPressのDB内部にランキングデータを保存しないのでDBの負担にならない。

参照:http://simple-ga-ranking.org/ja/

続きを読む

Amazon Cognito User Poolsを使ってZendeskのヘルプセンターにシングルサインオンを行う

概要

Amazon Cognito User Poolsで認証認可を行うアプリケーションからZendeskへSSOをする場合を考えてみます。
自分たちのwebサービス用のダッシュボードからサポートやヘルプデスクはZendeskに投げてしまいたいというケースは結構あると思うのですが、そういったユースケースに使えると思います。

構成

Untitled.png

構成はAPI Gateway + Lambdaの構成で考えます。
まず、前段のAPI認証では、API GatewayのCustom Authorizerの機能を使います。詳細はAmazon API Gateway の Custom Authorizerを使い、User PoolsのユーザでAPI認証を行うにあります。

API認証を通過して認可を受ければ、SSO用LambdaファンクションでZendeskへのSSOを実施します。

Zendeskの設定

JWT(JSON Webトークン)を使用したシングルサインオンの設定
今回はこちらを使用してSSOを実装します。

スクリーンショット 2016-06-01 9.27.42.png
Zendeskのコンパネからエンドユーザに対するSSOを有効化してください。その際に共有シークレットが表示されるのでそれをメモしてください。共有シークレットは必ず外部に漏れないように気をつけましょう。

SSO Lambda function

'use strict';
var jwt = require('jwt-simple');
var uuid = require('node-uuid');

var subdomain = '<Zendeskのサブドメイン>';
var shared_key = '<Zendeskの共有シークレット>';

module.exports.handler = function(event, context) {
  var payload = {
    iat: (new Date().getTime() / 1000),
    jti: uuid.v4(),
    name: event.email,
    email: event.email
  };
  var token = jwt.encode(payload, shared_key);
  var sso_endpoint = 'https://' + subdomain + '.zendesk.com/access/jwt?jwt=' + token;
  context.succeed(sso_endpoint);
};

SSO用のエンドポイントを返却します。後はクライアント側でlocation.href = JSON.parse(sso_endpoint);とかやってあげるとZendeskにシングルサインオン実施されます。

実践

1. User Poolsを使ったアプリケーションにログインします。

スクリーンショット 2016-06-01 9.35.30.png

2. horike@digitalcube.jpでログインを行えました。そしてサポートのボタンをクリックします。

スクリーンショット 2016-06-01 9.36.01.png

3. SSOが走ってZendeskへリダイレクトされます。Zendeskで側を確認すると自動でhorike@digitalcube.jpというユーザが作られているのがわかります。

スクリーンショット 2016-06-01 9.36.33.png

続きを読む

TwilioAPIを使用してZabbix + AWS CloudWatchのシステム監視で異常検知した時に電話で通知する

はじめに

Webサイトやサーバの監視において、Webサイト停止やサーバ停止等の異常を検知した場合、メールで異常を通知する事が多いと思います。

「Twilio」というクラウドAPIサービスを使用すると、RubyやPHPといった様々なプログラム言語から、指定した電話番号に対して、簡単に電話をかけたりSMS通知を行なえます。
http://twilio.kddi-web.com/

この間、ZabbixやAWS CloudWatchによるシステム監視で、Webサイト停止やサーバ停止といった異常を検知した時、TwilioAPI(Ruby)を使用して、電話で障害を通知する仕組みを作ってみましたので、まとめていこうと思います。

システム構成

以下のような構成で、ZabbixやAWS CloudWatchからTwilioAPIをコールして、電話で障害を通知する仕組みを作ってみました。

ZabbixサーバやTwilioAPIサーバ(詳細は後述)については、Amazon EC2のAmazon Linux上に構築しました。

構成図.png

Twilioの利用を開始するまでの流れ

まず、Twilio公式サイトにサインアップして、Twilioアカウントを作成します。
http://twilio.kddi-web.com/

スクリーンショット 2016-04-19 21.46.40.png

スクリーンショット 2016-04-19 21.47.50.png

Twilioアカウントを作成したら「プラグラマブル Voice」->「はじめよう」をクリックすると、「Twilio音声通話 電話番号」が発行されます。

スクリーンショット 2016-04-19 21.49.33.png

TwilioAPIを使って電話をかけると、発行された「Twilio音声通話 電話番号」の電話番号から電話がかかってきます。
https://jp.twilio.com/user/account/voice/phone-numbers

次に、APIクレデンシャル画面で、TwilioAPIを利用する為の「ACCOUNT SID」「AUTH TOKEN」と確認します。
https://jp.twilio.com/user/account/voice/getting-started

TwilioAPIを使用したTwilioクラウドサービスへの電話発信について

ZabbixやAWS CloudWatchから簡単に電話をかけられるよう、Ruby + SinatraでTwilioAPIサーバを作成してみました。

ZabbixやAWS CloudWatchからTwilioAPIサーバをコールする事で、Webサイトやサーバ監視で異常を検知した時、電話をかけれるようにしました。

TwilioAPIを使用して電話をかけるサンプルコード、またTwilioAPIを使う時に気をつけた方が良さそうな点について記載致します。

・TwilioAPIで電話をかけるには、TwilioクラウドサービスからTwilioAPIへのHTTPコールバック通信を通す必要があります。AWSのNetworkACLsやセキュリティグループで、TwilioクラウドサービスからTwilioAPIサーバへのHTTP通信を許可しておく必要があります。

https://twilioforkwc.zendesk.com/entries/82773249-TwilioがアクセスしてくるIPアドレスレンジは何ですか-

・サンプルコードでは、GETで電話をかける電話番号をパラメータ指定出来るようにしていますが、電話番号は秘匿した方が良い情報なので、実際の運用時にはGETでパラメータ渡さない方が良いと思います。また、発信先の電話番号は特定番号だけに絞る、API認証を設ける等の対応も適宜行なうのが良いかと思います。

・Twilioで電話をかける際には、電話番号をE.164形式に変換する必要があります。
  Twilioから電話をかける電話番号 090-XXXX-1234 → +8190XXXX1234
  Twilio音声通話 電話番号 050-XXXX-5678 → +8150XXXX5678

・サンプルコード内では「phony」を利用させて頂く事で、GETパラメータで「090-XXXX-1234」のような発信先の電話番号を指定する際、内部的に「+8190XXXX1234」のようなE.164形式の電話番号に変換し、Twilioクラウドサービスへ電話発信のリクエストを投げて、電話をかけるようにしています。
https://github.com/floere/phony/blob/ebcfcb42f3c50a8d1c9e23d9ae05b338c8cc6a95/qed/country-specific.md

・電話番号のE.164形式については、以下をご参照下さい。
https://www.nic.ad.jp/ja/basics/terms/E164.html

TwilioAPIで電話をかけるサンプルコード

以下がTwilioAPIのサンプルコードになります。

雑多なコードで済みませんが、以下のようにTwilioクラウドサービスが提供するAPI(client.account.calls.create)を利用する事で、指定した電話番号に電話をかける事が出来ます。

twilio_api_server.rb
[root@twilio-example-server ~]# cat /root/twilio/twilio_api_server.rb 
require 'rubygems'
require 'twilio-ruby'
require 'sinatra'
require 'sinatra/reloader'
require 'json'
require 'phony'

get '/call/test' do
  # put your own credentials here 
  @account_sid = 'Twilioアカウント APIクレデンシャルのACCOUNT SID'
  @auth_token = 'Twilioアカウント APIクレデンシャルのAUTH TOKEN'

  @to_tel_number = '+8190XXXX1234'
  @from_tel_number = '+8150XXXX5678'

  # set up a client to talk to the Twilio REST API 
  @client = Twilio::REST::Client.new @account_sid, @auth_token 

  call = @client.account.calls.create(
      :url => "http://demo.twilio.com/docs/voice.xml",
      :to => @to_tel_number,
      :from => @from_tel_number
  )
  puts call.to

  "Twilio API Test Target Tel Number = [#@to_tel_number]]"
end

get '/call' do

  if params['api_key'] == nil
    halt 400, 'API Key Parameter Not Found!'
  end

  if params['api_key'] != 'twilio-api-sample-key'
    halt 400, 'API Key Wrong!'
  end

  if params['to_tel_number'] == nil
    halt 400, 'To E.164 Telephones Number Parameter Not Found!'
  end

  if params['to_tel_number'].count("-") != 2 then
    halt 400, 'To Telephones Number Format Error [XXX-XXXX-XXXX]!'
  end

  if params['tel_messages_type'] == nil
    halt 400, 'Telephones Messages Type Parameter Not Found!'
  end

  # put your own credentials here
  @account_sid = 'Twilioアカウント APIクレデンシャルのACCOUNT SID'
  @auth_token = 'Twilioアカウント APIクレデンシャルのAUTH TOKEN'

  @to_tel_number = params['to_tel_number']
  @tel_messages_type = params['tel_messages_type']
  @from_tel_number = '+8150XXXX5678'

  ## https://github.com/floere/phony/blob/ebcfcb42f3c50a8d1c9e23d9ae05b338c8cc6a95/qed/country-specific.md
  @japan = Phony["81"]
  @to_tel_number = @japan.normalize( @to_tel_number )
  @to_tel_number = '+81' + @to_tel_number
  ##

  if @tel_messages_type == "zabbix_site_alert" then
    @twiml_url = 'http://TwiMLサーバのIPアドレスやFQDN/twilio_test_zabbix_site_alert.xml'
  elsif @tel_messages_type == "cloudwatch_disk_alert" then
    @twiml_url = 'http://TwiMLサーバのIPアドレスやFQDN/twilio_test_cloudwatch_disk_alert.xml'
  elsif @tel_messages_type == "cloudwatch_instance_stop_alert" then
    @twiml_url = 'http://TwiMLサーバのIPアドレスやFQDN/twilio_test_cloudwatch_instance_alert.xml'
  else
    @twiml_url = 'http://TwiMLサーバのIPアドレスやFQDN/twilio_test.xml'
  end

  # set up a client to talk to the Twilio REST API
  @client = Twilio::REST::Client.new @account_sid, @auth_token

  call = @client.account.calls.create(
        :url => @twiml_url,
        :to => @to_tel_number,
        :from => @from_tel_number
  )
  puts call.to

  "Twilio API Test Target Tel Number = [#@to_tel_number]]"
end

get '/' do
  erb :index
end

get '/about' do
  erb :about
end

post '/confirm' do

  if params[:to_tel_number] == '' || params[:to_tel_number] == nil then
    halt 400, 'To E.164 Telephones Number Parameter Not Found!'
  end

  if params[:to_tel_number].count("-") != 2 then
    halt 400, 'To Telephones Number Format Error [-] Not Found! Example Number Format [XXX-XXXX-XXXX]!'
  end

  @to_tel_number = params[:to_tel_number]

  @japan = Phony["81"]
  @to_tel_number = @japan.normalize( @to_tel_number )
  @to_tel_number = '+81' + @to_tel_number
  ##

  # put your own credentials here
  @account_sid = 'Twilioアカウント APIクレデンシャルのACCOUNT SID'
  @auth_token = 'Twilioアカウント APIクレデンシャルのAUTH TOKEN'

  @from_tel_number = '+8150XXXX5678'

  @twiml_url = 'http://TwiMLサーバのIPアドレスやFQDN/twilio_test.xml'

  # set up a client to talk to the Twilio REST API
  @client = Twilio::REST::Client.new @account_sid, @auth_token

  call = @client.account.calls.create(
      :url => @twiml_url,
      :to => @to_tel_number,
      :from => @from_tel_number
  )
  puts call.to

  erb :confirm

end
[root@twilio-example-server ~]#

TwilioAPIから電話をかけれるようにするには、TwilioAPIサーバ上でサンプルコードを実行します。

[root@twilio-example-server ~]# ruby /root/twilio/twilio_api_server.rb -o 0.0.0.0 -p 80 &
[1] 3337
[root@twilio-example-server ~]#

[root@twilio-example-server ~]# ps awux | grep -v grep | grep ruby
root      3337  0.8  6.1 220624 30932 pts/0    Sl   19:42   0:00 ruby /root/twilio/twilio_api_server.rb -o 0.0.0.0 -p 80
[root@twilio-example-server ~]#  

・Twilioから電話かけた時に流す音声メッセージは「TwiML」というファイルで定義します。

TwiMLファイルはTwilioAPIサーバ自身に置いても、別のHTTPサーバに置いても良いようです。今回は別のサーバにTwiMLファイル置けるか試したかったので、TwilioAPIサーバ以外にTwiMLファイルを作成してみました。

TwiMLファイルのサンプル
[root@TwiML-example-server ~]# cat /var/www/html/twilio_test_zabbix_site_alert.xml
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Say language="ja-jp">TwilioとZabbix</Say>
    <Say language="ja-jp">の監視テストです。</Say>
    <Say language="ja-jp">監視対象サイト</Say>
    <Say language="ja-jp">が停止しました。</Say>
</Response>
[root@TwiML-example-server ~]# 

TwilioAPIで電話をかける例

Webブラウザを起動し、以下のようにTwilioAPIサーバへアクセスすると、090-XXXX-1234に電話をかける事が出来ます。

http://TwilioAPIサーバのIPアドレスやFQDN/call?api_key=twilio-api-sample-key&to_tel_number=”090-XXXX-1234″&tel_messages_type=zabbix

ZabbixやAWS CloudWatchのシステム監視で異常を検知した時、上記のようにTwilioAPIをコールすると、電話をかける事が出来ます。
電話を取ると、TwiMLファイルに記述したメッセージが流れます。

ZabbixからTilioAPIサーバ経由で電話をかける

Zabbixのアクションで以下のようなアクションを設定し、監視トリガーでアクションを設定すると、監視で異常を検知した時に電話をかける事が出来ます。

Zabbixで設定するアクション
/usr/bin/curl -s "http://TwilioAPIサーバのIPアドレスやFQDN/call?api_key=twilio-api-sample-key&to_tel_number=%22090-XXXX-1234%22&tel_messages_type=zabbix_site_alert"

zabbix1.png

zabbix2.png

zabbix3.png

AWS CloudWatchからTwilioAPIサーバ経由で電話をかける

AWS CloudWatchからは直接APIをコール出来ないので、AWS Lambdaに以下のようなファンクションを作成します。

AWS CloudWatchの監視で異常を検知した時、AWS CloudWatch -> AWS SNS -> AWS Lambdaファンクションを実行するように設定します。これによりAWS CloudWatchによる監視で、EC2インスタンスの停止やディスク使用率超過等を検知した時、電話をかける事が出来ます。

TwilioAPIで電話をかけるLambdaファンクションのサンプルコード
console.log('Loading function');

exports.handler = function(event, context) {
    var exec = require('child_process').exec;

    var cmd = "curl -s 'http://TwilioAPIサーバのIPアドレスやFQDN/call?api_key=twilio-api-sample-key&to_tel_number=%22090-XXXX-1234%22&tel_messages_type=cloudwatch_disk_alert'"
    var child = exec(cmd, function(error, stdout, stderr) {
        if (!error) {
            console.log('standard out: ' + stdout);
            console.log('standard error: ' + stderr);
            context.done();
        } else {
            console.log("error code: " + error.code + ", err: " + error);
            context.done(error,'lambda');
        }
    });
};

スクリーンショット 2016-04-19 21.02.31.png

スクリーンショット 2016-04-19 21.03.22.png

スクリーンショット 2016-04-19 21.05.50.png

スクリーンショット 2016-04-19 21.08.28.png


ざっとまとめてみましたが、障害の緊急度や影響度を踏まえて、軽微な障害では、電話による通知でなく、SMSによる通知でも良いかもしれませんね。

メール・電話といった障害通知手段を上手く組み合わせて、システム障害を検知しやすくしたいですね。

細かい設定や情報はあらためて記載していきたいと思います。

続きを読む