tech.guitarrapc.cóm

Technical updates

Azure Functions - C# で Nuget パッケージを利用してみた

さて、Azure Functions の基本的な利用、GitHub や VSTS でのCI まで見てきました。

以前みた中で残っている、Azure Functions を本番で利用できるようにする最後の砦が「外部ライブラリの利用」です。

tech.guitarrapc.com

外部ライブラリの利用。つまり、Node.js でいうところの npm、.NET でいうところの NuGet です。これができないと、標準ライブラリだけで頑張ることになり、できることが限られるので超重要です。

www.npmjs.com

NuGet Gallery | Home

今回は、NuGetを Azure Functions で利用する方法を見てみましょう。NuGet が利用できれば、C# にかぎらず F# や PowerShell でも利用できますからね。

ちなみに npm はこの動画で!さくっと npm install するだけです。

https://i.imgur.com/4DL1BWd.gif

目次

Azure Functions での NuGet パッケージ定義

はじめにいいます。#r <PackageName> ではだめです。ちょっと工夫がいります。

ここではサンプルとして、Github が開発/公開している Octokit を Azure Functions で利用するようにしましょう。

www.nuget.org

NuGet のバージョンを確認しておく

VS Code や Visual Studio で NuGet を利用されたことがある方なら、NuGet パッケージのバージョン表記についてご存知でしょう。

Azure Functions で NuGet を利用するにあたり、当然ながら何をみてバージョンを指定とするか把握する必要があります。

記事時点でOctokit の最新バージョンは 0.19.0、過去のバージョンは 0.18.0 という表記スタイルであることがわかります。

つまり、Octokit のバージョン指定は次の通りです。

パッケージ名 バージョン表記
Octokit 0.19.0

簡単ですね。これだけ把握していればok です。

project.json を作成して定義

ASP.NET 5 や .NET Core と同様に、Azure Functions での NuGet パッケージの指定は project.json を使います。

ただし、そのフォーマットは ASP.NET 5 とは違います。

github.com

NuGet の project.json フォーマットとなります。

NuGet Package Dependency Resolution | Microsoft Learn

Octokit 0.19.0 を指定するなら、以下のような project.json を 作成します。どことなく npm のフォーマットに近い...?

gist.github.com

Azure Functions は、Function ごとにフォルダが分離していることを説明しました。そこで、project.json を、Function ごとにフォルダに配置します。現時点では、project.json は Visual Studio Online や Kudu、あるいは Git CI などで配置することとなります。

project.json を配置すること*1で、project.lock.json が自動生成されます。ここを見ると NuGet パッケージが取り込まれたことがわかります。

さぁ、これでなんと Azure Functions における NuGet パッケージの定義は完了です。NuGet パッケージは、project.json で定義することで、自動的に作成した Function に取り込まれます。

そう、NuGet Package に関しては、コード上で #r Octokit#r D:/home/data/Functions/packages/nuget/OctoKit/0.19.0/lib/net45/Octokit.dll のようなことは不要です。というか、このようなファイル指定の読み込みは パッケージを不完全な形で取り込んでしまうのでやってはダメです。*2

あくまでも、#r <アセンブリ名> は、GAC などから必要なアセンブリ参照を追加するためと思えばいいでしょう。

お次は待ちに待ったコードです。

Function で NuGet パッケージを利用する

NuGet Pakckage を定義できたので、次はパッケージのライブラリを利用してみましょう。

Octokit を使って、リクエスト時に指定した ownerRepositorycommit sha 一覧を取得してみます。

gist.github.com

Compile が通ります。

普通になんの支障もなく using Octokit; をして、コードがかけていることがわかります。

あとは、入力に相当するサンプル json をおいて

gist.github.com

実行してみましょう。

Commit Id 一覧が取れましたね!ばっちりです。

Chatwork への送信

では別のサンプルとして、Azure Functions から Chatwork にメッセージを送信するため、Chatwork.Api の NuGet パッケージを利用してみましょう。

www.nuget.org

まずは project.json を作成します。

gist.github.com

問題なく package.lock.json が生成されたらok です。

ではコードを書きましょう。一点注意なのは、Chawork.Api は、#r "System.Threading.Tasks" の参照だけ追加で必要です。

gist.github.com

あとは、Request Body で、RoomIdMessage を指定します。今回はあえて Slack と語句を合わせて channeltext として json を受け取るようにしました。

gist.github.com

実行して

メッセージが無事にChatwork に通知されましたね!ばっちりです。

補足

いくつか補足しておきましょう。

複数 dependencies の記述

npm 同様、以下のようにすればok です。

gist.github.com

すでに project.json を作った Function におけるpackage の差し替え

同じプロジェクトで使っている NuGetの追加や差し替えの時について補足しましょう。

package の差し替え、追加はpackage.json を書き換えるだけでok です。これで自動的に package.lock.json が書き換わります。

CI

このように触っているとやはり、Github での CI がベストかな、という印象です。表の GUI で指定できるといいんですけどね。

もし CI をする場合、Restore を自動的にさせるため、Custom Script を利用してみてください。

github.com

まとめ

さぁ、これで Azure Functions に関する憂いはほぼ解消したので社内でしょうか?ぜひみなさんも試してください。

今回のサンプルも、リポジトリに追加しておいたのでご参考までにどうぞ。

github.com

ドキュメントがなかったので苦労しました。 この記事を書き終えた後に、StackOverflow に NuGet 利用についてスレッドが追加されました。

stackoverflow.com

Azure Functions の神々に感謝です : thx @crandycodes, @paulbatum

*1:VS Online ならSAVE したタイミング

*2:やって痛い目に会いました。実行時エラーになります。

