Skip to content

feat(azurebackup): Add security configure-encryption command for CMK#2609

Open
shrja-ms wants to merge 1 commit intomicrosoft:mainfrom
shrja-ms:user/azurebackup-cmk-encryption
Open

feat(azurebackup): Add security configure-encryption command for CMK#2609
shrja-ms wants to merge 1 commit intomicrosoft:mainfrom
shrja-ms:user/azurebackup-cmk-encryption

Conversation

@shrja-ms
Copy link
Copy Markdown
Contributor

@shrja-ms shrja-ms commented May 8, 2026

Summary

Adds azurebackup security configure-encryption command that configures Customer-Managed Key (CMK) encryption on both Recovery Services vaults (RSV) and Backup vaults (DPP) using a key from Azure Key Vault.

Changes

New Command: azurebackup security configure-encryption

Usage:

azmcp azurebackup security configure-encryption \
  --subscription <subscription> \
  --resource-group <resource-group> \
  --vault <vault> \
  --key-vault-uri <key-vault-uri> \
  --key-name <key-name> \
  --identity-type <SystemAssigned|UserAssigned> \
  [--vault-type <rsv|dpp>] \
  [--key-version <key-version>] \
  [--user-assigned-identity-id <arm-id>]

Features:

  • Supports both RSV and DPP vault types with auto-detection
  • SystemAssigned and UserAssigned managed identity types
  • Optional --key-version to pin a specific key version (omit for latest/autorotation)
  • --user-assigned-identity-id required when --identity-type is UserAssigned
  • ARM ID validation on --user-assigned-identity-id
  • URI validation on --key-vault-uri
  • Uses [CommandMetadata] attribute pattern
  • Telemetry tags via AzureBackupTelemetryTags.AddVaultTags
  • ValidateSubscriptionFormat in RSV path (consistent with other RSV operations)
  • Comprehensive error handling for 400/403/404/409 status codes with actionable messages

RSV Implementation: Uses VaultPropertiesEncryption with CmkKekIdentity on RecoveryServicesVaultPatch. Note: For RSV, CMK can only be enabled on new vaults with no registered items (enforced by Azure API, documented in 400 error message).

DPP Implementation: Uses BackupVaultEncryptionSettings via BackupVaultSecuritySettings on DataProtectionBackupVaultPatch. DPP supports CMK before or after protecting items.

Files Changed (16 files, ~851 lines)

Category Files
Command SecurityConfigureEncryptionCommand.cs (new), SecurityConfigureEncryptionOptions.cs (new)
Options AzureBackupOptionDefinitions.cs (+4 const names, +4 Option fields: key-vault-uri, key-name, key-version, user-assigned-identity-id)
Service IAzureBackupService.cs, AzureBackupService.cs (routing), IRsvBackupOperations.cs, RsvBackupOperations.cs, IDppBackupOperations.cs, DppBackupOperations.cs
Registration AzureBackupSetup.cs (DI + command group), AzureBackupJsonContext.cs (AOT)
Unit Tests SecurityConfigureEncryptionCommandTests.cs - 23 tests
Live Tests AzureBackupCommandTests.cs - 2 [LiveTestOnly] tests (RSV + DPP SystemAssigned)
Documentation azmcp-commands.md, e2eTestPrompts.md (3 prompts), changelog YAML

Validation

Check Result
dotnet build 0 errors, 0 warnings
Unit tests 412/412 passed (23 new CMK + 389 existing)
Live tests build Succeeds
dotnet format --verify-no-changes Clean
ToolDescriptionEvaluator All 3 prompts rank #1 (confidence: 0.70, 0.77, 0.60)
Commands metadata Regenerated via Update-AzCommandsMetadata.ps1
Changelog entry servers/Azure.Mcp.Server/changelog-entries/1778209045130.yaml

Design Decisions

  1. No hardcoded InfrastructureEncryption - omitted from the patch so the vault existing infrastructure encryption state is preserved. Users can configure this separately during vault creation.
  2. Validation at command layer only - identity type and user-assigned-identity-id validation is done in RegisterOptions validators, not duplicated in service layer.
  3. DPP support included - Research confirmed Backup vaults support CMK via BackupVaultEncryptionSettings on the vault patch SecuritySettings (per Azure docs).

