#secret #azure #azure-sdk #security #sdk #keyvault #microsoft-azure

azure_security_keyvault_secrets

Rust wrappers around Microsoft Azure REST APIs - Azure KeyVault Secrets

1 unstable release

new 0.1.0 Feb 19, 2025

#1245 in Network programming


Used in akv-cli

MIT license

345KB
6.5K SLoC

Azure Key Vault secrets client library for Rust

Azure Key Vault is a cloud service that provides a secure storage of secrets, such as passwords and database connection strings.

The Azure Key Vault secrets client library allows you to securely store and control the access to tokens, passwords, API keys, and other secrets. This library offers operations to create, retrieve, update, delete, purge, backup, restore, and list the secrets and its versions.

Source code | Package (crates.io) | API reference documentation | Product documentation

Getting started

Install the package

Install the Azure Key Vault secrets client library for Rust with Cargo:

cargo add azure_security_keyvault_secrets

Prerequisites

  • An Azure subscription.
  • An existing Azure Key Vault. If you need to create an Azure Key Vault, you can use the Azure Portal or Azure CLI.
  • Authorization to an existing Azure Key Vault using either RBAC (recommended) or access control.

If you use the Azure CLI, replace <your-resource-group-name> and <your-key-vault-name> with your own, unique names:

az keyvault create --resource-group <your-resource-group-name> --name <your-key-vault-name>

Install dependencies

Add the following crates to your project:

cargo add azure_identity tokio

Authenticate the client

In order to interact with the Azure Key Vault service, you'll need to create an instance of the SecretClient. You need a vault url, which you may see as "DNS Name" in the portal, and credentials to instantiate a client object.

The example shown below use a DefaultAzureCredential, which is appropriate for most local development environments. Additionally, we recommend using a managed identity for authentication in production environments. You can find more information on different ways of authenticating and their corresponding credential types in the Azure Identity documentation.

The DefaultAzureCredential will automatically pick up on an Azure CLI authentication. Ensure you are logged in with the Azure CLI:

az login

Instantiate a DefaultAzureCredential to pass to the client. The same instance of a token credential can be used with multiple clients if they will be authenticating with the same identity.

Set and Get a Secret

use azure_identity::DefaultAzureCredential;
use azure_security_keyvault_secrets::{
    models::{SecretBundle, SecretSetParameters},
    ResourceExt, SecretClient,
};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create a new secret client
    let credential = DefaultAzureCredential::new()?;
    let client = SecretClient::new(
        "https://your-key-vault-name.vault.azure.net/",
        credential.clone(),
        None,
    )?;

    // Create a new secret using the secret client.
    let secret_set_parameters = SecretSetParameters {
        value: Some("secret-value".into()),
        ..Default::default()
    };

    let secret: SecretBundle = client
        .set_secret("secret-name", secret_set_parameters.try_into()?, None)
        .await?
        .into_body()
        .await?;

    // Get version of created secret.
    let version = secret.resource_id()?.version.unwrap_or_default();

    // Retrieve a secret using the secret client.
    let secret: SecretBundle = client
        .get_secret("secret-name", version.as_ref(), None)
        .await?
        .into_body()
        .await?;
    println!("{:?}", secret.value);

    Ok(())
}

Key concepts

SecretBundle

A SecretBundle is the fundamental resource within Azure Key Vault. From a developer's perspective, Azure Key Vault APIs accept and return secret values as strings.

SecretClient

The SecretClient provides asynchronous operations for working with Key Vault secrets.

Thread safety

We guarantee that all client instance methods are thread-safe and independent of each other. This ensures that the recommendation of reusing client instances is always safe, even across threads.

Examples

The following section provides several code snippets using the SecretClient, covering some of the most common Azure Key Vault secrets service related tasks:

Create a secret

set_secret creates a Key Vault secret to be stored in the Azure Key Vault. If a secret with the same name already exists, then a new version of the secret is created.

use azure_identity::DefaultAzureCredential;
use azure_security_keyvault_secrets::{models::SecretSetParameters, ResourceExt, SecretClient};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let credential = DefaultAzureCredential::new()?;
    let client = SecretClient::new(
        "https://your-key-vault-name.vault.azure.net/",
        credential.clone(),
        None,
    )?;

    // Create a new secret using the secret client.
    let secret_set_parameters = SecretSetParameters {
        value: Some("secret-value".into()),
        ..Default::default()
    };

    let secret = client
        .set_secret("secret-name", secret_set_parameters.try_into()?, None)
        .await?
        .into_body()
        .await?;

    println!(
        "Secret Name: {:?}, Value: {:?}, Version: {:?}",
        secret.resource_id()?.name,
        secret.value,
        secret.resource_id()?.version
    );

    Ok(())
}