Azure Functions を GitHub と Continuous Integrationして自動デプロイされるようにしてみた

前回、Azure Functions を AWS Lambda を使っている一人としての視点で軽く触ってみました。

tech.guitarrapc.com

さて、作ったらデプロイですよね。*1かつ Github や CI とどのように連携するかは大事です。

見てみましょう。

目次

AWS Lambda の Configuration Deployment

ここでAWS Lambda を考えると、そのデプロイフローは極めて面倒です。

もちろん、AWS Lambda も Visual Studio + AWS Toolkit for Visual Studio | AWS を使えば、AWS Lambda に直接コードをデプロイも可能です。*2

しかし CI でほげもげして、となるとやはりつらいものです。以下のように試行錯誤をちょくちょく考えます。

qiita.com

aws.typepad.com

単純に GitHub に push したら、Lambda がデプロイされるように連携したいというケースが多いんですけどね。

Azure Functions の Continuous Deployment

では Azure Functions はどうでしょうか?

連携したい Azure Functions で、Function app settings を選択すると、Configure Continuous Integration というボタンが見つかります。ここから以下のソースと Webhookでのデプロイが可能になります。

これは、通常の App Service (Web Apps含む)と変わらず全く同じです。つまり、以前書いたような Kudu を使った Custom Deploy も可能ということです。

tech.guitarrapc.com

それでは、まっさらな Azure Functions に対して、Github から自動デプロイされるように CI を組んでみます。

Continuous Integration 設定

Github の master ブランチに pushしたら、自動的に Azure Functions にデプロイされるようにしてみましょう。つまり以下の図です。

同期に際して、同期先の Azure Functions と 同期元の Github リポジトリを確認しましょう。

同期先の Azure Functions は、作成したてで空です。

同期元の Github リポジトリは、以下に作成してあります。前回の記事のコードを、Github CI するにあたって支障がないようにディレクトリ構成を組んでいます。

github.com

Azure Functions のディレクトリ構成

Visual Studio Online で Azure Functions を一見して分かる通り、各Function区切りは単純なディレクトリです。

そして、CI するとその Azure Functions 全体が差し替わります。そこで、今回組んだ Github のディレクトリ状態でGithub CI を組めば、自動デプロイが問題なく動作します。

Azure Functions で Github CI を組む

早速組みましょう。

Azure Functions で、Function app settings > Configure Continuous Integration > Setup から Source を Github にして認証を通します。あとは、連携するリポジトリ、ブランチを選べばok です。

決定するとすぐに通知が飛び、

1分以内にデプロイが完了します。

Azure Functionsを選択し直すか Refresh すれば、デプロイされているのがわかるでしょう。

簡単ですね。いつも通りです。

ちなみにAzure Functions でGithub CI を組んだ時に 「Github の Settings > Webhook」 を見ると、Web Apps の時と同じ Webhook 設定が追加されていることがわかります。

CI をした後はポータル上は Read only

CI って、ようはデプロイソース元がマスタとして絶対になるということです。これは非常に重要な概念で、CI しているのにデプロイ先を勝手に触ると「次のデプロイで直接変更した箇所がCI元のソースで上書かれる」ということになります。つまり、Github なり VSTS なりなんでも CI をしたなら デプロイ先のSource Control されているコードを触るのは原則望ましくない結果を招きやすいということです。

Azure Functions も、CI を組むと Develop のコード上部に以下の表示となります。

Read only - because you have started editing with source control, this view is read only.

読んだ通りです。非常に良い対応だと個人的には思います。おそらく、CI をしていて直接触るべきシーンはほぼ0かなと。Lambda でもそうですしね。

ただ、コード部分が一見すると普通に見えるのはどうでしょうか。(実際はコードを直接入力できなくなっています。)

グレイアウトして選択に影響するのは困ります。それよりは全然いいですし、上部のRead only 表示で気づけるものの、css でコード部分を背景を薄い灰色にするといった配色で示すのも良い気もします。

気になるポイント

改善されると嬉しいポイントです。

Request Body はどこ?

Visual Studio Online のどこを見ても、Request Body に該当するファイルがないのです。なので、今回 Github CI を組んでもこの通り空です。これなんとかならないのですかね?

逆にいうと、CI でのデプロイ結果に左右されないんですが、ちゃんと同期してくれた方が嬉しいです。

まとめ

デプロイに関しては、圧倒的な Azure Functions の楽さです。AWS Lambda もこうしてほしいんですけどねぇ。

以下の記事と同様に、カスタムデプロイもいいでしょう。

tech.guitarrapc.com

もちろん、VSTS や Jenkins + MSDeploy も通常の Web Apps と一緒なので、簡単です。ただ、Web Deploy が必要になると厄介なので、CI サービスによっては使えなかったりします。とはいえ、そこで Local git を選ぶよりは Github がいいですね。

単純なケースであれば、ブランチを切って開発 > 各ブランチをCI > CIでテストも担保 > Pull Request を master にマージ > 自動的に Azure Functions へデプロイなどでもいいでしょう。

これで、作成、Github管理、CI まで通してみました。プレビューなので全面的とは行きませんが、本番で使えるレベルの高い完成度で動いています。

あとは、モニター機能を心待ちにしつつ、ぜひ皆さんも使ってみてください。*3

次回は、Nuget パッケージや npm パッケージの利用方法を見てみましょう。

tech.guitarrapc.com

*1:Web 上で書くとか初めの1回だけです。

*2:めちゃめちゃ便利なので、CI介さないなら最強

*3:いつどうして実行されたのか追えないと困るシーンは容易に予想されるので

Azure Functions - C#で Github Webhoook や VSTS Build 通知 を Slack に通知してみた

