Skip to content

Commit

Permalink
Remove service credentials from DefaultAzureCredential
Browse files Browse the repository at this point in the history
Resolves Azure#2093
  • Loading branch information
heaths committed Feb 12, 2025
1 parent 1ac0936 commit 1f5fa76
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 144 deletions.
42 changes: 31 additions & 11 deletions sdk/identity/azure_identity/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,47 @@
# 0.20.0 (2024-02)
# Release History

## 0.22.0 (Unreleased)

### Breaking Changes

- Removed service credentials from `DefaultAzureCredential` ([#2093](https://github.com/Azure/azure-sdk-for-rust/issues/2093))

## 0.20.0 (2024-02)

### Breaking Changes

- [#1532](https://github.com/Azure/azure-sdk-for-rust/pull/1532) add `azure_identity::create_credential()`, `SpecificAzureCredential`, `AppServiceManagedIdentityCredential`, `VirtualMachineManagedIdentityCredential`
- BREAKING CHANGE: `DefaultAzureCredentialBuilder::build` now returns a `Result`. If fails when it is unable to create at least one source credential.
- Most credentials may now fail earlier, when they are created, instead of only during `get_token`.
- `DefaultAzureCredential::default()` has been removed, because creating the credential may fail. Please use `azure_identity::create_default_credential()?` or `azure_identity::create_credential()?` instead.
- BREAKING CHANGE: `DefaultAzureCredentialBuilder::build` now returns a `Result`. If fails when it is unable to create at least one source credential.
- Most credentials may now fail earlier, when they are created, instead of only during `get_token`.
- `DefaultAzureCredential::default()` has been removed, because creating the credential may fail. Please use `azure_identity::create_default_credential()?` or `azure_identity::create_credential()?` instead.

## 0.18.0 (2023-12)

# 0.18.0 (2023-12)
### Breaking Changes

- Removed AutoRefreshingTokenCredential, instead all token credentials now implement caching

# 0.3.0 (2022-05)
## 0.3.0 (2022-05)

### Breaking Changes

- [#756](https://github.com/Azure/azure-sdk-for-rust/pull/756) Export credentials from azure_identity
- BREAKING CHANGE: the credential types have moved. For example:
- use `azure_identity::DefaultAzureCredential` instead of `azure_identity::token_credentials::DefaultAzureCredential`
- BREAKING CHANGE: the credential types have moved. For example:
- use `azure_identity::DefaultAzureCredential` instead of `azure_identity::token_credentials::DefaultAzureCredential`

### Bugs Fixed

- [#751](https://github.com/Azure/azure-sdk-for-rust/pull/751) datetime from azure cli token is in the local timezone
- [#748](https://github.com/Azure/azure-sdk-for-rust/pull/748) adding option to specify client_id for MSI

# 0.2.0 (2022-05)
## 0.2.0 (2022-05)

### Other Changes

- update to azure_core 0.2.1

# 0.1.1 (2022-01)
## 0.1.1 (2022-01)

### Features Added

- initial publish to [crates.io](https://crates.io/crates/azure_identity)
- Initial publish to [crates.io](https://crates.io/crates/azure_identity)
139 changes: 6 additions & 133 deletions sdk/identity/azure_identity/src/credentials/default_credentials.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,16 @@

#[cfg(not(target_arch = "wasm32"))]
use crate::AzureCliCredential;
use crate::{
credentials::cache::TokenCache, timeout::TimeoutExt, AppServiceManagedIdentityCredential,
ImdsId, TokenCredentialOptions, VirtualMachineManagedIdentityCredential,
};
use crate::{credentials::cache::TokenCache, TokenCredentialOptions};
use azure_core::{
credentials::{AccessToken, TokenCredential},
error::{Error, ErrorKind, ResultExt},
};
use std::{sync::Arc, time::Duration};
use std::sync::Arc;

/// Provides a mechanism of selectively disabling credentials used for a `DefaultAzureCredential` instance
pub struct DefaultAzureCredentialBuilder {
options: TokenCredentialOptions,
include_app_service_managed_identity_credential: bool,
include_virtual_machine_managed_identity_credential: bool,
#[cfg(not(target_arch = "wasm32"))]
include_azure_cli_credential: bool,
}
Expand All @@ -26,8 +21,6 @@ impl Default for DefaultAzureCredentialBuilder {
fn default() -> Self {
Self {
options: TokenCredentialOptions::default(),
include_app_service_managed_identity_credential: true,
include_virtual_machine_managed_identity_credential: true,
#[cfg(not(target_arch = "wasm32"))]
include_azure_cli_credential: true,
}
Expand All @@ -45,31 +38,6 @@ impl DefaultAzureCredentialBuilder {
self
}

/// Exclude using any managed identity credential
pub fn exclude_managed_identity_credential(&mut self) -> &mut Self {
self.include_app_service_managed_identity_credential = false;
self.include_virtual_machine_managed_identity_credential = false;
self
}

/// Exclude using virtual machine managed identity credential
pub fn exclude_virtual_machine_managed_identity_credential(&mut self) -> &mut Self {
self.include_virtual_machine_managed_identity_credential = false;
self
}

/// Include using virtual machine managed identity credential
pub fn include_virtual_machine_managed_identity_credential(&mut self) -> &mut Self {
self.include_virtual_machine_managed_identity_credential = true;
self
}

/// Include using app service managed identity credential
pub fn include_app_service_managed_identity_credential(&mut self) -> &mut Self {
self.include_app_service_managed_identity_credential = true;
self
}

/// Exclude using credential from the cli
#[cfg(not(target_arch = "wasm32"))]
pub fn exclude_azure_cli_credential(&mut self) -> &mut Self {
Expand All @@ -80,12 +48,6 @@ impl DefaultAzureCredentialBuilder {
/// Get a list of the credential types to include.
fn included(&self) -> Vec<DefaultAzureCredentialType> {
let mut sources = Vec::new();
if self.include_app_service_managed_identity_credential {
sources.push(DefaultAzureCredentialType::AppService);
}
if self.include_virtual_machine_managed_identity_credential {
sources.push(DefaultAzureCredentialType::VirtualMachine);
}
#[cfg(not(target_arch = "wasm32"))]
if self.include_azure_cli_credential {
sources.push(DefaultAzureCredentialType::AzureCli);
Expand All @@ -100,25 +62,9 @@ impl DefaultAzureCredentialBuilder {
included: &Vec<DefaultAzureCredentialType>,
) -> azure_core::Result<Vec<DefaultAzureCredentialKind>> {
let mut sources = Vec::<DefaultAzureCredentialKind>::with_capacity(included.len());
let mut errors = Vec::new();
let errors = Vec::new();
for source in included {
match source {
DefaultAzureCredentialType::AppService => {
match AppServiceManagedIdentityCredential::new(self.options.clone()) {
Ok(credential) => {
sources.push(DefaultAzureCredentialKind::AppService(credential))
}
Err(error) => errors.push(error),
}
}
DefaultAzureCredentialType::VirtualMachine => {
sources.push(DefaultAzureCredentialKind::VirtualMachine(
VirtualMachineManagedIdentityCredential::new(
ImdsId::SystemAssigned,
self.options.clone(),
)?,
));
}
#[cfg(not(target_arch = "wasm32"))]
DefaultAzureCredentialType::AzureCli => {
if let Ok(credential) = AzureCliCredential::new() {
Expand Down Expand Up @@ -149,19 +95,13 @@ impl DefaultAzureCredentialBuilder {
/// Types that may be enabled for use by `DefaultAzureCredential`.
#[derive(Debug, PartialEq)]
enum DefaultAzureCredentialType {
AppService,
VirtualMachine,
#[cfg(not(target_arch = "wasm32"))]
AzureCli,
}

/// Types of `TokenCredential` supported by `DefaultAzureCredential`
#[derive(Debug)]
pub(crate) enum DefaultAzureCredentialKind {
/// `TokenCredential` from managed identity that has been assigned to an App Service.
AppService(Arc<AppServiceManagedIdentityCredential>),
/// `TokenCredential` from managed identity that has been assigned to a virtual machine.
VirtualMachine(Arc<VirtualMachineManagedIdentityCredential>),
#[cfg(not(target_arch = "wasm32"))]
/// `TokenCredential` from Azure CLI.
AzureCli(Arc<AzureCliCredential>),
Expand All @@ -172,27 +112,6 @@ pub(crate) enum DefaultAzureCredentialKind {
impl TokenCredential for DefaultAzureCredentialKind {
async fn get_token(&self, scopes: &[&str]) -> azure_core::Result<AccessToken> {
match self {
DefaultAzureCredentialKind::AppService(credential) => {
credential.get_token(scopes).await.context(
ErrorKind::Credential,
"error getting managed identity credential for App Service",
)
}
DefaultAzureCredentialKind::VirtualMachine(credential) => {
// IMDS timeout is only limited to 1 second when used in DefaultAzureCredential
credential
.get_token(scopes)
.timeout(Duration::from_secs(1))
.await
.context(
ErrorKind::Credential,
"getting virtual machine managed identity credential timed out",
)?
.context(
ErrorKind::Credential,
"error getting virtual machine managed identity credential",
)
}
#[cfg(not(target_arch = "wasm32"))]
DefaultAzureCredentialKind::AzureCli(credential) => {
credential.get_token(scopes).await.context(
Expand All @@ -206,10 +125,6 @@ impl TokenCredential for DefaultAzureCredentialKind {
/// Clear the credential's cache.
async fn clear_cache(&self) -> azure_core::Result<()> {
match self {
DefaultAzureCredentialKind::AppService(credential) => credential.clear_cache().await,
DefaultAzureCredentialKind::VirtualMachine(credential) => {
credential.clear_cache().await
}
#[cfg(not(target_arch = "wasm32"))]
DefaultAzureCredentialKind::AzureCli(credential) => credential.clear_cache().await,
}
Expand Down Expand Up @@ -324,24 +239,17 @@ mod tests {
let builder = DefaultAzureCredentialBuilder::new();
#[cfg(not(target_arch = "wasm32"))]
assert!(builder.include_azure_cli_credential);
assert!(builder.include_app_service_managed_identity_credential);
assert!(builder.include_virtual_machine_managed_identity_credential);

#[cfg(not(target_arch = "wasm32"))]
{
let mut builder = DefaultAzureCredentialBuilder::new();
builder.exclude_azure_cli_credential();
assert!(!builder.include_azure_cli_credential);
assert!(builder.include_app_service_managed_identity_credential);
assert!(builder.include_virtual_machine_managed_identity_credential);
}

let mut builder = DefaultAzureCredentialBuilder::new();
builder.exclude_managed_identity_credential();
let builder = DefaultAzureCredentialBuilder::new();
#[cfg(not(target_arch = "wasm32"))]
assert!(builder.include_azure_cli_credential);
assert!(!builder.include_app_service_managed_identity_credential);
assert!(!builder.include_virtual_machine_managed_identity_credential);
}

#[test]
Expand All @@ -350,25 +258,7 @@ mod tests {
let builder = DefaultAzureCredentialBuilder::new();
assert_eq!(
builder.included(),
vec![
DefaultAzureCredentialType::AppService,
DefaultAzureCredentialType::VirtualMachine,
DefaultAzureCredentialType::AzureCli,
]
);
}

/// test excluding virtual machine managed identity credential
#[test]
fn test_exclude_virtual_machine_managed_identity_credential() {
let mut builder = DefaultAzureCredentialBuilder::new();
builder.exclude_virtual_machine_managed_identity_credential();
assert_eq!(
builder.included(),
vec![
DefaultAzureCredentialType::AppService,
DefaultAzureCredentialType::AzureCli,
]
vec![DefaultAzureCredentialType::AzureCli,]
);
}

Expand All @@ -377,23 +267,6 @@ mod tests {
fn test_exclude_azure_cli_credential() {
let mut builder = DefaultAzureCredentialBuilder::new();
builder.exclude_azure_cli_credential();
assert_eq!(
builder.included(),
vec![
DefaultAzureCredentialType::AppService,
DefaultAzureCredentialType::VirtualMachine,
]
);
}

/// test excluding managed identity credential
#[test]
fn test_exclude_managed_identity_credential() {
let mut builder = DefaultAzureCredentialBuilder::new();
builder.exclude_managed_identity_credential();
assert_eq!(
builder.included(),
vec![DefaultAzureCredentialType::AzureCli,]
);
assert!(builder.included().is_empty());
}
}
2 changes: 2 additions & 0 deletions sdk/identity/azure_identity/src/timeout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub(crate) struct Timeout<F, D> {
}

impl<F, D> Timeout<F, D> {
#[allow(dead_code)]
pub(crate) fn new(future: F, deadline: D) -> Self {
Self {
future,
Expand Down Expand Up @@ -59,6 +60,7 @@ impl<F: Future, D: Future> Future for Timeout<F, D> {
}
}

#[allow(dead_code)]
pub(crate) trait TimeoutExt: Future {
fn timeout(self, duration: Duration) -> Timeout<Self, Sleep>
where
Expand Down

0 comments on commit 1f5fa76

Please sign in to comment.