Skip to content
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

Conditional report censoring #3571

Merged
merged 7 commits into from
Feb 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions app/api_report.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ import (
// Raw report handler
func makeRawReportHandler(rep Reporter) CtxHandlerFunc {
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
report, err := rep.Report(ctx, time.Now())
rawReport, err := rep.Report(ctx, time.Now())
if err != nil {
respondWith(w, http.StatusInternalServerError, err)
return
}
respondWith(w, http.StatusOK, report)
censorCfg := report.GetCensorConfigFromRequest(r)
respondWith(w, http.StatusOK, report.CensorRawReport(rawReport, censorCfg))
}
}

Expand Down
20 changes: 17 additions & 3 deletions app/api_topology.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"time"

"context"

"github.com/gorilla/mux"
log "github.com/sirupsen/logrus"

Expand Down Expand Up @@ -41,14 +42,17 @@ type rendererHandler func(context.Context, render.Renderer, render.Transformer,

// Full topology.
func handleTopology(ctx context.Context, renderer render.Renderer, transformer render.Transformer, rc detailed.RenderContext, w http.ResponseWriter, r *http.Request) {
censorCfg := report.GetCensorConfigFromRequest(r)
nodeSummaries := detailed.Summaries(ctx, rc, render.Render(ctx, rc.Report, renderer, transformer).Nodes)
respondWith(w, http.StatusOK, APITopology{
Nodes: detailed.Summaries(ctx, rc, render.Render(ctx, rc.Report, renderer, transformer).Nodes),
Nodes: detailed.CensorNodeSummaries(nodeSummaries, censorCfg),
})
}

// Individual nodes.
func handleNode(ctx context.Context, renderer render.Renderer, transformer render.Transformer, rc detailed.RenderContext, w http.ResponseWriter, r *http.Request) {
var (
censorCfg = report.GetCensorConfigFromRequest(r)
vars = mux.Vars(r)
topologyID = vars["topology"]
nodeID = vars["id"]
Expand All @@ -71,7 +75,8 @@ func handleNode(ctx context.Context, renderer render.Renderer, transformer rende
nodes.Nodes[nodeID] = node
nodes.Filtered--
}
respondWith(w, http.StatusOK, APINode{Node: detailed.MakeNode(topologyID, rc, nodes.Nodes, node)})
rawNode := detailed.MakeNode(topologyID, rc, nodes.Nodes, node)
respondWith(w, http.StatusOK, APINode{Node: detailed.CensorNode(rawNode, censorCfg)})
}

// Websocket for the full topology.
Expand Down Expand Up @@ -120,6 +125,7 @@ func handleWebsocket(
wait = make(chan struct{}, 1)
topologyID = mux.Vars(r)["topology"]
startReportingAt = deserializeTimestamp(r.Form.Get("timestamp"))
censorCfg = report.GetCensorConfigFromRequest(r)
channelOpenedAt = time.Now()
)

Expand All @@ -145,7 +151,15 @@ func handleWebsocket(
log.Errorf("Error generating report: %v", err)
return
}
newTopo := detailed.Summaries(ctx, RenderContextForReporter(rep, re), render.Render(ctx, re, renderer, filter).Nodes)

newTopo := detailed.CensorNodeSummaries(
detailed.Summaries(
ctx,
RenderContextForReporter(rep, re),
render.Render(ctx, re, renderer, filter).Nodes,
),
censorCfg,
)
diff := detailed.TopoDiff(previousTopo, newTopo)
previousTopo = newTopo

Expand Down
2 changes: 1 addition & 1 deletion probe/docker/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const (
CPUSystemCPUUsage = "docker_cpu_system_cpu_usage"

LabelPrefix = "docker_label_"
EnvPrefix = "docker_env_"
EnvPrefix = report.DockerEnvPrefix
)

// These 'constants' are used for node states.
Expand Down
3 changes: 1 addition & 2 deletions probe/process/reporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package process

import (
"strconv"
"strings"

"github.com/weaveworks/common/mtime"
"github.com/weaveworks/scope/report"
Expand Down Expand Up @@ -93,7 +92,7 @@ func (r *Reporter) processTopology() (report.Topology, error) {

if p.Cmdline != "" {
if r.noCommandLineArguments {
node = node.WithLatest(Cmdline, now, strings.Split(p.Cmdline, " ")[0])
node = node.WithLatest(Cmdline, now, report.StripCommandArgs(p.Cmdline))
} else {
node = node.WithLatest(Cmdline, now, p.Cmdline)
}
Expand Down
48 changes: 48 additions & 0 deletions render/detailed/censor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package detailed

import (
"github.com/weaveworks/scope/report"
)

func censorNodeSummary(s NodeSummary, cfg report.CensorConfig) NodeSummary {
if cfg.HideCommandLineArguments && s.Metadata != nil {
// Iterate through all the metadata rows and strip the
// arguments from all the values containing a command
// (while making sure everything is done in a non-mutable way).
metadata := []report.MetadataRow{}
for _, row := range s.Metadata {
if report.IsCommandEntry(row.ID) {
row.Value = report.StripCommandArgs(row.Value)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this mutating the existing row?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't since:

  • range in the loop above returns a copy of row and we're changing that copy.
  • The test is passing and normally it should fail if any of these operations are mutating since we're not resetting the test set between test cases for this test.

}
metadata = append(metadata, row)
}
s.Metadata = metadata
}
if cfg.HideEnvironmentVariables && s.Tables != nil {
// Copy across all the tables except the environment
// variable ones (ensuring the operation is non-mutable).
tables := []report.Table{}
for _, table := range s.Tables {
if !report.IsEnvironmentVarsEntry(table.ID) {
tables = append(tables, table)
}
}
s.Tables = tables
}
return s
}

// CensorNode removes any sensitive data from a node.
func CensorNode(node Node, cfg report.CensorConfig) Node {
node.NodeSummary = censorNodeSummary(node.NodeSummary, cfg)
return node
}

// CensorNodeSummaries removes any sensitive data from a list of node summaries.
func CensorNodeSummaries(summaries NodeSummaries, cfg report.CensorConfig) NodeSummaries {
censored := NodeSummaries{}
for key := range summaries {
censored[key] = censorNodeSummary(summaries[key], cfg)
}
return censored
}
228 changes: 228 additions & 0 deletions render/detailed/censor_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
package detailed_test

import (
"reflect"
"testing"

"github.com/weaveworks/common/test"
"github.com/weaveworks/scope/render/detailed"
"github.com/weaveworks/scope/report"
)

func TestCensorNode(t *testing.T) {
node := detailed.Node{
NodeSummary: detailed.NodeSummary{
Metadata: []report.MetadataRow{
{ID: "cmdline", Label: "Command", Value: "prog -a --b=c"},
},
Tables: []report.Table{
{ID: "blibli", Rows: []report.Row{{ID: "bli"}}},
{ID: "docker_env_", Rows: []report.Row{{ID: "env_var"}}},
},
},
}

for _, c := range []struct {
label string
have, want detailed.Node
}{
{
label: "no censoring",
have: detailed.CensorNode(node, report.CensorConfig{
HideCommandLineArguments: false,
HideEnvironmentVariables: false,
}),
want: detailed.Node{
NodeSummary: detailed.NodeSummary{
Metadata: []report.MetadataRow{
{ID: "cmdline", Label: "Command", Value: "prog -a --b=c"},
},
Tables: []report.Table{
{ID: "blibli", Rows: []report.Row{{ID: "bli"}}},
{ID: "docker_env_", Rows: []report.Row{{ID: "env_var"}}},
},
},
},
},
{
label: "censor only command line args",
have: detailed.CensorNode(node, report.CensorConfig{
HideCommandLineArguments: true,
HideEnvironmentVariables: false,
}),
want: detailed.Node{
NodeSummary: detailed.NodeSummary{
Metadata: []report.MetadataRow{
{ID: "cmdline", Label: "Command", Value: "prog"},
},
Tables: []report.Table{
{ID: "blibli", Rows: []report.Row{{ID: "bli"}}},
{ID: "docker_env_", Rows: []report.Row{{ID: "env_var"}}},
},
},
},
},
{
label: "censor only env variables",
have: detailed.CensorNode(node, report.CensorConfig{
HideCommandLineArguments: false,
HideEnvironmentVariables: true,
}),
want: detailed.Node{
NodeSummary: detailed.NodeSummary{
Metadata: []report.MetadataRow{
{ID: "cmdline", Label: "Command", Value: "prog -a --b=c"},
},
Tables: []report.Table{
{ID: "blibli", Rows: []report.Row{{ID: "bli"}}},
},
},
},
},
{
label: "censor both command line args and env vars",
have: detailed.CensorNode(node, report.CensorConfig{
HideCommandLineArguments: true,
HideEnvironmentVariables: true,
}),
want: detailed.Node{
NodeSummary: detailed.NodeSummary{
Metadata: []report.MetadataRow{
{ID: "cmdline", Label: "Command", Value: "prog"},
},
Tables: []report.Table{
{ID: "blibli", Rows: []report.Row{{ID: "bli"}}},
},
},
},
},
} {
if !reflect.DeepEqual(c.want, c.have) {
t.Errorf("%s - %s", c.label, test.Diff(c.want, c.have))
}
}
}

func TestCensorNodeSummaries(t *testing.T) {
summaries := detailed.NodeSummaries{
"a": detailed.NodeSummary{
Metadata: []report.MetadataRow{
{ID: "blublu", Label: "blabla", Value: "blu blu"},
{ID: "docker_container_command", Label: "Command", Value: "scope --token=blibli"},
},
},
"b": detailed.NodeSummary{
Metadata: []report.MetadataRow{
{ID: "cmdline", Label: "Command", Value: "prog -a --b=c"},
},
Tables: []report.Table{
{ID: "blibli", Rows: []report.Row{{ID: "bli"}}},
{ID: "docker_env_", Rows: []report.Row{{ID: "env_var"}}},
},
},
}

for _, c := range []struct {
label string
have, want detailed.NodeSummaries
}{
{
label: "no censoring",
have: detailed.CensorNodeSummaries(summaries, report.CensorConfig{
HideCommandLineArguments: false,
HideEnvironmentVariables: false,
}),
want: detailed.NodeSummaries{
"a": detailed.NodeSummary{
Metadata: []report.MetadataRow{
{ID: "blublu", Label: "blabla", Value: "blu blu"},
{ID: "docker_container_command", Label: "Command", Value: "scope --token=blibli"},
},
},
"b": detailed.NodeSummary{
Metadata: []report.MetadataRow{
{ID: "cmdline", Label: "Command", Value: "prog -a --b=c"},
},
Tables: []report.Table{
{ID: "blibli", Rows: []report.Row{{ID: "bli"}}},
{ID: "docker_env_", Rows: []report.Row{{ID: "env_var"}}},
},
},
},
},
{
label: "censor only command line args",
have: detailed.CensorNodeSummaries(summaries, report.CensorConfig{
HideCommandLineArguments: true,
HideEnvironmentVariables: false,
}),
want: detailed.NodeSummaries{
"a": detailed.NodeSummary{
Metadata: []report.MetadataRow{
{ID: "blublu", Label: "blabla", Value: "blu blu"},
{ID: "docker_container_command", Label: "Command", Value: "scope"},
},
},
"b": detailed.NodeSummary{
Metadata: []report.MetadataRow{
{ID: "cmdline", Label: "Command", Value: "prog"},
},
Tables: []report.Table{
{ID: "blibli", Rows: []report.Row{{ID: "bli"}}},
{ID: "docker_env_", Rows: []report.Row{{ID: "env_var"}}},
},
},
},
},
{
label: "censor only env variables",
have: detailed.CensorNodeSummaries(summaries, report.CensorConfig{
HideCommandLineArguments: false,
HideEnvironmentVariables: true,
}),
want: detailed.NodeSummaries{
"a": detailed.NodeSummary{
Metadata: []report.MetadataRow{
{ID: "blublu", Label: "blabla", Value: "blu blu"},
{ID: "docker_container_command", Label: "Command", Value: "scope --token=blibli"},
},
},
"b": detailed.NodeSummary{
Metadata: []report.MetadataRow{
{ID: "cmdline", Label: "Command", Value: "prog -a --b=c"},
},
Tables: []report.Table{
{ID: "blibli", Rows: []report.Row{{ID: "bli"}}},
},
},
},
},
{
label: "censor both command line args and env vars",
have: detailed.CensorNodeSummaries(summaries, report.CensorConfig{
HideCommandLineArguments: true,
HideEnvironmentVariables: true,
}),
want: detailed.NodeSummaries{
"a": detailed.NodeSummary{
Metadata: []report.MetadataRow{
{ID: "blublu", Label: "blabla", Value: "blu blu"},
{ID: "docker_container_command", Label: "Command", Value: "scope"},
},
},
"b": detailed.NodeSummary{
Metadata: []report.MetadataRow{
{ID: "cmdline", Label: "Command", Value: "prog"},
},
Tables: []report.Table{
{ID: "blibli", Rows: []report.Row{{ID: "bli"}}},
},
},
},
},
} {
if !reflect.DeepEqual(c.want, c.have) {
t.Errorf("%s - %s", c.label, test.Diff(c.want, c.have))
}
}
}
Loading