読者です 読者をやめる 読者になる 読者になる

mmts1007’s diary

プログラミング関連の技術系ブログです。

SAML 認証を Ruby on Rails で試してみた

Ruby Rails SAML 認証技術

SAML 認証に触れる機会があったので、 Ruby on RailsSAML 認証するサンプルアプリを作ってみた
折角なので、SAML とは何なのか?あたりからまとめてみようと思います。

SAML とは

まずは、SAML とは何なのか

  • 読み方は サムル
  • Security Assertion Markup Language の略
  • 異なるサービス、アプリケーション間で認証情報を交換するための仕組み
    • これによりシングルサインオン(1度のログインで、複数のアプリが利用可能になること) が実現できる

登場人物

Identity Provider

  • 略称は IdP
  • 実際の認証処理を行う人。認証したユーザの情報(ID、 メールアドレス等)を提供してくれる

Service Provider

  • 略称は SP
  • 認証情報を利用する人

今回は SP のサンプルを作成しました。

認証フロー

SAML の認証フローのイメージです。 f:id:mmts1007:20170121235429p:plain

  1. ユーザは SP に対してログインを試みる
  2. SP は Idp に対して認証リクエストを送信する
  3. IdP はユーザにログイン画面を表示する
  4. ユーザはログイン情報を入力する(ex. ID / Password)
  5. IdP は入力情報を検証し、正しければ SP に認証結果を送信
  6. SP は認証結果を検証し、正しければユーザをログインさせる


SAML の説明はこのあたりにして、サンプルアプリについて説明します

構成

IdP

サンプルアプリを動かすためには IdP が必要なので、今回は IdP に Azure Active Directory を利用しました。

azure.microsoft.com

SP

SP は以下の技術要素で作成

また、SAML のライブラリとして ruby-saml を使用しました。

github.com

サンプルアプリ

サンプルアプリはメモ管理アプリとなっています。
Azure AD で認証したユーザのメモ一覧・登録・更新・削除ができる簡単なものです。

SAML 連携部分の実装は https://github.com/onelogin/ruby-saml のサンプル https://github.com/onelogin/ruby-saml-example をベースに
少し修正を入れたものになっています。
(SAML 部分の実装はほぼサンプルのままです)

github.com

動作確認

http://localhost:3000 にアクセス
「Azure AD で Login」をクリック f:id:mmts1007:20170122020523p:plain

Microsoft アカウント(IdP)のログインページが表示される
ID / Password を入力 f:id:mmts1007:20170122020841p:plain

メモアプリ(SP)にログインする f:id:mmts1007:20170122020539p:plain

まとめ

SP を作るためにはもっとゴリゴリ書く必要があるかと思っていたのですが、
https://github.com/onelogin/ruby-saml がとても使いやすく、IdP の設定情報を記述するだけで動かすことができました。サンプルもあるのも良かったです。

Grafana を使ってサーバメモリ使用率、CPU使用率を可視化する

top コマンドや free コマンドなどで確認していたサーバ負荷状況をグラフィカルに見やすできないのかと思い調べたところ、Grafana という可視化ツールがあったので試してみました。

Grafana とは

grafana.org

  • インフラや、アプリケーションの分析データなど時系列データを可視化するためのダッシュボードツール
  • デフォルトで複数のデータストアをサポートしている
    • Graphite
    • Elasticsearch
    • Cloudwatch
    • Prometheus
    • InfluxDB

今回は InfluxDB を利用しました。

構成

VagrantVM を 2個立ち上げて作成しました。

  • 負荷状況を送信するサーバ(CentOS 6.7)
  • Grafana, InfluxDB サーバ(CentOS 6.7)
    • 本来は Grafana と InfluxDB は別サーバにすべきだと思いますが、お試しのため同居させています。

f:id:mmts1007:20170110182941p:plain

  1. 負荷情報を確認したいサーバの CPU, メモリ情報を InfluxDB に送信
  2. InfluxDB は CPU, メモリ情報を DB に格納
  3. ブラウザから Grafana ダッシュボードにアクセス
  4. Grafana はダッシュボードを表示するために必要な情報を InfluxDB から取得し、ダッシュボードを表示する

インストール手順

Grafana のインストール

http://docs.grafana.org/installation/rpm/ を参考に Grafana をインストール

# Grafana のインストール
$ sudo yum install https://grafanarel.s3.amazonaws.com/builds/grafana-4.0.2-1481203731.x86_64.rpm

