Merge pull request #7551 from krzyszko/gcp_encryption_key

Googlecompute builder image encryption support
This commit is contained in:
Megan Marsh 2019-05-07 15:59:59 -07:00 committed by GitHub
commit fdae14bc18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 84 additions and 46 deletions

View File

@ -13,6 +13,7 @@ import (
"github.com/hashicorp/packer/helper/config" "github.com/hashicorp/packer/helper/config"
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate" "github.com/hashicorp/packer/template/interpolate"
compute "google.golang.org/api/compute/v1"
) )
var reImageFamily = regexp.MustCompile(`^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$`) var reImageFamily = regexp.MustCompile(`^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$`)
@ -27,40 +28,41 @@ type Config struct {
AccountFile string `mapstructure:"account_file"` AccountFile string `mapstructure:"account_file"`
ProjectId string `mapstructure:"project_id"` ProjectId string `mapstructure:"project_id"`
AcceleratorType string `mapstructure:"accelerator_type"` AcceleratorType string `mapstructure:"accelerator_type"`
AcceleratorCount int64 `mapstructure:"accelerator_count"` AcceleratorCount int64 `mapstructure:"accelerator_count"`
Address string `mapstructure:"address"` Address string `mapstructure:"address"`
DisableDefaultServiceAccount bool `mapstructure:"disable_default_service_account"` DisableDefaultServiceAccount bool `mapstructure:"disable_default_service_account"`
DiskName string `mapstructure:"disk_name"` DiskName string `mapstructure:"disk_name"`
DiskSizeGb int64 `mapstructure:"disk_size"` DiskSizeGb int64 `mapstructure:"disk_size"`
DiskType string `mapstructure:"disk_type"` DiskType string `mapstructure:"disk_type"`
ImageName string `mapstructure:"image_name"` ImageName string `mapstructure:"image_name"`
ImageDescription string `mapstructure:"image_description"` ImageDescription string `mapstructure:"image_description"`
ImageFamily string `mapstructure:"image_family"` ImageEncryptionKey *compute.CustomerEncryptionKey `mapstructure:"image_encryption_key"`
ImageLabels map[string]string `mapstructure:"image_labels"` ImageFamily string `mapstructure:"image_family"`
ImageLicenses []string `mapstructure:"image_licenses"` ImageLabels map[string]string `mapstructure:"image_labels"`
InstanceName string `mapstructure:"instance_name"` ImageLicenses []string `mapstructure:"image_licenses"`
Labels map[string]string `mapstructure:"labels"` InstanceName string `mapstructure:"instance_name"`
MachineType string `mapstructure:"machine_type"` Labels map[string]string `mapstructure:"labels"`
Metadata map[string]string `mapstructure:"metadata"` MachineType string `mapstructure:"machine_type"`
MinCpuPlatform string `mapstructure:"min_cpu_platform"` Metadata map[string]string `mapstructure:"metadata"`
Network string `mapstructure:"network"` MinCpuPlatform string `mapstructure:"min_cpu_platform"`
NetworkProjectId string `mapstructure:"network_project_id"` Network string `mapstructure:"network"`
OmitExternalIP bool `mapstructure:"omit_external_ip"` NetworkProjectId string `mapstructure:"network_project_id"`
OnHostMaintenance string `mapstructure:"on_host_maintenance"` OmitExternalIP bool `mapstructure:"omit_external_ip"`
Preemptible bool `mapstructure:"preemptible"` OnHostMaintenance string `mapstructure:"on_host_maintenance"`
RawStateTimeout string `mapstructure:"state_timeout"` Preemptible bool `mapstructure:"preemptible"`
Region string `mapstructure:"region"` RawStateTimeout string `mapstructure:"state_timeout"`
Scopes []string `mapstructure:"scopes"` Region string `mapstructure:"region"`
ServiceAccountEmail string `mapstructure:"service_account_email"` Scopes []string `mapstructure:"scopes"`
SourceImage string `mapstructure:"source_image"` ServiceAccountEmail string `mapstructure:"service_account_email"`
SourceImageFamily string `mapstructure:"source_image_family"` SourceImage string `mapstructure:"source_image"`
SourceImageProjectId string `mapstructure:"source_image_project_id"` SourceImageFamily string `mapstructure:"source_image_family"`
StartupScriptFile string `mapstructure:"startup_script_file"` SourceImageProjectId string `mapstructure:"source_image_project_id"`
Subnetwork string `mapstructure:"subnetwork"` StartupScriptFile string `mapstructure:"startup_script_file"`
Tags []string `mapstructure:"tags"` Subnetwork string `mapstructure:"subnetwork"`
UseInternalIP bool `mapstructure:"use_internal_ip"` Tags []string `mapstructure:"tags"`
Zone string `mapstructure:"zone"` UseInternalIP bool `mapstructure:"use_internal_ip"`
Zone string `mapstructure:"zone"`
Account AccountFile Account AccountFile
stateTimeout time.Duration stateTimeout time.Duration

View File

@ -156,6 +156,21 @@ func TestConfigPrepare(t *testing.T) {
"foo bar", "foo bar",
true, true,
}, },
{
"image_encryption_key",
map[string]string{"kmsKeyName": "foo"},
false,
},
{
"image_encryption_key",
map[string]string{"No such key": "foo"},
true,
},
{
"image_encryption_key",
map[string]string{"kmsKeyName": "foo", "RawKey": "foo"},
false,
},
{ {
"scopes", "scopes",
[]string{}, []string{},

View File

@ -3,6 +3,8 @@ package googlecompute
import ( import (
"crypto/rsa" "crypto/rsa"
"time" "time"
compute "google.golang.org/api/compute/v1"
) )
// Driver is the interface that has to be implemented to communicate // Driver is the interface that has to be implemented to communicate
@ -11,7 +13,7 @@ import (
type Driver interface { type Driver interface {
// CreateImage creates an image from the given disk in Google Compute // CreateImage creates an image from the given disk in Google Compute
// Engine. // Engine.
CreateImage(name, description, family, zone, disk string, image_labels map[string]string, image_licenses []string) (<-chan *Image, <-chan error) CreateImage(name, description, family, zone, disk string, image_labels map[string]string, image_licenses []string, image_encryption_key *compute.CustomerEncryptionKey) (<-chan *Image, <-chan error)
// DeleteImage deletes the image with the given name. // DeleteImage deletes the image with the given name.
DeleteImage(name string) <-chan error DeleteImage(name string) <-chan error

View File

@ -104,15 +104,16 @@ func NewDriverGCE(ui packer.Ui, p string, a *AccountFile) (Driver, error) {
}, nil }, nil
} }
func (d *driverGCE) CreateImage(name, description, family, zone, disk string, image_labels map[string]string, image_licenses []string) (<-chan *Image, <-chan error) { func (d *driverGCE) CreateImage(name, description, family, zone, disk string, image_labels map[string]string, image_licenses []string, image_encryption_key *compute.CustomerEncryptionKey) (<-chan *Image, <-chan error) {
gce_image := &compute.Image{ gce_image := &compute.Image{
Description: description, Description: description,
Name: name, Name: name,
Family: family, Family: family,
Labels: image_labels, Labels: image_labels,
Licenses: image_licenses, Licenses: image_licenses,
SourceDisk: fmt.Sprintf("%s%s/zones/%s/disks/%s", d.service.BasePath, d.projectId, zone, disk), ImageEncryptionKey: image_encryption_key,
SourceType: "RAW", SourceDisk: fmt.Sprintf("%s%s/zones/%s/disks/%s", d.service.BasePath, d.projectId, zone, disk),
SourceType: "RAW",
} }
imageCh := make(chan *Image, 1) imageCh := make(chan *Image, 1)

View File

@ -1,6 +1,10 @@
package googlecompute package googlecompute
import "fmt" import (
"fmt"
compute "google.golang.org/api/compute/v1"
)
// DriverMock is a Driver implementation that is a mocked out so that // DriverMock is a Driver implementation that is a mocked out so that
// it can be used for tests. // it can be used for tests.
@ -8,6 +12,7 @@ type DriverMock struct {
CreateImageName string CreateImageName string
CreateImageDesc string CreateImageDesc string
CreateImageFamily string CreateImageFamily string
CreateImageEncryptionKey *compute.CustomerEncryptionKey
CreateImageLabels map[string]string CreateImageLabels map[string]string
CreateImageLicenses []string CreateImageLicenses []string
CreateImageZone string CreateImageZone string
@ -82,7 +87,7 @@ type DriverMock struct {
WaitForInstanceErrCh <-chan error WaitForInstanceErrCh <-chan error
} }
func (d *DriverMock) CreateImage(name, description, family, zone, disk string, image_labels map[string]string, image_licenses []string) (<-chan *Image, <-chan error) { func (d *DriverMock) CreateImage(name, description, family, zone, disk string, image_labels map[string]string, image_licenses []string, image_encryption_key *compute.CustomerEncryptionKey) (<-chan *Image, <-chan error) {
d.CreateImageName = name d.CreateImageName = name
d.CreateImageDesc = description d.CreateImageDesc = description
d.CreateImageFamily = family d.CreateImageFamily = family
@ -90,6 +95,7 @@ func (d *DriverMock) CreateImage(name, description, family, zone, disk string, i
d.CreateImageLicenses = image_licenses d.CreateImageLicenses = image_licenses
d.CreateImageZone = zone d.CreateImageZone = zone
d.CreateImageDisk = disk d.CreateImageDisk = disk
d.CreateImageEncryptionKey = image_encryption_key
if d.CreateImageResultProjectId == "" { if d.CreateImageResultProjectId == "" {
d.CreateImageResultProjectId = "test" d.CreateImageResultProjectId = "test"
} }

View File

@ -40,7 +40,7 @@ func (s *StepCreateImage) Run(ctx context.Context, state multistep.StateBag) mul
imageCh, errCh := driver.CreateImage( imageCh, errCh := driver.CreateImage(
config.ImageName, config.ImageDescription, config.ImageFamily, config.Zone, config.ImageName, config.ImageDescription, config.ImageFamily, config.Zone,
config.DiskName, config.ImageLabels, config.ImageLicenses) config.DiskName, config.ImageLabels, config.ImageLicenses, config.ImageEncryptionKey)
var err error var err error
select { select {
case err = <-errCh: case err = <-errCh:

View File

@ -47,6 +47,7 @@ func TestStepCreateImage(t *testing.T) {
assert.Equal(t, d.CreateImageDisk, c.DiskName, "Incorrect disk passed to driver.") assert.Equal(t, d.CreateImageDisk, c.DiskName, "Incorrect disk passed to driver.")
assert.Equal(t, d.CreateImageLabels, c.ImageLabels, "Incorrect image_labels passed to driver.") assert.Equal(t, d.CreateImageLabels, c.ImageLabels, "Incorrect image_labels passed to driver.")
assert.Equal(t, d.CreateImageLicenses, c.ImageLicenses, "Incorrect image_licenses passed to driver.") assert.Equal(t, d.CreateImageLicenses, c.ImageLicenses, "Incorrect image_licenses passed to driver.")
assert.Equal(t, d.CreateImageEncryptionKey, c.ImageEncryptionKey, "Incorrect image_encryption_key passed to driver.")
} }
func TestStepCreateImage_errorOnChannel(t *testing.T) { func TestStepCreateImage_errorOnChannel(t *testing.T) {

View File

@ -270,6 +270,17 @@ builder.
- `image_name` (string) - The unique name of the resulting image. Defaults to - `image_name` (string) - The unique name of the resulting image. Defaults to
`"packer-{{timestamp}}"`. `"packer-{{timestamp}}"`.
- `image_encryption_key` (object of encryption key) - Image encryption key to apply to the created image. Possible values:
* kmsKeyName - The name of the encryption key that is stored in Google Cloud KMS.
* RawKey: - A 256-bit customer-supplied encryption key, encodes in RFC 4648 base64.
example:
``` json
{
"kmsKeyName": "projects/${project}/locations/${region}/keyRings/computeEngine/cryptoKeys/computeEngine/cryptoKeyVersions/4"
}
```
- `instance_name` (string) - A name to give the launched instance. Beware - `instance_name` (string) - A name to give the launched instance. Beware
that this must be unique. Defaults to `"packer-{{uuid}}"`. that this must be unique. Defaults to `"packer-{{uuid}}"`.