public async Task <IChallengeResponder> ParseChallengeResponderAsync(CertificateRenewalOptions cfg, CancellationToken cancellationToken)
        {
            var certStore = ParseCertificateStore(cfg);
            var target    = ParseTargetResource(cfg);
            var cr        = cfg.ChallengeResponder ?? new GenericEntry
            {
                Type       = "storageAccount",
                Properties = JObject.FromObject(new StorageProperties
                {
                    AccountName  = ConvertToValidStorageAccountName(target.Name),
                    KeyVaultName = certStore.Name
                })
            };

            switch (cr.Type.ToLowerInvariant())
            {
            case "storageaccount":
                var props = cr.Properties?.ToObject <StorageProperties>() ?? new StorageProperties
                {
                    KeyVaultName = cr.Name,
                    AccountName  = ConvertToValidStorageAccountName(cr.Name)
                };

                // try MSI first, must do check if we can read to know if we have access
                var accountName = props.AccountName;
                if (string.IsNullOrEmpty(accountName))
                {
                    accountName = ConvertToValidStorageAccountName(target.Name);
                }

                var storage = await _storageFactory.FromMsiAsync(accountName, props.ContainerName, cancellationToken);

                // verify that MSI access works, fallback otherwise
                // not ideal since it's a readonly check
                // -> we need Blob Contributor for challenge persist but user could set Blob Reader and this check would pass
                // alternative: write + delete a file from container as a check
                try
                {
                    await storage.ExistsAsync(FileNameForPermissionCheck, cancellationToken);
                }
                catch (RequestFailedException e) when(e.Status == (int)HttpStatusCode.Forbidden)
                {
                    _logger.LogWarning($"MSI access to storage {accountName} failed. Attempting fallbacks via connection string. (You can ignore this warning if you don't use MSI authentication).");
                    var connectionString = props.ConnectionString;

                    if (string.IsNullOrEmpty(connectionString))
                    {
                        // falback to secret in keyvault
                        var keyVaultName = props.KeyVaultName;
                        if (string.IsNullOrEmpty(keyVaultName))
                        {
                            keyVaultName = certStore.Name;
                        }

                        _logger.LogInformation($"No connection string in config, checking keyvault {keyVaultName} for secret {props.SecretName}");
                        try
                        {
                            connectionString = await GetSecretAsync(keyVaultName, props.SecretName, cancellationToken);
                        }
                        catch (Exception ex)
                        {
                            throw new AggregateException($"Failed to get connectionstring in secret {props.SecretName} from keyvault {keyVaultName}. If you intended to use storage MSI access, set \"Storage Blob Data Contributor\" on the respective storage container (permissions might take more than 10 minutes to take effect)", new[] { ex });
                        }
                    }
                    if (string.IsNullOrEmpty(connectionString))
                    {
                        throw new InvalidOperationException($"MSI access failed for {accountName} and could not find fallback connection string for storage access. Unable to proceed with Let's encrypt challenge");
                    }

                    storage = _storageFactory.FromConnectionString(connectionString, props.ContainerName);
                }
                return(new AzureStorageHttpChallengeResponder(storage, props.Path));

            default:
                throw new NotImplementedException(cr.Type);
            }
        }