# Grafana を起動
$ sudo service grafana-server start

http://192.168.33.10:3000/login にブラウザからアクセスし、Grafana のログイン画面が開くことを確認 f:id:mmts1007:20170110190024p:plain

InfluxDB のインストール

https://www.influxdata.com/downloads/ に記載されている「RedHat & CentOS」のとおり実施

f:id:mmts1007:20170110191059p:plain

# influxDB をダウンロード
$ wget https://dl.influxdata.com/influxdb/releases/influxdb-1.1.1.x86_64.rpm

# インストール
$ sudo yum localinstall -y influxdb-1.1.1.x86_64.rpm

# InfluxDB 起動
$ sudo service influxdb start

InfluxDB データベースの作成

https://docs.influxdata.com/influxdb/v1.1/introduction/getting_started/ を参考にデータベースを作成します。

$ influx
Visit https://enterprise.influxdata.com to register for updates, InfluxDB server management, and monitoring.
Connected to http://localhost:8086 version 1.1.1
InfluxDB shell version: 1.1.1
> CREATE DATABASE grafana

# DB が作成されているか確認
> SHOW DATABASES
name: databases
name
----
_internal
grafana

Grafana のセットアップ

Grafana の管理画面から利用するデータストアや、ダッシュボードの設定します。

  1. http://192.168.33.10:3000/login にブラウザからアクセス(admin/admin でログイン)
  2. 左上 Grafana アイコンクリック → 「Data Sources」 をクリック f:id:mmts1007:20170110202657p:plain

  3. 「Add Data Source」をクリック f:id:mmts1007:20170110202952p:plain

  4. InfluxDB の情報を入力、「Add」をクリック f:id:mmts1007:20170110203120p:plain

負荷情報の取得方法

InfluxDB へのデータアクセス方法は、複数サポートしています。
今回は負荷情報を確認したいサーバから InfluxDB の HTTP API を利用して負荷情報を送信します。

CLI

https://docs.influxdata.com/influxdb/v1.1/tools/shell/

$ influx -execute 'SELECT * FROM "h2o_feet" LIMIT 3' -database="NOAA_water_database" -precision=rfc3339
name: h2o_feet
--------------
time                           level description        location         water_level
2015-08-18T00:00:00Z     below 3 feet               santa_monica     2.064
2015-08-18T00:00:00Z     between 6 and 9 feet  coyote_creek  8.12
2015-08-18T00:06:00Z     between 6 and 9 feet  coyote_creek  8.005

HTTP API

https://docs.influxdata.com/influxdb/v1.1/tools/api/

$ curl -i -XPOST "http://localhost:8086/write?db=mydb&precision=s" --data-binary 'mymeas,mytag=1 myfield=90 1463683075'

クライアントライブラリ

https://docs.influxdata.com/influxdb/v1.1/tools/api_client_libraries/

実際に利用したコマンドは以下のとおり

メモリの使用率を取得するスクリプト

while true; do
  curl -i -s -XPOST 'http://192.168.33.10:8086/write?db=grafana' --data-binary "memory,host=serverA,region=jp_east value=`free -t | grep Total | sed 's/[\t ]\+/\t/g' | cut -f3`"
  sleep 5
done

CPU の使用率を取得するスクリプト

while true; do
  idle=`mpstat | tail -n 1 | sed 's/[\t ]\+/\t/g' | cut -f11`
  rate_of_cpu=`echo "100-${idle}" | bc`
  curl -i -s -XPOST 'http://192.168.33.10:8086/write?db=grafana' --data-binary "cup,host=serverA,region=jp_east value=${rate_of_cpu}"
  sleep 5
done

まとめ

ダッシュボードを作成し、以下のような値が取得できるようになりました。 f:id:mmts1007:20170111000020p:plain

過去のデータも確認することができますし、毎回サーバにログインする手間もなくなるので楽になりそうですね。

本番で運用するためには Grafana の admin ユーザのパスワード変更や、InfluxDB の パスワード設定などセキュリティの設定をする必要があります。(今回は Vagrant 上にお試しで作ったのでセキュリティ部分に関しては設定していません)

傘が必要か通知する bot を作った

Ruby Rake Heroku Slack

注意:今回は趣味全開の内容です。

ことりちゃんが毎朝 Slack に今日傘が必要か通知する bot を作りました。

f:id:mmts1007:20160320181655p:plain

その日の降水確率が 50% を超えている時は、傘を忘れないよう Mention 付きでメッセージを投稿します。

