azure-sdk-for-net icon indicating copy to clipboard operation
azure-sdk-for-net copied to clipboard

[BUG] Cannot re-create a secret in KeyVault even after purging

Open MattW52 opened this issue 2 years ago • 1 comments
trafficstars

Library name and version

Azure.Security.KeyVault.Secrets 4.4.0

Describe the bug

I am trying to delete a secret from KeyVault and replace it with another with the same key.

The KeyVault has Soft-delete enabled and Purge protection disabled.

Despite following the steps outlined at https://learn.microsoft.com/en-us/azure/key-vault/secrets/quick-create-net?tabs=azure-cli#sample-code when I try to create the secret again, an exception is thrown.

Expected behavior

The old secret should be successfully deleted so that a new secret with the same key can be created.

Actual behavior

The following exception is thrown:

Azure.RequestFailedException: Secret mySecret is currently being deleted and cannot be re-created; retry later. Status: 409 (Conflict) ErrorCode: Conflict

Content: {"error":{"code":"Conflict","message":"Secret mySecret is currently being deleted and cannot be re-created; retry later.","innererror":{"code":"ObjectIsBeingDeleted"}}}

Headers: Cache-Control: no-cache Pragma: no-cache x-ms-keyvault-region: uksouth x-ms-client-request-id: 92f45d1f-cfcc-43bc-9367-2e64aba5e1bf x-ms-request-id: 4685a803-62b0-46e0-a35e-3d15712c3d18 x-ms-keyvault-service-version: 1.9.713.1 x-ms-keyvault-network-info: conn_type=Ipv4;addr=90.253.118.37;act_addr_fam=InterNetwork; X-Content-Type-Options: REDACTED Strict-Transport-Security: REDACTED Date: Fri, 17 Feb 2023 10:04:32 GMT Content-Length: 168 Content-Type: application/json; charset=utf-8 Expires: -1

at Azure.Security.KeyVault.KeyVaultPipeline.SendRequestAsync(Request request, CancellationToken cancellationToken) at Azure.Security.KeyVault.KeyVaultPipeline.SendRequestAsync[TContent,TResult](RequestMethod method, TContent content, Func`1 resultFactory, CancellationToken cancellationToken, String[] path) at Azure.Security.KeyVault.Secrets.SecretClient.SetSecretAsync(KeyVaultSecret secret, CancellationToken cancellationToken) at Azure.Security.KeyVault.Secrets.SecretClient.SetSecretAsync(String name, String value, CancellationToken cancellationToken) at key_vault_console_app.Program.Main(String[] args) in C:\Repos\Sandpit\ConsoleApp2\ConsoleApp2\Program.cs:line 45 at key_vault_console_app.Program.<Main>(String[] args)

Reproduction Steps

I have created a console app based on https://learn.microsoft.com/en-us/azure/key-vault/secrets/quick-create-net?tabs=azure-cli#sample-code and added a step to add the secret again:

class Program
{
    static async Task Main(string[] args)
    {
        const string secretName = "mySecret";
        var keyVaultName = "MYKEYVAULTNAME";
        var kvUri = $"https://{keyVaultName}.vault.azure.net";

        var client = new SecretClient(new Uri(kvUri), new DefaultAzureCredential());

        Console.Write("Input the value of your secret > ");
        var secretValue = Console.ReadLine();

        Console.Write($"Creating a secret in {keyVaultName} called '{secretName}' with the value '{secretValue}' ...");
        await client.SetSecretAsync(secretName, secretValue);
        Console.WriteLine(" done.");

        Console.WriteLine("Forgetting your secret.");
        secretValue = string.Empty;
        Console.WriteLine($"Your secret is '{secretValue}'.");

        Console.WriteLine($"Retrieving your secret from {keyVaultName}.");
        var secret = await client.GetSecretAsync(secretName);
        Console.WriteLine($"Your secret is '{secret.Value.Value}'.");

        Console.Write($"Deleting your secret from {keyVaultName} ...");
        DeleteSecretOperation operation = await client.StartDeleteSecretAsync(secretName);
        // You only need to wait for completion if you want to purge or recover the secret.
        await operation.WaitForCompletionAsync();
        Console.WriteLine(" done.");

        Console.Write($"Purging your secret from {keyVaultName} ...");
        await client.PurgeDeletedSecretAsync(secretName);
        Console.WriteLine(" done.");
        
        // Additional step:
        Console.Write($"Creating a secret in {keyVaultName} called '{secretName}' with the value '{secretValue}' ...");
        await client.SetSecretAsync(secretName, secretValue);
        Console.WriteLine(" done.");
    }
}

Environment

No response

MattW52 avatar Feb 17 '23 11:02 MattW52

Thank you for your feedback. Tagging and routing to the team member best able to assist.

jsquire avatar Feb 17 '23 14:02 jsquire

Thanks for the feedback! We are routing this to the appropriate team for follow-up. cc @RandalliLama, @schaabs, @jlichwa.

Issue Details

Library name and version

Azure.Security.KeyVault.Secrets 4.4.0

Describe the bug

I am trying to delete a secret from KeyVault and replace it with another with the same key.

The KeyVault has Soft-delete enabled and Purge protection disabled.

Despite following the steps outlined at https://learn.microsoft.com/en-us/azure/key-vault/secrets/quick-create-net?tabs=azure-cli#sample-code when I try to create the secret again, an exception is thrown.

Expected behavior

The old secret should be successfully deleted so that a new secret with the same key can be created.

Actual behavior

The following exception is thrown:

Azure.RequestFailedException: Secret mySecret is currently being deleted and cannot be re-created; retry later. Status: 409 (Conflict) ErrorCode: Conflict

Content: {"error":{"code":"Conflict","message":"Secret mySecret is currently being deleted and cannot be re-created; retry later.","innererror":{"code":"ObjectIsBeingDeleted"}}}

Headers: Cache-Control: no-cache Pragma: no-cache x-ms-keyvault-region: uksouth x-ms-client-request-id: 92f45d1f-cfcc-43bc-9367-2e64aba5e1bf x-ms-request-id: 4685a803-62b0-46e0-a35e-3d15712c3d18 x-ms-keyvault-service-version: 1.9.713.1 x-ms-keyvault-network-info: conn_type=Ipv4;addr=90.253.118.37;act_addr_fam=InterNetwork; X-Content-Type-Options: REDACTED Strict-Transport-Security: REDACTED Date: Fri, 17 Feb 2023 10:04:32 GMT Content-Length: 168 Content-Type: application/json; charset=utf-8 Expires: -1

at Azure.Security.KeyVault.KeyVaultPipeline.SendRequestAsync(Request request, CancellationToken cancellationToken) at Azure.Security.KeyVault.KeyVaultPipeline.SendRequestAsync[TContent,TResult](RequestMethod method, TContent content, Func`1 resultFactory, CancellationToken cancellationToken, String[] path) at Azure.Security.KeyVault.Secrets.SecretClient.SetSecretAsync(KeyVaultSecret secret, CancellationToken cancellationToken) at Azure.Security.KeyVault.Secrets.SecretClient.SetSecretAsync(String name, String value, CancellationToken cancellationToken) at key_vault_console_app.Program.Main(String[] args) in C:\Repos\Sandpit\ConsoleApp2\ConsoleApp2\Program.cs:line 45 at key_vault_console_app.Program.<Main>(String[] args)