AWS Lambda といえば、Amazon Web Service が提供する Node.js や Python、Java を使ったサーバーレスなコード実行基盤です。

AWS Lambda(イベント発生時にコードを実行)| AWS

これって、単純にコードをサーバーなしに実行できるだけじゃなくて、「AWSリソースのイベントをトリガーに様々なリソースを連動させる」「APIGateway と連動することで、AWS以外の適当なWebHook をトリガーに様々なリソースを連動させる」といったことが可能になります。つまり、本質はリソースとリソースをつなぐ歯車の役割を果たすのです。しかもコードで自在に操作を制御できる。

だからこそグラニもAWS Lambda は大好きで、発表されてすぐに GitHub WebHook でIssue や Pull Request を Chatwork に通知する基盤を Node.js で作ったり、Route53 の処理など様々な箇所で活用しています。

さてBuild 2016 で、ついにAzureによる同様の基盤が発表されました。それが、Azure Functions です。

build.microsoft.com

azure.microsoft.com

今回は、Azure Function Apps を使った Webhook 処理をいくつか C# で書いてみましょう。

目次

Azure Functions

実際に Azure Functions で何ができるかは、公式ドキュメントが詳しいです。

azure.microsoft.com

azure.microsoft.com

幸いにもコード処理部分は動画になっており、ただの文章よりもそうとう理解が進みます。もう少し複雑な処理も動画に追加されるともっと嬉しいです。

azure.microsoft.com

あとは先人の知恵もあります。

blog.xin9le.net

blog.nnasaki.com

blog.shibayan.jp

今後、あっという間に、AWS Lambda 相当の記事はどんどん出るんじゃないですかね。Advent Calendar とかも作るといいでしょう。

qiita.com

qiita.com

qiita.com

価格

AWS Lambda もですが、Azure Functions は実行した分のみの課金です。計測は2つあります。

azure.microsoft.com

1 つが、メモリ*コンピュート時間

With Azure Functions you only pay for what you use with compute metered to the nearest 100ms at Per/GB price based on the time your function runs and the memory size of the function space you choose. Function space size can range from 128mb to 1536mb. With the first 400k GB/Sec free.

もう1つがリクエスト。100万リクエストまでは無料らしいですね。

Azure Function requests are charged per million requests, with the first 1 million requests free.

Dynamic Hosting Plan ってなんなんですかね? ドキュメントが見つけられない.... Azure Functions 専用のプランらしく、今は気にしなくていいそうですが。ちなみに Azure Functions を作成するときに、Dynamic と Classic を選択できますが、Dynamic を選ぶと実行できるリージョンが今は限定されます。

Azure Functions hosted on the Dynamic Hosting plan will be available via the monthly free grant through April 22nd, with paid preview available after that date.

azure.microsoft.com

@shibayan さんが詳細を調べてらっしゃいました。さすがです。

blog.shibayan.jp

テスト

リモートデバッグを含めて AWS Lambda が提供できていない高度なデバッグビリティを担保しているのはとても素晴らしいですね。AWS頑張れ。

azure.microsoft.com

困ったときは

公式に stackoverflow や MSDN フォーラムと案内があります。特に stackoverflow は中の人もちょくちょく回答してくださっているので、オススメです。

Kudu

AppService なのでKuduも見れます。

方法は、見たい Azure Function を選択 > Function App settings > Tools > Kudu とブレードをたどる方法。

あるいは、AppService 共通の scm を付与したアドレスで。アドレスは例えば、test という Azure Functionsなら https://test.scm.azurewebsites.net/ になります。

Lambda でのメモリとの比較とかできたり面白いです。

Visual Studio Online

また VSO にも対応しています。

これも方法は Kudu 同様で 見たい Azure Function を選択 > Function App settings > Tools > Visual Studio Online とブレードをたどる方法。

あるいは、AppService 共通の scm を付与したアドレスに末尾 /dev付与で。アドレスは例えば、test という Azure Functionsなら https://test.scm.azurewebsites.net/dev/wwwroot/ になります。

VSO では、見事にC# 実行中身の .csx や .json も見えててとても良いです。

もちろん VSO で編集すると、Azure Functions にも反映します。

Azure Functions の利点

いくつかあります。

幅広い言語対応

AWS Lambda を上回る圧倒的なメリットです。

サービス 言語対応
Azure Functions C#, Node.js(JavaScript), Python, F#, PHP, batch, bash, Java, PowerShell
AWS Lambda Node.js (JavaScript), Python, Java (Java 8 互換)

とはいえ、現状は以下の通り言語によって手厚さが違います。とりあえずメイン対応は、C# と Node.js がそろってる感じです。Python と Java が同程度にそろうとだいぶん使う人を選ばなくなるかなと思います。

言語 テンプレート対応
Batch
C#
JavaScript
Bash
PHP
PowerShell
Python
Azure リソースのイベント駆動処理

AWS Lambda のメリットが、デフォルトで aws-sdk 参照、IAM Role 制御、VPC対応によるAWSリソースの自在なコントロールです。Azure Functions も同様に Azure のリソースをトリガーに処理を走らせることができます。リリース直後の現在の blob について触れている記事もあります。

blog.nnasaki.com

今は Blob、EventHub、StorageQueue の対応のようですが、AWS Lambda 同様に対応が増えていくでしょう。とりあえず、Cloud Watch 相当の Application Insight でトリガーは Webhook で出来そうなので、モニタリング系の連動はたやすそうですね。

もちろんUser Voice で追加希望は効果が高いでしょう。

https://feedback.azure.com

