From 562796f3afeb0708599c2ac513054047f1c1f649 Mon Sep 17 00:00:00 2001 From: Phil Schneider Date: Wed, 11 Oct 2023 14:21:50 +0200 Subject: [PATCH] chore: mask sensitive log data (#290) * chore: mask sensitive log data Refs: CPLP-3255 --------- Co-authored-by: Norbert Truchsess Reviewed-by: Norbert Truchsess --- DEPENDENCIES | 1 + src/Portal.Backend.sln | 15 ++++ .../Framework.Logging.csproj | 85 ++++++++++--------- .../Framework.Logging/LoggingExtensions.cs | 14 +++ .../MaskingOperator/SecretOperator.cs | 37 ++++++++ .../Framework.Logging.Tests.csproj | 48 +++++++++++ .../SecretOperatorTests.cs | 46 ++++++++++ .../Framework.Logging.Tests/Usings.cs | 24 ++++++ 8 files changed, 228 insertions(+), 42 deletions(-) create mode 100644 src/framework/Framework.Logging/MaskingOperator/SecretOperator.cs create mode 100644 tests/framework/Framework.Logging.Tests/Framework.Logging.Tests.csproj create mode 100644 tests/framework/Framework.Logging.Tests/SecretOperatorTests.cs create mode 100644 tests/framework/Framework.Logging.Tests/Usings.cs diff --git a/DEPENDENCIES b/DEPENDENCIES index 2586121a24..ee9e80d8a6 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -35,6 +35,7 @@ nuget/nuget/-/Serilog.AspNetCore/7.0.0, Apache-2.0 AND MIT, approved, #10084 nuget/nuget/-/Serilog.Enrichers.CorrelationId/3.0.1, MIT, approved, clearlydefined nuget/nuget/-/Serilog.Enrichers.Environment/2.2.0, Apache-2.0, approved, clearlydefined nuget/nuget/-/Serilog.Enrichers.Process/2.0.2, Apache-2.0, approved, clearlydefined +nuget/nuget/-/Serilog.Enrichers.Sensitive/1.7.3, MIT, approved, clearlydefined nuget/nuget/-/Serilog.Enrichers.Thread/3.1.0, Apache-2.0, approved, clearlydefined nuget/nuget/-/Serilog.Extensions.Hosting/7.0.0, Apache-2.0, approved, #10078 nuget/nuget/-/Serilog.Extensions.Logging/7.0.0, Apache-2.0, approved, #10070 diff --git a/src/Portal.Backend.sln b/src/Portal.Backend.sln index b493ebc00f..a63d8cd9a6 100644 --- a/src/Portal.Backend.sln +++ b/src/Portal.Backend.sln @@ -232,6 +232,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OnboardingServiceProvider.L EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetworkRegistration.Executor.Tests", "..\tests\processes\NetworkRegistration.Executor.Tests\NetworkRegistration.Executor.Tests.csproj", "{F1A5A73C-2B8C-4959-A128-CC5A8DECCB1B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Framework.Logging.Tests", "..\tests\framework\Framework.Logging.Tests\Framework.Logging.Tests.csproj", "{146865E5-7DFF-4CC2-8521-9E22CFCEEA20}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1466,6 +1468,18 @@ Global {F1A5A73C-2B8C-4959-A128-CC5A8DECCB1B}.Release|x64.Build.0 = Release|Any CPU {F1A5A73C-2B8C-4959-A128-CC5A8DECCB1B}.Release|x86.ActiveCfg = Release|Any CPU {F1A5A73C-2B8C-4959-A128-CC5A8DECCB1B}.Release|x86.Build.0 = Release|Any CPU + {146865E5-7DFF-4CC2-8521-9E22CFCEEA20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {146865E5-7DFF-4CC2-8521-9E22CFCEEA20}.Debug|Any CPU.Build.0 = Debug|Any CPU + {146865E5-7DFF-4CC2-8521-9E22CFCEEA20}.Debug|x64.ActiveCfg = Debug|Any CPU + {146865E5-7DFF-4CC2-8521-9E22CFCEEA20}.Debug|x64.Build.0 = Debug|Any CPU + {146865E5-7DFF-4CC2-8521-9E22CFCEEA20}.Debug|x86.ActiveCfg = Debug|Any CPU + {146865E5-7DFF-4CC2-8521-9E22CFCEEA20}.Debug|x86.Build.0 = Debug|Any CPU + {146865E5-7DFF-4CC2-8521-9E22CFCEEA20}.Release|Any CPU.ActiveCfg = Release|Any CPU + {146865E5-7DFF-4CC2-8521-9E22CFCEEA20}.Release|Any CPU.Build.0 = Release|Any CPU + {146865E5-7DFF-4CC2-8521-9E22CFCEEA20}.Release|x64.ActiveCfg = Release|Any CPU + {146865E5-7DFF-4CC2-8521-9E22CFCEEA20}.Release|x64.Build.0 = Release|Any CPU + {146865E5-7DFF-4CC2-8521-9E22CFCEEA20}.Release|x86.ActiveCfg = Release|Any CPU + {146865E5-7DFF-4CC2-8521-9E22CFCEEA20}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1474,6 +1488,7 @@ Global SolutionGuid = {2EB6265F-323A-4BF3-969E-003D64A14B64} EndGlobalSection GlobalSection(NestedProjects) = preSolution + {146865E5-7DFF-4CC2-8521-9E22CFCEEA20} = {323C198D-A8C6-4EB0-8B79-72624275E35F} {A43B5ACA-1209-46E9-84DB-A48553ED623E} = {323C198D-A8C6-4EB0-8B79-72624275E35F} {1EAF34DA-6D16-4F5E-86F4-344185F53942} = {323C198D-A8C6-4EB0-8B79-72624275E35F} {A5BEDD89-7280-466E-8D14-EC5E177AAD07} = {323C198D-A8C6-4EB0-8B79-72624275E35F} diff --git a/src/framework/Framework.Logging/Framework.Logging.csproj b/src/framework/Framework.Logging/Framework.Logging.csproj index ce1dea0d8d..0504174a44 100644 --- a/src/framework/Framework.Logging/Framework.Logging.csproj +++ b/src/framework/Framework.Logging/Framework.Logging.csproj @@ -1,42 +1,43 @@ - - - - - - Org.Eclipse.TractusX.Portal.Backend.Framework.Logging - Org.Eclipse.TractusX.Portal.Backend.Framework.Logging - net7.0 - enable - enable - - - - - - - - - - - - - - + + + + + + Org.Eclipse.TractusX.Portal.Backend.Framework.Logging + Org.Eclipse.TractusX.Portal.Backend.Framework.Logging + net7.0 + enable + enable + + + + + + + + + + + + + + + diff --git a/src/framework/Framework.Logging/LoggingExtensions.cs b/src/framework/Framework.Logging/LoggingExtensions.cs index 060e636493..32da331a69 100644 --- a/src/framework/Framework.Logging/LoggingExtensions.cs +++ b/src/framework/Framework.Logging/LoggingExtensions.cs @@ -20,8 +20,10 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Logging.MaskingOperator; using Serilog; using Serilog.Core; +using Serilog.Enrichers.Sensitive; using Serilog.Events; using Serilog.Formatting.Json; @@ -38,6 +40,12 @@ public static IHostBuilder AddLogging(this IHostBuilder host, Action { configuration + .Enrich.WithSensitiveDataMasking(opt => + { + opt.Mode = MaskingMode.Globally; + opt.MaskValue = "*****"; + opt.MaskingOperators.Add(new SecretOperator()); + }) .MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning) .ReadFrom.Configuration(context.Configuration) .WriteTo.Console(new JsonFormatter(renderMessage: true)); @@ -57,6 +65,12 @@ public static void EnsureInitialized() return; Log.Logger = new LoggerConfiguration() + .Enrich.WithSensitiveDataMasking(opt => + { + opt.Mode = MaskingMode.Globally; + opt.MaskValue = "*****"; + opt.MaskingOperators.Add(new SecretOperator()); + }) .MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning) .WriteTo.Console(new JsonFormatter(renderMessage: true)) .CreateBootstrapLogger(); diff --git a/src/framework/Framework.Logging/MaskingOperator/SecretOperator.cs b/src/framework/Framework.Logging/MaskingOperator/SecretOperator.cs new file mode 100644 index 0000000000..d763b2065f --- /dev/null +++ b/src/framework/Framework.Logging/MaskingOperator/SecretOperator.cs @@ -0,0 +1,37 @@ +/******************************************************************************** + * Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +using Serilog.Enrichers.Sensitive; +using System.Text.RegularExpressions; + +namespace Org.Eclipse.TractusX.Portal.Backend.Framework.Logging.MaskingOperator; + +public class SecretOperator : RegexMaskingOperator +{ + private const string SecretPattern = "(secret|password)=(.*?)&"; + + public SecretOperator() + : base(SecretPattern, RegexOptions.IgnoreCase | RegexOptions.Compiled) + { + } + + protected override string PreprocessMask(string mask, Match match) => $"{match.Groups[1]}={mask}&"; + + protected override bool ShouldMaskInput(string input) => input.Contains("secret=", StringComparison.InvariantCultureIgnoreCase) || input.Contains("password=", StringComparison.InvariantCultureIgnoreCase); +} diff --git a/tests/framework/Framework.Logging.Tests/Framework.Logging.Tests.csproj b/tests/framework/Framework.Logging.Tests/Framework.Logging.Tests.csproj new file mode 100644 index 0000000000..e48e34ad11 --- /dev/null +++ b/tests/framework/Framework.Logging.Tests/Framework.Logging.Tests.csproj @@ -0,0 +1,48 @@ + + + + + Org.Eclipse.TractusX.Portal.Backend.Framework.Logging.Tests + Org.Eclipse.TractusX.Portal.Backend.Framework.Logging.Tests + net7.0 + enable + enable + false + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + diff --git a/tests/framework/Framework.Logging.Tests/SecretOperatorTests.cs b/tests/framework/Framework.Logging.Tests/SecretOperatorTests.cs new file mode 100644 index 0000000000..f23dcd06a3 --- /dev/null +++ b/tests/framework/Framework.Logging.Tests/SecretOperatorTests.cs @@ -0,0 +1,46 @@ +/******************************************************************************** + * Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +using Org.Eclipse.TractusX.Portal.Backend.Framework.Logging.MaskingOperator; +using Serilog.Enrichers.Sensitive; + +namespace Org.Eclipse.TractusX.Portal.Backend.Framework.Logging.Tests; + +public class SecretOperatorTests +{ + [Theory] + [InlineData("foobarsecret=1234&deadbeef", "foobarsecret=****&deadbeef", true)] + [InlineData("foobarpassword=1234&deadbeef", "foobarpassword=****&deadbeef", true)] + [InlineData("foobarSecret=1234&deadbeefPassword=5678&", "foobarSecret=****&deadbeefPassword=****&", true)] + [InlineData("foobarpasssword=1234&deadbeef", null, false)] + public void Mask_ReturnsExpected(string input, string matchResult, bool match) + { + //Arrange + var sut = new SecretOperator(); + + //Act + var result = sut.Mask(input, "****"); + + //Assert + result.Should().Match(x => + x.Match == match && + x.Result == matchResult + ); + } +} diff --git a/tests/framework/Framework.Logging.Tests/Usings.cs b/tests/framework/Framework.Logging.Tests/Usings.cs new file mode 100644 index 0000000000..65016aec51 --- /dev/null +++ b/tests/framework/Framework.Logging.Tests/Usings.cs @@ -0,0 +1,24 @@ +/******************************************************************************** + * Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +global using AutoFixture; +global using AutoFixture.AutoFakeItEasy; +global using FakeItEasy; +global using FluentAssertions; +global using Xunit;