Skip to content

Commit 1522978

Browse files
odubajDTkhushijain21
authored andcommitted
[processor/redaction] introduce allowed_values parameter in processor config (open-telemetry#37638)
<!--Ex. Fixing a bug - Describe the bug and how this fixes the issue. Ex. Adding a feature - Explain what this achieves.--> #### Description Introduce `allowed_values` parameter to the processor config. If the value of an allowed key matches the regular expression for an allowed value, the matching part of the value is not masked even if it matches the regular expression for a blocked value. <!-- Issue number (e.g. open-telemetry#1234) or full URL to issue, if applicable. --> #### Link to tracking issue Fixes open-telemetry#35840 --------- Signed-off-by: odubajDT <[email protected]>
1 parent c73e663 commit 1522978

File tree

8 files changed

+192
-83
lines changed

8 files changed

+192
-83
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: processor/redaction
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: "Introduce 'allowed_values' parameter for allowed values of attributes"
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [35840]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: []

processor/redactionprocessor/README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ processors:
7878
blocked_values:
7979
- "4[0-9]{12}(?:[0-9]{3})?" ## Visa credit card number
8080
- "(5[1-5][0-9]{14})" ## MasterCard number
81+
# AllowedValues is a list of regular expressions for allowing values of
82+
# blocked span attributes. Values that match are not masked.
83+
allowed_values:
84+
8185
# summary controls the verbosity level of the diagnostic attributes that
8286
# the processor adds to the spans/logs/datapoints when it redacts or masks other
8387
# attributes. In some contexts a list of redacted attributes leaks
@@ -101,9 +105,11 @@ If `allowed_keys` is empty, then no attributes are allowed. All
101105
attributes are removed in that case. To keep all span attributes, you should
102106
explicitly set `allow_all_keys` to true.
103107

104-
`blocked_values` applies to the values of the allowed keys. If the value of an
105-
allowed key matches the regular expression for a blocked value, the matching
106-
part of the value is then masked with a fixed length of asterisks.
108+
`blocked_values` and `allowed_values` applies to the values of the allowed keys.
109+
If the value of an allowed key matches the regular expression for an allowed value, the matching
110+
part of the value is not masked even if it matches the regular expression for a blocked value.
111+
If the value matches the regular expression for a blocked value only, the matching
112+
part of the value is masked with a fixed length of asterisks.
107113

108114
For example, if `notes` is on the list of allowed keys, then the `notes`
109115
attribute is retained. However, if there is a value such as a credit card

processor/redactionprocessor/config.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,13 @@ type Config struct {
2020
IgnoredKeys []string `mapstructure:"ignored_keys"`
2121

2222
// BlockedValues is a list of regular expressions for blocking values of
23-
// allowed span attributes. Values that match are masked
23+
// allowed span attributes. Values that match are masked.
2424
BlockedValues []string `mapstructure:"blocked_values"`
2525

26+
// AllowedValues is a list of regular expressions for allowing values of
27+
// blocked span attributes. Values that match are not masked.
28+
AllowedValues []string `mapstructure:"allowed_values"`
29+
2630
// Summary controls the verbosity level of the diagnostic attributes that
2731
// the processor adds to the spans when it redacts or masks other
2832
// attributes. In some contexts a list of redacted attributes leaks

processor/redactionprocessor/config_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ func TestLoadConfig(t *testing.T) {
3030
AllowedKeys: []string{"description", "group", "id", "name"},
3131
IgnoredKeys: []string{"safe_attribute"},
3232
BlockedValues: []string{"4[0-9]{12}(?:[0-9]{3})?", "(5[1-5][0-9]{14})"},
33+
AllowedValues: []string{"[email protected]"},
3334
Summary: debug,
3435
},
3536
},

processor/redactionprocessor/factory_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ func TestDefaultConfiguration(t *testing.T) {
1616
c := createDefaultConfig().(*Config)
1717
assert.Empty(t, c.AllowedKeys)
1818
assert.Empty(t, c.BlockedValues)
19+
assert.Empty(t, c.AllowedValues)
1920
}
2021

2122
func TestCreateTestProcessor(t *testing.T) {

processor/redactionprocessor/processor.go

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ type redaction struct {
2626
ignoreList map[string]string
2727
// Attribute values blocked in a span
2828
blockRegexList map[string]*regexp.Regexp
29+
// Attribute values allowed in a span
30+
allowRegexList map[string]*regexp.Regexp
2931
// Redaction processor configuration
3032
config *Config
3133
// Logger
@@ -36,16 +38,23 @@ type redaction struct {
3638
func newRedaction(ctx context.Context, config *Config, logger *zap.Logger) (*redaction, error) {
3739
allowList := makeAllowList(config)
3840
ignoreList := makeIgnoreList(config)
39-
blockRegexList, err := makeBlockRegexList(ctx, config)
41+
blockRegexList, err := makeRegexList(ctx, config.BlockedValues)
4042
if err != nil {
4143
// TODO: Placeholder for an error metric in the next PR
4244
return nil, fmt.Errorf("failed to process block list: %w", err)
4345
}
4446

47+
allowRegexList, err := makeRegexList(ctx, config.AllowedValues)
48+
if err != nil {
49+
// TODO: Placeholder for an error metric in the next PR
50+
return nil, fmt.Errorf("failed to process allow list: %w", err)
51+
}
52+
4553
return &redaction{
4654
allowList: allowList,
4755
ignoreList: ignoreList,
4856
blockRegexList: blockRegexList,
57+
allowRegexList: allowRegexList,
4958
config: config,
5059
logger: logger,
5160
}, nil
@@ -159,6 +168,7 @@ func (s *redaction) processAttrs(_ context.Context, attributes pcommon.Map) {
159168
// TODO: Use the context for recording metrics
160169
var toDelete []string
161170
var toBlock []string
171+
var allowed []string
162172
var ignoring []string
163173

164174
// Identify attributes to redact and mask in the following sequence
@@ -186,8 +196,17 @@ func (s *redaction) processAttrs(_ context.Context, attributes pcommon.Map) {
186196
}
187197
}
188198

189-
// Mask any blocked values for the other attributes
190199
strVal := value.Str()
200+
201+
// Allow any values matching the allowed list regex
202+
for _, compiledRE := range s.allowRegexList {
203+
if match := compiledRE.MatchString(strVal); match {
204+
allowed = append(allowed, k)
205+
return true
206+
}
207+
}
208+
209+
// Mask any blocked values for the other attributes
191210
var matched bool
192211
for _, compiledRE := range s.blockRegexList {
193212
match := compiledRE.MatchString(strVal)
@@ -212,6 +231,7 @@ func (s *redaction) processAttrs(_ context.Context, attributes pcommon.Map) {
212231
// Add diagnostic information to the span
213232
s.addMetaAttrs(toDelete, attributes, redactedKeys, redactedKeyCount)
214233
s.addMetaAttrs(toBlock, attributes, maskedValues, maskedValueCount)
234+
s.addMetaAttrs(allowed, attributes, allowedValues, allowedValueCount)
215235
s.addMetaAttrs(ignoring, attributes, "", ignoredKeyCount)
216236
}
217237

@@ -239,13 +259,15 @@ func (s *redaction) addMetaAttrs(redactedAttrs []string, attributes pcommon.Map,
239259
}
240260

241261
const (
242-
debug = "debug"
243-
info = "info"
244-
redactedKeys = "redaction.redacted.keys"
245-
redactedKeyCount = "redaction.redacted.count"
246-
maskedValues = "redaction.masked.keys"
247-
maskedValueCount = "redaction.masked.count"
248-
ignoredKeyCount = "redaction.ignored.count"
262+
debug = "debug"
263+
info = "info"
264+
redactedKeys = "redaction.redacted.keys"
265+
redactedKeyCount = "redaction.redacted.count"
266+
maskedValues = "redaction.masked.keys"
267+
maskedValueCount = "redaction.masked.count"
268+
allowedValues = "redaction.allowed.keys"
269+
allowedValueCount = "redaction.allowed.count"
270+
ignoredKeyCount = "redaction.ignored.count"
249271
)
250272

251273
// makeAllowList sets up a lookup table of allowed span attribute keys
@@ -282,16 +304,16 @@ func makeIgnoreList(c *Config) map[string]string {
282304
return ignoreList
283305
}
284306

285-
// makeBlockRegexList precompiles all the blocked regex patterns
286-
func makeBlockRegexList(_ context.Context, config *Config) (map[string]*regexp.Regexp, error) {
287-
blockRegexList := make(map[string]*regexp.Regexp, len(config.BlockedValues))
288-
for _, pattern := range config.BlockedValues {
307+
// makeRegexList precompiles all the regex patterns in the defined list
308+
func makeRegexList(_ context.Context, valuesList []string) (map[string]*regexp.Regexp, error) {
309+
regexList := make(map[string]*regexp.Regexp, len(valuesList))
310+
for _, pattern := range valuesList {
289311
re, err := regexp.Compile(pattern)
290312
if err != nil {
291313
// TODO: Placeholder for an error metric in the next PR
292-
return nil, fmt.Errorf("error compiling regex in block list: %w", err)
314+
return nil, fmt.Errorf("error compiling regex in list: %w", err)
293315
}
294-
blockRegexList[pattern] = re
316+
regexList[pattern] = re
295317
}
296-
return blockRegexList, nil
318+
return regexList, nil
297319
}

0 commit comments

Comments
 (0)