Skip to content

Commit 08a2485

Browse files
Use Microsoft.Security.Utilities.Core package for the 'new' secret masker (#5169)
When a new feature flag `DistributedTask.Agent.EnableNewMaskerAndRegexes` is enabled, a new corresponding agent knob `AZP_ENABLE_NEW_MASKER_AND_REGEXES` is turned on, we replace the use of `Microsoft.TeamFoundation.DistributedTask.Logging.SecretMasker` with `Microsoft.Security.Utilities.SecurityMasker` from the https://www.nuget.org/packages/Microsoft.Security.Utilities.Core package and https://github.com/microsoft/security-utilities repo. This flag also enables the package's `WellKnownRegexPatterns.PreciselyClassifiedSecurityKeys` regex patterns. This class of pattern has high confidence, effectively admitting no false positives. It is also strongly oriented on detecting the latest Azure provider API key formats. The new knob/flag pair replaces `DistributedTask.Agent.UseMaskingPerformanceEnhancements`/`AZP_ENABLE_NEW_SECRET_MASKER`, which would use a built-in `SecretMasker` that was implemented in this repo, along with a subset of the aforementioned `PreciselyClassifiedSecurityKeys` patterns also re-implemented in this repo. That code is therefore deleted in this change. Note that in the absence of feature flags, the default behavior remains unchanged. Benchmarking shows masking with the new feature enabled outperforming masking with it disabled even though the new feature also brings the added value of 30 additional patterns. Co-authored-by: Michael C. Fanning <[email protected]>
1 parent 140a3e2 commit 08a2485

31 files changed

+542
-1303
lines changed

src/Agent.Listener/JobDispatcher.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -398,11 +398,11 @@ private async Task RunAsync(Pipelines.AgentJobRequestMessage message, WorkerDisp
398398
{
399399

400400
var featureFlagProvider = HostContext.GetService<IFeatureFlagProvider>();
401-
var newSecretMaskerFeaturFlagStatus = await featureFlagProvider.GetFeatureFlagAsync(HostContext, "DistributedTask.Agent.UseMaskingPerformanceEnhancements", Trace);
401+
var newMaskerAndRegexesFeatureFlagStatus = await featureFlagProvider.GetFeatureFlagAsync(HostContext, "DistributedTask.Agent.EnableNewMaskerAndRegexes", Trace);
402402
var environment = new Dictionary<string, string>();
403-
if (newSecretMaskerFeaturFlagStatus?.EffectiveState == "On")
403+
if (newMaskerAndRegexesFeatureFlagStatus?.EffectiveState == "On")
404404
{
405-
environment.Add("AZP_ENABLE_NEW_SECRET_MASKER", "true");
405+
environment.Add("AZP_ENABLE_NEW_MASKER_AND_REGEXES", "true");
406406
}
407407
// Start the process channel.
408408
// It's OK if StartServer bubbles an execption after the worker process has already started.

src/Agent.Sdk/Agent.Sdk.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
</PropertyGroup>
88

99
<ItemGroup>
10+
<PackageReference Include="Microsoft.Security.Utilities.Core" Version="1.17.0" />
1011
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
1112
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="6.0.0-preview.5.21301.5" />
1213
<PackageReference Include="System.Management" Version="4.7.0" />

src/Agent.Sdk/Knob/AgentKnobs.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -675,10 +675,10 @@ public class AgentKnobs
675675
new PipelineFeatureSource("UseNode20ToStartContainer"),
676676
new BuiltInDefaultKnobSource("false"));
677677

678-
public static readonly Knob EnableNewSecretMasker = new Knob(
679-
nameof(EnableNewSecretMasker),
678+
public static readonly Knob EnableNewMaskerAndRegexes = new Knob(
679+
nameof(EnableNewMaskerAndRegexes),
680680
"If true, the agent will use new SecretMasker with additional filters & performance enhancements",
681-
new EnvironmentKnobSource("AZP_ENABLE_NEW_SECRET_MASKER"),
681+
new EnvironmentKnobSource("AZP_ENABLE_NEW_MASKER_AND_REGEXES"),
682682
new BuiltInDefaultKnobSource("false"));
683683

684684
public static readonly Knob AddDockerInitOption = new Knob(

src/Agent.Sdk/SecretMasking/ILoggedSecretMasker.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
3-
//using Microsoft.TeamFoundation.DistributedTask.Logging;
4-
using ValueEncoder = Microsoft.TeamFoundation.DistributedTask.Logging.ValueEncoder;
3+
54
using System;
65

6+
using Microsoft.TeamFoundation.DistributedTask.Logging;
7+
78
namespace Agent.Sdk.SecretMasking
89
{
910
/// <summary>
10-
/// Extended ISecretMasker interface that is adding support of logging secret masker methods
11+
/// Extended ISecretMasker interface that adds support for logging the origin of
12+
/// regexes, encoders and literal secret values.
1113
/// </summary>
12-
public interface ILoggedSecretMasker : ISecretMasker
14+
public interface ILoggedSecretMasker : ISecretMasker, IDisposable
1315
{
1416
static int MinSecretLengthLimit { get; }
1517

src/Agent.Sdk/SecretMasking/ISecret.cs

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/Agent.Sdk/SecretMasking/ISecretMasker.cs

Lines changed: 0 additions & 23 deletions
This file was deleted.

src/Agent.Sdk/SecretMasking/LegacyLoggedSecretMasker.cs

Lines changed: 0 additions & 141 deletions
This file was deleted.

src/Agent.Sdk/SecretMasking/LoggedSecretMasker.cs

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,19 @@
22
// Copyright (c) Microsoft Corporation.
33
// Licensed under the MIT License.
44
using System;
5-
using ValueEncoder = Microsoft.TeamFoundation.DistributedTask.Logging.ValueEncoder;
6-
using ISecretMaskerVSO = Microsoft.TeamFoundation.DistributedTask.Logging.ISecretMasker;
5+
6+
using Microsoft.TeamFoundation.DistributedTask.Logging;
77

88
namespace Agent.Sdk.SecretMasking
99
{
1010
/// <summary>
11-
/// Extended secret masker service, that allows to log origins of secrets
11+
/// Extended secret masker service that allows specifying the origin of any
12+
/// masking operation. It works by wrapping an existing ISecretMasker
13+
/// implementation and an optionally settable ITraceWriter instance for
14+
/// secret origin logging operations. In the agent today, this class can be
15+
/// initialized with two distinct ISecretMasker implementations, the one
16+
/// that ships in VSO itself, and the official Microsoft open source secret
17+
/// masker, implemented at https://github/microsoft/security-utilities.
1218
/// </summary>
1319
public class LoggedSecretMasker : ILoggedSecretMasker
1420
{
@@ -43,6 +49,7 @@ public void AddValue(string pattern)
4349
/// <param name="origin">Origin of the secret</param>
4450
public void AddValue(string value, string origin)
4551
{
52+
// WARNING: Do not log the value here, it is a secret!
4653
this.Trace($"Setting up value for origin: {origin}");
4754
if (value == null)
4855
{
@@ -64,6 +71,7 @@ public void AddRegex(string pattern)
6471
/// <param name="origin"></param>
6572
public void AddRegex(string pattern, string origin)
6673
{
74+
// WARNING: Do not log the pattern here, it could be very specifc and contain a secret!
6775
this.Trace($"Setting up regex for origin: {origin}.");
6876
if (pattern == null)
6977
{
@@ -117,7 +125,6 @@ public void AddValueEncoder(ValueEncoder encoder)
117125
public void AddValueEncoder(ValueEncoder encoder, string origin)
118126
{
119127
this.Trace($"Setting up value for origin: {origin}");
120-
this.Trace($"Length: {encoder.ToString().Length}.");
121128
if (encoder == null)
122129
{
123130
this.Trace($"Encoder is empty.");
@@ -127,7 +134,7 @@ public void AddValueEncoder(ValueEncoder encoder, string origin)
127134
AddValueEncoder(encoder);
128135
}
129136

130-
public ISecretMasker Clone()
137+
public LoggedSecretMasker Clone()
131138
{
132139
return new LoggedSecretMasker(this._secretMasker.Clone());
133140
}
@@ -137,6 +144,24 @@ public string MaskSecrets(string input)
137144
return this._secretMasker.MaskSecrets(input);
138145
}
139146

140-
ISecretMaskerVSO ISecretMaskerVSO.Clone() => this.Clone();
147+
ISecretMasker ISecretMasker.Clone() => this.Clone();
148+
149+
public void Dispose()
150+
{
151+
Dispose(true);
152+
GC.SuppressFinalize(this);
153+
}
154+
155+
protected virtual void Dispose(bool disposing)
156+
{
157+
if (disposing)
158+
{
159+
if (_secretMasker is IDisposable disposable)
160+
{
161+
disposable.Dispose();
162+
}
163+
_secretMasker = null;
164+
}
165+
}
141166
}
142167
}

0 commit comments

Comments
 (0)