adding support for root volume encryption for amazon-chroot
This commit is contained in:
parent
72c1912b60
commit
504c3807f7
|
@ -10,11 +10,14 @@ package chroot
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"runtime"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/hashicorp/hcl/v2/hcldec"
|
||||
awscommon "github.com/hashicorp/packer/builder/amazon/common"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/hashicorp/packer/packer-plugin-sdk/chroot"
|
||||
"github.com/hashicorp/packer/packer-plugin-sdk/common"
|
||||
"github.com/hashicorp/packer/packer-plugin-sdk/multistep"
|
||||
|
@ -169,6 +172,26 @@ type Config struct {
|
|||
// [`dynamic_block`](/docs/configuration/from-1.5/expressions#dynamic-blocks)
|
||||
// will allow you to create those programatically.
|
||||
RootVolumeTag config.KeyValues `mapstructure:"root_volume_tag" required:"false"`
|
||||
// Whether or not to encrypt the volumes that are *launched*. By default, Packer will keep
|
||||
// the encryption setting to what it was in the source image when set to `false`. Setting true will
|
||||
// always result in an encrypted one.
|
||||
RootVolumeEncryptBoot config.Trilean `mapstructure:"root_volume_encrypt_boot" required:"false"`
|
||||
// ID, alias or ARN of the KMS key to use for *launched* volumes encryption.
|
||||
//
|
||||
// Set this value if you select `root_volume_encrypt_boot`, but don't want to use the
|
||||
// region's default KMS key.
|
||||
//
|
||||
// If you have a custom kms key you'd like to apply to the launch volume,
|
||||
// and are only building in one region, it is more efficient to set this
|
||||
// and `root_volume_encrypt_boot` to `true` and not use `encrypt_boot` and `kms_key_id`. This saves
|
||||
// potentially many minutes at the end of the build by preventing Packer
|
||||
// from having to copy and re-encrypt the image at the end of the build.
|
||||
//
|
||||
// For valid formats see *KmsKeyId* in the [AWS API docs -
|
||||
// CopyImage](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CopyImage.html).
|
||||
// This field is validated by Packer, when using an alias, you will have to
|
||||
// prefix `kms_key_id` with `alias/`.
|
||||
RootVolumeKmsKeyId string `mapstructure:"root_volume_kms_key_id" required:"false"`
|
||||
// what architecture to use when registering the final AMI; valid options
|
||||
// are "x86_64" or "arm64". Defaults to "x86_64".
|
||||
Architecture string `mapstructure:"ami_architecture" required:"false"`
|
||||
|
@ -322,6 +345,17 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
|
|||
errs = packersdk.MultiErrorAppend(
|
||||
errs, errors.New("If root_device_name is specified, ami_block_device_mappings must be specified"))
|
||||
}
|
||||
|
||||
if b.config.RootVolumeKmsKeyId != "" {
|
||||
if b.config.RootVolumeEncryptBoot.False() {
|
||||
errs = packer.MultiErrorAppend(
|
||||
errs, errors.New("If you have set root_kms_key_id, root_encrypt_boot must also be true."))
|
||||
} else if b.config.RootVolumeEncryptBoot.True() && !validateKmsKey(b.config.RootVolumeKmsKeyId) {
|
||||
errs = packer.MultiErrorAppend(
|
||||
errs, fmt.Errorf("%q is not a valid KMS Key Id.", b.config.RootVolumeKmsKeyId))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
valid := false
|
||||
for _, validArch := range []string{"x86_64", "arm64"} {
|
||||
|
@ -406,6 +440,8 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
|
|||
RootVolumeType: b.config.RootVolumeType,
|
||||
RootVolumeSize: b.config.RootVolumeSize,
|
||||
RootVolumeTags: b.config.RootVolumeTags,
|
||||
RootVolumeEncryptBoot: b.config.RootVolumeEncryptBoot,
|
||||
RootVolumeKmsKeyId: b.config.RootVolumeKmsKeyId,
|
||||
Ctx: b.config.ctx,
|
||||
},
|
||||
&StepAttachVolume{
|
||||
|
@ -501,3 +537,22 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
|
|||
|
||||
return artifact, nil
|
||||
}
|
||||
|
||||
func validateKmsKey(kmsKey string) (valid bool) {
|
||||
kmsKeyIdPattern := `[a-f0-9-]+$`
|
||||
aliasPattern := `alias/[a-zA-Z0-9:/_-]+$`
|
||||
kmsArnStartPattern := `^arn:aws(-us-gov)?:kms:([a-z]{2}-(gov-)?[a-z]+-\d{1})?:(\d{12}):`
|
||||
if regexp.MustCompile(fmt.Sprintf("^%s", kmsKeyIdPattern)).MatchString(kmsKey) {
|
||||
return true
|
||||
}
|
||||
if regexp.MustCompile(fmt.Sprintf("^%s", aliasPattern)).MatchString(kmsKey) {
|
||||
return true
|
||||
}
|
||||
if regexp.MustCompile(fmt.Sprintf("%skey/%s", kmsArnStartPattern, kmsKeyIdPattern)).MatchString(kmsKey) {
|
||||
return true
|
||||
}
|
||||
if regexp.MustCompile(fmt.Sprintf("%s%s", kmsArnStartPattern, aliasPattern)).MatchString(kmsKey) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -76,6 +76,8 @@ type FlatConfig struct {
|
|||
SourceAmiFilter *common.FlatAmiFilterOptions `mapstructure:"source_ami_filter" required:"false" cty:"source_ami_filter" hcl:"source_ami_filter"`
|
||||
RootVolumeTags map[string]string `mapstructure:"root_volume_tags" required:"false" cty:"root_volume_tags" hcl:"root_volume_tags"`
|
||||
RootVolumeTag []config.FlatKeyValue `mapstructure:"root_volume_tag" required:"false" cty:"root_volume_tag" hcl:"root_volume_tag"`
|
||||
RootVolumeEncryptBoot *bool `mapstructure:"root_volume_encrypt_boot" required:"false" cty:"root_volume_encrypt_boot" hcl:"root_volume_encrypt_boot"`
|
||||
RootVolumeKmsKeyId *string `mapstructure:"root_volume_kms_key_id" required:"false" cty:"root_volume_kms_key_id" hcl:"root_volume_kms_key_id"`
|
||||
Architecture *string `mapstructure:"ami_architecture" required:"false" cty:"ami_architecture" hcl:"ami_architecture"`
|
||||
}
|
||||
|
||||
|
@ -155,7 +157,13 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
|||
"source_ami": &hcldec.AttrSpec{Name: "source_ami", Type: cty.String, Required: false},
|
||||
"source_ami_filter": &hcldec.BlockSpec{TypeName: "source_ami_filter", Nested: hcldec.ObjectSpec((*common.FlatAmiFilterOptions)(nil).HCL2Spec())},
|
||||
"root_volume_tags": &hcldec.AttrSpec{Name: "root_volume_tags", Type: cty.Map(cty.String), Required: false},
|
||||
<<<<<<< HEAD
|
||||
"root_volume_tag": &hcldec.BlockListSpec{TypeName: "root_volume_tag", Nested: hcldec.ObjectSpec((*config.FlatKeyValue)(nil).HCL2Spec())},
|
||||
=======
|
||||
"root_volume_tag": &hcldec.BlockListSpec{TypeName: "root_volume_tag", Nested: hcldec.ObjectSpec((*hcl2template.FlatKeyValue)(nil).HCL2Spec())},
|
||||
"root_volume_encrypt_boot": &hcldec.AttrSpec{Name: "root_volume_encrypt_boot", Type: cty.Bool, Required: false},
|
||||
"root_volume_kms_key_id": &hcldec.AttrSpec{Name: "root_volume_kms_key_id", Type: cty.String, Required: false},
|
||||
>>>>>>> d2717fdcb (adding support for root volume encryption for amazon-chroot)
|
||||
"ami_architecture": &hcldec.AttrSpec{Name: "ami_architecture", Type: cty.String, Required: false},
|
||||
}
|
||||
return s
|
||||
|
|
|
@ -9,9 +9,12 @@ import (
|
|||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
awscommon "github.com/hashicorp/packer/builder/amazon/common"
|
||||
"github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer/packer-plugin-sdk/template/interpolate"
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
// StepCreateVolume creates a new volume from the snapshot of the root
|
||||
|
@ -25,6 +28,8 @@ type StepCreateVolume struct {
|
|||
RootVolumeSize int64
|
||||
RootVolumeType string
|
||||
RootVolumeTags map[string]string
|
||||
RootVolumeEncryptBoot config.Trilean
|
||||
RootVolumeKmsKeyId string
|
||||
Ctx interpolate.Context
|
||||
}
|
||||
|
||||
|
@ -148,11 +153,21 @@ func (s *StepCreateVolume) buildCreateVolumeInput(az string, rootDevice *ec2.Blo
|
|||
SnapshotId: rootDevice.Ebs.SnapshotId,
|
||||
VolumeType: rootDevice.Ebs.VolumeType,
|
||||
Iops: rootDevice.Ebs.Iops,
|
||||
Encrypted: rootDevice.Ebs.Encrypted,
|
||||
KmsKeyId: rootDevice.Ebs.KmsKeyId,
|
||||
}
|
||||
if s.RootVolumeSize > *rootDevice.Ebs.VolumeSize {
|
||||
createVolumeInput.Size = aws.Int64(s.RootVolumeSize)
|
||||
}
|
||||
|
||||
if s.RootVolumeEncryptBoot.True() {
|
||||
createVolumeInput.Encrypted = aws.Bool(true)
|
||||
}
|
||||
|
||||
if s.RootVolumeKmsKeyId != "" {
|
||||
createVolumeInput.KmsKeyId = aws.String(s.RootVolumeKmsKeyId)
|
||||
}
|
||||
|
||||
if s.RootVolumeType == "" || s.RootVolumeType == *rootDevice.Ebs.VolumeType {
|
||||
return createVolumeInput, nil
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
confighelper "github.com/hashicorp/packer/helper/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
@ -14,6 +15,7 @@ func buildTestRootDevice() *ec2.BlockDeviceMapping {
|
|||
VolumeSize: aws.Int64(10),
|
||||
SnapshotId: aws.String("snap-1234"),
|
||||
VolumeType: aws.String("gp2"),
|
||||
Encrypted: aws.Bool(false),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -72,3 +74,24 @@ func TestCreateVolume_gp2_to_io1(t *testing.T) {
|
|||
_, err := stepCreateVolume.buildCreateVolumeInput("test-az", testRootDevice)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestCreateVolume_Encrypted(t *testing.T) {
|
||||
stepCreateVolume := StepCreateVolume{RootVolumeEncryptBoot: confighelper.TrileanFromBool(true)}
|
||||
testRootDevice := buildTestRootDevice()
|
||||
ret, err := stepCreateVolume.buildCreateVolumeInput("test-az", testRootDevice)
|
||||
assert.NoError(t, err)
|
||||
// Ensure that the new value is equal to the the value passed in
|
||||
assert.Equal(t, confighelper.TrileanFromBool(*ret.Encrypted), stepCreateVolume.RootVolumeEncryptBoot)
|
||||
}
|
||||
|
||||
func TestCreateVolume_Custom_KMS_Key_Encrypted(t *testing.T) {
|
||||
stepCreateVolume := StepCreateVolume{
|
||||
RootVolumeEncryptBoot: confighelper.TrileanFromBool(true),
|
||||
RootVolumeKmsKeyId: "alias/1234",
|
||||
}
|
||||
testRootDevice := buildTestRootDevice()
|
||||
ret, err := stepCreateVolume.buildCreateVolumeInput("test-az", testRootDevice)
|
||||
assert.NoError(t, err)
|
||||
// Ensure that the new value is equal to the value passed in
|
||||
assert.Equal(t, *ret.KmsKeyId, stepCreateVolume.RootVolumeKmsKeyId)
|
||||
}
|
||||
|
|
|
@ -130,5 +130,25 @@
|
|||
[`dynamic_block`](/docs/configuration/from-1.5/expressions#dynamic-blocks)
|
||||
will allow you to create those programatically.
|
||||
|
||||
- `root_volume_encrypt_boot` (boolean) - Whether or not to encrypt the volumes that are *launched*. By default, Packer will keep
|
||||
the encryption setting to what it was in the source image when set to `false`. Setting true will
|
||||
always result in an encrypted one.
|
||||
|
||||
- `root_volume_kms_key_id` (string) - ID, alias or ARN of the KMS key to use for *launched* volumes encryption.
|
||||
|
||||
Set this value if you select `root_volume_encrypt_boot`, but don't want to use the
|
||||
region's default KMS key.
|
||||
|
||||
If you have a custom kms key you'd like to apply to the launch volume,
|
||||
and are only building in one region, it is more efficient to set this
|
||||
and `root_volume_encrypt_boot` to `true` and not use `encrypt_boot` and `kms_key_id`. This saves
|
||||
potentially many minutes at the end of the build by preventing Packer
|
||||
from having to copy and re-encrypt the image at the end of the build.
|
||||
|
||||
For valid formats see *KmsKeyId* in the [AWS API docs -
|
||||
CopyImage](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CopyImage.html).
|
||||
This field is validated by Packer, when using an alias, you will have to
|
||||
prefix `kms_key_id` with `alias/`.
|
||||
|
||||
- `ami_architecture` (string) - what architecture to use when registering the final AMI; valid options
|
||||
are "x86_64" or "arm64". Defaults to "x86_64".
|
||||
|
|
Loading…
Reference in New Issue