Retrieve a secret

get_secret retrieves a secret previously stored in the Azure Key Vault. Setting the secret-version to an empty string will return the latest version.

use azure_identity::DefaultAzureCredential;
use azure_security_keyvault_secrets::SecretClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let credential = DefaultAzureCredential::new()?;
    let client = SecretClient::new(
        "https://your-key-vault-name.vault.azure.net/",
        credential.clone(),
        None,
    )?;

    // Retrieve a secret using the secret client.
    let secret = client
        .get_secret("secret-name", "secret-version", None)
        .await?
        .into_body()
        .await?;

    println!("Secret Value: {:?}", secret.value);

    Ok(())
}

Update an existing secret

update_secret updates a secret previously stored in the Azure Key Vault. Only the attributes of the secret are updated. To update the value, call SecretClient::set_secret on a secret with the same name.

use azure_identity::DefaultAzureCredential;
use azure_security_keyvault_secrets::{models::SecretUpdateParameters, SecretClient};
use std::collections::HashMap;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let credential = DefaultAzureCredential::new()?;
    let client = SecretClient::new(
        "https://your-key-vault-name.vault.azure.net/",
        credential.clone(),
        None,
    )?;

    // Update a secret using the secret client.
    let secret_update_parameters = SecretUpdateParameters {
        content_type: Some("text/plain".into()),
        tags: Some(HashMap::from_iter(vec![(
            "tag-name".into(),
            "tag-value".into(),
        )])),
        ..Default::default()
    };

    client
        .update_secret(
            "secret-name",
            "",
            secret_update_parameters.try_into()?,
            None,
        )
        .await?
        .into_body()
        .await?;

    Ok(())
}

Delete a secret

delete_secret will tell Key Vault to delete a secret but it is not deleted immediately. It will not be deleted until the service-configured data retention period - the default is 90 days - or until you call purge_secret on the returned DeletedSecretBundle.id.

use azure_identity::DefaultAzureCredential;
use azure_security_keyvault_secrets::SecretClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let credential = DefaultAzureCredential::new()?;
    let client = SecretClient::new(
        "https://your-key-vault-name.vault.azure.net/",
        credential.clone(),
        None,
    )?;

    // Delete a secret using the secret client.
    client.delete_secret("secret-name", None).await?;

    Ok(())
}

List secrets

This example lists all the secrets in the specified Azure Key Vault. The value is not returned when listing all secrets. You will need to call SecretClient::get_secret to retrieve the value.

use azure_identity::DefaultAzureCredential;
use azure_security_keyvault_secrets::{ResourceExt, SecretClient};
use futures::TryStreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create a new secret client
    let credential = DefaultAzureCredential::new()?;
    let client = SecretClient::new(
        "https://your-key-vault-name.vault.azure.net/",
        credential.clone(),
        None,
    )?;

    let mut pager = client.get_secrets(None)?.into_stream();
    while let Some(secrets) = pager.try_next().await? {
        let Some(secrets) = secrets.into_body().await?.value else {
            continue;
        };

        for secret in secrets {
            // Get the secret name from the ID.
            let name = secret.resource_id()?.name;
            println!("Found Secret with Name: {}", name);
        }
    }

    Ok(())
}

Troubleshooting

General

When you interact with the Azure Key Vault secrets client library using the Rust SDK, errors returned by the service correspond to the same HTTP status codes returned for REST API requests.

For example, if you try to retrieve a secret that doesn't exist in your Azure Key Vault, a 404 error is returned, indicating Not Found.

use azure_identity::DefaultAzureCredential;
use azure_security_keyvault_secrets::SecretClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let credential = DefaultAzureCredential::new()?;
    let client = SecretClient::new(
        "https://ronnieg-keyvault.vault.azure.net/",
        credential.clone(),
        None,
    )?;

    match client.get_secret("secret-name", "", None).await {
        Ok(response) => println!("Secret Value: {:?}", response.into_body().await?.value),
        Err(err) => println!("Error: {:#?}", err.into_inner()?),
    }

    Ok(())
}

You will notice that additional information is logged, like the Client Request ID of the operation.

Error: HttpError {
    status: NotFound,
    details: ErrorDetails {
        code: Some(
            "SecretNotFound",
        ),
        message: Some(
            "A secret with (name/id) secret-name1 was not found in this key vault. If you recently deleted this secret you may be able to recover it using the correct recovery command. For help resolving this issue, please see https://go.microsoft.com/fwlink/?linkid=2125182",
        ),
    },
    ..
}

Contributing

See the CONTRIBUTING.md for details on building, testing, and contributing to these libraries.

This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://opensource.microsoft.com/cla/.

When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.

Dependencies

~14–26MB
~383K SLoC