Invoking Livetests

Copilot submitted PRs are not trustworthy by default. Users with write access to the repo need to validate the contents of this PR before leaving a comment with the text /azp run mcp - pullrequest - live. This will trigger the necessary livetest workflows to complete required validation.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Azure Backup security command to configure Customer-Managed Key (CMK) encryption for both Recovery Services vaults (RSV) and Backup vaults (DPP), wiring it through the AzureBackup service layer, registering it in DI/command groups, and updating docs/tests for coverage.

Changes:

  • Introduces azurebackup security configure-encryption command + options binding/validation and AOT JSON source-gen registration.
  • Adds CMK encryption implementation paths for RSV and DPP vaults, plus service-layer routing with vault-type auto-detection.
  • Expands unit tests, live tests, command docs, e2e prompts, and server changelog entry.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tools/Azure.Mcp.Tools.AzureBackup/src/Commands/Security/SecurityConfigureEncryptionCommand.cs New command implementation, option registration/validation, error/status mapping, telemetry tagging.
tools/Azure.Mcp.Tools.AzureBackup/src/Options/Security/SecurityConfigureEncryptionOptions.cs New options model for CMK parameters (KV URI/name/version, identity settings).
tools/Azure.Mcp.Tools.AzureBackup/src/Options/AzureBackupOptionDefinitions.cs Adds new CMK-related CLI options (key vault URI/name/version, user-assigned identity id).
tools/Azure.Mcp.Tools.AzureBackup/src/Services/IAzureBackupService.cs Adds ConfigureEncryptionAsync API surface.
tools/Azure.Mcp.Tools.AzureBackup/src/Services/AzureBackupService.cs Routes configure-encryption to RSV vs DPP based on resolved vault type.
tools/Azure.Mcp.Tools.AzureBackup/src/Services/IRsvBackupOperations.cs Adds RSV operations contract for CMK configuration.
tools/Azure.Mcp.Tools.AzureBackup/src/Services/RsvBackupOperations.cs Implements RSV CMK patch operation using vault encryption properties.
tools/Azure.Mcp.Tools.AzureBackup/src/Services/IDppBackupOperations.cs Adds DPP operations contract for CMK configuration.
tools/Azure.Mcp.Tools.AzureBackup/src/Services/DppBackupOperations.cs Implements DPP CMK patch operation using backup vault security/encryption settings.
tools/Azure.Mcp.Tools.AzureBackup/src/Commands/AzureBackupJsonContext.cs Registers new command result for System.Text.Json source generation (AOT).
tools/Azure.Mcp.Tools.AzureBackup/src/AzureBackupSetup.cs Registers the new command in DI and adds it under the security command group.
tools/Azure.Mcp.Tools.AzureBackup/tests/Azure.Mcp.Tools.AzureBackup.UnitTests/Security/SecurityConfigureEncryptionCommandTests.cs Adds unit tests for option validation and response/error behaviors.
tools/Azure.Mcp.Tools.AzureBackup/tests/Azure.Mcp.Tools.AzureBackup.LiveTests/AzureBackupCommandTests.cs Adds LiveTestOnly end-to-end tests for RSV/DPP system-assigned identity paths.
servers/Azure.Mcp.Server/docs/azmcp-commands.md Documents the new command and its arguments.
servers/Azure.Mcp.Server/docs/e2eTestPrompts.md Adds prompts for tool-description evaluation/e2e prompt coverage.
servers/Azure.Mcp.Server/changelog-entries/1778209045130.yaml Adds changelog entry under “Features Added”.

Comment on lines +1104 to +1126
var normalizedIdentity = identityType.ToUpperInvariant();

// Build the full key URI: {keyVaultUri}/keys/{keyName}[/{keyVersion}]
var kvUri = keyVaultUri.TrimEnd('/');
var keyUriString = string.IsNullOrEmpty(keyVersion)
? $"{kvUri}/keys/{keyName}"
: $"{kvUri}/keys/{keyName}/{keyVersion}";

