Skip to content

Commit 3f0789e

Browse files
Update AzureKeyVault to use modern KeyVault SDK. (#88)
1 parent 8caed88 commit 3f0789e

5 files changed

Lines changed: 81 additions & 102 deletions

File tree

samples/SampleWebApp/SampleWebApp.csproj

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,8 @@
5656
<PackageReference Include="Azure.Identity">
5757
<Version>1.0.0</Version>
5858
</PackageReference>
59-
<PackageReference Include="Microsoft.Azure.KeyVault">
60-
<Version>2.3.2</Version>
61-
</PackageReference>
62-
<PackageReference Include="Microsoft.Azure.Services.AppAuthentication">
63-
<Version>1.0.1</Version>
64-
</PackageReference>
65-
<PackageReference Include="Microsoft.IdentityModel.Clients.ActiveDirectory">
66-
<Version>3.19.2</Version>
59+
<PackageReference Include="Azure.Security.KeyVault.Secrets">
60+
<Version>4.0.0</Version>
6761
</PackageReference>
6862
<PackageReference Include="Newtonsoft.Json">
6963
<Version>11.0.1</Version>

samples/SampleWebApp/Web.config

Lines changed: 38 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
<add name="KeyPerFile" directoryPath="~/../KeyPerFileSampleRoot" mode="Strict" keyDelimiter="--" type="Microsoft.Configuration.ConfigurationBuilders.KeyPerFileConfigBuilder, Microsoft.Configuration.ConfigurationBuilders.KeyPerFile, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
4646

4747
<add name="KV1" vaultName="${ConfigBuilderTestKeyVaultName}" type="Microsoft.Configuration.ConfigurationBuilders.AzureKeyVaultConfigBuilder, Microsoft.Configuration.ConfigurationBuilders.Azure, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
48-
<add name="KV2" vaultName="${ConfigBuilderTestKeyVaultName}" version="d14197de791c4ffe8e79bc7fc0f766b0" type="Microsoft.Configuration.ConfigurationBuilders.AzureKeyVaultConfigBuilder, Microsoft.Configuration.ConfigurationBuilders.Azure, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
48+
<add name="KV2" vaultName="${ConfigBuilderTestKeyVaultName}" preloadSecretNames="false" version="d14197de791c4ffe8e79bc7fc0f766b0" type="Microsoft.Configuration.ConfigurationBuilders.AzureKeyVaultConfigBuilder, Microsoft.Configuration.ConfigurationBuilders.Azure, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
4949
<add name="KV3" vaultName="${ConfigBuilderTestKeyVaultName}" mode="Greedy" type="Microsoft.Configuration.ConfigurationBuilders.AzureKeyVaultConfigBuilder, Microsoft.Configuration.ConfigurationBuilders.Azure, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
5050
<add name="KV4" vaultName="${ConfigBuilderTestKeyVaultName}" mode="Greedy" version="0de51928e49144ce86eb1de9056ac937" type="Microsoft.Configuration.ConfigurationBuilders.AzureKeyVaultConfigBuilder, Microsoft.Configuration.ConfigurationBuilders.Azure, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
5151

@@ -59,7 +59,7 @@
5959
</builders>
6060
</configBuilders>
6161

62-
<appSettings configBuilders="Environment,Secrets,Json,KeyPerFile">
62+
<appSettings configBuilders="Environment,Secrets,Json,KeyPerFile,KV1,KV2,KV3,KV4">
6363
<add key="app~Settings_Colon-and$friends@super+duper,awesome#cool:Test." value="true"/>
6464
<add key="WINDIR" value="Will be replaced by 'Environment' in Strict and Greedy modes."/>
6565
<add key="SYSTEMDRIVE" value="Will initally be replaced by 'Environment' in Strict and Greedy modes... but then superceded by 'Secrets' in the same modes."/>
@@ -114,8 +114,15 @@
114114
<httpRuntime targetFramework="4.7.1"/>
115115
</system.web>
116116

117-
<runtime>
118-
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
117+
<system.codedom>
118+
<compilers>
119+
<compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /nowarn:1659;1699;1701"/>
120+
<compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+"/>
121+
</compilers>
122+
</system.codedom>
123+
124+
<runtime>
125+
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
119126
<dependentAssembly>
120127
<assemblyIdentity name="System.Xml.XPath.XDocument" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
121128
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0"/>
@@ -165,47 +172,33 @@
165172
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0"/>
166173
</dependentAssembly>
167174
<dependentAssembly>
168-
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral"/>
169-
<bindingRedirect oldVersion="0.0.0.0-11.0.0.0" newVersion="11.0.0.0"/>
170-
</dependentAssembly>
171-
<dependentAssembly>
172-
<assemblyIdentity name="Microsoft.IdentityModel.Clients.ActiveDirectory" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
173-
<bindingRedirect oldVersion="0.0.0.0-3.19.2.6005" newVersion="3.19.2.6005"/>
174-
</dependentAssembly>
175-
<dependentAssembly>
176-
<assemblyIdentity name="Microsoft.IdentityModel.Clients.ActiveDirectory.Platform" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
177-
<bindingRedirect oldVersion="0.0.0.0-3.19.2.6005" newVersion="3.19.2.6005"/>
178-
</dependentAssembly>
179-
<dependentAssembly>
180-
<assemblyIdentity name="Azure.Core" publicKeyToken="92742159e12e44c8" culture="neutral"/>
181-
<bindingRedirect oldVersion="0.0.0.0-1.0.1.0" newVersion="1.0.1.0"/>
182-
</dependentAssembly>
183-
<dependentAssembly>
184-
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
185-
<bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1"/>
186-
</dependentAssembly>
187-
<dependentAssembly>
188-
<assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
189-
<bindingRedirect oldVersion="0.0.0.0-4.1.4.0" newVersion="4.1.4.0"/>
190-
</dependentAssembly>
191-
<dependentAssembly>
192-
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
193-
<bindingRedirect oldVersion="0.0.0.0-4.0.5.0" newVersion="4.0.5.0"/>
194-
</dependentAssembly>
195-
<dependentAssembly>
196-
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
175+
<assemblyIdentity name="System.ValueTuple" publicKeyToken="CC7B13FFCD2DDD51" culture="neutral"/>
197176
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0"/>
198177
</dependentAssembly>
199-
<dependentAssembly>
200-
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
201-
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0"/>
202-
</dependentAssembly>
203-
</assemblyBinding>
204-
</runtime>
205-
<system.codedom>
206-
<compilers>
207-
<compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /nowarn:1659;1699;1701"/>
208-
<compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+"/>
209-
</compilers>
210-
</system.codedom>
178+
<dependentAssembly>
179+
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral"/>
180+
<bindingRedirect oldVersion="0.0.0.0-11.0.0.0" newVersion="11.0.0.0"/>
181+
</dependentAssembly>
182+
<dependentAssembly>
183+
<assemblyIdentity name="Azure.Core" publicKeyToken="92742159e12e44c8" culture="neutral"/>
184+
<bindingRedirect oldVersion="0.0.0.0-1.0.1.0" newVersion="1.0.1.0"/>
185+
</dependentAssembly>
186+
<dependentAssembly>
187+
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
188+
<bindingRedirect oldVersion="0.0.0.0-4.0.5.0" newVersion="4.0.5.0"/>
189+
</dependentAssembly>
190+
<dependentAssembly>
191+
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
192+
<bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1"/>
193+
</dependentAssembly>
194+
<dependentAssembly>
195+
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
196+
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0"/>
197+
</dependentAssembly>
198+
<dependentAssembly>
199+
<assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
200+
<bindingRedirect oldVersion="0.0.0.0-4.1.4.0" newVersion="4.1.4.0"/>
201+
</dependentAssembly>
202+
</assemblyBinding>
203+
</runtime>
211204
</configuration>

src/Azure/Azure.csproj

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
<ItemGroup>
4141
<Reference Include="System" />
4242
<Reference Include="System.Configuration" />
43-
<Reference Include="System.Net.Http" />
4443
</ItemGroup>
4544
<ItemGroup>
4645
<Compile Include="AzureKeyVaultConfigBuilder.cs" />
@@ -53,14 +52,11 @@
5352
</ProjectReference>
5453
</ItemGroup>
5554
<ItemGroup>
56-
<PackageReference Include="Microsoft.Azure.KeyVault">
57-
<Version>2.3.2</Version>
55+
<PackageReference Include="Azure.Identity">
56+
<Version>1.0.0</Version>
5857
</PackageReference>
59-
<PackageReference Include="Microsoft.Azure.Services.AppAuthentication">
60-
<Version>1.0.1</Version>
61-
</PackageReference>
62-
<PackageReference Include="Microsoft.IdentityModel.Clients.ActiveDirectory">
63-
<Version>3.19.2</Version>
58+
<PackageReference Include="Azure.Security.KeyVault.Secrets">
59+
<Version>4.0.0</Version>
6460
</PackageReference>
6561
</ItemGroup>
6662
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

src/Azure/AzureKeyVaultConfigBuilder.cs

Lines changed: 35 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
using System.Text.RegularExpressions;
1010
using System.Threading.Tasks;
1111

12-
using Microsoft.Azure.KeyVault;
13-
using Microsoft.Azure.KeyVault.Models;
14-
using Microsoft.Azure.Services.AppAuthentication;
12+
using Azure;
13+
using Azure.Identity;
14+
using Azure.Security.KeyVault.Secrets;
1515

1616
namespace Microsoft.Configuration.ConfigurationBuilders
1717
{
@@ -35,7 +35,7 @@ public class AzureKeyVaultConfigBuilder : KeyValueConfigBuilder
3535
private bool _preload;
3636
private bool _preloadFailed;
3737

38-
private KeyVaultClient _kvClient;
38+
private SecretClient _kvClient;
3939
private List<string> _allKeys;
4040

4141
/// <summary>
@@ -58,6 +58,8 @@ protected override void LazyInitialize(string name, NameValueCollection config)
5858
_uri = UpdateConfigSettingWithAppSettings(uriTag);
5959
_vaultName = UpdateConfigSettingWithAppSettings(vaultNameTag);
6060
_version = UpdateConfigSettingWithAppSettings(versionTag);
61+
if (String.IsNullOrWhiteSpace(_version))
62+
_version = null;
6163

6264
if (String.IsNullOrWhiteSpace(_uri))
6365
{
@@ -83,8 +85,7 @@ protected override void LazyInitialize(string name, NameValueCollection config)
8385
// Connect to KeyVault
8486
try
8587
{
86-
AzureServiceTokenProvider tokenProvider = new AzureServiceTokenProvider(_connectionString);
87-
_kvClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(tokenProvider.KeyVaultTokenCallback));
88+
_kvClient = new SecretClient(new Uri(_uri), new DefaultAzureCredential());
8889
}
8990
catch (Exception)
9091
{
@@ -130,10 +131,10 @@ public override ICollection<KeyValuePair<string, string>> GetAllValues(string pr
130131
{
131132
// Azure Key Vault keys are case-insensitive, so there shouldn't be any races here.
132133
// Include version information. It will get filtered out later before updating config.
133-
SecretBundle secret = t.Result;
134+
KeyVaultSecret secret = t.Result;
134135
if (secret != null)
135136
{
136-
string versionedKey = key + "/" + (secret.SecretIdentifier.Version ?? "0");
137+
string versionedKey = key + "/" + (secret.Properties?.Version ?? "0");
137138
d[versionedKey] = secret.Value;
138139
}
139140
})));
@@ -184,31 +185,36 @@ public override string UpdateKey(string rawKey)
184185
return new VersionedKey(rawKey).Key;
185186
}
186187

