Skip to content

Commit db70b74

Browse files
committed
Geometric key size progression during snapshotting. Fixes #3034.
1 parent e9b8168 commit db70b74

File tree

2 files changed

+53
-14
lines changed

2 files changed

+53
-14
lines changed

src/WebJobs.Script.WebHost/Security/KeyManagement/SecretManager.cs

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ public async virtual Task<HostSecretsInfo> GetHostSecretsAsync()
9393
{
9494
_logger?.LogDebug(Resources.TraceNonDecryptedHostSecretRefresh);
9595
await PersistSecretsAsync(hostSecrets, null, true);
96+
hostSecrets = GenerateHostSecrets(hostSecrets);
9697
await RefreshSecretsAsync(hostSecrets);
9798
}
9899

@@ -139,13 +140,7 @@ public async virtual Task<IDictionary<string, string>> GetFunctionSecretsAsync(s
139140
// no secrets exist for this function so generate them
140141
string message = string.Format(Resources.TraceFunctionSecretGeneration, functionName);
141142
_logger.LogDebug(message);
142-
secrets = new FunctionSecrets
143-
{
144-
Keys = new List<Key>
145-
{
146-
GenerateKey(ScriptConstants.DefaultFunctionKeyName)
147-
}
148-
};
143+
secrets = GenerateFunctionSecrets();
149144

150145
await PersistSecretsAsync(secrets, functionName);
151146
}
@@ -160,6 +155,7 @@ public async virtual Task<IDictionary<string, string>> GetFunctionSecretsAsync(s
160155
string message = string.Format(Resources.TraceNonDecryptedFunctionSecretRefresh, functionName);
161156
_logger?.LogDebug(message);
162157
await PersistSecretsAsync(secrets, functionName, true);
158+
secrets = GenerateFunctionSecrets(secrets);
163159
await RefreshSecretsAsync(secrets, functionName);
164160
}
165161

@@ -378,13 +374,53 @@ private HostSecrets GenerateHostSecrets()
378374
{
379375
MasterKey = GenerateKey(ScriptConstants.DefaultMasterKeyName),
380376
FunctionKeys = new List<Key>
377+
{
378+
GenerateKey(ScriptConstants.DefaultFunctionKeyName)
379+
},
380+
SystemKeys = new List<Key>()
381+
};
382+
}
383+
384+
private HostSecrets GenerateHostSecrets(HostSecrets secrets)
385+
{
386+
if (secrets.MasterKey.IsEncrypted)
387+
{
388+
secrets.MasterKey.Value = GenerateSecret();
389+
}
390+
secrets.SystemKeys = RegenerateList(secrets.SystemKeys);
391+
secrets.FunctionKeys = RegenerateList(secrets.FunctionKeys);
392+
return secrets;
393+
}
394+
395+
private FunctionSecrets GenerateFunctionSecrets()
396+
{
397+
return new FunctionSecrets
398+
{
399+
Keys = new List<Key>
381400
{
382401
GenerateKey(ScriptConstants.DefaultFunctionKeyName)
383-
},
384-
SystemKeys = new List<Key>()
402+
}
385403
};
386404
}
387405

406+
private FunctionSecrets GenerateFunctionSecrets(FunctionSecrets secrets)
407+
{
408+
secrets.Keys = RegenerateList(secrets.Keys);
409+
return secrets;
410+
}
411+
412+
private IList<Key> RegenerateList(IList<Key> list)
413+
{
414+
return list.Select(k =>
415+
{
416+
if (k.IsEncrypted)
417+
{
418+
k.Value = GenerateSecret();
419+
}
420+
return k;
421+
}).ToList();
422+
}
423+
388424
private Task RefreshSecretsAsync<T>(T secrets, string keyScope = null) where T : ScriptSecrets
389425
{
390426
var refreshedSecrets = secrets.Refresh(_keyValueConverterFactory);

test/WebJobs.Script.Tests/Security/SecretManagerTests.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -496,9 +496,9 @@ public async Task GetHostSecrets_WhenNonDecryptedHostSecrets_SavesAndRefreshes()
496496
}
497497

498498
Assert.NotNull(hostSecrets);
499-
Assert.Equal(hostSecrets.MasterKey, "cryptoError");
499+
Assert.NotEqual(hostSecrets.MasterKey, "cryptoError");
500500
var result = JsonConvert.DeserializeObject<HostSecrets>(File.ReadAllText(Path.Combine(directory.Path, ScriptConstants.HostMetadataFileName)));
501-
Assert.Equal(result.MasterKey.Value, "!cryptoError");
501+
Assert.Equal(result.MasterKey.Value, "!" + hostSecrets.MasterKey);
502502
Assert.Equal(1, Directory.GetFiles(directory.Path, $"host.{ScriptConstants.Snapshot}*").Length);
503503
}
504504
}
@@ -536,9 +536,9 @@ public async Task GetFunctiontSecrets_WhenNonDecryptedSecrets_SavesAndRefreshes(
536536
}
537537

538538
Assert.NotNull(functionSecrets);
539-
Assert.Equal(functionSecrets["Key1"], "cryptoError");
539+
Assert.NotEqual(functionSecrets["Key1"], "cryptoError");
540540
var result = JsonConvert.DeserializeObject<FunctionSecrets>(File.ReadAllText(Path.Combine(directory.Path, functionName + ".json")));
541-
Assert.Equal(result.GetFunctionKey("Key1", functionName).Value, "!cryptoError");
541+
Assert.Equal(result.GetFunctionKey("Key1", functionName).Value, "!" + functionSecrets["Key1"]);
542542
Assert.Equal(1, Directory.GetFiles(directory.Path, $"{functionName}.{ScriptConstants.Snapshot}*").Length);
543543
}
544544
}
@@ -755,7 +755,10 @@ private Mock<IKeyValueConverterFactory> GetConverterFactoryMock(bool simulateWri
755755

756756
var mockValueWriter = new Mock<IKeyValueWriter>();
757757
mockValueWriter.Setup(r => r.WriteValue(It.IsAny<Key>()))
758-
.Returns<Key>(k => new Key(k.Name, simulateWriteConversion ? "!" + k.Value : k.Value) { IsEncrypted = simulateWriteConversion });
758+
.Returns<Key>(k =>
759+
{
760+
return new Key(k.Name, simulateWriteConversion ? "!" + k.Value : k.Value) { IsEncrypted = simulateWriteConversion };
761+
});
759762

760763
var mockValueConverterFactory = new Mock<IKeyValueConverterFactory>();
761764
mockValueConverterFactory.Setup(f => f.GetValueReader(It.IsAny<Key>()))

0 commit comments

Comments
 (0)