4
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

Organization

Azure Managed Identityを使ってソースから資格情報を追い出す

はじめに

クラウドでアプリケーションを開発するにあたり真っ先に考えるのが資格情報をどう取り扱うかですよね。

たとえば、FunctionsからBlobStorageにファイルを保存するときのことを考えてみましょう。
BlobStorageのストレージアカウントのアクセスキーをソースコードに直接書くことでアクセスすることは可能ですが、そのソースコードをそのままGithubにcommitしてしまい漏洩してしまう・・・なんてことは想像できますしAWSではよく話題になってますよね。

こういったリスクを排除するためにあらかじめアクセスするサービス同士を繋いでおくことで、資格情報(アクセスキー)を使わずリソースにアクセスすることが可能となります。
この仕組みを実現するのがAzure Managed Identityです。

Azure Managed IdentityはAzure ADの機能の一つで料金はかかりません。

ちなみにAzure Managed Identityは以前はMSI(Managed Service Identity)なんて呼ばれていました。

AWSだと?

AWSでもほぼ似たような仕組みが存在します。
EC2にS3のIAM Roleを付与しておくことで、EC2上のアプリケーションでAWS SDKを使って実装するときにアクセスキー・シークレットアクセスキーを使わずS3にアクセスできます。

AWSでは以下のURLにアクセスすることで一時的なセキュリティ情報を取得してリソースにアクセスることができます。
ちなみにAWS SDKを使っている場合は以下のURLを意識することはありません。

http://169.254.169.254/latest/meta-data/iam/security-credentials/[ロール名]

やっていこう

AWSの場合は、IAMロールを作成してEC2 RoleやLambda Functionsに割り当てていくだけで実現できるのですがAzureの場合は少し面倒です。実際にやってみましょう。

nodejsとJavaのサンプルを用意しました。

Azure FunctionsからBlobStorageにデータを保存する

Azure Functions(nodejs)からBlobStorageにデータを保存する部分をManagedIdentityを使って実装してみたいと思います。

マネージドIDを有効にする

Functionsの設定画面を開いて、IDをクリックします。

image.png

オンにして保存すると、オブジェクトIDが振られます

image.png

オブジェクトIDが発番されると、オブジェクトIDに対して権限を設定することができるようになります。
つまりFunctionがBlobStorageのアクセス権を持つように設定することが可能になります。

ストレージアカウントでIAMの設定を開きます。

「ロールの割り当て」タブを選択し、「追加」をクリックします。

image.png

Blobに対するアクセス権を設定して保存をクリックします。

image.png

これでFunctionにBlobStorageにアクセスする権限が付きました。

あとは、nodejsでBlobへアクセスするコードをいつも通り実装するだけです。

    const az = require("@azure/identity");
    const tokenCredential = new az.ManagedIdentityCredential();
    const blobServiceClient = new BlobServiceClient('https://' + storageAccount + '.blob.core.windows.net', tokenCredential);

ポイントは2行目です。new ManagedIdentityCredential()ってやるだけで資格情報(Credential)が取れるので、あとはBlobServiceClientに渡してあげるだけです。とても簡単ですね。
内部ではhttp://169.254.169.254/metadata/identity/oauth2/tokenにアクセスして一時的な認証情報を取得しています。
BlobServiceClientが取れてしまえばこっちのものなので、あとはAPIに従って実装しましょう。

Azure FunctionsでKeyVaultのSecretの値を取得する

とある仕事でAzureFunctionsからOAuth2.0(ClientCredentialsFlow)を使ってデータを取得する必要がでてきました。
話はそれますが、ClientCredentialsFlowはClientID, ClientSecret, Scopeを設定してAccessTokenを取得するフローになります。ClientIDとClientSecretは正しく管理されていることが前提ですので、ソースコード上にハードコードするのはマズいですよね。今回はAzureKeyVaultに格納することにしました。FunctionsでKeyVaultを扱ってみましょう。

FunctionsのマネージドIDの設定は先ほどと同じなので省略します。

KeyVaultのIAMの設定を行いますが流れはストレージアカウントの場合と同様です。
「ロールの割り当て」タブを選択し、「追加」をクリックします。

image.png

役割を設定し、選択のテキストボックスでFunction名を使って検索し設定していきます。
(ここでFunction名が出てこない場合は、ManagedIdentityの設定がうまくいっていないということです)

image.png