個人的な予測では、AWS Lambda 同様、Azure Functions はプラットフォームのリソース間疎結合を担うものという位置づけになるはずなので「クラウドプラットフォームの要」となり急速に発展すると思います。*1

CI 統合

VS だけでなく、VSTS や GitHub、Bitbucket、OneDrive、Dropboxなどからデプロイ統合が可能です。これも AWS Lambda ではとてもつらかった部分で、良く学んで Azure の従来の方法がうまく機能していると思います。

AWS Lambda + API Gateway 同様の処理

HttpTrigger や Generic Webhoook 、TimerTrigger は API Gateway + AWS Lambda で可能です。同様のことが Azure Functions のみでできるのは良いことです。TimerTrigger に至っては Lambda と同じく cron 指定です。違和感なく触れるでしょう。

もちろん Authentication/Authorization もあります。様々な IdP と連動しているのはとてもいいですね。

気になるポイント

AWS Lambda を触っていて Azure Functions を触ると気になるポイントがあります。

リソースアクセス制御

もとから Azure で気になるポイントになりますが、IAM Roleに相当するリソースの他リソースへのアクセス制御ってどうなるのかなというのは気になります。

外部ライブラリの利用

Node.js で async module が欲しい場合など、外部リソースの参照をどうしたものか不明です。AWS Lambda でいうところの Zip アップロード的なものはどうなるのかなと?普通に requires() が効く感じがしますが。

C# でも、NuGet 参照したいときにどうしたものかなと。C# に関しては、CSharp Scripting のようなので、現状では限定されている感じですが詳細がいまいち不明です。*2

github.com

Azure Functions も VS からデプロイできますが、AWS Lambda も Visual Studio から直接デプロイ、現在設定されている Function をもとに新規作成などが可能なので、AWS Console 一切見ずに設定可能です。

Monitor

Coming Soon とのことです。一見すると、かなり良さげです。いや実際これでいいんですよ。AWS Lambda のモニターはみにくいです。

Token による制御

ヘッダに Token ID を入れる認証は単純ですが強力です。しかし、AzureFunctions にはtoken での認証は GitHub Webhook type 以外になさそうな....? Authorization/Authentication でできると思ったのですが、すべて IdP 連携だったため token での制御ができないものでしょうか....?

github.com

できないと幾つか考慮が必要になります。

  • URL が漏れたら、Functions 作り直してURL変更するしかない? *3
  • 連携系で IdP でのID連動はかなりつらい (通常対応してないです)
  • webHookType を github にするというのも手でしょうが、X-Hub-Signature の計算とかいちいち入れるのっていう

設定できる気がしますが、見つけれませんでした...。

作成

さくっと Azure Functions を作成します。

Azure Portal で 追加 (+) > 検索窓で Function と入れれば Function App が表示されます。

Create を選択します。

あとは必要な入力をすればokです。

3分程度で出来上がります。

サンプル

3つ C# での Azure Functions を作ってみましょう。Node.js は AWS Lambda で散々作る羽目になったのでもういいです。

  • Slack に通知
  • GitHub Issue へのコメント を Webhook で受け取ってSlack に通知
  • VSTS のビルド完了を Webhok で受け取ってSlack に通知
Slackに通知

Slack に通知部分を切り出して、他から呼びだすための Azure Functions です。通知が複数回ないならFunctions を分けないほうがいいでしょうが、多くの場合は処理と通知を分けたくなるのではないでしょうか。

Json で受け取って Slack に通知するので、Generic Webhook で作成します。

あとは Slack の Incoming Webhook API に POST する処理をサクッと書きます。

gist.github.com

Azure Functions もLambda 同様、サンプルとなるjson を Request Body においておきます。

gist.github.com

この辺のデバッグやローカルで書き書き処理は、Visual Studio より LinqPad が安定ですねぇ。わたしは。

ローカルでサクッと動いたら、Save してから Run しましょう。

問題なく Slack に通知が来ましたね。

GitHub Issue へのコメント を Webhook で受け取ってSlack に通知

次は GitHub Issue へのコメントを Github Webhook で受け取って、Slack に通知してみましょう。

今回のはここを参考にするといいでしょう。

azure.microsoft.com

デモをみたり、テンプレートをみると、GitHub Webhook - Node が目に留まり C# がないのでコレを選びたくなるのですが、言語が違うので今回は Generic WebHook をまず選択します。

とはいえ、サンプルJSON や処理の参考になるので一個作っておくといいでしょう。ということで、みてみるとなるほどです。

GitHub の Webhook 設定

さて、C# - Generic WebHook で作成した Azure Functions ですが、まずは GitHub Webhook 対応しましょう。Integrateタブ に行って WebHook typeGitHub に変更します。

これで Develop タブに、Github Secret 欄が出ています。

次に GitHub のWebhook を掛けたいリポジトリ > Settings > Webhooks % services に行きます。

Payload URL に Azure Functions の Function UrlのURLをいれて、Secret に Azure Functions の Github Secretの値 を入れればok です。

Azure Functions のコード

さて、コメントをする前にコードを書きましょう。とりあえず GitHub Comment が書かれたときに内容を受け取るだけならこれでok です。*4

gist.github.com

これでGitHub Issue にコメントすれば、GitHub Webhook でトリガーされて Azure Functions の Logs に表示されます。

Slack への通知

さて、あとはSlack通知の Azure Functions に POST するようにコードを付け加えます。

gist.github.com

Save してからコメントしてみると、Slack に通知されますね。

VSTS のビルド完了を Webhok で受け取ってSlack に通知

残りは Visual Studio Team Service のビルド完了通知を Slack に通知してみましょう。Xamarin の Test Cloud なども含めて、VSTSは機能強化が著しいです。

