O Sertão será Cloud

Don’t lose your head configuring TypeScript Azure Functions for Access to Azure Key Vault and…

Don’t lose your head configuring TypeScript Azure Functions for Access to Azure Key Vault and Managed Identities

Welcome to the fourth article in our series focused on configuring Azure Functions to access Azure services based on SOLID principles. In previous articles, we explored how to interact with Azure Blob Storage, Azure Data Tables, and Azure Storage Queue. In this article, we will delve into accessing the Azure Key Vault using the Azure Key Vault SDK.

{artigo 3}

Configuring Azure Functions for Azure Table Access with SOLID and Factory Pattern in TypeScript

Step 1: Environment Setup

Before you start, make sure you have the following dependencies installed:

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

Note: If you need to see Steps 2 to 3, refer to the previous article on the topic:

Como Configurar o Azure Blob Service Client Aplicando os Princípios SOLID em uma Azure Function com…

Step 4: Setting Up the Factory for Secret Clients

Now let’s create a factory that uses CredentialProvider to instantiate 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);
}
}

Step 5: Implementing in Azure Function

Now let’s see how we can integrate this structure into an Azure Function, demonstrating each authentication method.

Example 1: Azure Function with System-assigned Managed Identity

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);
}
}

Example 2: Azure Function with User-assigned Managed Identity

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;

Example 3: Azure Function with Service Principal

import { AzureFunction, Context, HttpRequest } from "@azure/functions";
import { SecretClientFactory } from "./SecretClientFactory";
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;

Conclusion

In this article, we’ve demonstrated how to configure Azure Functions to access Azure Key Vault with various authentication methods using Factory Pattern. This approach not only simplifies code maintenance and extension but also ensures robust and scalable implementation.

References

Início Rápido – Criar uma conexão de serviço no aplicativo de funções por meio do portal do Azure