Merge pull request #6787 from hashicorp/nilable_encrypt
amazon: Nilable encrypt setting
This commit is contained in:
commit
d3ed89ab86
|
@ -273,12 +273,6 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||||
EnableAMISriovNetSupport: b.config.AMISriovNetSupport,
|
EnableAMISriovNetSupport: b.config.AMISriovNetSupport,
|
||||||
EnableAMIENASupport: b.config.AMIENASupport,
|
EnableAMIENASupport: b.config.AMIENASupport,
|
||||||
},
|
},
|
||||||
&awscommon.StepCreateEncryptedAMICopy{
|
|
||||||
KeyID: b.config.AMIKmsKeyId,
|
|
||||||
EncryptBootVolume: b.config.AMIEncryptBootVolume,
|
|
||||||
Name: b.config.AMIName,
|
|
||||||
AMIMappings: b.config.AMIBlockDevices.AMIMappings,
|
|
||||||
},
|
|
||||||
&awscommon.StepAMIRegionCopy{
|
&awscommon.StepAMIRegionCopy{
|
||||||
AccessConfig: &b.config.AccessConfig,
|
AccessConfig: &b.config.AccessConfig,
|
||||||
Regions: b.config.AMIRegions,
|
Regions: b.config.AMIRegions,
|
||||||
|
|
|
@ -23,7 +23,7 @@ type AMIConfig struct {
|
||||||
AMISriovNetSupport bool `mapstructure:"sriov_support"`
|
AMISriovNetSupport bool `mapstructure:"sriov_support"`
|
||||||
AMIForceDeregister bool `mapstructure:"force_deregister"`
|
AMIForceDeregister bool `mapstructure:"force_deregister"`
|
||||||
AMIForceDeleteSnapshot bool `mapstructure:"force_delete_snapshot"`
|
AMIForceDeleteSnapshot bool `mapstructure:"force_delete_snapshot"`
|
||||||
AMIEncryptBootVolume bool `mapstructure:"encrypt_boot"`
|
AMIEncryptBootVolume *bool `mapstructure:"encrypt_boot"`
|
||||||
AMIKmsKeyId string `mapstructure:"kms_key_id"`
|
AMIKmsKeyId string `mapstructure:"kms_key_id"`
|
||||||
AMIRegionKMSKeyIDs map[string]string `mapstructure:"region_kms_key_ids"`
|
AMIRegionKMSKeyIDs map[string]string `mapstructure:"region_kms_key_ids"`
|
||||||
SnapshotTags TagMap `mapstructure:"snapshot_tags"`
|
SnapshotTags TagMap `mapstructure:"snapshot_tags"`
|
||||||
|
@ -59,7 +59,7 @@ func (c *AMIConfig) Prepare(accessConfig *AccessConfig, ctx *interpolate.Context
|
||||||
|
|
||||||
errs = append(errs, c.prepareRegions(accessConfig)...)
|
errs = append(errs, c.prepareRegions(accessConfig)...)
|
||||||
|
|
||||||
if len(c.AMIUsers) > 0 && c.AMIEncryptBootVolume {
|
if len(c.AMIUsers) > 0 && c.AMIEncryptBootVolume != nil && *c.AMIEncryptBootVolume {
|
||||||
errs = append(errs, fmt.Errorf("Cannot share AMI with encrypted boot volume"))
|
errs = append(errs, fmt.Errorf("Cannot share AMI with encrypted boot volume"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ func (c *AMIConfig) Prepare(accessConfig *AccessConfig, ctx *interpolate.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(c.SnapshotUsers) > 0 {
|
if len(c.SnapshotUsers) > 0 {
|
||||||
if len(c.AMIKmsKeyId) == 0 && c.AMIEncryptBootVolume {
|
if len(c.AMIKmsKeyId) == 0 && c.AMIEncryptBootVolume != nil && *c.AMIEncryptBootVolume {
|
||||||
errs = append(errs, fmt.Errorf("Cannot share snapshot encrypted with default KMS key"))
|
errs = append(errs, fmt.Errorf("Cannot share snapshot encrypted with default KMS key"))
|
||||||
}
|
}
|
||||||
if len(c.AMIRegionKMSKeyIDs) > 0 {
|
if len(c.AMIRegionKMSKeyIDs) > 0 {
|
||||||
|
|
|
@ -138,7 +138,7 @@ func TestAMIConfigPrepare_regions(t *testing.T) {
|
||||||
|
|
||||||
c.SnapshotUsers = []string{"foo", "bar"}
|
c.SnapshotUsers = []string{"foo", "bar"}
|
||||||
c.AMIKmsKeyId = "123-abc-456"
|
c.AMIKmsKeyId = "123-abc-456"
|
||||||
c.AMIEncryptBootVolume = true
|
c.AMIEncryptBootVolume = &[]bool{true}[0]
|
||||||
c.AMIRegions = []string{"us-east-1", "us-west-1"}
|
c.AMIRegions = []string{"us-east-1", "us-west-1"}
|
||||||
c.AMIRegionKMSKeyIDs = map[string]string{
|
c.AMIRegionKMSKeyIDs = map[string]string{
|
||||||
"us-east-1": "123-456-7890",
|
"us-east-1": "123-456-7890",
|
||||||
|
@ -161,7 +161,7 @@ func TestAMIConfigPrepare_regions(t *testing.T) {
|
||||||
func TestAMIConfigPrepare_Share_EncryptedBoot(t *testing.T) {
|
func TestAMIConfigPrepare_Share_EncryptedBoot(t *testing.T) {
|
||||||
c := testAMIConfig()
|
c := testAMIConfig()
|
||||||
c.AMIUsers = []string{"testAccountID"}
|
c.AMIUsers = []string{"testAccountID"}
|
||||||
c.AMIEncryptBootVolume = true
|
c.AMIEncryptBootVolume = &[]bool{true}[0]
|
||||||
|
|
||||||
accessConf := testAccessConfig()
|
accessConf := testAccessConfig()
|
||||||
|
|
||||||
|
@ -178,7 +178,7 @@ func TestAMIConfigPrepare_Share_EncryptedBoot(t *testing.T) {
|
||||||
|
|
||||||
func TestAMIConfigPrepare_ValidateKmsKey(t *testing.T) {
|
func TestAMIConfigPrepare_ValidateKmsKey(t *testing.T) {
|
||||||
c := testAMIConfig()
|
c := testAMIConfig()
|
||||||
c.AMIEncryptBootVolume = true
|
c.AMIEncryptBootVolume = aws.Bool(true)
|
||||||
|
|
||||||
accessConf := testAccessConfig()
|
accessConf := testAccessConfig()
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
type BlockDevice struct {
|
type BlockDevice struct {
|
||||||
DeleteOnTermination bool `mapstructure:"delete_on_termination"`
|
DeleteOnTermination bool `mapstructure:"delete_on_termination"`
|
||||||
DeviceName string `mapstructure:"device_name"`
|
DeviceName string `mapstructure:"device_name"`
|
||||||
Encrypted bool `mapstructure:"encrypted"`
|
Encrypted *bool `mapstructure:"encrypted"`
|
||||||
IOPS int64 `mapstructure:"iops"`
|
IOPS int64 `mapstructure:"iops"`
|
||||||
NoDevice bool `mapstructure:"no_device"`
|
NoDevice bool `mapstructure:"no_device"`
|
||||||
SnapshotId string `mapstructure:"snapshot_id"`
|
SnapshotId string `mapstructure:"snapshot_id"`
|
||||||
|
@ -71,9 +71,8 @@ func buildBlockDevices(b []BlockDevice) []*ec2.BlockDeviceMapping {
|
||||||
// You cannot specify Encrypted if you specify a Snapshot ID
|
// You cannot specify Encrypted if you specify a Snapshot ID
|
||||||
if blockDevice.SnapshotId != "" {
|
if blockDevice.SnapshotId != "" {
|
||||||
ebsBlockDevice.SnapshotId = aws.String(blockDevice.SnapshotId)
|
ebsBlockDevice.SnapshotId = aws.String(blockDevice.SnapshotId)
|
||||||
} else if blockDevice.Encrypted {
|
|
||||||
ebsBlockDevice.Encrypted = aws.Bool(blockDevice.Encrypted)
|
|
||||||
}
|
}
|
||||||
|
ebsBlockDevice.Encrypted = blockDevice.Encrypted
|
||||||
|
|
||||||
if blockDevice.KmsKeyId != "" {
|
if blockDevice.KmsKeyId != "" {
|
||||||
ebsBlockDevice.KmsKeyId = aws.String(blockDevice.KmsKeyId)
|
ebsBlockDevice.KmsKeyId = aws.String(blockDevice.KmsKeyId)
|
||||||
|
@ -93,7 +92,7 @@ func (b *BlockDevice) Prepare(ctx *interpolate.Context) error {
|
||||||
"for every device in the block device mapping.")
|
"for every device in the block device mapping.")
|
||||||
}
|
}
|
||||||
// Warn that encrypted must be true when setting kms_key_id
|
// Warn that encrypted must be true when setting kms_key_id
|
||||||
if b.KmsKeyId != "" && b.Encrypted == false {
|
if b.KmsKeyId != "" && b.Encrypted != nil && *b.Encrypted == false {
|
||||||
return fmt.Errorf("The device %v, must also have `encrypted: "+
|
return fmt.Errorf("The device %v, must also have `encrypted: "+
|
||||||
"true` when setting a kms_key_id.", b.DeviceName)
|
"true` when setting a kms_key_id.", b.DeviceName)
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ func TestBlockDevice(t *testing.T) {
|
||||||
VolumeType: "gp2",
|
VolumeType: "gp2",
|
||||||
VolumeSize: 8,
|
VolumeSize: 8,
|
||||||
DeleteOnTermination: true,
|
DeleteOnTermination: true,
|
||||||
Encrypted: true,
|
Encrypted: aws.Bool(true),
|
||||||
},
|
},
|
||||||
|
|
||||||
Result: &ec2.BlockDeviceMapping{
|
Result: &ec2.BlockDeviceMapping{
|
||||||
|
@ -90,7 +90,7 @@ func TestBlockDevice(t *testing.T) {
|
||||||
VolumeType: "gp2",
|
VolumeType: "gp2",
|
||||||
VolumeSize: 8,
|
VolumeSize: 8,
|
||||||
DeleteOnTermination: true,
|
DeleteOnTermination: true,
|
||||||
Encrypted: true,
|
Encrypted: aws.Bool(true),
|
||||||
KmsKeyId: "2Fa48a521f-3aff-4b34-a159-376ac5d37812",
|
KmsKeyId: "2Fa48a521f-3aff-4b34-a159-376ac5d37812",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,10 @@ func listEC2Regions(ec2conn ec2iface.EC2API) ([]string, error) {
|
||||||
return regions, nil
|
return regions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateRegion returns true if the supplied region is a valid AWS
|
// ValidateRegion returns an nil if the regions are valid
|
||||||
// region and false if it's not.
|
// and exists; otherwise an error.
|
||||||
|
// ValidateRegion calls ec2conn.DescribeRegions to get the list of
|
||||||
|
// regions available to this account.
|
||||||
func (c *AccessConfig) ValidateRegion(regions ...string) error {
|
func (c *AccessConfig) ValidateRegion(regions ...string) error {
|
||||||
ec2conn, err := c.NewEC2Connection()
|
ec2conn, err := c.NewEC2Connection()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -50,7 +52,7 @@ func (c *AccessConfig) ValidateRegion(regions ...string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(invalidRegions) > 0 {
|
if len(invalidRegions) > 0 {
|
||||||
return fmt.Errorf("Invalid region(s): %v", invalidRegions)
|
return fmt.Errorf("Invalid region(s): %v, available regions: %v", invalidRegions, validRegions)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ type StepAMIRegionCopy struct {
|
||||||
AccessConfig *AccessConfig
|
AccessConfig *AccessConfig
|
||||||
Regions []string
|
Regions []string
|
||||||
RegionKeyIds map[string]string
|
RegionKeyIds map[string]string
|
||||||
EncryptBootVolume bool
|
EncryptBootVolume *bool // nil means preserve
|
||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,13 @@ func (s *StepAMIRegionCopy) Run(ctx context.Context, state multistep.StateBag) m
|
||||||
snapshots := state.Get("snapshots").(map[string][]string)
|
snapshots := state.Get("snapshots").(map[string][]string)
|
||||||
ami := amis[*ec2conn.Config.Region]
|
ami := amis[*ec2conn.Config.Region]
|
||||||
|
|
||||||
|
if s.EncryptBootVolume != nil {
|
||||||
|
// encrypt_boot was set, we now have to copy the temporary
|
||||||
|
// AMI with required encryption setting.
|
||||||
|
// temp image was created by stepCreateAMI.
|
||||||
|
s.Regions = append(s.Regions, *ec2conn.Config.Region)
|
||||||
|
}
|
||||||
|
|
||||||
if len(s.Regions) == 0 {
|
if len(s.Regions) == 0 {
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
}
|
}
|
||||||
|
@ -37,23 +44,24 @@ func (s *StepAMIRegionCopy) Run(ctx context.Context, state multistep.StateBag) m
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
var regKeyID string
|
var regKeyID string
|
||||||
errs := new(packer.MultiError)
|
errs := new(packer.MultiError)
|
||||||
|
|
||||||
|
wg.Add(len(s.Regions))
|
||||||
for _, region := range s.Regions {
|
for _, region := range s.Regions {
|
||||||
if region == *ec2conn.Config.Region {
|
if region == *ec2conn.Config.Region && s.EncryptBootVolume == nil {
|
||||||
ui.Message(fmt.Sprintf(
|
ui.Message(fmt.Sprintf(
|
||||||
"Avoiding copying AMI to duplicate region %s", region))
|
"Avoiding copying AMI to duplicate region %s", region))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Add(1)
|
|
||||||
ui.Message(fmt.Sprintf("Copying to: %s", region))
|
ui.Message(fmt.Sprintf("Copying to: %s", region))
|
||||||
|
|
||||||
if s.EncryptBootVolume {
|
if s.EncryptBootVolume != nil && *s.EncryptBootVolume {
|
||||||
regKeyID = s.RegionKeyIds[region]
|
regKeyID = s.RegionKeyIds[region]
|
||||||
}
|
}
|
||||||
|
|
||||||
go func(region string) {
|
go func(region string) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
id, snapshotIds, err := amiRegionCopy(ctx, state, s.AccessConfig, s.Name, ami, region, *ec2conn.Config.Region, regKeyID)
|
id, snapshotIds, err := amiRegionCopy(ctx, state, s.AccessConfig, s.Name, ami, region, *ec2conn.Config.Region, regKeyID, s.EncryptBootVolume)
|
||||||
lock.Lock()
|
lock.Lock()
|
||||||
defer lock.Unlock()
|
defer lock.Unlock()
|
||||||
amis[region] = id
|
amis[region] = id
|
||||||
|
@ -85,20 +93,16 @@ func (s *StepAMIRegionCopy) Cleanup(state multistep.StateBag) {
|
||||||
|
|
||||||
// amiRegionCopy does a copy for the given AMI to the target region and
|
// amiRegionCopy does a copy for the given AMI to the target region and
|
||||||
// returns the resulting ID and snapshot IDs, or error.
|
// returns the resulting ID and snapshot IDs, or error.
|
||||||
func amiRegionCopy(ctx context.Context, state multistep.StateBag, config *AccessConfig, name string, imageId string,
|
func amiRegionCopy(ctx context.Context, state multistep.StateBag, config *AccessConfig, name, imageId,
|
||||||
target string, source string, keyID string) (string, []string, error) {
|
target, source, keyId string, encrypt *bool) (string, []string, error) {
|
||||||
snapshotIds := []string{}
|
snapshotIds := []string{}
|
||||||
isEncrypted := false
|
|
||||||
|
|
||||||
// Connect to the region where the AMI will be copied to
|
// Connect to the region where the AMI will be copied to
|
||||||
session, err := config.Session()
|
session, err := config.Session()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", snapshotIds, err
|
return "", snapshotIds, err
|
||||||
}
|
}
|
||||||
// if we've provided a map of key ids to regions, use those keys.
|
|
||||||
if len(keyID) > 0 {
|
|
||||||
isEncrypted = true
|
|
||||||
}
|
|
||||||
regionconn := ec2.New(session.Copy(&aws.Config{
|
regionconn := ec2.New(session.Copy(&aws.Config{
|
||||||
Region: aws.String(target),
|
Region: aws.String(target),
|
||||||
HTTPClient: commonhelper.HttpClientWithEnvironmentProxy(),
|
HTTPClient: commonhelper.HttpClientWithEnvironmentProxy(),
|
||||||
|
@ -108,8 +112,8 @@ func amiRegionCopy(ctx context.Context, state multistep.StateBag, config *Access
|
||||||
SourceRegion: &source,
|
SourceRegion: &source,
|
||||||
SourceImageId: &imageId,
|
SourceImageId: &imageId,
|
||||||
Name: &name,
|
Name: &name,
|
||||||
Encrypted: aws.Bool(isEncrypted),
|
Encrypted: encrypt,
|
||||||
KmsKeyId: aws.String(keyID),
|
KmsKeyId: aws.String(keyId),
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -27,7 +27,7 @@ func (s *StepDeregisterAMI) Run(_ context.Context, state multistep.StateBag) mul
|
||||||
|
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||||
// Add the session region to list of regions will will deregister AMIs in
|
// Add the session region to list of regions will deregister AMIs in
|
||||||
regions := append(s.Regions, *ec2conn.Config.Region)
|
regions := append(s.Regions, *ec2conn.Config.Region)
|
||||||
|
|
||||||
for _, region := range regions {
|
for _, region := range regions {
|
||||||
|
|
|
@ -1,178 +0,0 @@
|
||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
|
||||||
"github.com/aws/aws-sdk-go/service/ec2"
|
|
||||||
"github.com/hashicorp/packer/helper/multistep"
|
|
||||||
"github.com/hashicorp/packer/packer"
|
|
||||||
)
|
|
||||||
|
|
||||||
type StepCreateEncryptedAMICopy struct {
|
|
||||||
image *ec2.Image
|
|
||||||
KeyID string
|
|
||||||
EncryptBootVolume bool
|
|
||||||
Name string
|
|
||||||
AMIMappings []BlockDevice
|
|
||||||
ToDelete []*string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StepCreateEncryptedAMICopy) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
|
||||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
|
||||||
ui := state.Get("ui").(packer.Ui)
|
|
||||||
kmsKeyId := s.KeyID
|
|
||||||
|
|
||||||
// Encrypt boot not set, so skip step
|
|
||||||
if !s.EncryptBootVolume {
|
|
||||||
if kmsKeyId != "" {
|
|
||||||
log.Printf("Ignoring KMS Key ID: %s, encrypted=false", kmsKeyId)
|
|
||||||
}
|
|
||||||
return multistep.ActionContinue
|
|
||||||
}
|
|
||||||
|
|
||||||
ui.Say("Creating Encrypted AMI Copy")
|
|
||||||
|
|
||||||
amis := state.Get("amis").(map[string]string)
|
|
||||||
var region, id string
|
|
||||||
if amis != nil {
|
|
||||||
for region, id = range amis {
|
|
||||||
break // There is only ever one region:ami pair in this map
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ui.Say(fmt.Sprintf("Copying AMI: %s(%s)", region, id))
|
|
||||||
|
|
||||||
if kmsKeyId != "" {
|
|
||||||
ui.Say(fmt.Sprintf("Encrypting with KMS Key ID: %s", kmsKeyId))
|
|
||||||
}
|
|
||||||
|
|
||||||
copyOpts := &ec2.CopyImageInput{
|
|
||||||
Name: &s.Name, // Try to overwrite existing AMI
|
|
||||||
SourceImageId: aws.String(id),
|
|
||||||
SourceRegion: aws.String(region),
|
|
||||||
Encrypted: aws.Bool(true),
|
|
||||||
KmsKeyId: aws.String(kmsKeyId),
|
|
||||||
}
|
|
||||||
|
|
||||||
copyResp, err := ec2conn.CopyImage(copyOpts)
|
|
||||||
if err != nil {
|
|
||||||
err := fmt.Errorf("Error copying AMI: %s", err)
|
|
||||||
state.Put("error", err)
|
|
||||||
ui.Error(err.Error())
|
|
||||||
return multistep.ActionHalt
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for the copy to become ready
|
|
||||||
ui.Say("Waiting for AMI copy to become ready...")
|
|
||||||
if err := WaitUntilAMIAvailable(ctx, ec2conn, *copyResp.ImageId); err != nil {
|
|
||||||
err := fmt.Errorf("Error waiting for AMI Copy: %s", err)
|
|
||||||
state.Put("error", err)
|
|
||||||
ui.Error(err.Error())
|
|
||||||
return multistep.ActionHalt
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the encrypted AMI image, we need the new snapshot id's
|
|
||||||
encImagesResp, err := ec2conn.DescribeImages(&ec2.DescribeImagesInput{ImageIds: []*string{aws.String(*copyResp.ImageId)}})
|
|
||||||
if err != nil {
|
|
||||||
err := fmt.Errorf("Error searching for AMI: %s", err)
|
|
||||||
state.Put("error", err)
|
|
||||||
ui.Error(err.Error())
|
|
||||||
return multistep.ActionHalt
|
|
||||||
}
|
|
||||||
encImage := encImagesResp.Images[0]
|
|
||||||
var encSnapshots []string
|
|
||||||
for _, blockDevice := range encImage.BlockDeviceMappings {
|
|
||||||
if blockDevice.Ebs != nil && blockDevice.Ebs.SnapshotId != nil {
|
|
||||||
encSnapshots = append(encSnapshots, *blockDevice.Ebs.SnapshotId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the unencrypted AMI image
|
|
||||||
unencImagesResp, err := ec2conn.DescribeImages(&ec2.DescribeImagesInput{ImageIds: []*string{aws.String(id)}})
|
|
||||||
if err != nil {
|
|
||||||
err := fmt.Errorf("Error searching for AMI: %s", err)
|
|
||||||
state.Put("error", err)
|
|
||||||
ui.Error(err.Error())
|
|
||||||
return multistep.ActionHalt
|
|
||||||
}
|
|
||||||
unencImage := unencImagesResp.Images[0]
|
|
||||||
|
|
||||||
// Remove unencrypted AMI
|
|
||||||
ui.Say("Deregistering unencrypted AMI")
|
|
||||||
deregisterOpts := &ec2.DeregisterImageInput{ImageId: aws.String(id)}
|
|
||||||
if _, err := ec2conn.DeregisterImage(deregisterOpts); err != nil {
|
|
||||||
ui.Error(fmt.Sprintf("Error deregistering AMI, may still be around: %s", err))
|
|
||||||
return multistep.ActionHalt
|
|
||||||
}
|
|
||||||
|
|
||||||
// Figure out which unencrypted snapshot(s) to delete
|
|
||||||
snapshots := state.Get("snapshots").(map[string][]string)
|
|
||||||
|
|
||||||
OuterLoop:
|
|
||||||
for _, blockDevice := range unencImage.BlockDeviceMappings {
|
|
||||||
if blockDevice.Ebs != nil && blockDevice.Ebs.SnapshotId != nil {
|
|
||||||
// If this packer run didn't create it, then don't delete it
|
|
||||||
for _, origDevice := range s.AMIMappings {
|
|
||||||
if origDevice.SnapshotId == *blockDevice.Ebs.SnapshotId {
|
|
||||||
ui.Message(fmt.Sprintf("Keeping Snapshot ID: %s", *blockDevice.Ebs.SnapshotId))
|
|
||||||
continue OuterLoop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s.ToDelete = append(s.ToDelete, aws.String(*blockDevice.Ebs.SnapshotId))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace original AMI ID with Encrypted ID in state
|
|
||||||
amis[region] = *copyResp.ImageId
|
|
||||||
snapshots[region] = encSnapshots
|
|
||||||
state.Put("amis", amis)
|
|
||||||
state.Put("snapshots", snapshots)
|
|
||||||
|
|
||||||
imagesResp, err := ec2conn.DescribeImages(&ec2.DescribeImagesInput{ImageIds: []*string{copyResp.ImageId}})
|
|
||||||
if err != nil {
|
|
||||||
err := fmt.Errorf("Error searching for AMI: %s", err)
|
|
||||||
state.Put("error", err)
|
|
||||||
ui.Error(err.Error())
|
|
||||||
return multistep.ActionHalt
|
|
||||||
}
|
|
||||||
s.image = imagesResp.Images[0]
|
|
||||||
|
|
||||||
return multistep.ActionContinue
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StepCreateEncryptedAMICopy) Cleanup(state multistep.StateBag) {
|
|
||||||
if s.image == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_, cancelled := state.GetOk(multistep.StateCancelled)
|
|
||||||
_, halted := state.GetOk(multistep.StateHalted)
|
|
||||||
if !cancelled && !halted {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
|
||||||
ui := state.Get("ui").(packer.Ui)
|
|
||||||
|
|
||||||
ui.Say("Deregistering the AMI because cancellation or error...")
|
|
||||||
deregisterOpts := &ec2.DeregisterImageInput{ImageId: s.image.ImageId}
|
|
||||||
if _, err := ec2conn.DeregisterImage(deregisterOpts); err != nil {
|
|
||||||
ui.Error(fmt.Sprintf("Error deregistering AMI, may still be around: %s", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ui.Say("Deleting unencrypted snapshots")
|
|
||||||
for _, snap := range s.ToDelete {
|
|
||||||
ui.Message(fmt.Sprintf("Deleting Snapshot ID: %s", *snap))
|
|
||||||
deleteSnapOpts := &ec2.DeleteSnapshotInput{
|
|
||||||
SnapshotId: snap,
|
|
||||||
}
|
|
||||||
if _, err := ec2conn.DeleteSnapshot(deleteSnapOpts); err != nil {
|
|
||||||
ui.Error(fmt.Sprintf("Error deleting snapshot, may still be around: %s", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -223,12 +223,6 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||||
Regions: b.config.AMIRegions,
|
Regions: b.config.AMIRegions,
|
||||||
},
|
},
|
||||||
&stepCreateAMI{},
|
&stepCreateAMI{},
|
||||||
&awscommon.StepCreateEncryptedAMICopy{
|
|
||||||
KeyID: b.config.AMIKmsKeyId,
|
|
||||||
EncryptBootVolume: b.config.AMIEncryptBootVolume,
|
|
||||||
Name: b.config.AMIName,
|
|
||||||
AMIMappings: b.config.AMIBlockDevices.AMIMappings,
|
|
||||||
},
|
|
||||||
&awscommon.StepAMIRegionCopy{
|
&awscommon.StepAMIRegionCopy{
|
||||||
AccessConfig: &b.config.AccessConfig,
|
AccessConfig: &b.config.AccessConfig,
|
||||||
Regions: b.config.AMIRegions,
|
Regions: b.config.AMIRegions,
|
||||||
|
|
|
@ -24,13 +24,13 @@ func (s *stepCreateAMI) Run(ctx context.Context, state multistep.StateBag) multi
|
||||||
|
|
||||||
// Create the image
|
// Create the image
|
||||||
amiName := config.AMIName
|
amiName := config.AMIName
|
||||||
if config.AMIEncryptBootVolume {
|
if config.AMIEncryptBootVolume != nil {
|
||||||
// to avoid having a temporary unencrypted
|
// encrypt_boot was set, so we will create a temporary image
|
||||||
// image named config.AMIName
|
// and then create a copy of it with the correct encrypt_boot
|
||||||
amiName = random.AlphaNum(7)
|
amiName = random.AlphaNum(7)
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.Say(fmt.Sprintf("Creating unencrypted AMI %s from instance %s", amiName, *instance.InstanceId))
|
ui.Say(fmt.Sprintf("Creating AMI %s from instance %s", amiName, *instance.InstanceId))
|
||||||
createOpts := &ec2.CreateImageInput{
|
createOpts := &ec2.CreateImageInput{
|
||||||
InstanceId: instance.InstanceId,
|
InstanceId: instance.InstanceId,
|
||||||
Name: &amiName,
|
Name: &amiName,
|
||||||
|
@ -94,17 +94,19 @@ func (s *stepCreateAMI) Cleanup(state multistep.StateBag) {
|
||||||
if s.image == nil {
|
if s.image == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
|
||||||
_, cancelled := state.GetOk(multistep.StateCancelled)
|
_, cancelled := state.GetOk(multistep.StateCancelled)
|
||||||
_, halted := state.GetOk(multistep.StateHalted)
|
_, halted := state.GetOk(multistep.StateHalted)
|
||||||
if !cancelled && !halted {
|
encryptBootSet := config.AMIEncryptBootVolume != nil
|
||||||
|
if !cancelled && !halted && !encryptBootSet {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
|
||||||
ui.Say("Deregistering the AMI because cancellation or error...")
|
ui.Say("Deregistering the AMI because cancellation, error or it was temporary (encrypt_boot was set)...")
|
||||||
deregisterOpts := &ec2.DeregisterImageInput{ImageId: s.image.ImageId}
|
deregisterOpts := &ec2.DeregisterImageInput{ImageId: s.image.ImageId}
|
||||||
if _, err := ec2conn.DeregisterImage(deregisterOpts); err != nil {
|
if _, err := ec2conn.DeregisterImage(deregisterOpts); err != nil {
|
||||||
ui.Error(fmt.Sprintf("Error deregistering AMI, may still be around: %s", err))
|
ui.Error(fmt.Sprintf("Error deregistering AMI, may still be around: %s", err))
|
||||||
|
|
|
@ -249,11 +249,6 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||||
EnableAMISriovNetSupport: b.config.AMISriovNetSupport,
|
EnableAMISriovNetSupport: b.config.AMISriovNetSupport,
|
||||||
EnableAMIENASupport: b.config.AMIENASupport,
|
EnableAMIENASupport: b.config.AMIENASupport,
|
||||||
},
|
},
|
||||||
&awscommon.StepCreateEncryptedAMICopy{
|
|
||||||
KeyID: b.config.AMIKmsKeyId,
|
|
||||||
EncryptBootVolume: b.config.AMIEncryptBootVolume,
|
|
||||||
Name: b.config.AMIName,
|
|
||||||
},
|
|
||||||
&awscommon.StepAMIRegionCopy{
|
&awscommon.StepAMIRegionCopy{
|
||||||
AccessConfig: &b.config.AccessConfig,
|
AccessConfig: &b.config.AccessConfig,
|
||||||
Regions: b.config.AMIRegions,
|
Regions: b.config.AMIRegions,
|
||||||
|
|
|
@ -141,11 +141,10 @@ each category, the available configuration keys are alphabetized.
|
||||||
documentation on enabling enhanced
|
documentation on enabling enhanced
|
||||||
networking](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking.html#enabling_enhanced_networking).
|
networking](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking.html#enabling_enhanced_networking).
|
||||||
|
|
||||||
- `encrypt_boot` (boolean) - Instruct packer to automatically create a copy
|
- `encrypt_boot` (boolean) - Whether or not to encrypt the resulting AMI when
|
||||||
of the AMI with an encrypted boot volume (discarding the initial
|
copying a provisioned instance to an AMI. By default, Packer will keep the
|
||||||
unencrypted AMI in the process). Packer will always run this operation,
|
encryption setting to what it was in the source image. Setting `false` will
|
||||||
even if the base AMI has an encrypted boot volume to start with. Default
|
result in an unencrypted image, and `true` will result in an encrypted one.
|
||||||
`false`.
|
|
||||||
|
|
||||||
- `force_deregister` (boolean) - Force Packer to first deregister an existing
|
- `force_deregister` (boolean) - Force Packer to first deregister an existing
|
||||||
AMI if one with the same name already exists. Default `false`.
|
AMI if one with the same name already exists. Default `false`.
|
||||||
|
@ -187,6 +186,9 @@ each category, the available configuration keys are alphabetized.
|
||||||
device mapping.
|
device mapping.
|
||||||
|
|
||||||
- `encrypted` (boolean) - Indicates whether or not to encrypt the volume.
|
- `encrypted` (boolean) - Indicates whether or not to encrypt the volume.
|
||||||
|
By default, Packer will keep the encryption setting to what it was in
|
||||||
|
the source image. Setting `false` will result in an unencrypted device,
|
||||||
|
and `true` will result in an encrypted one.
|
||||||
|
|
||||||
- `kms_key_id` (string) - The ARN for the KMS encryption key. When
|
- `kms_key_id` (string) - The ARN for the KMS encryption key. When
|
||||||
specifying `kms_key_id`, `encrypted` needs to be set to `true`. For
|
specifying `kms_key_id`, `encrypted` needs to be set to `true`. For
|
||||||
|
|
|
@ -91,7 +91,10 @@ builder.
|
||||||
example, `/dev/sdh` or `xvdh`). Required for every device in the block
|
example, `/dev/sdh` or `xvdh`). Required for every device in the block
|
||||||
device mapping.
|
device mapping.
|
||||||
|
|
||||||
- `encrypted` (boolean) - Indicates whether to encrypt the volume or not
|
- `encrypted` (boolean) - Indicates whether or not to encrypt the volume.
|
||||||
|
By default, Packer will keep the encryption setting to what it was in
|
||||||
|
the source image. Setting `false` will result in an unencrypted device,
|
||||||
|
and `true` will result in an encrypted one.
|
||||||
|
|
||||||
- `iops` (number) - The number of I/O operations per second (IOPS) that
|
- `iops` (number) - The number of I/O operations per second (IOPS) that
|
||||||
the volume supports. See the documentation on
|
the volume supports. See the documentation on
|
||||||
|
@ -220,18 +223,16 @@ builder.
|
||||||
Attempting to do so will cause an error.
|
Attempting to do so will cause an error.
|
||||||
|
|
||||||
!> **Warning!** Additional costs may be incurred by enabling T2
|
!> **Warning!** Additional costs may be incurred by enabling T2
|
||||||
Unlimited - even for instances that would usually qualify for the [AWS Free
|
Unlimited - even for instances that would usually qualify for the
|
||||||
Tier](https://aws.amazon.com/free/).
|
[AWS Free Tier](https://aws.amazon.com/free/).
|
||||||
|
|
||||||
- `encrypt_boot` (boolean) - Instruct packer to automatically create a copy
|
- `encrypt_boot` (boolean) - Whether or not to encrypt the resulting AMI when
|
||||||
of the AMI with an encrypted boot volume (discarding the initial
|
copying a provisioned instance to an AMI. By default, Packer will keep the
|
||||||
unencrypted AMI in the process). Packer will always run this operation,
|
encryption setting to what it was in the source image. Setting `false` will
|
||||||
even if the base AMI has an encrypted boot volume to start with. Default
|
result in an unencrypted image, and `true` will result in an encrypted one.
|
||||||
`false`.
|
|
||||||
|
- `force_delete_snapshot` (boolean) - Force Packer to delete snapshots associated with
|
||||||
- `force_delete_snapshot` (boolean) - Force Packer to delete snapshots
|
AMIs, which have been deregistered by `force_deregister`. Default `false`.
|
||||||
associated with AMIs, which have been deregistered by `force_deregister`.
|
|
||||||
Default `false`.
|
|
||||||
|
|
||||||
- `force_deregister` (boolean) - Force Packer to first deregister an existing
|
- `force_deregister` (boolean) - Force Packer to first deregister an existing
|
||||||
AMI if one with the same name already exists. Default `false`.
|
AMI if one with the same name already exists. Default `false`.
|
||||||
|
|
|
@ -81,6 +81,9 @@ builder.
|
||||||
device mapping.
|
device mapping.
|
||||||
|
|
||||||
- `encrypted` (boolean) - Indicates whether or not to encrypt the volume.
|
- `encrypted` (boolean) - Indicates whether or not to encrypt the volume.
|
||||||
|
By default, Packer will keep the encryption setting to what it was in
|
||||||
|
the source image. Setting `false` will result in an unencrypted device,
|
||||||
|
and `true` will result in an encrypted one.
|
||||||
|
|
||||||
- `iops` (number) - The number of I/O operations per second (IOPS) that
|
- `iops` (number) - The number of I/O operations per second (IOPS) that
|
||||||
the volume supports. See the documentation on
|
the volume supports. See the documentation on
|
||||||
|
@ -212,11 +215,10 @@ builder.
|
||||||
Unlimited - even for instances that would usually qualify for the [AWS Free
|
Unlimited - even for instances that would usually qualify for the [AWS Free
|
||||||
Tier](https://aws.amazon.com/free/).
|
Tier](https://aws.amazon.com/free/).
|
||||||
|
|
||||||
- `encrypt_boot` (boolean) - Instruct packer to automatically create a copy
|
- `encrypt_boot` (boolean) - Whether or not to encrypt the resulting AMI when
|
||||||
of the AMI with an encrypted boot volume (discarding the initial
|
copying a provisioned instance to an AMI. By default, Packer will keep the
|
||||||
unencrypted AMI in the process). Packer will always run this operation,
|
encryption setting to what it was in the source image. Setting `false` will
|
||||||
even if the base AMI has an encrypted boot volume to start with. Default
|
result in an unencrypted image, and `true` will result in an encrypted one.
|
||||||
`false`.
|
|
||||||
|
|
||||||
- `force_deregister` (boolean) - Force Packer to first deregister an existing
|
- `force_deregister` (boolean) - Force Packer to first deregister an existing
|
||||||
AMI if one with the same name already exists. Default `false`.
|
AMI if one with the same name already exists. Default `false`.
|
||||||
|
|
|
@ -69,7 +69,10 @@ builder.
|
||||||
- `delete_on_termination` (boolean) - Indicates whether the EBS volume is
|
- `delete_on_termination` (boolean) - Indicates whether the EBS volume is
|
||||||
deleted on instance termination.
|
deleted on instance termination.
|
||||||
|
|
||||||
- `encrypted` (boolean) - Indicates whether to encrypt the volume or not
|
- `encrypted` (boolean) - Indicates whether or not to encrypt the volume.
|
||||||
|
By default, Packer will keep the encryption setting to what it was in
|
||||||
|
the source image. Setting `false` will result in an unencrypted device,
|
||||||
|
and `true` will result in an encrypted one.
|
||||||
|
|
||||||
- `kms_key_id` (string) - The ARN for the KMS encryption key. When
|
- `kms_key_id` (string) - The ARN for the KMS encryption key. When
|
||||||
specifying `kms_key_id`, `encrypted` needs to be set to `true`. For
|
specifying `kms_key_id`, `encrypted` needs to be set to `true`. For
|
||||||
|
|
|
@ -110,7 +110,10 @@ builder.
|
||||||
example, `/dev/sdh` or `xvdh`). Required for every device in the block
|
example, `/dev/sdh` or `xvdh`). Required for every device in the block
|
||||||
device mapping.
|
device mapping.
|
||||||
|
|
||||||
- `encrypted` (boolean) - Indicates whether to encrypt the volume or not
|
- `encrypted` (boolean) - Indicates whether or not to encrypt the volume.
|
||||||
|
By default, Packer will keep the encryption setting to what it was in
|
||||||
|
the source image. Setting `false` will result in an unencrypted device,
|
||||||
|
and `true` will result in an encrypted one.
|
||||||
|
|
||||||
- `iops` (number) - The number of I/O operations per second (IOPS) that
|
- `iops` (number) - The number of I/O operations per second (IOPS) that
|
||||||
the volume supports. See the documentation on
|
the volume supports. See the documentation on
|
||||||
|
|
Loading…
Reference in New Issue