Skip to content

Commit

Permalink
add diffMaskRules to mask sensitive fields
Browse files Browse the repository at this point in the history
  • Loading branch information
cppforlife committed Jan 24, 2020
1 parent bcf08b0 commit 9ce675a
Show file tree
Hide file tree
Showing 22 changed files with 398 additions and 72 deletions.
9 changes: 9 additions & 0 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ diffAgainstLastAppliedFieldExclusionRules:
- apiVersionKindMatcher:
apiVersion: apps/v1
kind: Deployment

diffMaskRules:
- path: [data]
resourceMatchers:
- apiVersionKindMatcher:
apiVersion: v1
kind: Secret
```
`rebaseRules` specify origin of field values. Kubernetes cluster generates (or defaults) some field values, hence these values will need to be merged in future to avoid flagging them during diffing. Common example is `v1/Service`'s `spec.clusterIP` field is automatically populated if it's not set. See [HPA and Deployment rebase](hpa-deployment-rebase.md) example.
Expand All @@ -65,6 +72,8 @@ diffAgainstLastAppliedFieldExclusionRules:

`diffAgainstLastAppliedFieldExclusionRules` specify which fields should be removed before diff-ing against last applied resource. These rules are useful for fields are "owned" by the cluster/controllers, and are only later updated. For example `Deployment` resource has an annotation that gets set after a little bit of time after resource is created/updated (not during resource admission). It's typically not necessary to use this configuration.

`diffMaskRules` specify which field values should be masked in diff. By default `v1/Secret`'s `data` fields are masked. Currently only applied to `deploy` command.

### Resource matchers

Resource matchers (as used by `rebaseRules` and `ownershipLabelRules`):
Expand Down
1 change: 1 addition & 0 deletions docs/diff.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Diff changes (line-by-line diffs) are useful for looking at actual changes:

- `--diff-changes=bool` (`-c`) (default `false`) shows line-by-line diffs
- `--diff-context=int` (default `2`) controls number of lines to show around changed lines
- `--diff-mask=bool` (default `true`) controls whether to mask sensitive fields

Controlling how diffing is done:

Expand Down
10 changes: 7 additions & 3 deletions pkg/kapp/clusterapply/change_set_view.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package clusterapply

import (
"github.com/cppforlife/go-cli-ui/ui"
ctlconf "github.com/k14s/kapp/pkg/kapp/config"
ctldiff "github.com/k14s/kapp/pkg/kapp/diff"
)

Expand All @@ -13,19 +14,22 @@ type ChangeSetViewOpts struct {

type ChangeSetView struct {
changeViews []ChangeView
maskRules []ctlconf.DiffMaskRule
opts ChangeSetViewOpts

changesView *ChangesView
}

func NewChangeSetView(changeViews []ChangeView, opts ChangeSetViewOpts) *ChangeSetView {
return &ChangeSetView{changeViews, opts, nil}
func NewChangeSetView(changeViews []ChangeView,
maskRules []ctlconf.DiffMaskRule, opts ChangeSetViewOpts) *ChangeSetView {

return &ChangeSetView{changeViews, maskRules, opts, nil}
}

func (v *ChangeSetView) Print(ui ui.UI) {
if v.opts.Changes {
for _, view := range v.changeViews {
textDiffView := ctldiff.NewTextDiffView(view.TextDiff(), v.opts.TextDiffViewOpts)
textDiffView := ctldiff.NewTextDiffView(view.ConfigurableTextDiff(), v.maskRules, v.opts.TextDiffViewOpts)
ui.BeginLinef("--- %s %s\n", applyOpCodeUI[view.ApplyOp()], view.Resource().Description())
ui.PrintBlock([]byte(textDiffView.String()))
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/kapp/clusterapply/changes_view.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type ChangeView interface {

ApplyOp() ClusterChangeApplyOp
WaitOp() ClusterChangeWaitOp
TextDiff() ctldiff.TextDiff
ConfigurableTextDiff() *ctldiff.ConfigurableTextDiff
}

type ChangesView struct {
Expand Down
4 changes: 3 additions & 1 deletion pkg/kapp/clusterapply/cluster_change.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,9 @@ func (c *ClusterChange) WaitDescription() string {
func (c *ClusterChange) Resource() ctlres.Resource { return c.change.NewOrExistingResource() }
func (c *ClusterChange) ExistingResource() ctlres.Resource { return c.change.ExistingResource() }

func (c *ClusterChange) TextDiff() ctldiff.TextDiff { return c.change.TextDiff() }
func (c *ClusterChange) ConfigurableTextDiff() *ctldiff.ConfigurableTextDiff {
return c.change.ConfigurableTextDiff()
}

func (c *ClusterChange) applyErr(err error) error {
if err == nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/kapp/cmd/app/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ func (o *DeleteOptions) calculateAndPresentChanges(existingResources []ctlres.Re

{ // Present cluster changes in UI
changeViews := ctlcap.ClusterChangesAsChangeViews(clusterChanges)
changeSetView := ctlcap.NewChangeSetView(changeViews, o.DiffFlags.ChangeSetViewOpts)
changeSetView := ctlcap.NewChangeSetView(changeViews, nil, o.DiffFlags.ChangeSetViewOpts)
changeSetView.Print(o.ui)
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/kapp/cmd/app/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ func (o *DeployOptions) calculateAndPresentChanges(existingResources,

{ // Present cluster changes in UI
changeViews := ctlcap.ClusterChangesAsChangeViews(clusterChanges)
changeSetView := ctlcap.NewChangeSetView(changeViews, o.DiffFlags.ChangeSetViewOpts)
changeSetView := ctlcap.NewChangeSetView(changeViews, conf.DiffMaskRules(), o.DiffFlags.ChangeSetViewOpts)
changeSetView.Print(o.ui)
changesSummary = changeSetView.Summary()
}
Expand Down
7 changes: 5 additions & 2 deletions pkg/kapp/cmd/tools/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ func (o *DiffOptions) Run() error {
changeViews = append(changeViews, DiffChangeView{change})
}

ctlcap.NewChangeSetView(changeViews, o.DiffFlags.ChangeSetViewOpts).Print(o.ui)
// TODO support adding custom config for mask rules?
ctlcap.NewChangeSetView(changeViews, nil, o.DiffFlags.ChangeSetViewOpts).Print(o.ui)

return nil
}
Expand Down Expand Up @@ -112,4 +113,6 @@ func (v DiffChangeView) ApplyOp() ctlcap.ClusterChangeApplyOp {
// Since we are diffing changes without a cluster, there will be no wait operations
func (v DiffChangeView) WaitOp() ctlcap.ClusterChangeWaitOp { return ctlcap.ClusterChangeWaitOpNoop }

func (v DiffChangeView) TextDiff() ctldiff.TextDiff { return v.change.TextDiff() }
func (v DiffChangeView) ConfigurableTextDiff() *ctldiff.ConfigurableTextDiff {
return v.change.ConfigurableTextDiff()
}
2 changes: 2 additions & 0 deletions pkg/kapp/cmd/tools/diff_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,7 @@ func (s *DiffFlags) SetWithPrefix(prefix string, cmd *cobra.Command) {
cmd.Flags().BoolVarP(&s.Changes, prefix+"changes", "c", false, "Show changes")

cmd.Flags().IntVar(&s.Context, prefix+"context", 2, "Show number of lines around changed lines")
cmd.Flags().BoolVar(&s.Mask, prefix+"mask", true, "Apply masking rules")

cmd.Flags().BoolVar(&s.AgainstLastApplied, prefix+"against-last-applied", true, "Show changes against last applied copy when possible")
}
8 changes: 8 additions & 0 deletions pkg/kapp/config/conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,14 @@ func (c Conf) TemplateRules() []TemplateRule {
return result
}

func (c Conf) DiffMaskRules() []DiffMaskRule {
var result []DiffMaskRule
for _, config := range c.configs {
result = append(result, config.DiffMaskRules...)
}
return result
}

func (c Conf) AdditionalLabels() map[string]string {
result := map[string]string{}
for _, config := range c.configs {
Expand Down
6 changes: 6 additions & 0 deletions pkg/kapp/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type Config struct {
OwnershipLabelRules []OwnershipLabelRule
LabelScopingRules []LabelScopingRule
TemplateRules []TemplateRule
DiffMaskRules []DiffMaskRule

AdditionalLabels map[string]string
DiffAgainstLastAppliedFieldExclusionRules []DiffAgainstLastAppliedFieldExclusionRule
Expand Down Expand Up @@ -52,6 +53,11 @@ type TemplateRule struct {
AffectedResources TemplateAffectedResources
}

type DiffMaskRule struct {
ResourceMatchers []ResourceMatcher
Path ctlres.Path
}

type TemplateAffectedResources struct {
ObjectReferences []TemplateAffectedObjRef
// TODO support label injections?
Expand Down
5 changes: 5 additions & 0 deletions pkg/kapp/config/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ diffAgainstLastAppliedFieldExclusionRules:
- path: [metadata, annotations, "deployment.kubernetes.io/revision"]
resourceMatchers: *builtinAppsDeploymentWithRevAnnKey
diffMaskRules:
- path: [data]
resourceMatchers:
- apiVersionKindMatcher: {apiVersion: v1, kind: Secret}
ownershipLabelRules:
- path: [metadata, labels]
resourceMatchers:
Expand Down
47 changes: 8 additions & 39 deletions pkg/kapp/diff/change.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package diff

import (
"strings"

"github.com/cppforlife/go-patch/patch"
ctlres "github.com/k14s/kapp/pkg/kapp/resources"
"gopkg.in/yaml.v2"
Expand All @@ -28,7 +26,7 @@ type Change interface {
AppliedResource() ctlres.Resource

Op() ChangeOp
TextDiff() TextDiff
ConfigurableTextDiff() *ConfigurableTextDiff
OpsDiff() OpsDiff

IsIgnored() bool
Expand All @@ -40,8 +38,8 @@ type ChangeImpl struct {
// appliedRes is an unmodified copy of what's being applied
appliedRes ctlres.Resource

textDiff *TextDiff
opsDiff *OpsDiff
configurableTextDiff *ConfigurableTextDiff
opsDiff *OpsDiff
}

var _ Change = &ChangeImpl{}
Expand Down Expand Up @@ -87,7 +85,7 @@ func (d *ChangeImpl) Op() ChangeOp {
return ChangeOpDelete
}

if d.TextDiff().HasChanges() {
if d.ConfigurableTextDiff().Full().HasChanges() {
return ChangeOpUpdate
}

Expand All @@ -100,16 +98,12 @@ func (d *ChangeImpl) isIgnoredTransient() bool {
return d.existingRes != nil && d.newRes == nil && d.existingRes.Transient()
}

func (d *ChangeImpl) TextDiff() TextDiff {
func (d *ChangeImpl) ConfigurableTextDiff() *ConfigurableTextDiff {
// diff is called very often, so memoize
if d.textDiff != nil {
return *d.textDiff
if d.configurableTextDiff == nil {
d.configurableTextDiff = NewConfigurableTextDiff(d.existingRes, d.newRes, d.IsIgnored())
}

textDiff := d.calculateTextDiff()
d.textDiff = &textDiff

return *d.textDiff
return d.configurableTextDiff
}

func (d *ChangeImpl) OpsDiff() OpsDiff {
Expand All @@ -123,31 +117,6 @@ func (d *ChangeImpl) OpsDiff() OpsDiff {
return *d.opsDiff
}

func (d *ChangeImpl) calculateTextDiff() TextDiff {
existingLines := []string{}
newLines := []string{}

if d.existingRes != nil {
existingBytes, err := d.existingRes.AsYAMLBytes()
if err != nil {
panic("yamling existingRes") // TODO panic
}
existingLines = strings.Split(string(existingBytes), "\n")
}

if d.newRes != nil {
newBytes, err := d.newRes.AsYAMLBytes()
if err != nil {
panic("yamling newRes") // TODO panic
}
newLines = strings.Split(string(newBytes), "\n")
} else if d.IsIgnored() {
newLines = existingLines // show as no changes
}

return NewTextDiff(existingLines, newLines)
}

func (d *ChangeImpl) calculateOpsDiff() OpsDiff {
var existingObj interface{}
var newObj interface{}
Expand Down
14 changes: 8 additions & 6 deletions pkg/kapp/diff/change_precalculated.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ type ChangePrecalculated struct {
// appliedRes is an unmodified copy of what's being applied
appliedRes ctlres.Resource

op ChangeOp
textDiff TextDiff
opsDiff OpsDiff
op ChangeOp
configurableTextDiff *ConfigurableTextDiff
opsDiff OpsDiff
}

var _ Change = &ChangePrecalculated{}
Expand Down Expand Up @@ -49,8 +49,10 @@ func (d *ChangePrecalculated) NewResource() ctlres.Resource { return d.newR
func (d *ChangePrecalculated) ExistingResource() ctlres.Resource { return d.existingRes }
func (d *ChangePrecalculated) AppliedResource() ctlres.Resource { return d.appliedRes }

func (d *ChangePrecalculated) Op() ChangeOp { return d.op }
func (d *ChangePrecalculated) TextDiff() TextDiff { return d.textDiff }
func (d *ChangePrecalculated) OpsDiff() OpsDiff { return d.opsDiff }
func (d *ChangePrecalculated) Op() ChangeOp { return d.op }
func (d *ChangePrecalculated) ConfigurableTextDiff() *ConfigurableTextDiff {
return d.configurableTextDiff
}
func (d *ChangePrecalculated) OpsDiff() OpsDiff { return d.opsDiff }

func (d *ChangePrecalculated) IsIgnored() bool { return false }
8 changes: 4 additions & 4 deletions pkg/kapp/diff/change_set_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ metadata:
t.Fatalf("Expected non-err")
}

actualDiff := changes[0].TextDiff().FullString()
actualDiff := changes[0].ConfigurableTextDiff().Full().FullString()

expectedDiff := strings.Replace(` 0, 0 metadata:
1, 1 annotations:
Expand Down Expand Up @@ -115,7 +115,7 @@ metadata:
t.Fatalf("Expected non-err")
}