従来は、Web Apps で ASP.NET WebHooks を使うか Zapier が王道でした。

blogs.msdn.microsoft.com

zapier.com

ただ両者に一長一短があります。この隙間にほしかったのが、Lamdba 相当の処理、つまり Azure Functions です。ただし、NuGet が使えないため Hook が来た VSTS Job を参照してGithub を参照して、といった処理には向いていません。しかたにゃいので待ちましょう。

処理 メリット デメリット
ASP.NET Webhooks ごにょごにょ処理を噛ませることができるのでかなり自在に色々できます。 - Web Apps でいつ来るかわからない通知のためにずっと起動という無駄半端なさ
- エラーが起こったときに例外で死ぬ可能性がある
- Webhookを処理したいだけなのに持ち味が全く生かしきれません。
Zapier Webhook の解析、実行は完全お任せ最高です - Zapが5分単位のためリアルタイム性が損なわれる
- いろいろごにょごにょしようとすると、JavaScriptを書くことになる
- あれこれできないため若干窮屈な思いをします
Azure Functions - ごにょごにょ処理を噛ませることができるのである程度自在に色々できます。
- 必要な時にだけ処理されるのでコスト面も起動も気にしなくてok
- NuGet が使えないため楽にできることに制約があります。
- いろいろごにょごにょしようとするとそれなりにコードを書く必要があります

さっそく Generic WebHook で作ってみましょう。

今回のは、ここを参考にするといいでしょう。

Using VS Team Services Web Hooks with Azure Functions - Buck Hodges

VSTS の Webhook 設定

Azure Functions を作成したら、Function Url をコピーします。

このFunction Url を VSTS の Webhook に設定します。VSTS の 設定したいProject の Admin画面 > + ボタンで追加 > Web Hooks を選択 します。

Trigger の設定は、Build completed がいいでしょう。

SETTINGS > URL に 作成した Azure Functions の URL を貼り付けましょう。

RESOURCE VERSION は、2.0-preview.2 でも1.0 でもいいですが、ここでは 2.0-preview.2 のコードでサンプルを示します。

Azure Functions のコード

VSTS で TEST をすると REQUEST の JSON が拾えます。この JSON でテストするといいでしょう。

Azure Functions の Request Body に JSON 埋めて、テストが容易になるようにしておきます。

gist.github.com

また、JSON を dynamic ではなくクラスとして変換すると、LinqPad でのデバッグはとても楽ちんです。*5ということでサクッと書きます。

gist.github.com

ちなみに RESOURCE VERSION 1.0 の場合はこんな感じのクラスで JSON をデシリアライズできます。

gist.github.com

テストで Run 実行してみると問題なく解釈できていますね。

VSTSの Webhook から Test しても問題なくトリガーされています。

Slack への通知

最後にSlack通知の Azure Functions に POST するようにコードを付け加えます。

gist.github.com

Save してからビルドしたり、TEST するとSlack に通知されました。

まとめ

慣れの問題もありますが、Azure Functions を C# で書いていると、AWS Lambda の Node.js で苦労するようなこともまったくなく素直に書けます。癖がほとんどないので、かなり使いやすいでしょう。

あとは、Nuget 周りがいまいち読めない。。。。 #r でリファレンス基本効くらしいですが*6、Newtonsoft.Json 以外にどこまで通るのかしら?#r Microsoft.TeamFoundationServer.Client とかいけないんですよねぇ。

今後に期待しつつ、aws-sdk など処理を何かしら依存していないものは、Azure Functionsに寄せていこうかと思います。さて、AWS Lambda もいい刺激を受けて、今のデバッグやデプロイといった苦しい箇所がよくなってほしいですね。*7

あ、400記事目でした。

次回は、Azure Functions を GitHub と CI してみましょう。

tech.guitarrapc.com

*1:AWS Lambda が実際そうですね

*2:#r "Newtonsoft.Json" で Json.Net は利用できますが、結構他のは怒られます

*3:Token の Regenerate で済ませたいものです

*4:Issue の作成時のみ、更新時のみの処理を入れてくとなると、Switch 文などが始まるでしょう....

*5:Azure Functions 上だけなら dynamic でいいと思います

*6:CSharp Scripting の現行仕様より進んでる?

*7:C# 対応もね。Mono も MIT になったし入れてほしい

ADFS から AzureAD に IdPを完全移行したお話

クラウドサービスが数多あると、それぞれのサービスごとにユーザー名/パスワードといった認証を管理することは大変苦痛です。

これまでグラニでは、ADFS + AzureAD を使って Identity Federation を構成していたのですが、先日 ADFS を完全撤廃して AzureAD を中心とする SSO 環境に移行しました。

今回は、ADFS や IDaaS (ここで上げているAzureAD 以外にも OneLogin、Okta、PingFederate などを含める) によるSSO に関してです。

目次

なぜ SSO や ID連携を行うのか

そもそも、各クラウドサービスはそれぞれユーザー名/パスワードがあります。それでは困るのでしょうか?私はこれに関して、

「1つ、2つのサービスなら問題無いが、10、20と利用サービスが増えていくと困る。」

と、考えています。私が働いているグラニにおいても、当初は SSO を入れていませんでしたが利用サービスが拡大し来たため途中からSSOを導入しました。

パスワード管理は苦痛以外の何者でもない
  • いろいろなサービスを使う
  • それぞれのサービスでユーザー名/パスワードを求められる

このような時に良く言われるのが、それぞれのサービスでパスワードを変えなさい ということです。それはいいと思いますし同意です。しかし多くのサービスごとのパスワードを覚えたり、いちいちパスワードマネージャーに登録するのは簡単ですが大変なことです。*1

