BEACHSIDE BLOG

Azure と GitHub と C# が好きなエンジニアの個人メモ ( ・ㅂ・)و ̑̑

Cosmos DB で RBAC を構成して接続文字列の管理を不要にする ( Azure, PowerShell )

2月ごろに Azure Cosmos DBの RBAC のアナウンスされて気になってたけど放置してたのをついに書く時がきました(←気まぐれですが)。実装に関することはいつも通り C# の話になります。

書いてたら思った以上に長くなってしまいました...

Cosmos DB の RBAC とは

Cosmos DB の RBAC についての基礎知識やメリットをざっくり書いていきます。

接続文字列が不要になる

今でも多くの場合、データベースとアプリを接続するには接続文字列を使うことが多いでしょう。Azure Cosmos DB も同様です。
しかし、RBAC の機能を使うことで Cosmos DB へ接続する際の接続文字列が不要になります。
その代わりに RBAC の管理はもちろん必要になりますが、接続文字列を管理することでのリスクに比べるとベターなことが多いでしょう。

ロールによるアクセス制御が可能になる

Cosmos DB の接続文字列では、ロール(例えば read のみとか、read/write 両方できるとか)の制御はできません。
RBAC の機能を使うと、ロールにユーザーや Azure のリソース(ようは managed Identity)を割り当てることで細かい制御が可能になります。

例えばこんな感じです。

  • すべてのコンテナーに対して read 権限のみを与えるロールを作る
  • 特定のコンテナーに対してデータを追加できるが削除できないロールを作る
  • 特定の Azure Functions (の Managed Identity) にロールを付与することでアクセス制御をする

データプレーン操作の RBAC

重要なポイントのひとつとして、 Cosmos DB に対する RBAC には以下の2種類あり、今回のブログでとりあげているのは データプレーン操作の RBAC です。

種類 概要
データプレーン操作
(Data plane operations)
雑にいうとデータの読み取りとか削除の操作。2021年5月時点ではプレビュー中の機能。公式ドキュメントはこちら
管理プレーン操作
(Management plane operations)
雑な例だとデータベースやコンテナーの作成や RU の変更などの操作で、以前からある機能。公式ドキュメントはこちら

つまり Cosmos SDK を使ったプログラムで管理プレーンの操作をしたい場合は注意が必要です。むしろ管理プレーンの操作が動くと死にます。
具体的な例だと Database や Container がなければ作成する CreateIfNotExists メソッドを使っていたり、Cosmos DB の Change Feed 機能を使った Azure Functions で Lease container がなかったら作成する CreateLeaseCollectionIfNotExists =true のようなプログラムを書いてる場合です。

2021年5月 GA

2021年5月25日から開催された Build で GA の発表がありました。

azure.microsoft.com

ってかこのブログ、5月頭に書き始めてその間に PowerShell のネタ書いてたりで放置してたらもう6月も終わるのかと思っている今日この頃です。

前置きが思った以上に長くなりましたが本題に近づいていきましょう。

事前準備

Cosmos DB のリソース準備

ということでまずは Azure Portal で Cosmos DB がない場合はリソースを作成して、適当にデータベースとコンテナーを作る準備が必要ですが、そこが不明な場合はこちらの公式ドキュメントでセットアップしましょう。

Cosmos DB のリソースを作成したあと、クイックスタート をクリックして、Coreate 'Items' container のボタンをクリックすると、ToDoList というデータベースの中に Items という Container が作成されますので、とりあえずこの状態で話を進めます。

この方法で database/container を作成すると、RU の管理が container 毎になる点は注意です。よくわからんという場合は、RU を container 毎で管理するか database 単位で管理するかのドキュメントをご参照ください。Cosmos DB を使う上で大事なポイントのひとつです。

f:id:beachside:20210628161435p:plain

ついでに Management という container を作って、それぞれの container にデータを入れておきました。この時点での Cosmos DB の構成は以下のようにcontainer が2つある状態です。

f:id:beachside:20210628212509p:plain:w280

Az.CosmosDB module のインストール

RBAC の管理はそのうち Azure Portal からできるようになるかなと勝手に妄想してますが、2021年6月時点だとまだできないです。そのため RBAC を操作するには、以下どちらかを使う必要があります。

GA のタイミングで PowerShell は preview が外れるかと思ったら今のところ更新の様子がありません。

今回は私があまり使わない PowerShell を使っていきます。ちなみに Azure CLI も試しましたが当たり前に操作感はかわりませんのでブログには書かないで起きます。

以下のコマンドを実行して Az.CosmosDB module をインストールします。

Install-Module -Name Az.CosmosDB -AllowPrerelease

f:id:beachside:20210517154829p:plain

ちなみに私の場合、図にあるように Administrator で実行しろとエラーがでました。でその私のケースでの解決策がこちら

PowerShell で Install-Module をするとエラー "Administrator rights are required to install or update ..." を解決する - BEACHSIDE BLOG

PowerShell で Azure にサインイン

2021年5月時点ではコマンドを使った作成になりますので、今回は Azure PowerShell (Az.CosmosDB バージョン 2.0.1-preview) を使っていきます。ということでまずはローカル環境で Powershell を起動して Azure にログインしておきます。これが不明の場合は前回ブログに整理しておきましたのでご参照ください。

PowerShell で Azure に サインイン / テナント ( サブスクリプション ) 切り替え - BEACHSIDE BLOG

さて次からがようやく本題です。

RBAC の操作

ここからは PowerShell のコマンドを使って RBAC の操作をしていきます。

Role の一覧を見る

