forked from DataDog/datadog-agent
/
default.go
151 lines (137 loc) · 5.36 KB
/
default.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-present Datadog, Inc.
package scrubber
import (
"fmt"
"os"
"regexp"
"strings"
)
// DefaultScrubber is the scrubber used by the package-level cleaning functions.
//
// It includes a set of agent-specific replacers. It can scrub DataDog App
// and API keys, passwords from URLs, and multi-line PEM-formatted TLS keys and
// certificates. It contains special handling for YAML-like content (with
// lines of the form "key: value") and can scrub passwords, tokens, and SNMP
// community strings in such content.
//
// See default.go for details of these replacers.
var DefaultScrubber = &Scrubber{}
func init() {
AddDefaultReplacers(DefaultScrubber)
}
// AddDefaultReplacers to a scrubber. This is called automatically for
// DefaultScrubber, but can be used to initialize other, custom scrubbers with
// the default replacers.
func AddDefaultReplacers(scrubber *Scrubber) {
hintedAPIKeyReplacer := Replacer{
// If hinted, mask the value regardless if it doesn't match 32-char hexadecimal string
Regex: regexp.MustCompile(`(api_?key=)\b[a-zA-Z0-9]+([a-zA-Z0-9]{5})\b`),
Hints: []string{"api_key", "apikey"},
Repl: []byte(`$1***************************$2`),
}
hintedAPPKeyReplacer := Replacer{
// If hinted, mask the value regardless if it doesn't match 40-char hexadecimal string
Regex: regexp.MustCompile(`(ap(?:p|plication)_?key=)\b[a-zA-Z0-9]+([a-zA-Z0-9]{5})\b`),
Hints: []string{"app_key", "appkey", "application_key"},
Repl: []byte(`$1***********************************$2`),
}
apiKeyReplacer := Replacer{
Regex: regexp.MustCompile(`\b[a-fA-F0-9]{27}([a-fA-F0-9]{5})\b`),
Repl: []byte(`***************************$1`),
}
appKeyReplacer := Replacer{
Regex: regexp.MustCompile(`\b[a-fA-F0-9]{35}([a-fA-F0-9]{5})\b`),
Repl: []byte(`***********************************$1`),
}
// URI Generic Syntax
// https://tools.ietf.org/html/rfc3986
uriPasswordReplacer := Replacer{
Regex: regexp.MustCompile(`([A-Za-z][A-Za-z0-9+-.]+\:\/\/|\b)([^\:]+)\:([^\s]+)\@`),
Repl: []byte(`$1$2:********@`),
}
passwordReplacer := Replacer{
Regex: matchYAMLKeyPart(`(pass(word)?|pwd)`),
Hints: []string{"pass", "pwd"},
Repl: []byte(`$1 ********`),
}
tokenReplacer := Replacer{
Regex: matchYAMLKeyEnding(`token`),
Hints: []string{"token"},
Repl: []byte(`$1 ********`),
}
snmpReplacer := Replacer{
Regex: matchYAMLKey(`(community_string|authKey|privKey|community|authentication_key|privacy_key)`),
Hints: []string{"community_string", "authKey", "privKey", "community", "authentication_key", "privacy_key"},
Repl: []byte(`$1 ********`),
}
certReplacer := Replacer{
Regex: matchCert(),
Hints: []string{"BEGIN"},
Repl: []byte(`********`),
}
scrubber.AddReplacer(SingleLine, hintedAPIKeyReplacer)
scrubber.AddReplacer(SingleLine, hintedAPPKeyReplacer)
scrubber.AddReplacer(SingleLine, apiKeyReplacer)
scrubber.AddReplacer(SingleLine, appKeyReplacer)
scrubber.AddReplacer(SingleLine, uriPasswordReplacer)
scrubber.AddReplacer(SingleLine, passwordReplacer)
scrubber.AddReplacer(SingleLine, tokenReplacer)
scrubber.AddReplacer(SingleLine, snmpReplacer)
scrubber.AddReplacer(MultiLine, certReplacer)
}
func matchYAMLKeyPart(part string) *regexp.Regexp {
return regexp.MustCompile(fmt.Sprintf(`(\s*(\w|_)*%s(\w|_)*\s*:).+`, part))
}
func matchYAMLKey(key string) *regexp.Regexp {
return regexp.MustCompile(fmt.Sprintf(`(\s*%s\s*:).+`, key))
}
func matchYAMLKeyEnding(ending string) *regexp.Regexp {
return regexp.MustCompile(fmt.Sprintf(`(^\s*(\w|_)*%s\s*:).+`, ending))
}
func matchCert() *regexp.Regexp {
/*
Try to match as accurately as possible. RFC 7468's ABNF
Backreferences are not available in go, so we cannot verify
here that the BEGIN label is the same as the END label.
*/
return regexp.MustCompile(
`-----BEGIN (?:.*)-----[A-Za-z0-9=\+\/\s]*-----END (?:.*)-----`,
)
}
// ScrubFile scrubs credentials from the given file, using the
// default scrubber.
func ScrubFile(filePath string) ([]byte, error) {
return DefaultScrubber.ScrubFile(filePath)
}
// ScrubBytes scrubs credentials from the given slice of bytes,
// using the default scrubber.
func ScrubBytes(file []byte) ([]byte, error) {
return DefaultScrubber.ScrubBytes(file)
}
// ScrubLine scrubs credentials from a single line of text, using the default
// scrubber. It can be safely applied to URLs or to strings containing URLs.
// It does not run multi-line replacers, and should not be used on multi-line
// inputs.
func ScrubLine(url string) string {
return DefaultScrubber.ScrubLine(url)
}
// AddStrippedKeys adds to the set of YAML keys that will be recognized and have
// their values stripped. This modifies the DefaultScrubber directly.
func AddStrippedKeys(strippedKeys []string) {
if len(strippedKeys) > 0 {
configReplacer := Replacer{
Regex: matchYAMLKey(fmt.Sprintf("(%s)", strings.Join(strippedKeys, "|"))),
Hints: strippedKeys,
Repl: []byte(`$1 ********`),
}
DefaultScrubber.AddReplacer(SingleLine, configReplacer)
}
}
// NewWriter instantiates a Writer to the given file path with the given
// permissions, using the default scrubber.
func NewWriter(path string, perms os.FileMode) (*Writer, error) {
return newWriterWithScrubber(path, perms, DefaultScrubber)
}