in src/WebJobs.Script.WebHost/Security/KeyManagement/SecretManager.cs [83:163]
public async virtual Task<HostSecretsInfo> GetHostSecretsAsync()
{
if (_hostSecrets == null)
{
using (_metricsLogger.LatencyEvent(GetMetricEventName(MetricEventNames.SecretManagerGetHostSecrets)))
{
await _hostSecretsLock.WaitAsync();
HostSecrets hostSecrets;
try
{
_logger.LogDebug("Loading host secrets");
hostSecrets = await LoadSecretsAsync<HostSecrets>();
try
{
if (hostSecrets == null)
{
// host secrets do not yet exist so generate them
_logger.LogDebug(Resources.TraceHostSecretGeneration);
hostSecrets = GenerateHostSecrets();
await PersistSecretsAsync(hostSecrets);
}
}
catch (Exception ex)
{
_logger.LogDebug(ex, "Exception while generating host secrets. This can happen if another instance is also generating secrets. Attempting to read secrets again.");
hostSecrets = await LoadSecretsAsync<HostSecrets>();
if (hostSecrets == null)
{
_logger.LogError("Host secrets are still null on second attempt.");
throw;
}
}
try
{
// Host secrets will be in the original persisted state at this point (e.g. encrypted),
// so we read the secrets running them through the appropriate readers
hostSecrets = ReadHostSecrets(hostSecrets);
}
catch (CryptographicException ex) when (!ex.InnerException.IsFatal())
{
string message = string.Format(Resources.TraceNonDecryptedHostSecretRefresh, ex);
_logger.LogDebug(message);
await PersistSecretsAsync(hostSecrets, null, true);
hostSecrets = GenerateHostSecrets(hostSecrets);
await RefreshSecretsAsync(hostSecrets);
}
// If the persistence state of any of our secrets is stale (e.g. the encryption key has been rotated), update
// the state and persist the secrets
if (hostSecrets.HasStaleKeys)
{
_logger.LogDebug(Resources.TraceStaleHostSecretRefresh);
await RefreshSecretsAsync(hostSecrets);
}
// before caching any secrets, validate them
string masterKeyValue = hostSecrets.MasterKey.Value;
var functionKeys = hostSecrets.FunctionKeys.ToDictionary(p => p.Name, p => p.Value);
var systemKeys = hostSecrets.SystemKeys.ToDictionary(p => p.Name, p => p.Value);
ValidateHostSecrets(masterKeyValue, functionKeys, systemKeys);
_hostSecrets = new HostSecretsInfo
{
MasterKey = masterKeyValue,
FunctionKeys = functionKeys,
SystemKeys = systemKeys
};
}
finally
{
_hostSecretsLock.Release();
}
}
}
return _hostSecrets;
}