diff --git a/builder/amazon/common/access_config.go b/builder/amazon/common/access_config.go index 94c74121a..23d8dc3b4 100644 --- a/builder/amazon/common/access_config.go +++ b/builder/amazon/common/access_config.go @@ -16,12 +16,19 @@ import ( cleanhttp "github.com/hashicorp/go-cleanhttp" commonhelper "github.com/hashicorp/packer/helper/common" "github.com/hashicorp/packer/template/interpolate" + vaultapi "github.com/hashicorp/vault/api" ) type VaultAWSEngineOptions struct { - Name string `mapstructure:"name"` - RoleARN string `mapstructure:"role_arn"` - TTL string `mapstructure:"ttl"` + Name string `mapstructure:"name"` + RoleARN string `mapstructure:"role_arn"` + TTL string `mapstructure:"ttl"` + EngineName string `mapstructure:"engine_name"` +} + +func (v *VaultAWSEngineOptions) Empty() bool { + return len(v.Name) == 0 && len(v.RoleARN) == 0 && + len(v.EngineName) == 0 && len(v.TTL) == 0 } // AccessConfig is for common configuration related to AWS access @@ -130,26 +137,65 @@ func (c *AccessConfig) IsChinaCloud() bool { return strings.HasPrefix(c.SessionRegion(), "cn-") } +func (c *AccessConfig) GetCredsFromVault() error { + // const EnvVaultAddress = "VAULT_ADDR" + // const EnvVaultToken = "VAULT_TOKEN" + vaultConfig := vaultapi.DefaultConfig() + cli, err := vaultapi.NewClient(vaultConfig) + if err != nil { + return fmt.Errorf("Error getting Vault client: %s", err) + } + path := fmt.Sprintf("/%s/creds/%s", c.VaultAWSEngine.EngineName, + c.VaultAWSEngine.Name) + secret, err := cli.Logical().Read(path) + if err != nil { + return fmt.Errorf("Error reading vault secret: %s", err) + } + if secret == nil { + return fmt.Errorf("Vault Secret does not exist at the given path.") + } + + data, _ := secret.Data["data"] + unpacked := data.(map[string]interface{}) + c.AccessKey = unpacked["access_key"].(string) + c.SecretKey = unpacked["secret_key"].(string) + c.Token = unpacked["security_token"].(string) + + return nil +} + func (c *AccessConfig) Prepare(ctx *interpolate.Context) []error { var errs []error if c.SkipMetadataApiCheck { log.Println("(WARN) skip_metadata_api_check ignored.") } - // Either both access and secret key must be set or neither of them should - // be. - if c.VaultAWSEngine != nil { + + // Make sure it's obvious from the config how we're getting credentials: + // Vault, Packer config, or environemnt. + if !c.VaultAWSEngine.Empty() { if len(c.AccessKey) > 0 { errs = append(errs, fmt.Errorf("If you have set vault_aws_engine, you must not set"+ " the access_key or secret_key.")) } + // Go ahead and grab those credentials from Vault now, so we can set + // the keys and token now. + err := c.GetCredsFromVault() + if err != nil { + errs = append(errs, err) + } } + if (len(c.AccessKey) > 0) != (len(c.SecretKey) > 0) { errs = append(errs, fmt.Errorf("`access_key` and `secret_key` must both be either set or not set.")) } + // abort build early so I can test more quickly + errs = append(errs, + fmt.Errorf("Megan remove this error to continue with build: \n\nAccess: %s, \n\nSecret: %s, \n\nToken: %s", c.AccessKey, c.SecretKey, c.Token)) + return errs }