概要
Azure Blob Storageのデータを取得するAPIをローカルで動かした。
認証にはマネージドIDを使ってみたメモ。
コード
api/src/lib/azure-storage-with-credential.ts
import { DefaultAzureCredential } from '@azure/identity';
import { BlobServiceClient } from '@azure/storage-blob';
export const getBlobClient = () => {
const accountName = process.env.Azure_Storage_AccountName;
if (!accountName) throw Error('Azure Storage accountName not found');
const blobServiceClient = new BlobServiceClient(
`https://${accountName}.blob.core.windows.net`,
new DefaultAzureCredential(),
);
return blobServiceClient;
};
api/src/functions/magiaCharacter.ts
import {
app,
HttpRequest,
HttpResponseInit,
InvocationContext,
} from '@azure/functions';
import { getBlobClient } from '@yakumi-api/lib/azure-storage-with-credential';
export async function magiaCharacter(
request: HttpRequest,
context: InvocationContext,
): Promise<HttpResponseInit> {
const { uid, id } = request.params;
context.log(`uid: ${uid}, id: ${id}`);
const bloblClient = getBlobClient();
const container = bloblClient.getContainerClient('$web');
const blob = container.getBlobClient(
`fall-magia/character-data/${uid}/${id}/character-data.json`,
);
const res = await blob.download();
if (res.errorCode || !res.readableStreamBody) {
throw new Error('Blob not found');
}
const data = JSON.parse(
(await streamToBuffer(res.readableStreamBody)).toString(),
);
return {
status: 200,
headers: new Headers([['Content-Type', 'application/json']]),
body: JSON.stringify(data),
};
}
app.http('magiaCharacter', {
methods: ['GET'],
authLevel: 'anonymous',
route: 'magia-character/{uid}/{id}',
handler: magiaCharacter,
});
function streamToBuffer(
readableStreamBody: NodeJS.ReadableStream,
): Promise<Buffer> {
return new Promise((resolve, reject) => {
const chunks: Buffer[] = [];
readableStreamBody.on('data', (chunk) => {
const content = chunk instanceof Buffer ? chunk : Buffer.from(chunk);
chunks.push(content);
});
readableStreamBody.on('end', () => {
const buffer = Buffer.concat(chunks);
resolve(buffer);
});
readableStreamBody.on('error', reject);
});
}
マネージドIDの設定
リソースグループのアクセス制御(IAM)から設定する
BloBストレージのCRUD操作ができるロールを選択
メンバーから自分を選択
選択したメンバーになったことを確認して、選択ボタンを押下
条件は特になし
スコープがリソースグループ内になっていることを確認して、割り当て
確認
割り当て後、ローカルでnpm run start
でAPIを立ち上げ、アクセスしたところBlobコンテナ内のファイルを取得できた。
メモ
マネージドIDのロールを割り当てる前は下記のエラーが発生。
System.Private.CoreLib: Exception while executing function: Functions.magiaCharacter. System.Private.CoreLib: Result: Failure
Exception: This request is not authorized to perform this operation using this permission.
参考
Azure SDK for JavaScript を使用して Azure リソースに対して Azure でホストされるアプリを認証する
TypeScript を使って BLOB をダウンロードする
2024.09.19 追記
GUIではなくbicepを使って設定する方法を追記する。
infra/biceps/rbac.bicep
@description('Specifies the role definition ID used in the role assignment.')
param roleDefinitionID string
@description('Specifies the principal ID assigned to the role.')
param principalId string
// リソースグループの単位でロールを割り当てる
var roleAssignmentName= guid(principalId, roleDefinitionID, resourceGroup().id)
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: roleAssignmentName
properties: {
roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionID)
principalId: principalId
}
}
infra/bin/rbac.bash
#!/bin/bash
BIN_DIR=$(cd $(dirname $0) && pwd)
BICEP_DIR=$(cd $BIN_DIR/../biceps && pwd)
# 環境変数読み込み
source $BIN_DIR/.env
# ローカルでログイン中のユーザのIDを取得
PRINCIPAL_ID=$(az ad signed-in-user show --query id -o tsv)
# 組み込みロール
# https://learn.microsoft.com/ja-jp/azure/role-based-access-control/built-in-roles
# ストレージ BLOB データ共同作成者 のロールを割り当てる
cd $BICEP_DIR && az deployment group create \
--name frontendDeployment \
--template-file rbac.bicep \
--parameters roleDefinitionID=ba92f5b4-2d11-453d-a403-e96b0029c9fe \
principalId=$PRINCIPAL_ID \
-g $RESOURCE_GROUP_NAME
# ストレージ キュー データ共同作成者 のロールを割り当てる
cd $BICEP_DIR && az deployment group create \
--name frontendDeployment \
--template-file rbac.bicep \
--parameters roleDefinitionID=974c5e8b-45b9-4653-ba55-5f855dd0fb88 \
principalId=$PRINCIPAL_ID \
-g $RESOURCE_GROUP_NAME
参考: 組み込みロールのroleDefinitionID
参考: クイックスタート: Bicep を使用して Azure でのロールを割り当てる
なお、ローカルから接続する場合はファイアウォールの設定で許可する必要がある。
下記はすべて開けた場合のbicep
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: '${storageAccountName}storage'
location: location
sku: { name: storageAccountSku }
kind: 'StorageV2'
properties: {
+ allowBlobPublicAccess: true
minimumTlsVersion: 'TLS1_2'
+ publicNetworkAccess: 'Enabled'
}
}
試す。
ソースコード
cd apps/api && npm run dev
post http://localhost:7071/api/characters/async
Content-Type: application/json
{
"CharacterID": "test1",
"CharacterName": "テストキャラクターあるふぁ"
}