これでFunctionにキーコンテナ(KeyVault)にアクセスする権限が付きました。

あとは同じように実装していきます。

    const az = require("@azure/identity");
    const tokenCredential = new az.ManagedIdentityCredential();
    const url = 'https://' + config.keyContainer + '.vault.azure.net';
    const client = new SecretClient(url, tokenCredential);
    const clientId = await client.getSecret("xxxxxxxxxxxxxxx");

こちらもnew ManagedIdentityCredential()とするだけで資格情報が取得できるのでKeyVaultへアクセスするためのSecretClientのコンストラクタに設定してあげるだけです。

ACI(AzureContainerInstances)からKeyVaultへアクセスする

AzureContainerInstances(ACI)からCosmosDBにアクセスすることを考えていたのですが、これもManagedIdentityを使って・・・とおもったらそうはいきませんでした。
これは後ほど触れますが、CosmosDBがAzure AD 認証をサポートしていないためです。

ということで・・・これもKeyVaultのSecretにCosmosDBの接続文字列を保存して実装していこうと思います。

ACIでManaged Identityを有効化します。

IDをクリック

image.png

「オン」にして保存されるとオブジェクトIDが発番されます。

image.png

KeyVaultに対するIAMの設定は先ほどと同じなので省略します。

ACIからCosmosDBへのアクセスはJavaで書いていたのでManagedIdentityを使ってKeyVaultへアクセスする部分のコードを紹介します。

        Azure azure;
        try {
            azure = Azure.authenticate(
                    new MSICredentials(
                            AzureEnvironment.AZURE)).withDefaultSubscription();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        // アクセスキーを使ってKeyVaultからシークレットを取得
        Vault vault = azure.vaults().getByResourceGroup(keyvaultRg, keyvaultName);
        cosmosdbxxx = vault.secrets().getByName("cosmosdb-xxxxx").value();

SDKはVersion1.26.0を使ったのですが、クラスにManagedIdentityの古い名称(MSI)が残っています。
この名称に気づけずちょっと苦戦しましたが、これを使うことで簡単に資格情報が取得できます。

Managed Identityはまだまだ発展途上

今回の例ではACIからCosmosDBにアクセスするときにManagedIdentityを使って簡単に接続・・・・というわけにはいかず、CosmosDBの接続文字列を格納したKeyVaultへアクセスするためにKeyVaultを使いました。

このことからわかる通りすべてのサービスがすべてのサービスに対してManagedIdentityでアクセスできることがサポートされているわけではありません。

ManagedIDをサポートするAzureサービス(2019/12/16時点)

ManagedIdentityが設定できるサービスです。

  • Azure Virtual Machines
  • Azure 仮想マシン スケール セット
  • Azure App Service
  • Azure Blueprint
  • Azure Functions
  • Azure Logic Apps
  • Azure Data Factory V2
  • Azure API Management
  • Azure Container Instances
  • Azure Container Registry タスク

Azure AD 認証をサポートしている Azure サービス(2019/12/16時点)

ManagedIdentityに対してIAMの設定が行えるサービスととらえてください。

  • Azure Key Vault
  • Azure Data Lake
  • Azure SQL
  • Azure Event Hubs
  • Azure Service Bus
  • Azure Storage の BLOB とキュー
  • Azure Analysis Services

メタデータエンドポイントを使う上での注意点

Capital Oneデータ漏洩経路の考察

CapitalOneのデータ漏洩事件に関してとても分かりやすくまとめられていました。
メタデータエンドポイントを使ったことが悪いわけではなく、IAMロールの権限が非常に強力だったことも事故の影響が大きくなった原因とあります。

これはどのサービスを使う上でもそうですが、最小権限を付与するように注意しておくとよいでしょう。

さいごに

個人的に辛かったのはCosmosDBのAzureAD認証のサポートがなかったことと、AzureBatchにManagedIdentityが設定できなかったことです。AzureBatchはLogAnalyticsからも見放されているので、これからあまり発展しないのかな・・・ちょっと使うのやめようかな・・・と思ったりもしました。

新機能も良いのですが、MonitorやLogAnalyticsを幅広いサービスで使えるようになることやManagedIdentityといった地味だけどとても嬉しい機能のアップデートに力を入れてほしいなぁと思ってます。

マイクロソフトさんよろしくお願いします。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
4
Help us understand the problem. What are the problem?