2018年12月21日金曜日

TechSummitのおさらい③:Azure AD + Auth0 で条件付きアクセスを構成する

こんにちは、富士榮です。

そろそろディープになってきました。公式イベントで話すにはかなり気が引けるネタ度Maxです。

今回はAuth0(おーすぜろ)とAzure ADを組み合わせることで複雑なことをやろう!という話です。

もちろんAzure ADにはPremium P1/P2という複雑なことをやりたい人向けのプレミアなライセンスがありますので、お金に余裕のある方、一気通貫でサポートを頼みたい方は迷わずそちらを選んでください。

Auth0とは?

Auth0もMicrosoftやOkta、PingIdentity、OneLoginなどと同様にIDaaS(Identity as a Service)を提供しているサービスプロバイダです。jwt.io辺りで有名ですね。
ちなみにFounderは元マイクロソフトのEugenio Paceです。「A Guide to Claims-Based Identity and Access Control」をVittorio Bertocciと一緒に書いた人ですね。まだ彼がMSにいる時代にやり取りをしてサイン本をもらったりしたもんです(遠い目)。最近は共著のVittorioもAuth0へ移ったのが個人的なビッグニュースでした。

少し特徴的なのは「開発者向け」である、という売り出し方をしているところですね。開発者向けたる所以は、ひたすらかゆいところに手が届くから、というのが最大の理由だと思います。

このAuth0、実は別のサービスとしてWebtaskというFaaS(Function as a Service)を提供しており、ID関連の機能の各所にこのWebtaskをどんどん差し込んでいくことが出来るんです。このことにより、例えばid_tokenの中身を見て処理を実行したり、ID登録直後に別の処理を走らせたり、など開発者がやりたい放題出来てしまいます。


Azure AD + Auth0?

さて、Azure ADとAuth0を組み合わせると何が出来るのか?という話に移りたいと思います。
Auth0はAuth0自体にIDを保持して自身がIdPとして振舞う以外に、外部のIdP(Connectionと呼んでいます)とID連携する機能を持っています。また、当然のごとく外部のSPとID連携することもできます。
このことを使い、IDの保持とベーシックな認証機能はAzure ADで、複雑な処理(今回は条件付きアクセスと多要素認証)はAuth0で担当、というようなことを実現することが出来ます。
使えるプロトコルも多様なので、アプリ(今回はG Suite)とAuth0の間はSAML、Auth0とAzure ADの間はOpenID Connect、という構成を組んでみました。


Azure ADのアプリ(RP)としてAuth0を登録

早速構成していくわけですが、まずはAuth0の外部IdPとしてAzure ADを構成するためには、Azure ADのRelying Party(RP)としてAuth0を登録してあげる必要があります。具体的には、ReplyUrl(応答URL)にAuth0のエンドポイント(Callback)を登録し、Auth0側に設定するためのClient IDとClient SecretをAzure ADから払い出します。

Azure ADのアプリ登録メニューより登録を行います。
 Azure ADに登録するAuth0のCallback URLは以下の通りです。
  https://{テナント名}.auth0.com/login/callback


Auth0の外部IdPとしてAuth0を登録

次は、逆側の設定なので、Auth0にAzure ADの情報を登録していきます。
ちなみにAuth0はビルトインのConnectorとしてAzure ADが用意されているので、こちらを使ってもいいですし、OAuthを使ってカスタム接続するためのExtensionもあるのでこちらを使って接続しても問題はありません。

こちらがビルトインのAzure ADとの接続Connector

こちらがOAuthを使うExtension


私は後者のExtensionを使っています。(というかビルトインでAzure ADが存在しているのを知らなかった・・・)
Azure ADの認可エンドポイント、トークンエンドポイントと先ほどアプリ登録した際に取得したClient IDとClient Secretを登録します。