このパスワード管理という苦痛から逃れる手段はないのでしょうか?

SSO による認証の一本化

そこで用いられるのが Single Sign On (SSO / シングルサインオン) や ID連携です。SSO/ID連携 に対応しているサービスであれば、自分のPC にログインや ID連携元サービスにログインするだけで自動的にログインされます。ユーザー名だけ覚えておけば1回の認証が全サービスのログインに利用されるのです。

SSOに関しては、いい記事も多くあります。

https://blog.animereview.jp/aws-sso-securityblog.animereview.jp

http://lab.aratana.jp/entry/2015/10/30/150237lab.aratana.jp

しかも、Windows 10 なら Windows Hello でカメラ認証、デバイスの指紋認証でパスワードすら隠せたら?最高ですね。

まとめると、次の2つが、SSO や ID連携 を行う理由です。

  • SSO や ID連携によるパスワード管理からの解放
  • よりセキュアな環境を透過的に提供する
SSO 対応はサービス利用指針の一つになりうる

SSO がきっちり出来ているサービスなら、各サービスでログインする必要する必要すらなく透過的にログインされます。適切な人がアクセスしてきたら、認証をバイパスできる。これが SSO のスバラしいところです。一度SSO や ID連携できているサービスを体感すると、ユーザー名/パスワードしか対応していないサービスは非常に残念に感じます。

グラニにおいてもSSO はかなり重視しており、利用しているサービスでSSO に対応していない場合はリクエストしています。

以下の記事は少し過激な表現のタイトルですが、個人的には大筋ずれずに同意です。

https://blog.animereview.jp/saas-sso/blog.animereview.jp

世の中の多くのサービスは 「SSO を有償の中でも最上位に近いプランでのみ提供」していますが、標準的に提供しているサービスは好感度が天井知らずですね。

前知識

本記事は幾つか用語に関して理解している前提で書いています。前提知識となる情報をここでまとめておきます。

IdM実験室は神サイトです。ADFSやAzureAD使ってないとしても追っておくと幸せになれます。海外含めてここ以上に素晴らしいIdP の連携に関するサイトはそうそうありません。すごいです。

認証方式

SSO や Identity Federation (ID連携) などと一言にいっても、SAML, OpenID 2.0, OpenID Connect, JWT など複数の認証方式があります。

どれがどう違うか理解していないと、「ID連携したいサービスは認証方式に対応していなかった!」ということになりかねないので注意です。

認証方式に関しては、以下のリンクが参考になります。

www.sakimura.org

IdM実験室: [雑談]認証連携、ID連携そしてOAuth認証

www.slideshare.net

www.slideshare.net

企業において SSO と呼ばれるのは、多くが SAML2.0 を認証方式としているように思います。

CP, RP, IdP, SP

SAML などで用いられる用語に、CP (Claim Party), RP (Relying Party), IdP (Identity Provider), SP (Service Provider) があります。

ADFS ではそれぞれが何か理解しておく方が捗ります。

一方で、AzureAD や OneLogin を中心とした場合はざっくり IdP と SP が何か理解しておけば構築や挙動の理解には概ね問題ないでしょう。*2

IdP や SP の通信の流れは認証方式によって異なります。SSO に関わる ID連携で一番多いのは SAML なので、次のリンクがわかりやすく素敵です。

blog.cybozu.io

SAML通信のデバッグ

特に SAML においては、SAML Request / SAML Response の通信がどう流れるかは大事です。SAML は HTTP ヘッダにリクエストやレスポンスが埋め込まれます。しかし「その内容は人間が読むにはデコードが必要」、「HTTP通信がPOSTやRidirectで連続するため連続的に追うのは困難」です。

私が知っている中では、SAML tracer というFirefox Add-on が神で最強です。SAML通信も追跡してくれるので検証時に役立つでしょう。

addons.mozilla.org

他に、SAMLリクエスト、レスポンスをデコードしてくれる Webサービスもありますが、あまりSAML Response とか載せたくないので悩ましいですね。

https://rnd.feide.no/simplesaml/module.php/saml2debug/debug.php

www.samltool.com

デコードは単純なのでC# でやるのもいいのですが、追跡となると面倒でしょう。

stackoverflow.com

stackoverflow.com

やはりFirefox プラグインが私の中では一番です。

IDaaS について

AzureAD、OneLogin、Okta、PingFederate など多くのサービスがあります。これらはIdPとして機能するので、接続したい外部サービスと SAML や OpenID Connect での連携をしてくれます。

IDaaS はいいぞ。

www.atmarkit.co.jp

以前の構成

グラニではもともと、ADDS を中心として、 IdPにADFSとAzureAD を用いていました。

この構成は、スライドでいうところの 3. ハイブリッド① (クラウドAPL+ADFS) - ws-federation + 統合Windows認証) に該当します。*3

www.slideshare.net

IaaS(オンプレミス)環境では、ADFS や LDAP を使うことで IdP とできます。ADFS を使うことで、プラベートネットワーク(イントラネット)に配置した ADDS に外部サービスに直接繋がせることなく安全に ID連携できるわけです。

また、ADFSは要求規則を触ったりできるのでID連携のカスタマイズがある程度自在です。*4

しかしADFS を持つことは良いことばかりではありません。

IdP を自前で持つデメリット

ADFS や LDAP といったインスタンス(サーバー)を持つということは多くの運用負荷がかかります。

冗長構成の担保

外部サービスとのID連携をするなら、イントラネットに配置したADFSを直接インターネットに晒さないために「DMZゾーンに ADFSプロキシ も必要」となります。当然インスタンスがいつ落ちてもいいように、ADFS も ADFSプロキシ共に冗長構成を組む必要がでます。*5

