BEACHSIDE BLOG

MicrosoftとかC#を好むレンジャーの個人的メモ

DocumentDB - リソーストークンを使ったアクセス 1/2 ( Access to DocumentDB with resource tokens )

Xamarinで作ったモバイルアプリなどのクライアントから直接 (みんな大好き) DocumentDB にアクセスしたいシナリオがあった場合、

(例えば、 How To Build Planet Scale Mobile App in Minutes with Xamarin and DocumentDB | Blog | Microsoft Azure なシナリオ)

クライアント側のアプリのプログラムに DocumentDB のマスターキーを入れておくのは非常に危険です(ガチのアプリでそんなことする人はいないですよね♪)。

そんな場合、一時的なトークンで認証して DocumentDB にアクセスするのがベターな一例となります。 そんな実装の話です。

Overview

実装のイメージはこんな感じです(図はこちらから引用)。

f:id:beachside:20170206180238p:plain

1. クライアントは、"Mid-tier service"(いわば認証用のサーバー)にアクセス
(クライアントは、"Mid-tier service"にアクセス時には何らかのユーザー認証がされている前提)
2. “Mid-tier service"がDocumenDBへアクセスし、リソーストークンを取得
3. "Mid-tier service"が取得したリソーストークンをクライアントに渡す
4. クライアントは、リソーストークンを使ってDocomentDBにアクセス

  

リソーストークンは、DocumenDBの特定コレクションやパーティションキーに対して、有効期限と以下2種類の権限を付与することができます。

  • All : リソースに完全なアクセス許可
    (と、本家サイトに書いていますが、コレクション自体の削除はできず、コレクション内のDocumentに対してCRUDができることを検証済みなので、まぁ安全)

  • Read : 対象リソースに対して読み取りのみ可

リソーストークンは、DocumentDBのデータベースに紐づくユーザーに紐づくパーミッションに紐づいて設定することができます。
これについて詳しくは、DocumentDB 階層型リソース モデルと概念 | Microsoft Docs が参考になります。

Environment

  • Visual Studio 2017 Enterprise (RC)
  • DocumenDB Core (v1.0.0)
  • .NETCore.App (v1.1.0)

準備1:DocumentDBのインスタンスとコレクション作成

最初に今回のDocumenDBの構成ですが、コレクション(RDBでのテーブル的なもの)はCol1とCo2の2つがあり、2ユーザーを用意して権限を持たせます。

  • ユーザー1は、コレクション「Col1」のReadOnly権限を持っている
  • ユーザー2は、コレクション「Col2」のAll権限を持っている

f:id:beachside:20170207161845p:plain

(自分の絵心の無さに衝撃を受けました…)

では、Azure Portal からDocumentDBのデータベースを作成します。
この操作はポータルをみてポチポチするだけなので、本家サイトのリンクのみで…(サイト内の手順 1: DocumentDB アカウントを作成するを行うと作成できます)。

docs.microsoft.com

Azure Portalで、作成したデータベースのブレードを開き、「キー」をクリックすると、URIやプライマリーキーが確認できます、そしてのちほど使います。
(なお、読み取り専用キーもできているので、保守用に全リソースに対する読み取り権限を与えるならこれを使うってはありかなと。)

f:id:beachside:20170206192149p:plain

構成に合わせてざっくりとstructで定義を作りました。

データベースとコレクションを作成していきます。作成すると課金が発生しますので、自己責任にて気を付けてください♪
(料金についてはこちら

コレクションの作成

では、2つのコレクションを作りましょう。

CreateCollectionsAsync()メソッドを実行すると、データベースインスタンスが作られ、その下にCol1Col2というコレクションが2つできます。
価格レベルとスループットを指定していないので、Standardの400で作られます。

テスト用にデータも入れておきましょう。今回はシンプルにKeyTextのドキュメントを定義して….(サンプルなので、Jsonを「キャメルケースにせんのかいっ!」って突っ込みはなしです)、

サンプルのデータをINSERTします。

AzureのPoralでDocumentDBのブレードを開き、「クエリエクスプローラー」を使って見てみましょう。ちゃんとデータが入ってますね♪

f:id:beachside:20170206220215p:plain

idやその他諸々のinternal fieldsは自動で作られるんですが、その辺についてまとまったドキュメントがMSDNにない気がしますね。タイムスタンプとか、パーティション分割時用IDとか…今回は重要じゃないのでその話はとばします。

準備2:ユーザー、パーミッションの作成

流れとしては、ユーザーを作っておき、パーミッションを作るときにユーザーに紐づけます。

外部からは、1行目のCreateUsersAndPermissionsAsyncメソッドを呼ぶだけです。

8行目のCreateUsersAsyncメソッドでユーザーを作ります。ユーザーのIdは、事前にstructで登録したものです。その他諸々、インテリセンスを効かせながらパタパタと入力ができるので、structにしたってわけです(他でもこんなのを再利用しているので、書いただけなのですが)。

17行目のCreatePermissionsAsyncメソッドでパーミッションを作ります。
パーミッションは、Permissionクラスが用意されており、必要な値をセットしてあげます。
今回は、最初の構成で説明した通り、ResourceLinkと‘PermissionModeを指定してあげることで、特定のコレクションに対して特定の権限を付与しています。

  • ユーザー1は、コレクション「Col1」のReadOnly権限を持っている
  • ユーザー2は、コレクション「Col2」のAll権限を持っている

44行目のRequestOptionsでは、ResourceTokenExpirySecondsプロパティで有効期限を設定することができます。(ただ、検証したところ、20秒とか数分で登録しても設定が有効にならないのは….バグってるんでしょうか….まー今度もう少し検証しよう…)

パーミッションの設定は、27行目、39行目にあるように、Databaseに紐づくユーザーに対して登録します。

(各メソッドで無駄にレスポンスを受け取っているのは、登録したレスポンスの中身をデバッグで見て検証してただけです♪)

さて、動作検証のコーナーに進みたいところですが…..思った以上に長くなったので、続きは次回に….

参考

DocumentDB 階層型リソース モデルと概念 | Microsoft Docs

DocumentDB のデータへのアクセスをセキュリティで保護する方法 | Microsoft Docs