All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openmetadata.service.secrets.AzureKVSecretsManager Maven / Gradle / Ivy

There is a newer version: 1.5.11
Show newest version
package org.openmetadata.service.secrets;

import com.azure.core.credential.TokenCredential;
import com.azure.core.util.polling.SyncPoller;
import com.azure.identity.ClientSecretCredentialBuilder;
import com.azure.identity.DefaultAzureCredentialBuilder;
import com.azure.security.keyvault.secrets.SecretClient;
import com.azure.security.keyvault.secrets.SecretClientBuilder;
import com.azure.security.keyvault.secrets.models.DeletedSecret;
import com.azure.security.keyvault.secrets.models.KeyVaultSecret;
import com.azure.security.keyvault.secrets.models.SecretProperties;
import java.util.regex.Pattern;
import org.apache.logging.log4j.util.Strings;
import org.openmetadata.schema.security.secrets.SecretsManagerProvider;
import org.openmetadata.service.exception.SecretsManagerException;

public class AzureKVSecretsManager extends ExternalSecretsManager {

  private static AzureKVSecretsManager instance = null;
  private SecretClient client;

  public static final String CLIENT_ID = "clientId";
  public static final String CLIENT_SECRET = "clientSecret";
  public static final String TENANT_ID = "tenantId";
  public static final String VAULT_NAME = "vaultName";

  private AzureKVSecretsManager(
      SecretsManagerProvider secretsManagerProvider, SecretsConfig secretsConfig) {
    super(secretsManagerProvider, secretsConfig, 100);

    String vaultName =
        (String) secretsConfig.parameters().getAdditionalProperties().getOrDefault(VAULT_NAME, "");

    if (Strings.isBlank(vaultName)) {
      throw new SecretsManagerException(
          "Using Azure Secrets Manager we found a missing or empty `vaultName` parameter. Review your configuration. ");
    }

    TokenCredential credential = buildAzureCredentials(secretsConfig);

    String vaultUrl = String.format("https://%s.vault.azure.net/", vaultName);
    client = new SecretClientBuilder().vaultUrl(vaultUrl).credential(credential).buildClient();
  }

  /**
   * Build Azure's credentials using Azure Identity
   * We provide authentication either via Default Creds or by specifying the Client Secrets
   * docs
   * If the TENANT_ID is informed, we'll use the ClientSecretCredentialBuilder
   */
  private TokenCredential buildAzureCredentials(SecretsConfig secretsConfig) {
    if (secretsConfig != null
        && secretsConfig.parameters() != null
        && !Strings.isBlank(
            (String)
                secretsConfig.parameters().getAdditionalProperties().getOrDefault(TENANT_ID, ""))) {
      String clientId =
          (String) secretsConfig.parameters().getAdditionalProperties().getOrDefault(CLIENT_ID, "");
      String clientSecret =
          (String)
              secretsConfig.parameters().getAdditionalProperties().getOrDefault(CLIENT_SECRET, "");
      String tenantId =
          (String) secretsConfig.parameters().getAdditionalProperties().getOrDefault(TENANT_ID, "");

      return new ClientSecretCredentialBuilder()
          .clientId(clientId)
          .clientSecret(clientSecret)
          .tenantId(tenantId)
          .build();
    } else {
      return new DefaultAzureCredentialBuilder().build();
    }
  }

  /**
   * Azure Key Vault does not allow the default '/' separator: They can only contain alphanumeric characters and dashes.
   * Azure key vault does not need a prefixed separator.
   */
  @Override
  protected SecretsIdConfig builSecretsIdConfig() {
    return new SecretsIdConfig("-", Boolean.FALSE, "", Pattern.compile("[^A-Za-z0-9\\-]"));
  }

  @Override
  void storeSecret(String secretName, String secretValue) {
    client.setSecret(
        new KeyVaultSecret(secretName, cleanNullOrEmpty(secretValue))
            .setProperties(
                new SecretProperties().setTags(SecretsManager.getTags(getSecretsConfig()))));
  }

  @Override
  void updateSecret(String secretName, String secretValue) {
    // No specific update commands
    storeSecret(secretName, secretValue);
  }

  @Override
  String getSecret(String secretName) {
    return client.getSecret(secretName).getValue();
  }

  @Override
  protected void deleteSecretInternal(String secretName) {
    SyncPoller deletionPoller = client.beginDeleteSecret(secretName);
    deletionPoller.waitForCompletion();
  }

  public static AzureKVSecretsManager getInstance(SecretsConfig secretsConfig) {
    if (instance == null) {
      instance = new AzureKVSecretsManager(SecretsManagerProvider.MANAGED_AZURE_KV, secretsConfig);
    }
    return instance;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy