diff --git a/builder/alicloud/ecs/builder.go b/builder/alicloud/ecs/builder.go index 99d759dc2..176447fd3 100644 --- a/builder/alicloud/ecs/builder.go +++ b/builder/alicloud/ecs/builder.go @@ -67,7 +67,8 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { return nil, errs } - log.Println(common.ScrubConfig(b.config, b.config.AlicloudAccessKey, b.config.AlicloudSecretKey)) + packer.LogSecretFilter.Set(b.config.AlicloudAccessKey, b.config.AlicloudSecretKey) + log.Println(b.config) return nil, nil } diff --git a/builder/amazon/chroot/builder.go b/builder/amazon/chroot/builder.go index 052429e2e..5c5830d17 100644 --- a/builder/amazon/chroot/builder.go +++ b/builder/amazon/chroot/builder.go @@ -176,7 +176,8 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { return warns, errs } - log.Println(common.ScrubConfig(b.config, b.config.AccessKey, b.config.SecretKey, b.config.Token)) + packer.LogSecretFilter.Set(b.config.AccessKey, b.config.SecretKey, b.config.Token) + log.Println(b.config) return warns, nil } diff --git a/builder/amazon/common/step_get_password.go b/builder/amazon/common/step_get_password.go index 8b0d0c74c..997842269 100644 --- a/builder/amazon/common/step_get_password.go +++ b/builder/amazon/common/step_get_password.go @@ -95,7 +95,9 @@ WaitLoop: "Password (since debug is enabled): %s", s.Comm.WinRMPassword)) } // store so that we can access this later during provisioning + commonhelper.SetSharedState("winrm_password", s.Comm.WinRMPassword, s.BuildName) + packer.LogSecretFilter.Set(s.Comm.WinRMPassword) return multistep.ActionContinue } diff --git a/builder/amazon/ebs/builder.go b/builder/amazon/ebs/builder.go index 49185f229..2fd29e87f 100644 --- a/builder/amazon/ebs/builder.go +++ b/builder/amazon/ebs/builder.go @@ -39,7 +39,6 @@ type Builder struct { } func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { - log.Printf("SECRET: matt") b.config.ctx.Funcs = awscommon.TemplateFuncs err := config.Decode(&b.config, &config.DecodeOpts{ Interpolate: true, @@ -82,7 +81,8 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { return nil, errs } - log.Println(common.ScrubConfig(b.config, b.config.AccessKey, b.config.SecretKey, b.config.Token)) + packer.LogSecretFilter.Set(b.config.AccessKey, b.config.SecretKey, b.config.Token) + log.Println(b.config) return nil, nil } @@ -261,7 +261,6 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe // Run! b.runner = common.NewRunner(steps, b.config.PackerConfig, ui) b.runner.Run(state) - // If there was an error, return that if rawErr, ok := state.GetOk("error"); ok { return nil, rawErr.(error) diff --git a/builder/amazon/ebssurrogate/builder.go b/builder/amazon/ebssurrogate/builder.go index e9cc8ad7d..d9d5157a6 100644 --- a/builder/amazon/ebssurrogate/builder.go +++ b/builder/amazon/ebssurrogate/builder.go @@ -96,7 +96,8 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { return nil, errs } - log.Println(common.ScrubConfig(b.config, b.config.AccessKey, b.config.SecretKey, b.config.Token)) + packer.LogSecretFilter.Set(b.config.AccessKey, b.config.SecretKey, b.config.Token) + log.Println(b.config) return nil, nil } diff --git a/builder/amazon/ebsvolume/builder.go b/builder/amazon/ebsvolume/builder.go index 222febc56..8f0711bc3 100644 --- a/builder/amazon/ebsvolume/builder.go +++ b/builder/amazon/ebsvolume/builder.go @@ -81,7 +81,8 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { return nil, errs } - log.Println(common.ScrubConfig(b.config, b.config.AccessKey, b.config.SecretKey, b.config.Token)) + packer.LogSecretFilter.Set(b.config.AccessKey, b.config.SecretKey, b.config.Token) + log.Println(b.config) return nil, nil } diff --git a/builder/amazon/instance/builder.go b/builder/amazon/instance/builder.go index fb59fff95..051546d89 100644 --- a/builder/amazon/instance/builder.go +++ b/builder/amazon/instance/builder.go @@ -166,8 +166,8 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { if errs != nil && len(errs.Errors) > 0 { return nil, errs } - - log.Println(common.ScrubConfig(b.config, b.config.AccessKey, b.config.SecretKey, b.config.Token)) + packer.LogSecretFilter.Set(b.config.AccessKey, b.config.SecretKey, b.config.Token) + log.Println(b.config) return nil, nil } diff --git a/builder/azure/arm/config.go b/builder/azure/arm/config.go index 1abc8d494..a6b6c6edf 100644 --- a/builder/azure/arm/config.go +++ b/builder/azure/arm/config.go @@ -363,6 +363,7 @@ func setRuntimeValues(c *Config) { c.tmpAdminPassword = tempName.AdminPassword // store so that we can access this later during provisioning commonhelper.SetSharedState("winrm_password", c.tmpAdminPassword, c.PackerConfig.PackerBuildName) + packer.LogSecretFilter.Set(c.tmpAdminPassword) c.tmpCertificatePassword = tempName.CertificatePassword if c.TempComputeName == "" { diff --git a/builder/azure/arm/step_save_winrm_password.go b/builder/azure/arm/step_save_winrm_password.go index 700a4b048..3afac5ccf 100644 --- a/builder/azure/arm/step_save_winrm_password.go +++ b/builder/azure/arm/step_save_winrm_password.go @@ -5,6 +5,7 @@ import ( commonhelper "github.com/hashicorp/packer/helper/common" "github.com/hashicorp/packer/helper/multistep" + "github.com/hashicorp/packer/packer" ) type StepSaveWinRMPassword struct { @@ -15,6 +16,7 @@ type StepSaveWinRMPassword struct { func (s *StepSaveWinRMPassword) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { // store so that we can access this later during provisioning commonhelper.SetSharedState("winrm_password", s.Password, s.BuildName) + packer.LogSecretFilter.Set(s.Password) return multistep.ActionContinue } diff --git a/builder/digitalocean/config.go b/builder/digitalocean/config.go index 19c802c4b..451852829 100644 --- a/builder/digitalocean/config.go +++ b/builder/digitalocean/config.go @@ -138,6 +138,6 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { return nil, nil, errs } - common.ScrubConfig(c, c.APIToken) + packer.LogSecretFilter.Set(c.APIToken) return c, nil, nil } diff --git a/builder/googlecompute/step_create_windows_password.go b/builder/googlecompute/step_create_windows_password.go index 38d52d869..2b85aa2ed 100644 --- a/builder/googlecompute/step_create_windows_password.go +++ b/builder/googlecompute/step_create_windows_password.go @@ -33,6 +33,7 @@ func (s *StepCreateWindowsPassword) Run(_ context.Context, state multistep.State if c.Comm.WinRMPassword != "" { state.Put("winrm_password", c.Comm.WinRMPassword) + packer.LogSecretFilter.Set(c.Comm.WinRMPassword) return multistep.ActionContinue } @@ -114,6 +115,7 @@ func (s *StepCreateWindowsPassword) Run(_ context.Context, state multistep.State state.Put("winrm_password", data.password) commonhelper.SetSharedState("winrm_password", data.password, c.PackerConfig.PackerBuildName) + packer.LogSecretFilter.Set(data.password) return multistep.ActionContinue } diff --git a/builder/oneandone/config.go b/builder/oneandone/config.go index ff85bdc6d..f89453439 100644 --- a/builder/oneandone/config.go +++ b/builder/oneandone/config.go @@ -109,7 +109,6 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { if errs != nil && len(errs.Errors) > 0 { return nil, nil, errs } - common.ScrubConfig(c, c.Token) - + packer.LogSecretFilter.Set(c.Token) return &c, nil, nil } diff --git a/builder/openstack/builder.go b/builder/openstack/builder.go index 2938d67c0..9facfbdc4 100644 --- a/builder/openstack/builder.go +++ b/builder/openstack/builder.go @@ -57,7 +57,8 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { b.config.InstanceName = b.config.ImageName } - log.Println(common.ScrubConfig(b.config, b.config.Password)) + packer.LogSecretFilter.Set(b.config.Password) + log.Println(b.config) return nil, nil } diff --git a/builder/oracle/oci/step_get_default_credentials.go b/builder/oracle/oci/step_get_default_credentials.go index b7f6f71e9..1f4ea20b3 100644 --- a/builder/oracle/oci/step_get_default_credentials.go +++ b/builder/oracle/oci/step_get_default_credentials.go @@ -53,7 +53,7 @@ func (s *stepGetDefaultCredentials) Run(ctx context.Context, state multistep.Sta // store so that we can access this later during provisioning commonhelper.SetSharedState("winrm_password", s.Comm.WinRMPassword, s.BuildName) - + packer.LogSecretFilter.Set(s.Comm.WinRMPassword) return multistep.ActionContinue } diff --git a/builder/profitbricks/config.go b/builder/profitbricks/config.go index b38b8583c..f969d87de 100644 --- a/builder/profitbricks/config.go +++ b/builder/profitbricks/config.go @@ -122,7 +122,7 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { if errs != nil && len(errs.Errors) > 0 { return nil, nil, errs } - common.ScrubConfig(c, c.PBUsername) + packer.LogSecretFilter.Set(c.PBUsername) return &c, nil, nil } diff --git a/builder/scaleway/config.go b/builder/scaleway/config.go index 84b5e989e..4d677bcfc 100644 --- a/builder/scaleway/config.go +++ b/builder/scaleway/config.go @@ -119,6 +119,6 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { return nil, nil, errs } - common.ScrubConfig(c, c.Token) + packer.LogSecretFilter.Set(c.Token) return c, nil, nil } diff --git a/command/build.go b/command/build.go index a270bd785..39e761ba5 100644 --- a/command/build.go +++ b/command/build.go @@ -110,7 +110,6 @@ func (c *BuildCommand) Run(args []string) int { log.Printf("Build debug mode: %v", cfgDebug) log.Printf("Force build: %v", cfgForce) log.Printf("On error: %v", cfgOnError) - //log.Printf("my secrets: %v", c.CoreConfig. // Set the debug and force mode and prepare all the builds for _, b := range builds { diff --git a/command/meta.go b/command/meta.go index 4718f3939..b8dfdfbf5 100644 --- a/command/meta.go +++ b/command/meta.go @@ -29,8 +29,6 @@ type Meta struct { Cache packer.Cache Ui packer.Ui Version string - //Secrets []string - //secrets: []string{"matt"}, // These are set by command-line flags flagBuildExcept []string diff --git a/common/config.go b/common/config.go index aa632ceae..2f8b8f1f2 100644 --- a/common/config.go +++ b/common/config.go @@ -20,19 +20,6 @@ const PackerKeyEnv = "PACKER_KEY_INTERVAL" // shorter delay (e.g. 10ms) can be used on a workstation. See PackerKeyEnv. const PackerKeyDefault = 100 * time.Millisecond -// ScrubConfig is a helper that returns a string representation of -// any struct with the given values stripped out. -func ScrubConfig(target interface{}, values ...string) string { - conf := fmt.Sprintf("Config: %+v", target) - for _, value := range values { - if value == "" { - continue - } - conf = strings.Replace(conf, value, "", -1) - } - return conf -} - // ChooseString returns the first non-empty value. func ChooseString(vals ...string) string { for _, el := range vals { diff --git a/common/config_test.go b/common/config_test.go index 8f170fe1d..ab1790064 100644 --- a/common/config_test.go +++ b/common/config_test.go @@ -310,20 +310,3 @@ func TestFileExistsLocally(t *testing.T) { } } } - -func TestScrubConfig(t *testing.T) { - type Inner struct { - Baz string - } - type Local struct { - Foo string - Bar string - Inner - } - c := Local{"foo", "bar", Inner{"bar"}} - expect := "Config: {Foo:foo Bar: Inner:{Baz:}}" - conf := ScrubConfig(c, c.Bar) - if conf != expect { - t.Fatalf("got %s, expected %s", conf, expect) - } -} diff --git a/common/packer_config.go b/common/packer_config.go index 3a14f64b5..dcf77f9fb 100644 --- a/common/packer_config.go +++ b/common/packer_config.go @@ -4,10 +4,11 @@ package common // are sent by packer, properly tagged already so mapstructure can load // them. Embed this structure into your configuration class to get it. type PackerConfig struct { - PackerBuildName string `mapstructure:"packer_build_name"` - PackerBuilderType string `mapstructure:"packer_builder_type"` - PackerDebug bool `mapstructure:"packer_debug"` - PackerForce bool `mapstructure:"packer_force"` - PackerOnError string `mapstructure:"packer_on_error"` - PackerUserVars map[string]string `mapstructure:"packer_user_variables"` + PackerBuildName string `mapstructure:"packer_build_name"` + PackerBuilderType string `mapstructure:"packer_builder_type"` + PackerDebug bool `mapstructure:"packer_debug"` + PackerForce bool `mapstructure:"packer_force"` + PackerOnError string `mapstructure:"packer_on_error"` + PackerUserVars map[string]string `mapstructure:"packer_user_variables"` + PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables"` } diff --git a/common/shell-local/run.go b/common/shell-local/run.go index ede99e30d..c8f6160fc 100644 --- a/common/shell-local/run.go +++ b/common/shell-local/run.go @@ -70,12 +70,7 @@ func Run(ui packer.Ui, config *Config) (bool, error) { // buffers and for reading the final exit status. flattenedCmd := strings.Join(interpolatedCmds, " ") cmd := &packer.RemoteCmd{Command: flattenedCmd} - sanitized := flattenedCmd - if len(getWinRMPassword(config.PackerBuildName)) > 0 { - sanitized = strings.Replace(flattenedCmd, - getWinRMPassword(config.PackerBuildName), "*****", -1) - } - log.Printf("[INFO] (shell-local): starting local command: %s", sanitized) + log.Printf("[INFO] (shell-local): starting local command: %s", flattenedCmd) if err := cmd.StartWithUi(comm, ui); err != nil { return false, fmt.Errorf( "Error executing script: %s\n\n"+ @@ -204,5 +199,6 @@ func createFlattenedEnvVars(config *Config) (string, error) { func getWinRMPassword(buildName string) string { winRMPass, _ := commonhelper.RetrieveSharedState("winrm_password", buildName) + packer.LogSecretFilter.Set(winRMPass) return winRMPass } diff --git a/helper/config/decode.go b/helper/config/decode.go index 8e573dd13..27c1bf0b7 100644 --- a/helper/config/decode.go +++ b/helper/config/decode.go @@ -108,10 +108,11 @@ func Decode(target interface{}, config *DecodeOpts, raws ...interface{}) error { // detecting things like user variables from the raw configuration params. func DetectContext(raws ...interface{}) (*interpolate.Context, error) { var s struct { - BuildName string `mapstructure:"packer_build_name"` - BuildType string `mapstructure:"packer_builder_type"` - TemplatePath string `mapstructure:"packer_template_path"` - Vars map[string]string `mapstructure:"packer_user_variables"` + BuildName string `mapstructure:"packer_build_name"` + BuildType string `mapstructure:"packer_builder_type"` + TemplatePath string `mapstructure:"packer_template_path"` + Vars map[string]string `mapstructure:"packer_user_variables"` + SensitiveVars []string `mapstructure:"packer_sensitive_variables"` } for _, r := range raws { @@ -121,10 +122,11 @@ func DetectContext(raws ...interface{}) (*interpolate.Context, error) { } return &interpolate.Context{ - BuildName: s.BuildName, - BuildType: s.BuildType, - TemplatePath: s.TemplatePath, - UserVariables: s.Vars, + BuildName: s.BuildName, + BuildType: s.BuildType, + TemplatePath: s.TemplatePath, + UserVariables: s.Vars, + SensitiveVariables: s.SensitiveVars, }, nil } diff --git a/packer/core.go b/packer/core.go index 7bdb4f7b5..1aa20b3dd 100644 --- a/packer/core.go +++ b/packer/core.go @@ -25,10 +25,11 @@ type Core struct { // CoreConfig is the structure for initializing a new Core. Once a CoreConfig // is used to initialize a Core, it shouldn't be re-used or modified again. type CoreConfig struct { - Components ComponentFinder - Template *template.Template - Variables map[string]string - Version string + Components ComponentFinder + Template *template.Template + Variables map[string]string + SensitiveVariables []string + Version string } // The function type used to lookup Builder implementations. @@ -61,14 +62,16 @@ func NewCore(c *CoreConfig) (*Core, error) { variables: c.Variables, version: c.Version, } + if err := result.validate(); err != nil { return nil, err } if err := result.init(); err != nil { return nil, err } - LogSecretFilter.Set("matt") - //log.Printf("NewCore: %+v", result.Template.Variables["efoo"]) + for _, secret := range result.secrets { + LogSecretFilter.Set(secret) + } // Go through and interpolate all the build names. We should be able // to do this at this point with the variables. @@ -305,6 +308,16 @@ func (c *Core) init() error { c.variables[k] = def } + for _, v := range c.Template.SensitiveVariables { + def, err := interpolate.Render(v.Default, ctx) + if err != nil { + return fmt.Errorf( + "error interpolating default value for '%s': %s", + v, err) + } + c.secrets = append(c.secrets, def) + } + // Interpolate the push configuration if _, err := interpolate.RenderInterface(&c.Template.Push, c.Context()); err != nil { return fmt.Errorf("Error interpolating 'push': %s", err) diff --git a/packer/logs.go b/packer/logs.go index b5bb07b1c..e510fd069 100644 --- a/packer/logs.go +++ b/packer/logs.go @@ -28,10 +28,11 @@ func (l *secretFilter) SetOutput(output io.Writer) { func (l *secretFilter) Write(p []byte) (n int, err error) { for s := range l.s { - p = bytes.Replace(p, []byte(s), []byte(""), -1) + if s != "" { + p = bytes.Replace(p, []byte(s), []byte(""), -1) + } } return l.w.Write(p) - // return l.w.Write([]byte("foobar")) } func (l *secretFilter) get() (s []string) { diff --git a/post-processor/alicloud-import/post-processor.go b/post-processor/alicloud-import/post-processor.go index 853e97ef1..57344321c 100644 --- a/post-processor/alicloud-import/post-processor.go +++ b/post-processor/alicloud-import/post-processor.go @@ -113,7 +113,8 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { return errs } - log.Println(common.ScrubConfig(p.config, p.config.AlicloudAccessKey, p.config.AlicloudSecretKey)) + packer.LogSecretFilter.Set(p.config.AlicloudAccessKey, p.config.AlicloudSecretKey) + log.Println(p.config) return nil } diff --git a/post-processor/amazon-import/post-processor.go b/post-processor/amazon-import/post-processor.go index e42fb1ae7..c24b2f7ec 100644 --- a/post-processor/amazon-import/post-processor.go +++ b/post-processor/amazon-import/post-processor.go @@ -92,7 +92,8 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { return errs } - log.Println(common.ScrubConfig(p.config, p.config.AccessKey, p.config.SecretKey, p.config.Token)) + packer.LogSecretFilter.Set(p.config.AccessKey, p.config.SecretKey, p.config.Token) + log.Println(p.config) return nil } diff --git a/provisioner/ansible/provisioner.go b/provisioner/ansible/provisioner.go index 99c4d07d9..a7f8a0fde 100644 --- a/provisioner/ansible/provisioner.go +++ b/provisioner/ansible/provisioner.go @@ -555,6 +555,7 @@ func newSigner(privKeyFile string) (*signer, error) { func getWinRMPassword(buildName string) string { winRMPass, _ := commonhelper.RetrieveSharedState("winrm_password", buildName) + packer.LogSecretFilter.Set(winRMPass) return winRMPass } diff --git a/provisioner/powershell/provisioner.go b/provisioner/powershell/provisioner.go index f3600a4c3..0dccf78e7 100644 --- a/provisioner/powershell/provisioner.go +++ b/provisioner/powershell/provisioner.go @@ -481,6 +481,7 @@ func (p *Provisioner) createCommandTextNonPrivileged() (command string, err erro func getWinRMPassword(buildName string) string { winRMPass, _ := commonhelper.RetrieveSharedState("winrm_password", buildName) + packer.LogSecretFilter.Set(winRMPass) return winRMPass } diff --git a/template/interpolate/i.go b/template/interpolate/i.go index 02f56197a..d42d43d50 100644 --- a/template/interpolate/i.go +++ b/template/interpolate/i.go @@ -18,6 +18,9 @@ type Context struct { // "user" function reads from. UserVariables map[string]string + // SensitiveVariables is a list of variables to sanitize. + SensitiveVariables []string + // EnableEnv enables the env function EnableEnv bool diff --git a/template/parse.go b/template/parse.go index ad07729c8..d36cb9dc9 100644 --- a/template/parse.go +++ b/template/parse.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "io/ioutil" + "log" "os" "path/filepath" "sort" @@ -23,11 +24,12 @@ type rawTemplate struct { MinVersion string `mapstructure:"min_packer_version"` Description string - Builders []map[string]interface{} - Push map[string]interface{} - PostProcessors []interface{} `mapstructure:"post-processors"` - Provisioners []map[string]interface{} - Variables map[string]interface{} + Builders []map[string]interface{} + Push map[string]interface{} + PostProcessors []interface{} `mapstructure:"post-processors"` + Provisioners []map[string]interface{} + Variables map[string]interface{} + SensitiveVariables []string `mapstructure:"sensitive-variables"` RawContents []byte } @@ -60,6 +62,12 @@ func (r *rawTemplate) Template() (*Template, error) { continue } + for _, sVar := range r.SensitiveVariables { + if sVar == k { + result.SensitiveVariables = append(result.SensitiveVariables, &v) + } + } + result.Variables[k] = &v } diff --git a/template/template.go b/template/template.go index 389320c77..73bc094e4 100644 --- a/template/template.go +++ b/template/template.go @@ -18,11 +18,12 @@ type Template struct { Description string MinVersion string - Variables map[string]*Variable - Builders map[string]*Builder - Provisioners []*Provisioner - PostProcessors [][]*PostProcessor - Push Push + Variables map[string]*Variable + SensitiveVariables []*Variable + Builders map[string]*Builder + Provisioners []*Provisioner + PostProcessors [][]*PostProcessor + Push Push // RawContents is just the raw data for this template RawContents []byte