-
Notifications
You must be signed in to change notification settings - Fork 154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Diagnostics file writes use RedactSecretPaths #5745
Changes from all commits
117155b
8a7225d
279aec4
0cb68e5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Kind can be one of: | ||
# - breaking-change: a change to previously-documented behavior | ||
# - deprecation: functionality that is being removed in a later release | ||
# - bug-fix: fixes a problem in a previous version | ||
# - enhancement: extends functionality but does not break or fix existing behavior | ||
# - feature: new functionality | ||
# - known-issue: problems that we are aware of in a given version | ||
# - security: impacts on the security of a product or a user’s deployment. | ||
# - upgrade: important information for someone upgrading from a prior version | ||
# - other: does not fit into any of the other categories | ||
kind: enhancement | ||
|
||
# Change summary; a 80ish characters long description of the change. | ||
summary: Diagnostics files will redact secret_paths | ||
|
||
# Long description; in case the summary is not enough to describe the change | ||
# this field accommodate a description without length limits. | ||
# NOTE: This field will be rendered only for breaking-change and known-issue kinds at the moment. | ||
description: | | ||
The elastic-agent will use redact secret paths in files written in diagnostics bundles. | ||
Secret paths are expected to be specified as a top-level attribute in yaml data being written. | ||
|
||
# Affected component; usually one of "elastic-agent", "fleet-server", "filebeat", "metricbeat", "auditbeat", "all", etc. | ||
component: | ||
|
||
# PR URL; optional; the PR number that added the changeset. | ||
# If not present is automatically filled by the tooling finding the PR where this changelog fragment has been added. | ||
# NOTE: the tooling supports backports, so it's able to fill the original PR number instead of the backport PR number. | ||
# Please provide it if you are adding a fragment for a different PR. | ||
pr: https://github.com/elastic/elastic-agent/pull/5745 | ||
|
||
# Issue URL; optional; the GitHub issue related to this changeset (either closes or is part of). | ||
# If not present is automatically filled by the tooling with the issue linked to the PR number. | ||
#issue: https://github.com/owner/repo/1234 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -327,12 +327,13 @@ func writeRedacted(errOut, resultWriter io.Writer, fullFilePath string, fileResu | |
|
||
// Should we support json too? | ||
if fileResult.ContentType == "application/yaml" { | ||
unmarshalled := map[interface{}]interface{}{} | ||
unmarshalled := map[string]interface{}{} | ||
err := yaml.Unmarshal(fileResult.Content, &unmarshalled) | ||
if err != nil { | ||
// Best effort, output a warning but still include the file | ||
fmt.Fprintf(errOut, "[WARNING] Could not redact %s due to unmarshalling error: %s\n", fullFilePath, err) | ||
} else { | ||
unmarshalled = RedactSecretPaths(unmarshalled, errOut) | ||
redacted, err := yaml.Marshal(redactMap(errOut, unmarshalled)) | ||
if err != nil { | ||
// Best effort, output a warning but still include the file | ||
|
@@ -579,7 +580,6 @@ func saveLogs(name string, logPath string, zw *zip.Writer) error { | |
func RedactSecretPaths(mapStr map[string]any, errOut io.Writer) map[string]any { | ||
v, ok := mapStr["secret_paths"] | ||
if !ok { | ||
fmt.Fprintln(errOut, "No output redaction: secret_paths attribute not found.") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When a diagnostics action is ran secrets in the component related files are not redacted (structure does not match, and |
||
return mapStr | ||
} | ||
arr, ok := v.([]interface{}) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -140,6 +140,103 @@ mapping: | |
require.Empty(t, errOut.String()) | ||
} | ||
|
||
func TestRedactWithSecretPaths(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
input []byte | ||
expect string | ||
}{{ | ||
name: "no secret paths", | ||
input: []byte(`id: test-policy | ||
inputs: | ||
- type: test_input | ||
redactKey: secretValue | ||
outputs: | ||
default: | ||
type: elasticsearch | ||
api_key: secretKey | ||
redactOtherKey: secretOutputValue | ||
`), | ||
expect: `id: test-policy | ||
inputs: | ||
- redactKey: secretValue | ||
type: test_input | ||
outputs: | ||
default: | ||
api_key: <REDACTED> | ||
redactOtherKey: secretOutputValue | ||
type: elasticsearch | ||
Comment on lines
+151
to
+168
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think these would be more readable if inputs and outputs used the same indentation. |
||
`, | ||
}, { | ||
name: "secret_paths are redacted", | ||
input: []byte(`id: test-policy | ||
secret_paths: | ||
- inputs.0.redactKey | ||
- outputs.default.redactOtherKey | ||
inputs: | ||
- type: test_input | ||
redactKey: secretValue | ||
outputs: | ||
default: | ||
type: elasticsearch | ||
api_key: secretKey | ||
redactOtherKey: secretOutputValue | ||
`), | ||
expect: `id: test-policy | ||
inputs: | ||
- redactKey: <REDACTED> | ||
type: test_input | ||
outputs: | ||
default: | ||
api_key: <REDACTED> | ||
redactOtherKey: <REDACTED> | ||
type: elasticsearch | ||
secret_paths: | ||
- inputs.0.redactKey | ||
- outputs.default.redactOtherKey | ||
`, | ||
}, { | ||
name: "secret_paths contains extra keys", | ||
input: []byte(`id: test-policy | ||
secret_paths: | ||
- inputs.0.redactKey | ||
- inputs.1.missingKey | ||
- outputs.default.redactOtherKey | ||
inputs: | ||
- type: test_input | ||
redactKey: secretValue | ||
outputs: | ||
default: | ||
type: elasticsearch | ||
api_key: secretKey | ||
`), | ||
expect: `id: test-policy | ||
inputs: | ||
- redactKey: <REDACTED> | ||
type: test_input | ||
outputs: | ||
default: | ||
api_key: <REDACTED> | ||
type: elasticsearch | ||
secret_paths: | ||
- inputs.0.redactKey | ||
- inputs.1.missingKey | ||
- outputs.default.redactOtherKey | ||
`, | ||
}} | ||
|
||
for _, tc := range tests { | ||
t.Run(tc.name, func(t *testing.T) { | ||
file := client.DiagnosticFileResult{Content: tc.input, ContentType: "application/yaml"} | ||
var out bytes.Buffer | ||
err := writeRedacted(io.Discard, &out, "testPath", file) | ||
require.NoError(t, err) | ||
|
||
assert.Equal(t, tc.expect, out.String()) | ||
}) | ||
} | ||
} | ||
|
||
func TestUnitAndStateMapping(t *testing.T) { | ||
// this structure causes problems due to the compound agentruntime.ComponentUnitKey map key | ||
exampleState := agentruntime.ComponentState{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -174,11 +174,11 @@ const ( | |
"hosts": {{ toJson .FleetHosts }} | ||
}, | ||
"id": "{{.PolicyID}}", | ||
"secret_paths": ["inputs.0.secret_key"], | ||
"secret_paths": ["inputs.0.custom_attr"], | ||
"inputs": [ | ||
{ | ||
"id": "fake-input", | ||
"secret_key": "secretValue", | ||
"custom_attr": "secretValue", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've renamed to |
||
"revision": 1, | ||
"name": "fake-input", | ||
"type": "fake-input", | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think unmarshaling to
map[interface{}]interface{}
was a restriction with yaml.v2 which is not a part of yaml.v3, see go-yaml/yaml#139 (comment)