187-
private async Task<SecretBundle> GetValueAsync(string key)
188+
private async Task<KeyVaultSecret> GetValueAsync(string key)
188189
{
189190
if (_kvClient == null)
190191
return null;
191192

192193
VersionedKey vKey = new VersionedKey(key);
193194

195+
// If we successfully preloaded key names, see if the requested key is valid before making network request.
194196
if (!_preload || _preloadFailed || _allKeys.Contains(vKey.Key, StringComparer.OrdinalIgnoreCase))
195197
{
196198
try
197199
{
198-
string version = !String.IsNullOrWhiteSpace(_version) ? _version : vKey.Version;
200+
string version = _version ?? vKey.Version;
199201
if (version != null)
200202
{
201-
SecretBundle versionedSecret = await _kvClient.GetSecretAsync(_uri, vKey.Key, version);
203+
KeyVaultSecret versionedSecret = await _kvClient.GetSecretAsync(vKey.Key, version);
202204
return versionedSecret;
203205
}
204206

205-
SecretBundle secret = await _kvClient.GetSecretAsync(_uri, vKey.Key);
207+
KeyVaultSecret secret = await _kvClient.GetSecretAsync(vKey.Key);
206208
return secret;
207209
}
208-
catch (KeyVaultErrorException kve)
210+
catch (RequestFailedException rfex)
209211
{
210212
// Simply return null if the secret wasn't found
211-
if (kve.Body.Error.Code == "SecretNotFound" || kve.Body.Error.Code == "BadParameter")
213+
//if (rfex.ErrorCode == "SecretNotFound" || rfex.ErrorCode == "BadParameter")
214+
// .ErrorCode doesn't get populated. :/
215+
// "SecretNotFound" == 404
216+
// "BadParameter" = 400
217+
if (rfex.Status == 404 || rfex.Status == 400)
212218
return null;
213219

214220
// If there was a permission issue or some other error, let the exception bubble
@@ -230,35 +236,25 @@ private List<string> GetAllKeys()
230236

231237
try
232238
{
233-
// Get first page of secret keys
234-
var allSecrets = Task.Run(async () => { return await _kvClient.GetSecretsAsync(_uri); }).Result;
235-
foreach (var secretItem in allSecrets)
236-
keys.Add(secretItem.Identifier.Name);
237-
238-
// If there more more pages, get those too
239-
string nextPage = allSecrets.NextPageLink;
240-
while (!String.IsNullOrWhiteSpace(nextPage))
239+
foreach (SecretProperties secretProps in _kvClient.GetPropertiesOfSecrets())
241240
{
242-
var moreSecrets = Task.Run(async () => { return await _kvClient.GetSecretsNextAsync(nextPage); }).Result;
243-
foreach (var secretItem in moreSecrets)
244-
keys.Add(secretItem.Identifier.Name);
245-
nextPage = moreSecrets.NextPageLink;
241+
// Don't include disabled secrets
242+
if (!secretProps.Enabled.GetValueOrDefault())
243+
continue;
244+
245+
keys.Add(secretProps.Name);
246246
}
247247
}
248-
catch (AggregateException ae)
248+
catch (RequestFailedException rfex)
249249
{
250-
ae.Handle(ex =>
251-
{
252-
var exAsKve = ex as KeyVaultErrorException;
253-
// If List Permission on Secrets in not available return empty list of keys
254-
if (exAsKve != null && exAsKve.Body.Error.Code == "Forbidden")
255-
{
256-
_preloadFailed = true;
257-
return true;
258-
}
259-
else
260-
return Optional; // False == throw.
261-
});
250+
_preloadFailed = true;
251+
252+
// If List Permission on Secrets in not available return empty list of keys
253+
if (rfex.ErrorCode == "Forbidden")
254+
return keys;
255+
256+
if (!Optional)
257+
throw;
262258
}
263259

264260
return keys;

src/packages/ConfigurationBuilders.Azure.nupkg/Microsoft.Configuration.ConfigurationBuilders.Azure.nuspec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818

1919
<dependencies>
2020
<dependency id="Microsoft.Configuration.ConfigurationBuilders.Base" version="$NuGetPackageBaseDependencyVersion$" />
21-
<dependency id="Microsoft.Azure.KeyVault" version="2.3.2" />
22-
<dependency id="Microsoft.Azure.Services.AppAuthentication" version="1.0.1" />
21+
<dependency id="Azure.Security.KeyVault.Secrets" version="4.0.0" />
22+
<dependency id="Azure.Identity" version="1.0.0" />
2323
</dependencies>
2424
</metadata>
2525
</package>

0 commit comments

Comments
 (0)