Skip to content

Commit

Permalink
Merge pull request #3571 from weaveworks/implement-report-censorship
Browse files Browse the repository at this point in the history
Conditional report censoring
  • Loading branch information
fbarl authored Feb 26, 2019
2 parents c0b2690 + b9e692c commit 6074655
Show file tree
Hide file tree
Showing 13 changed files with 536 additions and 9 deletions.
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)
}
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

0 comments on commit 6074655

Please sign in to comment.