ちなみに、例のWebtaskを使ってGraph APIでAzure AD上のユーザ情報を取得することが出来ます。SAML Assertionに属性を入れてアプリに渡す必要があるので、必要な属性を取得する様にスクリプトを作ります。
function(accessToken, ctx, cb) {

  request.get('https://graph.microsoft.com/v1.0/me', {
      headers: {
        'Authorization': 'Bearer ' + accessToken,
      },
      json: true
    },

    function(e, r, u) {
      if (e) return cb(e);
      if (r.statusCode !== 200) return cb(new Error('StatusCode: ' + r.statusCode));
      var profile = {
        user_id: u.userPrincipalName,
        name: u.displayName,
        email: u.mail
      };
      cb(null, profile);
    });
}


直観的にわかりやすいスクリプトだと思うので、あまり解説する必要もないとは思いますが、トークンエンドポイントから取得したアクセストークンがコンテキストとコールバック先のオブジェクトと一緒に渡ってくるので、Graph APIにアクセスして必要な情報を取得、Profileとして設定して返却してあげる、という流れです。

G SuiteとAuth0をID連携

ここはこれまで何度となく解説してきたG Suiteのシングルサインオン設定の世界なので、G Suite側は目をつぶっていても構成できてしまう世界だと思いますので、Auth0側の設定を中心に。

ちなみにAuth0にはApplicationギャラリー的なプリセット・アプリのリストは存在しません。めちゃくちゃシンプルにNative App、SPA、Regular Web App、Machine to Machine Appの4種類しかありません。

G Suiteなど通常のアプリを使う場合はRegular Web Appを選びましょう。

また、Regular Web Appを選んだとしてもデフォルトではアプリと言っても単純なOAuthのクライアント登録しか出来ないので、AddOnという形でSAML等のプロトコルを設定してあげる必要があります。
SAMLの設定もかなりプログラマブルなので、Assertion内の各種パラメータをガリガリと書いていきます。本当に痒い所に手が届きます。ほぼ出来ないことは何もないので、Assertionの書き方の方言でうまくアプリと繋がらない、というトラブルとは無縁だと思います。その代わりSAML Assertionの中身の仕様について熟知している必要はありますが。


この構成のページからIdP MetadataやAssertion署名用の証明書のダウンロードなども可能なので、エンドポイントや証明書をG Suite側に設定してあげれば完了です。

これで一通り単純なシングルサインオンについて出来るようになっています。


条件付きアクセスを構成する

ここまでだとAuth0がG SuiteとAzure ADの間に挟まっている必要性が全くないので、最初に書いた通り、条件付きアクセスを構成してみます。
本来Azure ADではPremium P1のライセンスが必要な機能です。

Auth0での条件付きアクセスを構成するには、Rulesメニューよりルールを構成します。
このルールもJavascriptでガリガリと書いていくことが出来るので、ものすごく柔軟です。アクセス元の状態はContextから取得できるので、ソースIPやUser Agentなど様々な情報を見て多要素認証の適用の有無など各種条件を設定することが可能です。
function (user, context, callback) {
  const ipaddr = require('ipaddr.js');
  // 社内ネットワーク
  const corp_network = "x.x.x.x/16";
  // 対象のアプリケーションのclient_id
  const CLIENTS_WITH_MFA = ['G SuiteのClient Id'];

  // 接続元のソースIP
  const current_ip = ipaddr.parse(context.request.ip);
  if ((!current_ip.match(ipaddr.parseCIDR(corp_network)) && (CLIENTS_WITH_MFA.indexOf(context.clientID) !== -1))) {
      context.multifactor = {
        provider: 'google-authenticator',
        allowRememberBrowser: false
      };
  }

  callback(null, user, context);
}


ここまで構成すると社内アドレス以外からG Suiteを使おうとすると多要素認証(今回はGoogle Authenticator)を要求される様になります。



こんな感じでAzure AD+Auth0で見た目はぼぼAzure AD Premiumの条件付きアクセス、ということが実現できてしまいました(笑)。

まだまだネタは続きます。では次回!

0 件のコメント: