Não perca a cabeça configurando Typescript Azure Functions para Acesso ao Azure Key Vault e Identidades Gerenciadas

Cláudio Rapôso
4 min readJul 19, 2024

Bem-vindo ao quarto artigo da nossa série focada em configurar Azure Functions para acessar serviços do Azure com base nos princípios SOLID. Nos artigos anteriores, exploramos como interagir com Azure Blob Storage e Azure Data Tables e Azure Storage Queue. Neste artigo, vamos aprofundar o acesso ao Azure Key Vault utilizando o SDK do Azure Key Vault.

Passo 1: Configuração do Ambiente

Antes de começar, certifique-se de ter as seguintes dependências instaladas:

npm install @azure/identity @azure/keyvault-secrets

OBS: Caso precise ver os Passos 2 ao 3 veja o artigo anterior sobre o tema:

Passo 4: Configurando a Fábrica para Clientes de Segredos

Agora vamos criar uma fábrica que utiliza o CredentialProvider para instanciar o SecretClient.

import { SecretClient } from "@azure/keyvault-secrets";

/**
* Factory class for creating instances of SecretClient for Azure Key Vault.
*/
class SecretClientFactory {
private vaultUrl: string;
private credentialProvider: CredentialProvider;

/**
* Creates an instance of SecretClientClientFactory.
* @param {string} accountUrl - The account URL for the SecretClientClient.
* @param {CredentialProvider} credentialProvider - The provider for Azure credentials.
*/
constructor(accountUrl: string, credentialProvider: CredentialProvider) {
this.accountUrl = accountUrl;
this.credentialProvider = credentialProvider;
}

/**
* Creates a SecretClient instance.
* @returns {SecretClient} The SecretClient instance.
*/
createSecretClient(): SecretClient {
const credential = this.credentialProvider.getCredential();
return new SecretClient(this.vaultUrl, credential);
}
}

Passo 5: Implementando na Azure Function

Vamos agora ver como podemos integrar esta estrutura em uma Azure Function, demonstrando cada um dos métodos de autenticação.

Exemplo 1: Azure Function com Managed Identity Atribuída ao Sistema

import { AzureFunction, Context, HttpRequest } from "@azure/functions";
import { SecretClientFactory } from "./SecretClientFactory";
import { SystemAssignedManagedIdentityCredentialProvider } from "./SystemAssignedManagedIdentityCredentialProvider";

/**
* Azure Function triggered by an HTTP request.
* @param {Context} context - The Azure Function context object.
* @param {HttpRequest} req - The HTTP request object.
*/
const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
const vaultUrl = process.env.AZURE_KEYVAULT_RESOURCEENDPOINT;
const credentialProvider = new SystemAssignedManagedIdentityCredentialProvider();
const secretClientFactory = new SecretClientFactory(vaultUrl, credentialProvider);

const secretClient = secretClientFactory.createSecretClient()
const secret = await secretClient.getSecret("secretName");
context.res = {
status: 200,
body: { secret }
};
};

export default httpTrigger;

Exemplo 2: Azure Function com Managed Identity Atribuída ao Usuário

import { AzureFunction, Context, HttpRequest } from "@azure/functions";
import { SecretClientFactory } from "./SecretClientFactory";
import { UserAssignedManagedIdentityCredentialProvider } from "./UserAssignedManagedIdentityCredentialProvider";

/**
* Azure Function triggered by an HTTP request.
* @param {Context} context - The Azure Function context object.
* @param {HttpRequest} req - The HTTP request object.
*/
const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
const vaultUrl = process.env.AZURE_KEYVAULT_RESOURCEENDPOINT;
const clientId = process.env.AZURE_KEYVAULT_CLIENTID;
const credentialProvider = new UserAssignedManagedIdentityCredentialProvider(clientId);
const secretClientFactory = new SecretClientFactory(vaultUrl, credentialProvider);

const secretClient = secretClientFactory.createSecretClient()
const secret = await secretClient.getSecret("secretName");
context.res = {
status: 200,
body: { secret }
};
};

export default httpTrigger;

Exemplo 3: Azure Function com Service Principal

import { AzureFunction, Context, HttpRequest } from "@azure/functions";
import { QueueServiceClientFactory } from "./QueueServiceClientFactory";
import { ServicePrincipalCredentialProvider } from "./ServicePrincipalCredentialProvider";

/**
* Azure Function triggered by an HTTP request.
* @param {Context} context - The Azure Function context object.
* @param {HttpRequest} req - The HTTP request object.
*/
const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
const vaultUrl = process.env.AZURE_KEYVAULT_RESOURCEENDPOINT;
const tenantId = process.env.AZURE_KEYVAULT_TENANTID;
const clientId = process.env.AZURE_KEYVAULT_CLIENTID;
const clientSecret = process.env.AZURE_KEYVAULT_CLIENTSECRET;
const credentialProvider = new ServicePrincipalCredentialProvider(tenantId, clientId, clientSecret);
const secretClientFactory = new SecretClientFactory(vaultUrl, credentialProvider);

const secretClient = secretClientFactory.createSecretClient()
const secret = await secretClient.getSecret("secretName");
context.res = {
status: 200,
body: { secret }
};
};

export default httpTrigger;

Conclusão

Neste artigo, mostramos como configurar Azure Functions para acessar o Azure Key Vault com métodos de autenticação variados, criando um Factory Pattern. Esta abordagem não só facilita a manutenção e extensão do código, mas também garante uma implementação robusta e escalável.

Referências

--

--

Cláudio Rapôso
Cláudio Rapôso

Written by Cláudio Rapôso

Microsoft MVP | Software Architect | Teacher | Book Author | MCT | 12x Microsoft Certified Connect with me in https://www.linkedin.com/in/cfraposo

No responses yet