Adding custom shielded images support (GCP)

Adds `enable_secure_boot`, `enable_vtpm` and `enable_integrity_monitoring`
config options to enable building of custom Shielded GCP Compute images.

Feedback on this is more than welcome as this is my first attempt in
contributing to anything Packer related.

Packer is great for us to build custom images on top of GCP but we would
like to enhance that to support Shielded VM images. This will allow us
to have more secure and trusted images which our team(s) will be using.
This commit is contained in:
Svetlin Zamfirov 2020-03-30 15:05:16 +02:00 committed by Megan Marsh
parent 553b1fb9f8
commit d827f4f757
7 changed files with 99 additions and 13 deletions

View File

@ -57,6 +57,22 @@ type Config struct {
// Type of disk used to back your instance, like pd-ssd or pd-standard.
// Defaults to pd-standard.
DiskType string `mapstructure:"disk_type" required:"false"`
// Shielded VM offers verifiable integrity of your Compute Engine VM instances,
// so you can be confident your instances haven't been compromised by boot-
// or kernel-level malware or rootkits. Shielded VM's verifiable integrity
// is achieved through the use of:
// * Secure Boot - helps ensure that the system only runs authentic software
// by verifying the digital signature of all boot components, and halting
// the boot process if signature verification fails.
EnableSecureBoot bool `mapstructure:"enable_secure_boot" required:"false"`
// * virtual trusted platform module (vTPM)-enabled Measured Boot - A vTPM
// is a virtualized trusted platform module, which is a specialized computer
// chip you can use to protect objects, like keys and certificates, that
// you use to authenticate access to your system.
EnableVtpm bool `mapstructure:"enable_vtpm" required:"false"`
// * Integrity monitoring - Integrity monitoring helps you understand and
// make decisions about the state of your VM instances.
EnableIntegrityMonitoring bool `mapstructure:"enable_integrity_monitoring" required:"false"`
// The unique name of the resulting image. Defaults to
// `packer-{{timestamp}}`.
ImageName string `mapstructure:"image_name" required:"false"`
@ -222,6 +238,15 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
c.DiskType = "pd-standard"
}
// Disabling the vTPM also disables integrity monitoring, because integrity
// monitoring relies on data gathered by Measured Boot.
if !c.EnableVtpm {
if c.EnableIntegrityMonitoring {
errs = packer.MultiErrorAppend(errs,
errors.New("You cannot enable Integrity Monitoring when vTPM is disabled."))
}
}
if c.ImageDescription == "" {
c.ImageDescription = "Created by Packer"
}

View File

