diff --git a/post-processor/amazon-import/post-processor.go b/post-processor/amazon-import/post-processor.go index 58e91c9e8..2fbab390d 100644 --- a/post-processor/amazon-import/post-processor.go +++ b/post-processor/amazon-import/post-processor.go @@ -25,17 +25,21 @@ type Config struct { awscommon.AccessConfig `mapstructure:",squash"` // Variables specific to this post processor - S3Bucket string `mapstructure:"s3_bucket_name"` - S3Key string `mapstructure:"s3_key_name"` - SkipClean bool `mapstructure:"skip_clean"` - Tags map[string]string `mapstructure:"tags"` - Name string `mapstructure:"ami_name"` - Description string `mapstructure:"ami_description"` - Users []string `mapstructure:"ami_users"` - Groups []string `mapstructure:"ami_groups"` - LicenseType string `mapstructure:"license_type"` - RoleName string `mapstructure:"role_name"` - Format string `mapstructure:"format"` + S3Bucket string `mapstructure:"s3_bucket_name"` + S3Key string `mapstructure:"s3_key_name"` + S3Encryption string `mapstructure:"s3_encryption"` + S3EncryptionKey string `mapstructure:"s3_encryption_key"` + SkipClean bool `mapstructure:"skip_clean"` + Tags map[string]string `mapstructure:"tags"` + Name string `mapstructure:"ami_name"` + Description string `mapstructure:"ami_description"` + Users []string `mapstructure:"ami_users"` + Groups []string `mapstructure:"ami_groups"` + Encrypt bool `mapstructure:"ami_encrypt"` + KMSKey string `mapstructure:"ami_kms_key"` + LicenseType string `mapstructure:"license_type"` + RoleName string `mapstructure:"role_name"` + Format string `mapstructure:"format"` ctx interpolate.Context } @@ -99,6 +103,11 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { errs, fmt.Errorf("invalid format '%s'. Only 'ova', 'raw', 'vhd', 'vhdx', or 'vmdk' are allowed", p.config.Format)) } + if p.config.S3Encryption != "" && p.config.S3Encryption != "AES256" && p.config.S3Encryption != "aws:kms" { + errs = packer.MultiErrorAppend( + errs, fmt.Errorf("invalid s3 encryption format '%s'. Only 'AES256' and 'aws:kms' are allowed", p.config.S3Encryption)) + } + // Anything which flagged return back up the stack if len(errs.Errors) > 0 { return errs @@ -141,6 +150,10 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac return nil, false, fmt.Errorf("No %s image file found in artifact from builder", p.config.Format) } + if p.config.S3Encryption == "AES256" && p.config.S3EncryptionKey != "" { + ui.Message(fmt.Sprintf("Ignoring s3_encryption_key because s3_encryption is set to '%s'", p.config.S3Encryption)) + } + // open the source file log.Printf("Opening file %s to upload", source) file, err := os.Open(source) @@ -150,14 +163,24 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac ui.Message(fmt.Sprintf("Uploading %s to s3://%s/%s", source, p.config.S3Bucket, p.config.S3Key)) - // Copy the image file into the S3 bucket specified - uploader := s3manager.NewUploader(session) - _, err = uploader.Upload(&s3manager.UploadInput{ + // Prepare S3 request + updata := &s3manager.UploadInput{ Body: file, Bucket: &p.config.S3Bucket, Key: &p.config.S3Key, - }) - if err != nil { + } + + // Add encryption if specified in the config + if p.config.S3Encryption != "" { + updata.ServerSideEncryption = &p.config.S3Encryption + if p.config.S3Encryption == "aws:kms" && p.config.S3EncryptionKey != "" { + updata.SSEKMSKeyId = &p.config.S3EncryptionKey + } + } + + // Copy the image file into the S3 bucket specified + uploader := s3manager.NewUploader(session) + if _, err = uploader.Upload(updata); err != nil { return nil, false, fmt.Errorf("Failed to upload %s: %s", source, err) } @@ -171,6 +194,7 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac ec2conn := ec2.New(session) params := &ec2.ImportImageInput{ + Encrypted: &p.config.Encrypt, DiskContainers: []*ec2.ImageDiskContainer{ { Format: &p.config.Format, @@ -182,6 +206,10 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac }, } + if p.config.Encrypt && p.config.KMSKey != "" { + params.KmsKeyId = &p.config.KMSKey + } + if p.config.RoleName != "" { params.SetRoleName(p.config.RoleName) } diff --git a/website/source/docs/post-processors/amazon-import.html.md b/website/source/docs/post-processors/amazon-import.html.md index 34b6c01a7..95bb10958 100644 --- a/website/source/docs/post-processors/amazon-import.html.md +++ b/website/source/docs/post-processors/amazon-import.html.md @@ -67,11 +67,19 @@ Optional: imported AMI. By default this description is generated by the AMI import process. +- `ami_encrypt` (boolean) - Encrypt the resulting AMI using KMS. This defaults + to `false`. + - `ami_groups` (array of strings) - A list of groups that have access to launch the imported AMI. By default no groups have permission to launch the AMI. `all` will make the AMI publicly accessible. AWS currently doesn't accept any value other than "all". +- `ami_kms_key` (string) - The ID of the KMS key used to encrypt the AMI + if `ami_encrypt` is true. If set, the role specified in `role_name` must + be granted access to use this key. If not set, the account default KMS key + will be used. + - `ami_name` (string) - The name of the ami within the console. If not specified, this will default to something like `ami-import-sfwerwf`. Please note, specifying this option will result in a slightly longer execution @@ -112,6 +120,18 @@ Optional: - `role_name` (string) - The name of the role to use when not using the default role, 'vmimport' +- `s3_encryption` (string) - One of: `aws:kms`, or `AES256`. The algorithm + used to encrypt the artifact in S3. This **does not** encrypt the + resulting AMI, and is only used to encrypt the uploaded artifact before + it becomes an AMI. By default no encryption is used. + +- `s3_encryption_key` (string) - The KMS key ID to use when `aws:kms` is + specified in `s3_encryption`. This setting is ignored if AES is used + as Amazon does not currently support custom AES keys when using the VM + import service. If set, the role specified in `role_name` must be granted + access to use this key. If not set, and `s3_encryption` is set to `aws:kms`, + the account default KMS key will be used. + - `s3_key_name` (string) - The name of the key in `s3_bucket_name` where the OVA file will be copied to for import. If not specified, this will default to "packer-import-{{timestamp}}.ova". This key (i.e., the uploaded OVA)