f:id:mmts1007:20160323001324p:plain

これで、傘を忘れてびしょ濡れになることは少なくなるはず。

経緯

  • 3月初旬に傘を持って行かずびしょ濡れになり、後悔した
  • 毎朝傘を持っていくべきか調べて出勤するのは面倒臭い
  • 自分で作りたかった

という理由から、毎朝 Slack に傘が必要か通知する bot を作りました。

ソースコード

github.com

使用技術

  • Heroku
  • Ruby
  • Rake
  • Slack(Incoming WebHooks)

Heroku Scheduler を利用し、指定の時間に傘が必要か Slack に通知する Rake タスクを実行しています。
Slack への通知は Incoming WebHooks を利用しています。

降水確率の取得

傘の必要性はその日の降水確率から判断しています。 天気予報の Web API は種類があったのですが、降水確率を取得できる Web API はあまり見つけられず。
今回は 気象庁の天気予報情報を XML で配信 - drk7jp を利用しました。

指定の都道府県・地域の 6時間ごと(00-06, 06-12, 12-18, 18-24)の降水確率が取得できるため、1日の最高降水確率によってメッセージを分ける実装にしました。

text = case today.probabilities_of_rain.max
         when 50..100 # %
           DANGER_MESSAGE
         when 40..50 # %
           CAUTION_MESSAGE
         else
           NOTICE_MESSAGE
         end

https://github.com/mmts1007/rake_lake/blob/6ce6421ae942dc50f163d9a2cfeee7baa5cb9101/lib/tasks/slack/notify/probability_of_rain.rb#L24-L31

その他

heroku は Web 上から簡単に環境変数をセットできるため、 都道府県・地域・IncomingWebHook URL・メッセージは環境変数を利用して切り替えられるようにしました。

まとめ

趣味全開ですが、heroku を試すこともでき、実用性もあるので良しとしますw

技術情報の集め方

私の技術ネタ、情報の集め方を紹介
通勤中はこれらのページをざっくり見て、情報を集めています。
気になる記事をお気に入りして後でじっくり読んだり、帰宅して触ってみたりしています。

はてなブックマーク

はてなブックマーク - テクノロジー

はてなブックマークのテクノロジーカテゴリ
スマホアプリで閲覧しています。

Qaleidospace

Qaleidospace

Qiita のランキングサイトです。
期間を指定できるのも良いところです。 どんな技術が流行っているのかをチェックするために使っています。

GitHub(Trend)

github.com

GitHub ではトレンドランキングが表示できます。
言語で絞ることもできるので、私は Ruby, Java, JavaScript のトレンドを見ています。
世界的にどのような言語・ライブラリ・FWが人気なのか、動きが活発なのかをチェックしています。

こんな感じで毎日情報を集めています。
是非自分にあった情報の集め方の参考になればと思います。

構成管理ツールを作ってみた

siman(シーマン) という構成管理ツールを作りました。
(SImple configuration MANagement tool の略です。seaman ではありません。)

github.com

Vagrant仮想マシンを作るたびに環境構築するのが面倒だったので、楽にするためのツールを作成しました。 Chef よりもさらにシンプルに、Ruby を使わずにできたらと思いこの形になりました。 Chef の様にリモートサーバの構成管理は行えません。

"No." "実行内容" "レシピ(シェルスクリプト)の URL"

の形式でメニューを作成し、siman を実行すると
レシピを DL し、順次実行します。

冪等性を保つために、メニューの何番目まで実行したか記憶しています。 既に実行済みのメニューは再度実行されません。

レシピは URL 形式で指定するため

github.com

な感じでリポジトリに置いたシェルスクリプトの URL を指定したり、 Gist の URL を張るなりして使用します。

例えば、私は Rails の環境をよく作るので
rbenv を install -> ruby 2.2.3 を install -> rails を install といったメニューを作成しました。
(URL は git.io で短絡しています。)

001  install_rbenv     https://git.io/vzohD
002  install_ruby_223  https://git.io/vzohy
003  install_rails     https://git.io/vzohH

インストール方法等は siman/README.md at master · mmts1007/siman · GitHub を参考にしていただければと思います。

Ruby Enumerable#group_by を使ってみた

DB から取得したデータを Ruby 上でグルーピングしたくてドキュメントを漁っていたら見つけたので紹介。

経緯

DB に入っている

id task_type_id task_id
1 1 1
2 1 2
3 1 3
4 2 4
5 2 5
6 2 6