冗長構成の維持はELB を用いて透過的に扱えますが、インスタンスを持ちたくないというのが本音です。

証明書更新対応

ADFS には定期的に更新が必要な証明書が2つあります。トークン署名証明書サービス通信証明書 です。これらの証明書更新は、標準では自動化されていないため自動化を組む必要があります。めんどくさい。

  • トークン証明書は自己証明書なので期間を長くとることも可能です。*6
  • サービス通信証明書は、認証局事業者によって発行されたSSL証明書を利用する必要があるため期間をそこまで長く取れません
サービス/デーモンの管理

ADFS には、ADFSSrvサービスがあります。

サービスが落ちるとIdP として処理ができなくなります。Chef や PowerShell DSC を使って、サービスの起動を担保するべきでしょう。

またADFS は「特定の変更処理をする際にサービス再起動を求められる」ことがあります。いうまでもなく、ADFS は何かしらの理由でリクエスト処理を正常に行えなくなることもあります。そういった場合にもサービスを再起動しないといけません。

サービスの担保、めんどくさい。

DMZ の安全性担保

AWS 使えば楽勝です。が、ADFS Proxy に脆弱性があったら?と考えると、安全性は サービス提供された IDaaS とは雲泥の差があります。正直かなりアレです。

RP 構成をそれぞれに合わせないといけない

ADFS では、各サービスによってRP構成を変えないといけません。例えば Sales Force、例えば Google Apps それぞれが、全く違う構成です。これは「ただID連携をしたいだけなのに本質じゃない設定で少なからず悩まされる」ことを意味します。

RP設定で悩んだことがない人はいないかと思います。こういう無駄な悩みは属人性を生むのでなくしたい要素です。そのために Meta.xml などがあるのですがそれを提供しているサービスは稀です。

グラニの選択

説明した通り、グラニでは ADFS と AzureAD を外部サービスとの連携に使っていました。元よりAADSync を使って ADDS とディレクトリ同期もしていたため、イントラネットのアプリケーション認証は元から AzureAD です。つまり、ADFS は SSO(ID連携) のためにのみ用意していました。

なぜ AzureADを選ばなかったのかと思われると思います。ADFS 導入当時にもAzureAD や OneLogin、Okta を検討しましたが、

  • AzureAD はIdP Initiate しかサポートしていない
  • 他サービスはOffice365をサポートしていなかったり

と 幾つかの問題でADFS を選ばざるを得ませんでした。

IdM実験室: Azure ADのSAML対応(IdP編)

しかし、その後IDaaS の機能拡充もあり完全移行できる状況が整ったことから、ADFS から IDaaS へ移行することにしました。

AzureAD にした理由

IDaaS を幾つか検討をした結果 AzureAD Premium を選択しています。単純な連携ならPingFederate が最有力候補でしたが、AzureADにしたのは価格や融通に加えて幾つかの理由があります。

  • 他IDaaS より開発が活発
  • SAML認証も容易
  • カスタムフォーム認証機能の強力な補助
  • ユーザープロビジョニング機能も安価に利用可能
  • オンプレADDS へのパスワードライトバックの提供*7

さすが、ADDS との連動は強くこういう意図ではいい候補かと思います。

現在は AzureAD も SP Initiate にも対応したことに加えて、アプリケーション連携も増えておりクリティカルな問題は解消しています。

IdM実験室: 続Azure ADのSAML対応(IdP編)~SP Initiatedに対応

AzureAD 変化後の構成図

元から AzureAD を使っていたこともあり移行はスムーズにダウンタイム 0 で完了できました。

移行後は、ADFS 周りがすべて破棄されてシンプルになっています。

移行後はスライドでいうところの、4. ハイブリッド② (オンプレAPL+AAD/WAP) - ws-federation + 統合Windows認証) が近いでしょうか。実際のところ、ADDSが死んでいてもクラウドサービスとの接続はAzureAD が完結します。AzureAD単独のユーザー管理も可能なので「クラウド型」にかなり近い印象です。

AADConnect の 実行スケジュール が AADSync から変更になったことに注意

ADDS と AzureAD のディレクトリ同期は AADConnect で行っています。AADSync から AADConnect へのアップグレードと ADFS から ADDS への移動は何も問題ありません。おおよそ DirSync からのアップグレードと代わりないので、チュートリアル通りどうぞ。*8

azure.microsoft.com

1つだけ気をつける必要があるのが、ディレクトリ同期方法です。AADSync ではタスクスケジュールで同期がデフォルト3時間おきに実行されていました。これが AADConnectで、30分ごとにプロセスで実行されるように変更されました。*9このドキュメントがぱっと見つからないのでお気をつけて。

https://azure.microsoft.com/en-us/documentation/articles/active-directory-aadconnectsync-feature-scheduler/azure.microsoft.com

ADSync モジュールにすべてのコマンドがあるので確認しておいた方がいいです。

IDaaS 移行の結果

ADFS にあったデメリットがすべて解消しました。これは、AzureAD に限らず IDaaS にすることで得られるメリットです。

  • ADFS などはすべて破棄しているので、冗長構成の担保は不要です。ID連携の仕組みとして非常に堅牢になりました
  • トークン証明書やサービス通信証明書も担保が不要になりました
  • サービス/デーモン管理も不要です
  • DMZ 安全性担保も不要になりました
  • RP の構成も単純化されてたとえ初めて見る人でも構成可能になりました

他にもメリットがあります。

  • カスタムフォーム認証により「SSOに対応していないサービスだけど、共通IDでアクセスしたい」というケースも対応されました。*10
  • AzureAD 連携する対象を、ユーザーだけでなくグループ指定も容易に。*11