var armClient = await CreateArmClientAsync(tenant, retryPolicy, cancellationToken: cancellationToken);
var vaultId = RecoveryServicesVaultResource.CreateResourceIdentifier(subscription, resourceGroup, vaultName);
var vaultResource = armClient.GetRecoveryServicesVaultResource(vaultId);
var vault = await vaultResource.GetAsync(cancellationToken);

var kekIdentity = new CmkKekIdentity();
if (normalizedIdentity == "SYSTEMASSIGNED")
{
kekIdentity.UseSystemAssignedIdentity = true;
}
else
{
kekIdentity.UseSystemAssignedIdentity = false;
kekIdentity.UserAssignedIdentity = new ResourceIdentifier(userAssignedIdentityId!);
}
Comment on lines +906 to +924
var normalizedIdentity = identityType.ToUpperInvariant();

// Build the full key URI: {keyVaultUri}/keys/{keyName}[/{keyVersion}]
var kvUri = keyVaultUri.TrimEnd('/');
var keyUriString = string.IsNullOrEmpty(keyVersion)
? $"{kvUri}/keys/{keyName}"
: $"{kvUri}/keys/{keyName}/{keyVersion}";

var armClient = await CreateArmClientAsync(tenant, retryPolicy, cancellationToken: cancellationToken);
var vaultId = DataProtectionBackupVaultResource.CreateResourceIdentifier(subscription, resourceGroup, vaultName);
var vaultResource = armClient.GetDataProtectionBackupVaultResource(vaultId);

var kekIdentity = new BackupVaultCmkKekIdentity
{
IdentityType = normalizedIdentity == "SYSTEMASSIGNED"
? BackupVaultCmkKekIdentityType.SystemAssigned
: BackupVaultCmkKekIdentityType.UserAssigned,
IdentityId = normalizedIdentity == "USERASSIGNED" ? userAssignedIdentityId : null
};
Comment on lines +73 to +79
!Uri.TryCreate(keyVaultUri, UriKind.Absolute, out var uri))
{
commandResult.AddError("--key-vault-uri must be a valid URI (e.g., 'https://kv-name.vault.azure.net/').");
}
});
}

Adds azurebackup security configure-encryption command that enables
Customer-Managed Key (CMK) encryption on both Recovery Services vaults
(RSV) and Backup vaults (DPP) using a key from Azure Key Vault.

- Supports SystemAssigned and UserAssigned managed identity types
- Validates Key Vault URI, key name, and identity parameters
- ARM ID validation on user-assigned identity
- Supports both RSV and DPP vault types with auto-detection
- Uses [CommandMetadata] attribute pattern
- Does not hardcode InfrastructureEncryption (left unchanged)
- Includes 23 unit tests and 1 live test
@shrja-ms shrja-ms force-pushed the user/azurebackup-cmk-encryption branch from 3849e33 to 570e56d Compare May 8, 2026 05:20
Copy link
Copy Markdown
Contributor

@jongio jongio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RSV's ConfigureEncryptionAsync doesn't validate identityType at the service level, unlike DPP's version which validates at lines 907-917. The command-layer validator catches invalid inputs today, but these service methods are interface entry points - adding matching validation keeps them defensively consistent. One inline comment.

CI failures (4 build jobs) are infrastructure - 1ES Pipeline Templates credential provider 401s to the NuGet feed, not caused by this PR.

(nameof(identityType), identityType));
ValidateSubscriptionFormat(subscription);

var normalizedIdentity = identityType.ToUpperInvariant();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DppBackupOperations.ConfigureEncryptionAsync validates identity type and userAssignedIdentityId at the service level (lines 907-917 in that file). This RSV version skips that validation and falls into the else branch for any non-"SYSTEMASSIGNED" value, hitting userAssignedIdentityId! without a null check.

The command validator handles this today, but since both methods sit behind service interfaces, they should validate their own inputs. Consider adding the same guard after normalizedIdentity:

if (normalizedIdentity != "SYSTEMASSIGNED" && normalizedIdentity != "USERASSIGNED")
{
    throw new ArgumentException(
        $"Invalid identity type '{identityType}' for CMK encryption. Supported values: 'SystemAssigned', 'UserAssigned'.");
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Untriaged

Development

Successfully merging this pull request may close these issues.

3 participants