Created
October 18, 2019 09:16
-
-
Save JosXa/2e1925c58077fe97871bb56697128355 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Security.Cryptography.X509Certificates; | |
using System.Text; | |
using System.Text.RegularExpressions; | |
using System.Threading.Tasks; | |
using JetBrains.Annotations; | |
using Microsoft.Azure.Services.AppAuthentication; | |
using Microsoft.Azure.KeyVault; | |
namespace MyNamespace | |
{ | |
public enum CertificateType | |
{ | |
Pkcs12, | |
Pem | |
} | |
/// <summary> | |
/// Loosely based on https://github.com/Azure/azure-functions-host/issues/3907#issuecomment-473105492 | |
/// </summary> | |
public class KeyVaultReferenceSecretRetriever | |
{ | |
private static readonly bool isLocalEnvironment = | |
string.IsNullOrEmpty(Environment.GetEnvironmentVariable("WEBSITE_INSTANCE_ID")); | |
public async Task<string> RetrieveConfigValue(string settingName) | |
{ | |
if (isLocalEnvironment) | |
{ | |
var referenceString = Environment.GetEnvironmentVariable(settingName); | |
if (referenceString == null) | |
{ | |
throw new ArgumentException($"Setting for {settingName} could not be found."); | |
} | |
if (!referenceString.StartsWith("@")) | |
{ | |
throw new ArgumentException( | |
$"Can only work with key vault references, but this isn't one: {referenceString}", | |
nameof(settingName)); | |
} | |
// TODO: maybe there is a builtin somewhere that will parse these references for us... | |
var match = Regex.Match(referenceString, @"@Microsoft\.KeyVault\(SecretUri=(.*)\)"); | |
var configValue = match.Groups[1].Value; | |
AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider(); | |
KeyVaultClient keyVaultClient = new KeyVaultClient( | |
new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback)); | |
var secret = await keyVaultClient.GetSecretAsync(configValue).ConfigureAwait(false); | |
return secret.Value; | |
} | |
return Environment.GetEnvironmentVariable(settingName); | |
} | |
[ItemNotNull] | |
public async Task<X509Certificate> RetrieveCertificate(string settingName, CertificateType type) | |
{ | |
string certificateAsString = await RetrieveConfigValue(settingName); | |
switch (type) | |
{ | |
case CertificateType.Pem: | |
byte[] certBuffer = GetBytesFromPEM(certificateAsString, "CERTIFICATE"); | |
return new X509Certificate2(certBuffer); | |
case CertificateType.Pkcs12: | |
// TODO: so far untested | |
return new X509Certificate(Encoding.ASCII.GetBytes(certificateAsString)); | |
default: | |
throw new ArgumentException($"Unknown {nameof(CertificateType)}."); | |
} | |
} | |
byte[] GetBytesFromPEM(string pemString, string section) | |
{ | |
var header = $"-----BEGIN {section}-----"; | |
var footer = $"-----END {section}-----"; | |
var start = pemString.IndexOf(header, StringComparison.Ordinal); | |
if (start < 0) | |
return null; | |
start += header.Length; | |
var end = pemString.IndexOf(footer, start, StringComparison.Ordinal) - start; | |
if (end < 0) | |
return null; | |
return Convert.FromBase64String(pemString.Substring(start, end)); | |
} | |
} | |
} |
@avitryhard Hmm this is all I have right now. Do you have any concrete questions?
I have one case as bellow:
I'm using EF core code first. While I'm updating database by using termimal in my computer (dotnet ef database update). I want to get connection string from keyvault.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi JosXa, can you give me an example to implemented? Thanks