もともとアプリケーション連携も AzureAD は強力だったのでいいでしょう。GraphAPI で、認証プロバイダとしても活用できるのでAzureAD はその意味でも便利です。

グラニのユースケースでは、特にデメリットは生じていません。

AzureAD で対応できないものの対処

なんでもできるほど万能ではありません。むしろ細かい融通効かないので、結構残念なポイントは多いです。

とりあえず、カスタムフォーム認証のパスワードフィルの失敗度合いが高すぎてアレですね。

CloudForce.com とのSSO

AzureAD の SAML は、対応アプリケーションでも決まったフォーマットである必要があります。どういうことかというと、SalesForce における CloudForce.com ドメインでは連携できません。

Page Not Found

これに関しては、Google Apps を IdP とすることで連携しています。

support.google.com

Google Apps は、AzureAD とSSO しているためユーザーが行うべき認証はUI/UX共に変わりません。違和感皆無で利用できるの最高ですね。

Google Apps との日本語名ユーザーがいる場合のSSO

日本語名のユーザーがどうしてもSSO できないので悩んでいたら、ちょうどブログが更新されて救われました。

プロビジョニングは、以前無効になる問題にあい初期化ができない状況を確認したため利用していません。GADS や GAPS での連携を現状は行っています。

まとめ

「AzureAD 最高」とはいいませんが、良いサービスです。もし ADFS を外部サービスとの連携でしか使っていない場合は、AzureAD Premium に限らず各種 IDaaS へ移行を推奨します。

私の一番の推奨は PingFederate ですが、AzureAD もいい候補でしょう。

今後は、Managed Directory Service にしたいですね。GPOやDNS 周りがあるので、なんともバッチリなサービスがまだ見つかっていないのですが、Azure Active Directory Domain Service は後一歩で現実味を帯びそうです。

*1:つまり面倒

*2:全部理解しておけばより挙動が理解できます

*3:実際には Macがあるため、統合Windows認証で困るシーンがあるので 3. ハイブリッド① (クラウドAPL+ADFS) - ws-federation + フォーム認証) となります

*4:この時代になっても要求規則を書かせる仕組みはサイテーだと思いますが!

*5:この時点で冗長構成なら最低4台

*6:いいか悪いかは別として

*7:これは完全にリモートワークであっても同様の認証制御が可能ということを意味します

*8:むしろ私はアップグレードしてからみました

*9:任意の間隔に変更可能 : 最短30分

*10:すべてではない。むしろ結構AzureAD のカスタムフォームは動かない

*11:AzureAD Premium の機能です。ADFS と違って要求規則さわらなくていいので楽です。ただしグループのネストは非対応なので注意

Remote Desktop Web Access の Remote Apps が重複する問題の対処

Remote Desktop Service (リモートデスクトップサービス) には、RD Web Access (RD Web アクセス) と RD Session Host (RD セッションホスト)呼ばれる機能があります。

これらの機能を使うことで、Remote Desktop Service で展開している Remote Apps を公開できます。

今回は、この Remote Apps が重複して表示される問題への対処について。

目次

Remote Apps の公開

たとえば、以下のような RD Web Apps 公開設定します。

すると、Web Access に対してブラウザ経由でアクセスした際に 通常は以下のようにRemote Apps が公開されます。

このRemote Apps の実行はあくまでも Remote Desktop Service サーバーで実行されているので、一見すると Windows や iOS、Android など OS を問わず実行が可能です。

重複した表示

しかし、Remote Desktop Service の機能をアンインストールしてからインストールし直した場合に「RD Web Appsが重複して表示」される場合があります。

正確には、前回の構成で表示していた RD Web Apps が表示されてしまいます。つまり以下の状態。

この状態は利用者からするとかなり厄介で、今回の Remote Desktop Service 構成で設定した RD Remote Apps ではないアプリを選択するとエラーが発生します。Feed 表示でも同様に重複していることから、キャッシュによるものでもありません。しかも見た目で判断は不可能です。

2件ほど似たような事例がありますが、どれも違う場合に役に立つでしょう。

問題となった設定を探す

インストールの流れを疑ってみましょう。

Server Manager の GUI 表示

設定にしたがって Server Manager > Remote Desktop Service > Collection から設定した RD Web Apps を見て見るでしょう。しかし、重複はありません。

PowerShell での Collection 表示

また、PowerShell で RD Session Collection が重複しているか見ても重複はありません。

gist.github.com

CollectionName                 Size ResourceType       CollectionDescription
--------------                 ---- ------------       ---------------------
<設定した CollectionName>      1    RemoteApp プロ...  RD Session Collection
RDWeb のフォルダ状態

RDWeb の IIS 設定は、 %WinDir%\Web\RDWeb に中身があります。

当然キャッシュもなく、Default.aspx、Default.aspx.cs にも異常はありません。

つまり、物理構成でも論理構成でもないということです。

原因はレジストリ

RD Remote Apps の実態は、設定するとレジストリに登録されます。大事なのは、PublishFarms 以下です。

PowerShell を使うと楽でしょう。

gist.github.com

通常は上記のように設定した コレクション名のエントリのみになります。しかし重複している場合は、PublishedFarms 配下に設定していないコレクション名が存在しています。

対処

レジストリから設定していないコレクション名を削除して、Remote Desktop Service を再起動してください。*1これで Remote Apps の重複が修正されます。

もしこれでダメな場合は、Remote Desktop Service の機能を入れなおせば間違いなく治ります。

まとめ

Remote Desktop Service を入れなおした時は、レジストリが汚いままなので気をつけましょう。

*1:あるいはサーバー再起動でもいいです