こんな感じでデータを

[
  {
    task_type_id: 1,
    task_id: [1, 2, 3]
  },
  {
    task_type_id: 2,
    task_id: [4, 5, 6]
  }
]

こんな感じにタスクの種別に紐付いているタスクの一覧 JSONRuby で作りたかった。 task_type_id でグルーピングされた値が取れれば と思い、繰り返し関係を提供している Enumerable モジュールのドキュメントを漁った。

結果

案の定欲しいメソッドはあった。メソッド名見た瞬間、「これ!」ってなった。

instance method Enumerable#group_by (Ruby 2.2.0)

使い方

# DB から取得したデータ
records = [
  { id: 1, task_type_id: 1, task_id: 1 },
  { id: 2, task_type_id: 1, task_id: 2 },
  { id: 3, task_type_id: 1, task_id: 3 },
  { id: 4, task_type_id: 2, task_id: 4 },
  { id: 5, task_type_id: 2, task_id: 5 },
  { id: 6, task_type_id: 2, task_id: 6 }
]

records.group_by { |record| record[:task_type_id] }
# => {1=>[{:id=>1, :task_type_id=>1, :task_id=>1}, {:id=>2, :task_type_id=>1, :task_id=>2}, {:id=>3, :task_type_id=>1, :task_id=>3}], 2=>[{:id=>4, :task_type_id=>2, :task_id=>4}, {:id=>5, :task_type_id=>2, :task_id=>5}, {:id=>6, :task_type_id=>2, :task_id=>6}]}

ということで、task_type_id でグルーピングされた値を取得することができた。
後はデータの形式を求めている形に変換すれば完了

records.group_by { |record| record[:task_type_id] }
  .map { |k, v| { task_type_id: k, task_id: v.map { |e| e[:id] } } }

(group_by の後の map が分かりづらい気がする…。また考えよう。)

JJUG CCC 2015 Fall に行ってきた

2015/11/28 (土) に開催された JJUG CCC に行ってきました!

JJUG CCC 2015 Fall(11月28日開催) | 日本Javaユーザーグループ

各セッションのスライドは下記サイトにまとめられているようです。

techstars.jp

今回は下記セッションを聞いてきました

EF-1エバンジェリスト直伝!Kotlinを既存プロダクトで使う!

JVM で動くプログラミング言語 Kotlin の紹介でした。
Kotlin の概要から実戦へ投入する場合の方法等を紹介していました。

speakerdeck.com

AB-2 Javaエンジニアに知っておいて欲しい「KDDIクラウドプラットフォームサービス mBaaS by Kii」によるアプリ開発

mBaaS の説明でした。
mBaaS が流行ったら、バックエンドエンジニアの需要って減るのかなーなんて恐怖を感じていました。

CD-3 よくある業務開発の自動化事情

「あるある!」って頷きながら聞いていたセッションでした。
スピーカーの方の話し方が面白かった! 自動化はしたい、しなければと思っているけどどこの現場も苦労しているのかなと感じました。

www.slideshare.net

CD-4 クラウドネイティブアプリケーションとSpring Framework

マイクロサービス、クラウドネイティブといった技術を Spring, Netflix OSS 等を用いて紹介する内容でした。
Spring Cloud, Service Discovery, Histerics, cirkit breaker, Config Server などのクラウドネイティブのための技術が素晴らしいなと思いました。
また、いつかは業務で実戦したいと思いました。 (趣味でやるとしたら…自分でサービス立ち上げるしか!)

AB-6 【こっそり始める】Javaプログラマコーディングマイグレーション

このセッションも「あるある!」って感じでした。開場もよく笑いが起きていましたw
現場に新しい技術を入れていきたい私としてはとても参考になるセッションでした。
ピープルウェア読んでみたいなーと思いました。

www.slideshare.net

GH-7 てらだよしおの赤裸々タイム

JavaWindows 主に Azure 関連のお話だったり、てらださんへの質問だったりというお時間でした。
てらださんにとっては魔の時間だったのかと思いますw

まとめ

JJUG CCC などの外部のセミナーは最新技術などを学べるのですごく刺激になります。
特に今回は Kotlin, クラウドネイティブアプリケーション、Javaプログラマコーディングマイグレーションに興味を持ちました。
あと、今回初めて懇親会に参加させて頂きました。
LT がとても楽しかったです。そして、じゃんけん大会勝ちたかった…。

次回は今回興味を持った Kotlin について記事を書ければと思います。