@ -66,6 +66,9 @@ type FlatConfig struct {
DiskName *string `mapstructure:"disk_name" required:"false" cty:"disk_name"`
DiskSizeGb *int64 `mapstructure:"disk_size" required:"false" cty:"disk_size"`
DiskType *string `mapstructure:"disk_type" required:"false" cty:"disk_type"`
EnableSecureBoot *bool `mapstructure:"enable_secure_boot" required:"false" cty:"enable_secure_boot"`
EnableVtpm *bool `mapstructure:"enable_vtpm" required:"false" cty:"enable_vtpm"`
EnableIntegrityMonitoring *bool `mapstructure:"enable_integrity_monitoring" required:"false" cty:"enable_integrity_monitoring"`
ImageName *string `mapstructure:"image_name" required:"false" cty:"image_name"`
ImageDescription *string `mapstructure:"image_description" required:"false" cty:"image_description"`
ImageEncryptionKey *FlatCustomerEncryptionKey `mapstructure:"image_encryption_key" required:"false" cty:"image_encryption_key"`
@ -167,6 +170,9 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"disk_name": &hcldec.AttrSpec{Name: "disk_name", Type: cty.String, Required: false},
"disk_size": &hcldec.AttrSpec{Name: "disk_size", Type: cty.Number, Required: false},
"disk_type": &hcldec.AttrSpec{Name: "disk_type", Type: cty.String, Required: false},
"enable_secure_boot": &hcldec.AttrSpec{Name: "enable_secure_boot", Type: cty.Bool, Required: false},
"enable_vtpm": &hcldec.AttrSpec{Name: "enable_vtpm", Type: cty.Bool, Required: false},
"enable_integrity_monitoring": &hcldec.AttrSpec{Name: "enable_integrity_monitoring", Type: cty.Bool, Required: false},
"image_name": &hcldec.AttrSpec{Name: "image_name", Type: cty.String, Required: false},
"image_description": &hcldec.AttrSpec{Name: "image_description", Type: cty.String, Required: false},
"image_encryption_key": &hcldec.BlockSpec{TypeName: "image_encryption_key", Nested: hcldec.ObjectSpec((*FlatCustomerEncryptionKey)(nil).HCL2Spec())},

View File

@ -72,6 +72,9 @@ type InstanceConfig struct {
DisableDefaultServiceAccount bool
DiskSizeGb int64
DiskType string
EnableSecureBoot bool
EnableVtpm bool
EnableIntegrityMonitoring bool
Image *Image
Labels map[string]string
MachineType string

View File

@ -271,6 +271,7 @@ func (d *driverGCE) GetImageFromProject(project, name string, fromFamily bool) (
return nil, fmt.Errorf("Image, %s, could not be found in project: %s", name, project)
} else {
return &Image{
GuestOsFeatures: image.GuestOsFeatures,
Licenses: image.Licenses,
Name: image.Name,
ProjectId: project,
@ -466,7 +467,23 @@ func (d *driverGCE) RunInstance(c *InstanceConfig) (<-chan error, error) {
},
}
d.ui.Message("Requesting instance creation...")
// Shielded VMs configuration. If the user has set at least one of the
// options, the shielded VM configuration will reflect that. If they
// don't set any of the options the settings will default to the ones
// of the source compute image which is used for creating the virtual
// machine.
shieldedInstanceConfig := &compute.ShieldedInstanceConfig{
EnableSecureBoot: c.EnableSecureBoot,
EnableVtpm: c.EnableVtpm,
EnableIntegrityMonitoring: c.EnableIntegrityMonitoring,
}
shieldedUiMessage := ""
if c.EnableSecureBoot || c.EnableVtpm || c.EnableIntegrityMonitoring {
instance.ShieldedInstanceConfig = shieldedInstanceConfig
shieldedUiMessage = " Shielded VM"
}
d.ui.Message(fmt.Sprintf("Requesting%s instance creation...", shieldedUiMessage))
op, err := d.service.Instances.Insert(d.projectId, zone.Name, &instance).Do()
if err != nil {
return nil, err

View File

@ -2,9 +2,12 @@ package googlecompute
import (
"strings"
compute "google.golang.org/api/compute/v1"
)
type Image struct {
GuestOsFeatures []*compute.GuestOsFeature
Labels map[string]string
Licenses []string
Name string
@ -21,3 +24,12 @@ func (i *Image) IsWindows() bool {
}
return false
}
func (i *Image) IsSecureBootCompatible() bool {
for _, osFeature := range i.GuestOsFeatures {
if osFeature.Type == "SECURE_BOOT" {
return true
}
}
return false
}

View File

@ -107,6 +107,13 @@ func (s *StepCreateInstance) Run(ctx context.Context, state multistep.StateBag)
return multistep.ActionHalt
}
if c.EnableSecureBoot && !sourceImage.IsSecureBootCompatible() {
err := fmt.Errorf("Image: %s is not secure boot compatible. Please set 'enable_secure_boot' to false or choose another source image.", sourceImage.Name)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
ui.Say(fmt.Sprintf("Using image: %s", sourceImage.Name))
if sourceImage.IsWindows() && c.Comm.Type == "winrm" && c.Comm.WinRMPassword == "" {
@ -133,6 +140,9 @@ func (s *StepCreateInstance) Run(ctx context.Context, state multistep.StateBag)
DisableDefaultServiceAccount: c.DisableDefaultServiceAccount,
DiskSizeGb: c.DiskSizeGb,
DiskType: c.DiskType,
EnableSecureBoot: c.EnableSecureBoot,
EnableVtpm: c.EnableVtpm,
EnableIntegrityMonitoring: c.EnableIntegrityMonitoring,
Image: sourceImage,
Labels: c.Labels,
MachineType: c.MachineType,

View File

@ -25,6 +25,19 @@
- `disk_type` (string) - Type of disk used to back your instance, like pd-ssd or pd-standard.
Defaults to pd-standard.
- `enable_secure_boot` (bool) - Enable Secure Boot on a Shielded VM instance. Secure Boot helps ensure that the system
only runs authentic software by verifying the digital signature of all boot components, and halting the boot process
if signature verification fails.
[Details](https://cloud.google.com/security/shielded-cloud/shielded-vm#secure-boot)
- `enable_vtpm` (bool) - Enable virtualized trusted platform module on a Shielded VM instance.
[Details](https://cloud.google.com/security/shielded-cloud/shielded-vm#vtpm)
- `enable_integrity_monitoring` (bool) - Enable integrity monitoring on a Shielded VM instance. Integrity
monitoring helps you understand and make decisions about the state of your VM instances. Note: requires
enable_vtpm to be set to true.
[Details](https://cloud.google.com/security/shielded-cloud/shielded-vm#integrity-monitoring)
- `image_name` (string) - The unique name of the resulting image. Defaults to
`packer-{{timestamp}}`.