actualDiff := changes[0].TextDiff().FullString()
actualDiff := changes[0].ConfigurableTextDiff().Full().FullString()

expectedDiff := strings.Replace(` 0, 0 metadata:
1, 1 annotations:
Expand Down Expand Up @@ -187,7 +187,7 @@ metadata:
t.Fatalf("Expected non-err")
}

actualDiff := changes[0].TextDiff().FullString()
actualDiff := changes[0].ConfigurableTextDiff().Full().FullString()

expectedDiff := strings.Replace(` 0, 0 metadata:
1, 1 annotations:
Expand Down Expand Up @@ -263,7 +263,7 @@ metadata:
t.Fatalf("Expected non-err")
}

actualDiff := changes[0].TextDiff().FullString()
actualDiff := changes[0].ConfigurableTextDiff().Full().FullString()

expectedDiff := strings.Replace(` 0, 0 metadata:
1, 1 annotations:
Expand Down
2 changes: 1 addition & 1 deletion pkg/kapp/diff/change_set_with_templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ func (d ChangeSetWithTemplates) newAddChangeFromUpdateChange(
addChange := NewChangePrecalculated(nil, newRes, newRes)
// TODO private field access
addChange.op = ChangeOpAdd
addChange.textDiff = updateChange.TextDiff()
addChange.configurableTextDiff = updateChange.ConfigurableTextDiff()
addChange.opsDiff = updateChange.OpsDiff()
return addChange
}
Expand Down
Loading

0 comments on commit 9ce675a

Please sign in to comment.