builder/googlecompute: Optionally disable service account

The ability to use a service account other than the default was
introduced in #5928. This change adds to that by introducing the
'disable_default_service_account' config option. If true - and
'service_account_email' is not set - Packer will create a GCE VM
with no service account.
pull/5991/head
Evan Brown 8 years ago
parent 76e8d6e50b
commit 4a2c124ea2

@ -26,39 +26,39 @@ type Config struct {
AccountFile string `mapstructure:"account_file"`
ProjectId string `mapstructure:"project_id"`
AcceleratorType string `mapstructure:"accelerator_type"`
AcceleratorCount int64 `mapstructure:"accelerator_count"`
Address string `mapstructure:"address"`
DiskName string `mapstructure:"disk_name"`
DiskSizeGb int64 `mapstructure:"disk_size"`
DiskType string `mapstructure:"disk_type"`
ImageName string `mapstructure:"image_name"`
ImageDescription string `mapstructure:"image_description"`
ImageFamily string `mapstructure:"image_family"`
ImageLabels map[string]string `mapstructure:"image_labels"`
ImageLicenses []string `mapstructure:"image_licenses"`
InstanceName string `mapstructure:"instance_name"`
Labels map[string]string `mapstructure:"labels"`
MachineType string `mapstructure:"machine_type"`
Metadata map[string]string `mapstructure:"metadata"`
Network string `mapstructure:"network"`
NetworkProjectId string `mapstructure:"network_project_id"`
OmitExternalIP bool `mapstructure:"omit_external_ip"`
OnHostMaintenance string `mapstructure:"on_host_maintenance"`
Preemptible bool `mapstructure:"preemptible"`
RawStateTimeout string `mapstructure:"state_timeout"`
Region string `mapstructure:"region"`
Scopes []string `mapstructure:"scopes"`
SourceImage string `mapstructure:"source_image"`
SourceImageFamily string `mapstructure:"source_image_family"`
SourceImageProjectId string `mapstructure:"source_image_project_id"`
StartupScriptFile string `mapstructure:"startup_script_file"`
Subnetwork string `mapstructure:"subnetwork"`
Tags []string `mapstructure:"tags"`
UseInternalIP bool `mapstructure:"use_internal_ip"`
Zone string `mapstructure:"zone"`
ServiceAccountEmail string `mapstructure:"service_account_email"`
AcceleratorType string `mapstructure:"accelerator_type"`
AcceleratorCount int64 `mapstructure:"accelerator_count"`
Address string `mapstructure:"address"`
DisableDefaultServiceAccount bool `mapstructure:"disable_default_service_account"`
DiskName string `mapstructure:"disk_name"`
DiskSizeGb int64 `mapstructure:"disk_size"`
DiskType string `mapstructure:"disk_type"`
ImageName string `mapstructure:"image_name"`
ImageDescription string `mapstructure:"image_description"`
ImageFamily string `mapstructure:"image_family"`
ImageLabels map[string]string `mapstructure:"image_labels"`
ImageLicenses []string `mapstructure:"image_licenses"`
InstanceName string `mapstructure:"instance_name"`
Labels map[string]string `mapstructure:"labels"`
MachineType string `mapstructure:"machine_type"`
Metadata map[string]string `mapstructure:"metadata"`
Network string `mapstructure:"network"`
NetworkProjectId string `mapstructure:"network_project_id"`
OmitExternalIP bool `mapstructure:"omit_external_ip"`
OnHostMaintenance string `mapstructure:"on_host_maintenance"`
Preemptible bool `mapstructure:"preemptible"`
RawStateTimeout string `mapstructure:"state_timeout"`
Region string `mapstructure:"region"`
Scopes []string `mapstructure:"scopes"`
ServiceAccountEmail string `mapstructure:"service_account_email"`
SourceImage string `mapstructure:"source_image"`
SourceImageFamily string `mapstructure:"source_image_family"`
SourceImageProjectId string `mapstructure:"source_image_project_id"`
StartupScriptFile string `mapstructure:"startup_script_file"`
Subnetwork string `mapstructure:"subnetwork"`
Tags []string `mapstructure:"tags"`
UseInternalIP bool `mapstructure:"use_internal_ip"`
Zone string `mapstructure:"zone"`
Account AccountFile
stateTimeout time.Duration

@ -170,6 +170,32 @@ func TestConfigPrepare(t *testing.T) {
[]string{"https://www.googleapis.com/auth/cloud-platform"},
false,
},
{
"disable_default_service_account",
"",
false,
},
{
"disable_default_service_account",
nil,
false,
},
{
"disable_default_service_account",
false,
false,
},
{
"disable_default_service_account",
true,
false,
},
{
"disable_default_service_account",
"NOT A BOOL",
true,
},
}
for _, tc := range cases {

@ -58,28 +58,29 @@ type Driver interface {
}
type InstanceConfig struct {
AcceleratorType string
AcceleratorCount int64
Address string
Description string
DiskSizeGb int64
DiskType string
Image *Image
Labels map[string]string
MachineType string
Metadata map[string]string
Name string
Network string
NetworkProjectId string
OmitExternalIP bool
OnHostMaintenance string
Preemptible bool
Region string
ServiceAccountEmail string
Scopes []string
Subnetwork string
Tags []string
Zone string
AcceleratorType string
AcceleratorCount int64
Address string
Description string
DisableDefaultServiceAccount bool
DiskSizeGb int64
DiskType string
Image *Image
Labels map[string]string
MachineType string
Metadata map[string]string
Name string
Network string
NetworkProjectId string
OmitExternalIP bool
OnHostMaintenance string
Preemptible bool
Region string
ServiceAccountEmail string
Scopes []string
Subnetwork string
Tags []string
Zone string
}
// WindowsPasswordConfig is the data structue that GCE needs to encrypt the created

@ -343,12 +343,18 @@ func (d *driverGCE) RunInstance(c *InstanceConfig) (<-chan error, error) {
guestAccelerators = append(guestAccelerators, ac)
}
serviceAccount := &compute.ServiceAccount{
Email: "default",
Scopes: c.Scopes,
// Configure the instance's service account. If the user has set
// disable_default_service_account, then the default service account
// will not be used. If they also do not set service_account_email, then
// the instance will be created with no service account or scopes.
serviceAccount := &compute.ServiceAccount{}
if !c.DisableDefaultServiceAccount {
serviceAccount.Email = "default"
serviceAccount.Scopes = c.Scopes
}
if c.ServiceAccountEmail != "" {
serviceAccount.Email = c.ServiceAccountEmail
serviceAccount.Scopes = c.Scopes
}
// Create the instance information

@ -100,28 +100,29 @@ func (s *StepCreateInstance) Run(_ context.Context, state multistep.StateBag) mu
var metadata map[string]string
metadata, err = c.createInstanceMetadata(sourceImage, sshPublicKey)
errCh, err = d.RunInstance(&InstanceConfig{
AcceleratorType: c.AcceleratorType,
AcceleratorCount: c.AcceleratorCount,
Address: c.Address,
Description: "New instance created by Packer",
DiskSizeGb: c.DiskSizeGb,
DiskType: c.DiskType,
Image: sourceImage,
Labels: c.Labels,
MachineType: c.MachineType,
Metadata: metadata,
Name: name,
Network: c.Network,
NetworkProjectId: c.NetworkProjectId,
OmitExternalIP: c.OmitExternalIP,
OnHostMaintenance: c.OnHostMaintenance,
Preemptible: c.Preemptible,
Region: c.Region,
ServiceAccountEmail: c.ServiceAccountEmail,
Scopes: c.Scopes,
Subnetwork: c.Subnetwork,
Tags: c.Tags,
Zone: c.Zone,
AcceleratorType: c.AcceleratorType,
AcceleratorCount: c.AcceleratorCount,
Address: c.Address,
Description: "New instance created by Packer",
DisableDefaultServiceAccount: c.DisableDefaultServiceAccount,
DiskSizeGb: c.DiskSizeGb,
DiskType: c.DiskType,
Image: sourceImage,
Labels: c.Labels,
MachineType: c.MachineType,
Metadata: metadata,
Name: name,
Network: c.Network,
NetworkProjectId: c.NetworkProjectId,
OmitExternalIP: c.OmitExternalIP,
OnHostMaintenance: c.OnHostMaintenance,
Preemptible: c.Preemptible,
Region: c.Region,
ServiceAccountEmail: c.ServiceAccountEmail,
Scopes: c.Scopes,
Subnetwork: c.Subnetwork,
Tags: c.Tags,
Zone: c.Zone,
})
if err == nil {

@ -248,6 +248,54 @@ func TestStepCreateInstance_errorTimeout(t *testing.T) {
assert.False(t, ok, "State should not have an instance name.")
}
func TestStepCreateInstance_noServiceAccount(t *testing.T) {
state := testState(t)
step := new(StepCreateInstance)
defer step.Cleanup(state)
state.Put("ssh_public_key", "key")
c := state.Get("config").(*Config)
c.DisableDefaultServiceAccount = true
c.ServiceAccountEmail = ""
d := state.Get("driver").(*DriverMock)
d.GetImageResult = StubImage("test-image", "test-project", []string{}, 100)
// run the step
assert.Equal(t, step.Run(context.Background(), state), multistep.ActionContinue, "Step should have passed and continued.")
// cleanup
step.Cleanup(state)
// Check args passed to the driver.
assert.Equal(t, d.RunInstanceConfig.DisableDefaultServiceAccount, c.DisableDefaultServiceAccount, "Incorrect value for DisableDefaultServiceAccount passed to driver.")
assert.Equal(t, d.RunInstanceConfig.ServiceAccountEmail, c.ServiceAccountEmail, "Incorrect value for ServiceAccountEmail passed to driver.")
}
func TestStepCreateInstance_customServiceAccount(t *testing.T) {
state := testState(t)
step := new(StepCreateInstance)
defer step.Cleanup(state)
state.Put("ssh_public_key", "key")
c := state.Get("config").(*Config)
c.DisableDefaultServiceAccount = true
c.ServiceAccountEmail = "custom-service-account"
d := state.Get("driver").(*DriverMock)
d.GetImageResult = StubImage("test-image", "test-project", []string{}, 100)
// run the step
assert.Equal(t, step.Run(context.Background(), state), multistep.ActionContinue, "Step should have passed and continued.")
// cleanup
step.Cleanup(state)
// Check args passed to the driver.
assert.Equal(t, d.RunInstanceConfig.DisableDefaultServiceAccount, c.DisableDefaultServiceAccount, "Incorrect value for DisableDefaultServiceAccount passed to driver.")
assert.Equal(t, d.RunInstanceConfig.ServiceAccountEmail, c.ServiceAccountEmail, "Incorrect value for ServiceAccountEmail passed to driver.")
}
func TestCreateInstanceMetadata(t *testing.T) {
state := testState(t)
c := state.Get("config").(*Config)

@ -210,6 +210,9 @@ builder.
- `address` (string) - The name of a pre-allocated static external IP address.
Note, must be the name and not the actual IP address.
- `disable_default_service_account` (bool) - If true, the default service account will not be used if `service_account_email`
is not specified. Set this value to true and omit `service_account_email` to provision a VM with no service account.
- `disk_name` (string) - The name of the disk, if unset the instance name will be
used.
@ -269,7 +272,7 @@ builder.
to the region hosting the specified `zone`.
- `service_account_email` (string) - The service account to be used for launched instance. Defaults to
the project's default service account.
the project's default service account unless `disable_default_service_account` is true.
- `scopes` (array of strings) - The service account scopes for launched instance.
Defaults to:

Loading…
Cancel
Save