Azure KeyVault soft delete problem with Pulumi
Published: 2021-11-24 10:45:20

When you're creating a Pulumi stack, you want to regularly do `pulumi up` and `pulumi destroy`. Azure KeyVault's introduce a unique problem with this, they get 'soft' deleted, which causes this problem when you `pulumi up` after a `pulumi destroy`:

> An existing soft-deleted Key Vault exists with the Name "my-keyvault-name" in the location "southeastasia", however automatically recovering this KeyVault has been disabled via the "features" block.

You can manually purge the KeyVault from the Azure portal ![Manage deleted vaults](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i6qvzqj98x0z8by562s9.png)
but who wants to do that!

The error says that recovery was disabled...but I hadn't disabled anything. I was further confused because in the [docs](https://www.pulumi.com/registry/packages/azure/api-docs/keyvault/keyvault/) it says
> Note: This provider will automatically recover a soft-deleted Key Vault during Creation if one is found - you can opt out of this using the features configuration within the Provider configuration block.

It wasn't recovering so this note seems wrong. So given I should be able to 'opt out', I figured maybe I could opt in instead! This proved harder than expected, I found the property I needed to set in the excellent [docs](https://www.pulumi.com/registry/packages/azure/api-docs/provider/#providerfeatureskeyvault) - either `RecoverSoftDeletedKeyVaults` or `PurgeSoftDeleteOnDestroy`, but just how to set them eluded me (there may have been some swear words involved at this point).

After getting some help from the cool guru guy that put me onto Pulumi we managed to figure it out. So, if you have code like this to create your KeyVault:
`var keyVaultSoftDeleted = new KeyVault(keyVaultName, new KeyVaultArgs(){ /* set usual required properties */ });`

Change it to pass in a custom provider like this:
```
        var customProviderArgs = new AzureClassic.ProviderArgs()
        {
            Features = new ProviderFeaturesArgs()
            {
                KeyVault = new ProviderFeaturesKeyVaultArgs()
                {
                    // RecoverSoftDeletedKeyVaults = true,
                    PurgeSoftDeleteOnDestroy = true
                }
            }
        };

        var provider = new Pulumi.Azure.Provider("myprovider", customProviderArgs);
        stackConfig.KeyVault = new Pulumi.Azure.KeyVault.KeyVault(keyVaultName, new KeyVaultArgs() { /* set usual required properties */ }, 
            new CustomResourceOptions() { Provider = provider });
```

RecoverSoftDeletedKeyVaults is commented out because I tried that and got this error when testing up -> destroy -> up:
> Code="ConflictError" Message="A conflict occurred that prevented the operation from completing. The operation failed because the Key Vault 'my-keyvault-name' changed from the point the operation began. This can happen if parallel operations are being performed on the Key Vault.

So I **guess** the recover was attempted but Pulumi doesn't wait for it to complete.

Using PurgeSoftDeleteOnDestroy did exactly what I needed. After the destroy I double checked in deleted vaults and it definitely wasn't there, so my following `pulumi up` worked without issue.