GA 以降、2つの built-in ロールができました(Preview 期間中はありませんでした)。全ての container の Read only のロールと Read/Write できる Contributor のロールの2つです。

以下のコマンドで見てみましょう。

# TODO: 操作する Cosmos DB のアカウント名とリソースグループ名をセット
$accountName = ""
$resourceGroupName = ""

Get-AzCosmosDBSqlRoleDefinition -AccountName $accountName -ResourceGroupName $resourceGroupName

f:id:beachside:20210628162846p:plain

前述で「dedutuRead/Write できる Contributor のロール」とさらっと書きましたが、単純な Read も Write って制御ではなく、それぞれの操作を細かく制御できます。何ができるかは以下のドキュメントをチェックしましょう。

Cosmos DB の Custom Role を作成

Cosmos DB を操作して RBAC、つまりロールベースのアクセスコントロールをするためのロールを作成します。

New-AzCosmosDBSqlRoleDefinition を使ってロールを作成します。以下は、"Management" という container のみに対してすべてのアクションを実行できるロールを作成するコマンドです。

# TODO: 必要に応じて値をセット
$resourceGroupName = ""
$accountName = ""
$roleName ="Management container Contributor"

New-AzCosmosDBSqlRoleDefinition -AccountName $accountName `
    -ResourceGroupName $resourceGroupName `
    -Type CustomRole -RoleName $roleName `
    -DataAction @( `
        'Microsoft.DocumentDB/databaseAccounts/readMetadata',
        'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*', `
        'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*') `
    -AssignableScope "/dbs/ToDoList/colls/Management"

簡単に解説しておくと、

コードサンプルの最初にあるように3つの変数に値をセットします。

  • $resourceGroupName: Cosmos DB がおかれているリソースグループの名称
  • $accountName: Cosmos DB のアカウント名
  • $roleName: これから作成するロールの名前

それ以外では、

  • Type: CustomRole を指定します。
  • Data Action: どのリソースに対してどんなアクションができるかを定義します。1つのロールに対して複数定義できます。メタデータの読み込み、データの操作は全て可能という定義です。定義できるアクションはこちらで確認できます。
  • AssignableScope: 上記のコードだと"Management" という名称の container のみ DataAction で定義した操作が可能です。その他にデータベースやコンテナーレベルでの制御も可能です。詳しくはこちらで確認できます。

正しく実行出来たらこんな感じでレスポンスが返ってきます。レスポンスには数秒かかるので気長に待ちましょう。

f:id:beachside:20210628181017p:plain

レスポンスを待てずにぐちゃっと(?)した場合は、前述でも行った Get-AzCosmosDBSqlRoleDefinition でロールの一覧を確認できます。

ロールにユーザーや Managed Identity をアサインする

ロールができたら、そのロールが使えるユーザーや Azure のリソースの Managed Identity をアサインします。ユーザーなら Azure AD の ObjectID をセットします。"Azure のリソース" ってのは例えば特定の Azure Functions のインスタンスや Web Apps のリソースとかです。

  • 例えば特定の Azure Functions に割り当てたいなら、Azure ポータルからManaged Identity をサクッと設定して ID を取得しておきます(設定方法はこちら)。
  • ユーザーを割り当てたいなら、Azure Active Directory でそのユーザーの Object ID を取得しておきます。
  • -Scope の設定は
    • 全スコープを割り当てたいならドキュメントのサンプルのようにアカウント名をセットすればよいです。"/" でも行けます。
    • スコープを限定した Role の場合はそのスコープを割り当てます。前述で作成した "Management container Contributor" に何かをアサインするなら -Scope dbs/ToDoList/colls/Management をセットします。-Scope cosmos-beachside-sandbox20210628/dbs/ToDoList/colls/Management って入力してもいけたので、なんか緩いルールで入力してセットできるのが若干不安です。
# 
$principalId = "79fd8ad5-dd7c-42fa-bb37-401a0624c34f"

New-AzCosmosDBSqlRoleAssignment -AccountName $accountName `
    -ResourceGroupName $resourceGroupName `
    -RoleDefinitionName $roleName `
    -Scope "dbs/ToDoList/colls/Management" `
    -PrincipalId $principalId

アサインを削除する

アサインされたリストを以下のコマンドで見てみましょう。

Get-AzCosmosDBSqlRoleAssignment -ResourceGroupName $resourceGroupName -AccountName $accountName | Format-List

f:id:beachside:20210628195934p:plain

アサインの削除には Id が必要です。コマンドの結果を見ると Id がめっちゃ長いですが、削除する際は最後の GUID ぽいのだけで削除できます。例えばこんな感じ。

Remove-AzCosmosDBSqlRoleAssignment -AccountName $accountName -ResourceGroupName $resourceGroupName  -Id a2793668-cadc-43fc-95a4-c9d8c897aeb5

雑なサンプルコード

サンプルを書いた時には Console App は GenericHost 使ってたりしたので、ここではただの class のサンプルを書いておきます。

補足するのは NuGet で以下の2つ使ってる点くらいでしょうか。。。

  • Azure.Identity (v1.4.0)
  • Microsoft.Azure.Cosmos (v3.20.0)

ログの確認

この Data Plane の RBAC の操作のログは、以下のブログの Advanced auditing of data requests に書いてある通り、診断ログの設定をしておけばみれます。

Role-based access control with Azure AD now in preview | Azure Cosmos DB Blog

これについて書こうと思ったら診断ログの設定からだなーと思い、もう長くなったのでここら辺にしておきます。

参考

全般:

コマンドリファレンス: