Option to censor raw reports by command line args and env vars.

This commit is contained in:
Filip Barl
2019-02-15 17:31:08 +01:00
parent c0b2690679
commit 97fdcdc525
11 changed files with 103 additions and 21 deletions

View File

@@ -13,12 +13,16 @@ 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())
censorConfig := report.CensorConfig{
HideCommandLineArguments: r.URL.Query().Get("hideCommandLineArguments") == "true",
HideEnvironmentVariables: r.URL.Query().Get("hideEnvironmentVariables") == "true",
}
rawReport, err := rep.Report(ctx, time.Now())
if err != nil {
respondWith(w, http.StatusInternalServerError, err)
return
}
respondWith(w, http.StatusOK, report)
respondWith(w, http.StatusOK, report.CensorReport(rawReport, censorConfig))
}
}

View File

@@ -5,6 +5,7 @@ import (
"time"
"context"
"github.com/gorilla/mux"
log "github.com/sirupsen/logrus"
@@ -41,17 +42,21 @@ 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) {
var (
hideCommandLineArguments = true
)
respondWith(w, http.StatusOK, APITopology{
Nodes: detailed.Summaries(ctx, rc, render.Render(ctx, rc.Report, renderer, transformer).Nodes),
Nodes: detailed.Summaries(ctx, rc, hideCommandLineArguments, render.Render(ctx, rc.Report, renderer, transformer).Nodes),
})
}
// Individual nodes.
func handleNode(ctx context.Context, renderer render.Renderer, transformer render.Transformer, rc detailed.RenderContext, w http.ResponseWriter, r *http.Request) {
var (
vars = mux.Vars(r)
topologyID = vars["topology"]
nodeID = vars["id"]
vars = mux.Vars(r)
topologyID = vars["topology"]
nodeID = vars["id"]
hideCommandLineArguments = true
)
// We must not lose the node during filtering. We achieve that by
// (1) rendering the report with the base renderer, without
@@ -71,7 +76,7 @@ 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)})
respondWith(w, http.StatusOK, APINode{Node: detailed.MakeNode(topologyID, rc, hideCommandLineArguments, nodes.Nodes, node)})
}
// Websocket for the full topology.
@@ -81,6 +86,9 @@ func handleWebsocket(
w http.ResponseWriter,
r *http.Request,
) {
var (
hideCommandLineArguments = true
)
if err := r.ParseForm(); err != nil {
respondWith(w, http.StatusInternalServerError, err)
return
@@ -145,7 +153,7 @@ 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.Summaries(ctx, RenderContextForReporter(rep, re), hideCommandLineArguments, render.Render(ctx, re, renderer, filter).Nodes)
diff := detailed.TopoDiff(previousTopo, newTopo)
previousTopo = newTopo

View File

@@ -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.

View File

@@ -2,7 +2,6 @@ package process
import (
"strconv"
"strings"
"github.com/weaveworks/common/mtime"
"github.com/weaveworks/scope/report"
@@ -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)
}

View File

@@ -300,7 +300,7 @@ func setupFlags(flags *flags) {
flag.StringVar(&flags.probe.pluginsRoot, "probe.plugins.root", "/var/run/scope/plugins", "Root directory to search for plugins")
flag.BoolVar(&flags.probe.noControls, "probe.no-controls", false, "Disable controls (e.g. start/stop containers, terminals, logs ...)")
flag.BoolVar(&flags.probe.noCommandLineArguments, "probe.omit.cmd-args", false, "Disable collection of command-line arguments")
flag.BoolVar(&flags.probe.noEnvironmentVariables, "probe.omit.env-vars", true, "Disable collection of environment variables")
flag.BoolVar(&flags.probe.noEnvironmentVariables, "probe.omit.env-vars", false, "Disable collection of environment variables")
flag.BoolVar(&flags.probe.insecure, "probe.insecure", false, "(SSL) explicitly allow \"insecure\" SSL connections and transfers")
flag.StringVar(&flags.probe.resolver, "probe.resolver", "", "IP address & port of resolver to use. Default is to use system resolver.")

View File

@@ -86,12 +86,12 @@ type RenderContext struct {
// MakeNode transforms a renderable node to a detailed node. It uses
// aggregate metadata, plus the set of origin node IDs, to produce tables.
func MakeNode(topologyID string, rc RenderContext, ns report.Nodes, n report.Node) Node {
summary, _ := MakeNodeSummary(rc, n)
func MakeNode(topologyID string, rc RenderContext, hideCommandLineArguments bool, ns report.Nodes, n report.Node) Node {
summary, _ := MakeNodeSummary(rc, hideCommandLineArguments, n)
return Node{
NodeSummary: summary,
Controls: controls(rc.Report, n),
Children: children(rc, n),
Children: children(rc, hideCommandLineArguments, n),
Connections: []ConnectionsSummary{
incomingConnectionsSummary(topologyID, rc.Report, n, ns),
outgoingConnectionsSummary(topologyID, rc.Report, n, ns),
@@ -222,13 +222,13 @@ var nodeSummaryGroupSpecs = []struct {
},
}
func children(rc RenderContext, n report.Node) []NodeSummaryGroup {
func children(rc RenderContext, hideCommandLineArguments bool, n report.Node) []NodeSummaryGroup {
summaries := map[string][]NodeSummary{}
n.Children.ForEach(func(child report.Node) {
if child.ID == n.ID {
return
}
summary, ok := MakeNodeSummary(rc, child)
summary, ok := MakeNodeSummary(rc, hideCommandLineArguments, child)
if !ok {
return
}

View File

@@ -19,7 +19,7 @@ import (
)
func child(t *testing.T, r render.Renderer, id string) detailed.NodeSummary {
s, ok := detailed.MakeNodeSummary(detailed.RenderContext{Report: fixture.Report}, r.Render(context.Background(), fixture.Report).Nodes[id])
s, ok := detailed.MakeNodeSummary(detailed.RenderContext{Report: fixture.Report}, false, r.Render(context.Background(), fixture.Report).Nodes[id])
if !ok {
t.Fatalf("Expected node %s to be summarizable, but wasn't", id)
}

View File

@@ -151,7 +151,7 @@ func MakeBasicNodeSummary(r report.Report, n report.Node) (BasicNodeSummary, boo
}
// MakeNodeSummary summarizes a node, if possible.
func MakeNodeSummary(rc RenderContext, n report.Node) (NodeSummary, bool) {
func MakeNodeSummary(rc RenderContext, hideCommandLineArguments bool, n report.Node) (NodeSummary, bool) {
base, ok := MakeBasicNodeSummary(rc.Report, n)
if !ok {
return NodeSummary{}, false
@@ -449,13 +449,13 @@ func (s nodeSummariesByID) Less(i, j int) bool { return s[i].ID < s[j].ID }
type NodeSummaries map[string]NodeSummary
// Summaries converts RenderableNodes into a set of NodeSummaries
func Summaries(ctx context.Context, rc RenderContext, rns report.Nodes) NodeSummaries {
func Summaries(ctx context.Context, rc RenderContext, hideCommandLineArguments bool, rns report.Nodes) NodeSummaries {
span, ctx := opentracing.StartSpanFromContext(ctx, "detailed.Summaries")
defer span.Finish()
result := NodeSummaries{}
for id, node := range rns {
if summary, ok := MakeNodeSummary(rc, node); ok {
if summary, ok := MakeNodeSummary(rc, hideCommandLineArguments, node); ok {
for i, m := range summary.Metrics {
summary.Metrics[i] = m.Summary()
}

55
report/censor.go Normal file
View File

@@ -0,0 +1,55 @@
package report
import "strings"
// import log "github.com/sirupsen/logrus"
type keyMatcher func(string) bool
func keyEquals(fixedKey string) keyMatcher {
return func(key string) bool {
return key == fixedKey
}
}
func keyStartsWith(prefix string) keyMatcher {
return func(key string) bool {
return strings.HasPrefix(key, prefix)
}
}
type censorValueFunc func(string) string
func assignEmpty(key string) string {
return ""
}
func censorTopology(t *Topology, match keyMatcher, censor censorValueFunc) {
for nodeID := range t.Nodes {
for entryID := range t.Nodes[nodeID].Latest {
entry := &t.Nodes[nodeID].Latest[entryID]
if match(entry.key) {
// log.Infof("Blabla ... %s ... %s ... %s", entry.key, entry.Value, censor(entry.Value))
entry.Value = censor(entry.Value)
}
}
}
}
// CensorConfig describe which parts of the report needs to be censored.
type CensorConfig struct {
HideCommandLineArguments bool
HideEnvironmentVariables bool
}
// CensorReport removes any sensitive data from the report.
func CensorReport(r Report, cfg CensorConfig) Report {
if cfg.HideCommandLineArguments {
censorTopology(&r.Process, keyEquals(Cmdline), StripCommandArgs)
censorTopology(&r.Container, keyEquals(DockerContainerCommand), StripCommandArgs)
}
if cfg.HideEnvironmentVariables {
censorTopology(&r.Container, keyStartsWith(DockerEnvPrefix), assignEmpty)
}
return r
}

View File

@@ -43,6 +43,7 @@ const (
DockerContainerUptime = "docker_container_uptime"
DockerContainerRestartCount = "docker_container_restart_count"
DockerContainerNetworkMode = "docker_container_network_mode"
DockerEnvPrefix = "docker_env_"
// probe/kubernetes
KubernetesName = "kubernetes_name"
KubernetesNamespace = "kubernetes_namespace"
@@ -214,3 +215,7 @@ func lookupCommonKey(b []byte) string {
}
return string(b)
}
func isCommandKey(key string) bool {
return key == Cmdline || key == DockerContainerCommand
}

View File

@@ -4,6 +4,8 @@ import (
"sort"
"strconv"
"strings"
log "github.com/sirupsen/logrus"
)
const (
@@ -28,6 +30,11 @@ type MetadataTemplate struct {
From string `json:"from,omitempty"` // Defines how to get the value from a report node
}
// StripCommandArgs removes all the arguments from the command
func StripCommandArgs(command string) string {
return strings.Split(command, " ")[0]
}
// MetadataRow returns the row for a node
func (t MetadataTemplate) MetadataRow(n Node) (MetadataRow, bool) {
from := fromDefault
@@ -96,6 +103,10 @@ func (e MetadataTemplates) MetadataRows(n Node) []MetadataRow {
rows := make([]MetadataRow, 0, len(e))
for _, template := range e {
if row, ok := template.MetadataRow(n); ok {
if isCommandKey(row.ID) {
row.Value = StripCommandArgs(row.Value)
log.Infof("Blublu %s -- %v", n.ID, row)
}
rows = append(rows, row)
}
}