Reproduction Steps

I have created a console app based on https://learn.microsoft.com/en-us/azure/key-vault/secrets/quick-create-net?tabs=azure-cli#sample-code and added a step to add the secret again:

class Program
{
    static async Task Main(string[] args)
    {
        const string secretName = "mySecret";
        var keyVaultName = "MYKEYVAULTNAME";
        var kvUri = $"https://{keyVaultName}.vault.azure.net";

        var client = new SecretClient(new Uri(kvUri), new DefaultAzureCredential());

        Console.Write("Input the value of your secret > ");
        var secretValue = Console.ReadLine();

        Console.Write($"Creating a secret in {keyVaultName} called '{secretName}' with the value '{secretValue}' ...");
        await client.SetSecretAsync(secretName, secretValue);
        Console.WriteLine(" done.");

        Console.WriteLine("Forgetting your secret.");
        secretValue = string.Empty;
        Console.WriteLine($"Your secret is '{secretValue}'.");

        Console.WriteLine($"Retrieving your secret from {keyVaultName}.");
        var secret = await client.GetSecretAsync(secretName);
        Console.WriteLine($"Your secret is '{secret.Value.Value}'.");

        Console.Write($"Deleting your secret from {keyVaultName} ...");
        DeleteSecretOperation operation = await client.StartDeleteSecretAsync(secretName);
        // You only need to wait for completion if you want to purge or recover the secret.
        await operation.WaitForCompletionAsync();
        Console.WriteLine(" done.");

        Console.Write($"Purging your secret from {keyVaultName} ...");
        await client.PurgeDeletedSecretAsync(secretName);
        Console.WriteLine(" done.");
        
        // Additional step:
        Console.Write($"Creating a secret in {keyVaultName} called '{secretName}' with the value '{secretValue}' ...");
        await client.SetSecretAsync(secretName, secretValue);
        Console.WriteLine(" done.");
    }
}

Environment

No response

Author: MattW52
Assignees: heaths
Labels:

KeyVault, Service Attention, customer-reported, question, needs-team-attention, Service

Milestone: -

ghost avatar Feb 21 '23 19:02 ghost

Unfortunately, purging does take time and there's no way to poll for it like we do for deletions or recovery. This is a service limitation. @jlichwa for feedback. Is this something the service team might consider a change to?

@MattW52 alternatively, you can loop trying to create the key until it works, but can I ask why you're trying to purge a secret when creating a new one? You can create a new version just by calling SetSecret again. This way, old secrets are kept in case they are ever needed e.g., compare with possibly leaked credentials, make sure you don't reuse a past secret, etc.

heaths avatar Feb 21 '23 19:02 heaths

We integrate with 3rd party systems on-behalf of our Customers and use Key Vault to store config. Some of those 3rd parties require us to delete that config should the Customer decide to revoke our access. Some actually require us to demonstrate this behaviour before they will allow us to access live data.

Key Vault seemed like a good fit, I just need to get the purging to work.

Thanks.

MattW52 avatar Feb 22 '23 14:02 MattW52

Purging does work, though. You just can't expect to turn around and create a new key/secret/cert for ~30s in many cases. That seems like an impractical scenario. There is, unfortunately, no wait to monitor when a purge is complete. See #6514 from years back where this was discussed with the service team.

heaths avatar Feb 22 '23 17:02 heaths

It is async operation without ability to monitor completion. 30seconds sleep should be enough for demonstration purposes. It is not possible to introduce without changing service behavior, which would be a breaking change.

Key Vault Team

jlichwa avatar Feb 22 '23 18:02 jlichwa

Ok, thanks. I really meant "wait for the purging to work" rather than "get the purging to work".

MattW52 avatar Feb 22 '23 18:02 MattW52