mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-09-28 14:59:32 -04:00
gcp: support projects with no default permissions (#3656)
* helm/gcp: use service account in operator and joinservice * helm: format operator testdata * terraform/iam: create additional service account for VMs This service account is used in the following commits and is attached to the VMs * config: pass VM service account from iam create to cluster create via config * cli/iamcreate: limit name prefix length * docs: add minimal gcp IAM permissions
This commit is contained in:
parent
83e08e3e37
commit
66815a4a47
42 changed files with 771 additions and 466 deletions
|
@ -91,6 +91,7 @@ type GCPIAMConfig struct {
|
|||
Zone string
|
||||
ProjectID string
|
||||
ServiceAccountID string
|
||||
NamePrefix string
|
||||
}
|
||||
|
||||
// AzureIAMConfig holds the necessary values for Azure IAM configuration.
|
||||
|
@ -141,6 +142,7 @@ func (c *IAMCreator) createGCP(ctx context.Context, cl tfIAMClient, opts *IAMCon
|
|||
|
||||
vars := terraform.GCPIAMVariables{
|
||||
ServiceAccountID: opts.GCP.ServiceAccountID,
|
||||
NamePrefix: opts.GCP.NamePrefix,
|
||||
Project: opts.GCP.ProjectID,
|
||||
Region: opts.GCP.Region,
|
||||
Zone: opts.GCP.Zone,
|
||||
|
@ -158,7 +160,8 @@ func (c *IAMCreator) createGCP(ctx context.Context, cl tfIAMClient, opts *IAMCon
|
|||
return IAMOutput{
|
||||
CloudProvider: cloudprovider.GCP,
|
||||
GCPOutput: GCPIAMOutput{
|
||||
ServiceAccountKey: iamOutput.GCP.SaKey,
|
||||
ServiceAccountKey: iamOutput.GCP.SaKey,
|
||||
IAMServiceAccountVM: iamOutput.GCP.ServiceAccountVMMailAddress,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
@ -232,7 +235,8 @@ type IAMOutput struct {
|
|||
|
||||
// GCPIAMOutput contains the output information of a GCP IAM configuration.
|
||||
type GCPIAMOutput struct {
|
||||
ServiceAccountKey string `json:"serviceAccountID,omitempty"`
|
||||
ServiceAccountKey string `json:"serviceAccountID,omitempty"`
|
||||
IAMServiceAccountVM string `json:"iamServiceAccountVM,omitempty"`
|
||||
}
|
||||
|
||||
// AzureIAMOutput contains the output information of a Microsoft Azure IAM configuration.
|
||||
|
|
|
@ -22,6 +22,9 @@ import (
|
|||
// UpgradeRequiresIAMMigration returns true if the given cloud provider requires an IAM migration.
|
||||
func UpgradeRequiresIAMMigration(provider cloudprovider.Provider) bool {
|
||||
switch provider {
|
||||
case cloudprovider.GCP:
|
||||
// TODO(@3u13r): remove this case after the v2.22.0 release
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -231,6 +231,7 @@ func gcpTerraformVars(conf *config.Config, imageRef string) *terraform.GCPCluste
|
|||
InternalLoadBalancer: conf.InternalLoadBalancer,
|
||||
CCTechnology: ccTech,
|
||||
AdditionalLabels: conf.Tags,
|
||||
IAMServiceAccountVM: conf.Provider.GCP.IAMServiceAccountVM,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -240,6 +241,7 @@ func gcpTerraformIAMVars(conf *config.Config, oldVars terraform.GCPIAMVariables)
|
|||
Region: conf.Provider.GCP.Region,
|
||||
Zone: conf.Provider.GCP.Zone,
|
||||
ServiceAccountID: oldVars.ServiceAccountID,
|
||||
NamePrefix: oldVars.NamePrefix,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -256,6 +256,7 @@ func TestValidateInputs(t *testing.T) {
|
|||
ClientX509CertURL: "client_cert",
|
||||
}))
|
||||
cfg.Provider.GCP.ServiceAccountKeyPath = "saKey.json"
|
||||
cfg.Provider.GCP.IAMServiceAccountVM = "example@example.com"
|
||||
}
|
||||
|
||||
require.NoError(fh.WriteYAML(constants.ConfigFilename, cfg))
|
||||
|
|
|
@ -29,6 +29,9 @@ var (
|
|||
regionRegex = regexp.MustCompile(`^\w+-\w+[0-9]$`)
|
||||
// Source: https://cloud.google.com/resource-manager/reference/rest/v1/projects.
|
||||
gcpIDRegex = regexp.MustCompile(`^[a-z][-a-z0-9]{4,28}[a-z0-9]$`)
|
||||
|
||||
// We currently append 6 characters to the prefix, therefore we remove 6 characters from the gcpIDRegex.
|
||||
gcpPrefixRegex = regexp.MustCompile(`^[a-z][-a-z0-9]{4,22}[a-z0-9]$`)
|
||||
)
|
||||
|
||||
// newIAMCreateCmd returns a new cobra.Command for the iam create parent command. It needs another verb, and does nothing on its own.
|
||||
|
|
|
@ -456,6 +456,7 @@ func TestIAMCreateGCP(t *testing.T) {
|
|||
creator *stubIAMCreator
|
||||
zoneFlag string
|
||||
serviceAccountIDFlag string
|
||||
namePrefixFlag string
|
||||
projectIDFlag string
|
||||
yesFlag bool
|
||||
updateConfigFlag bool
|
||||
|
@ -466,6 +467,14 @@ func TestIAMCreateGCP(t *testing.T) {
|
|||
wantErr bool
|
||||
}{
|
||||
"iam create gcp": {
|
||||
setupFs: defaultFs,
|
||||
creator: &stubIAMCreator{id: validIAMIDFile},
|
||||
zoneFlag: "europe-west1-a",
|
||||
namePrefixFlag: "constell-test",
|
||||
projectIDFlag: "constell-1234",
|
||||
yesFlag: true,
|
||||
},
|
||||
"iam create gcp with deprecated serice account flag": {
|
||||
setupFs: defaultFs,
|
||||
creator: &stubIAMCreator{id: validIAMIDFile},
|
||||
zoneFlag: "europe-west1-a",
|
||||
|
@ -474,91 +483,91 @@ func TestIAMCreateGCP(t *testing.T) {
|
|||
yesFlag: true,
|
||||
},
|
||||
"iam create gcp with existing config": {
|
||||
setupFs: defaultFs,
|
||||
creator: &stubIAMCreator{id: validIAMIDFile},
|
||||
zoneFlag: "europe-west1-a",
|
||||
serviceAccountIDFlag: "constell-test",
|
||||
projectIDFlag: "constell-1234",
|
||||
yesFlag: true,
|
||||
existingConfigFiles: []string{constants.ConfigFilename},
|
||||
setupFs: defaultFs,
|
||||
creator: &stubIAMCreator{id: validIAMIDFile},
|
||||
zoneFlag: "europe-west1-a",
|
||||
namePrefixFlag: "constell-test",
|
||||
projectIDFlag: "constell-1234",
|
||||
yesFlag: true,
|
||||
existingConfigFiles: []string{constants.ConfigFilename},
|
||||
},
|
||||
"iam create gcp --update-config": {
|
||||
setupFs: defaultFs,
|
||||
creator: &stubIAMCreator{id: validIAMIDFile},
|
||||
zoneFlag: "europe-west1-a",
|
||||
serviceAccountIDFlag: "constell-test",
|
||||
projectIDFlag: "constell-1234",
|
||||
updateConfigFlag: true,
|
||||
yesFlag: true,
|
||||
existingConfigFiles: []string{constants.ConfigFilename},
|
||||
setupFs: defaultFs,
|
||||
creator: &stubIAMCreator{id: validIAMIDFile},
|
||||
zoneFlag: "europe-west1-a",
|
||||
namePrefixFlag: "constell-test",
|
||||
projectIDFlag: "constell-1234",
|
||||
updateConfigFlag: true,
|
||||
yesFlag: true,
|
||||
existingConfigFiles: []string{constants.ConfigFilename},
|
||||
},
|
||||
"iam create gcp existing terraform dir": {
|
||||
setupFs: defaultFs,
|
||||
creator: &stubIAMCreator{id: validIAMIDFile},
|
||||
zoneFlag: "europe-west1-a",
|
||||
serviceAccountIDFlag: "constell-test",
|
||||
projectIDFlag: "constell-1234",
|
||||
setupFs: defaultFs,
|
||||
creator: &stubIAMCreator{id: validIAMIDFile},
|
||||
zoneFlag: "europe-west1-a",
|
||||
namePrefixFlag: "constell-test",
|
||||
projectIDFlag: "constell-1234",
|
||||
|
||||
existingDirs: []string{constants.TerraformIAMWorkingDir},
|
||||
yesFlag: true,
|
||||
wantErr: true,
|
||||
},
|
||||
"iam create gcp invalid b64": {
|
||||
setupFs: defaultFs,
|
||||
creator: &stubIAMCreator{id: invalidIAMIDFile},
|
||||
zoneFlag: "europe-west1-a",
|
||||
serviceAccountIDFlag: "constell-test",
|
||||
projectIDFlag: "constell-1234",
|
||||
yesFlag: true,
|
||||
wantErr: true,
|
||||
setupFs: defaultFs,
|
||||
creator: &stubIAMCreator{id: invalidIAMIDFile},
|
||||
zoneFlag: "europe-west1-a",
|
||||
namePrefixFlag: "constell-test",
|
||||
projectIDFlag: "constell-1234",
|
||||
yesFlag: true,
|
||||
wantErr: true,
|
||||
},
|
||||
"interactive": {
|
||||
setupFs: defaultFs,
|
||||
creator: &stubIAMCreator{id: validIAMIDFile},
|
||||
zoneFlag: "europe-west1-a",
|
||||
serviceAccountIDFlag: "constell-test",
|
||||
projectIDFlag: "constell-1234",
|
||||
stdin: "yes\n",
|
||||
setupFs: defaultFs,
|
||||
creator: &stubIAMCreator{id: validIAMIDFile},
|
||||
zoneFlag: "europe-west1-a",
|
||||
namePrefixFlag: "constell-test",
|
||||
projectIDFlag: "constell-1234",
|
||||
stdin: "yes\n",
|
||||
},
|
||||
"interactive update config": {
|
||||
setupFs: defaultFs,
|
||||
creator: &stubIAMCreator{id: validIAMIDFile},
|
||||
zoneFlag: "europe-west1-a",
|
||||
serviceAccountIDFlag: "constell-test",
|
||||
projectIDFlag: "constell-1234",
|
||||
stdin: "yes\n",
|
||||
updateConfigFlag: true,
|
||||
existingConfigFiles: []string{constants.ConfigFilename},
|
||||
setupFs: defaultFs,
|
||||
creator: &stubIAMCreator{id: validIAMIDFile},
|
||||
zoneFlag: "europe-west1-a",
|
||||
namePrefixFlag: "constell-test",
|
||||
projectIDFlag: "constell-1234",
|
||||
stdin: "yes\n",
|
||||
updateConfigFlag: true,
|
||||
existingConfigFiles: []string{constants.ConfigFilename},
|
||||
},
|
||||
"interactive abort": {
|
||||
setupFs: defaultFs,
|
||||
creator: &stubIAMCreator{id: validIAMIDFile},
|
||||
zoneFlag: "europe-west1-a",
|
||||
serviceAccountIDFlag: "constell-test",
|
||||
projectIDFlag: "constell-1234",
|
||||
stdin: "no\n",
|
||||
wantAbort: true,
|
||||
setupFs: defaultFs,
|
||||
creator: &stubIAMCreator{id: validIAMIDFile},
|
||||
zoneFlag: "europe-west1-a",
|
||||
namePrefixFlag: "constell-test",
|
||||
projectIDFlag: "constell-1234",
|
||||
stdin: "no\n",
|
||||
wantAbort: true,
|
||||
},
|
||||
"interactive abort update config": {
|
||||
setupFs: defaultFs,
|
||||
creator: &stubIAMCreator{id: validIAMIDFile},
|
||||
zoneFlag: "europe-west1-a",
|
||||
serviceAccountIDFlag: "constell-test",
|
||||
projectIDFlag: "constell-1234",
|
||||
stdin: "no\n",
|
||||
wantAbort: true,
|
||||
updateConfigFlag: true,
|
||||
existingConfigFiles: []string{constants.ConfigFilename},
|
||||
setupFs: defaultFs,
|
||||
creator: &stubIAMCreator{id: validIAMIDFile},
|
||||
zoneFlag: "europe-west1-a",
|
||||
namePrefixFlag: "constell-test",
|
||||
projectIDFlag: "constell-1234",
|
||||
stdin: "no\n",
|
||||
wantAbort: true,
|
||||
updateConfigFlag: true,
|
||||
existingConfigFiles: []string{constants.ConfigFilename},
|
||||
},
|
||||
"unwritable fs": {
|
||||
setupFs: readOnlyFs,
|
||||
creator: &stubIAMCreator{id: validIAMIDFile},
|
||||
zoneFlag: "europe-west1-a",
|
||||
serviceAccountIDFlag: "constell-test",
|
||||
projectIDFlag: "constell-1234",
|
||||
yesFlag: true,
|
||||
updateConfigFlag: true,
|
||||
wantErr: true,
|
||||
setupFs: readOnlyFs,
|
||||
creator: &stubIAMCreator{id: validIAMIDFile},
|
||||
zoneFlag: "europe-west1-a",
|
||||
namePrefixFlag: "constell-test",
|
||||
projectIDFlag: "constell-1234",
|
||||
yesFlag: true,
|
||||
updateConfigFlag: true,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -590,6 +599,7 @@ func TestIAMCreateGCP(t *testing.T) {
|
|||
flags: gcpIAMCreateFlags{
|
||||
zone: tc.zoneFlag,
|
||||
serviceAccountID: tc.serviceAccountIDFlag,
|
||||
namePrefix: tc.serviceAccountIDFlag,
|
||||
projectID: tc.projectIDFlag,
|
||||
},
|
||||
},
|
||||
|
|
|
@ -31,13 +31,19 @@ func newIAMCreateGCPCmd() *cobra.Command {
|
|||
cmd.Flags().String("zone", "", "GCP zone the cluster will be deployed in (required)\n"+
|
||||
"Find a list of available zones here: https://cloud.google.com/compute/docs/regions-zones#available")
|
||||
must(cobra.MarkFlagRequired(cmd.Flags(), "zone"))
|
||||
cmd.Flags().String("serviceAccountID", "", "ID for the service account that will be created (required)\n"+
|
||||
"Must be 6 to 30 lowercase letters, digits, or hyphens.")
|
||||
must(cobra.MarkFlagRequired(cmd.Flags(), "serviceAccountID"))
|
||||
|
||||
cmd.Flags().String("serviceAccountID", "", "[Deprecated use \"--prefix\"]ID for the service account that will be created (required)\n"+
|
||||
"Must be 6 to 30 lowercase letters, digits, or hyphens. This flag is mutually exclusive with --prefix.")
|
||||
cmd.Flags().String("prefix", "", "Prefix for the service account ID and VM ID that will be created (required)\n"+
|
||||
"Must be letters, digits, or hyphens.")
|
||||
|
||||
cmd.Flags().String("projectID", "", "ID of the GCP project the configuration will be created in (required)\n"+
|
||||
"Find it on the welcome screen of your project: https://console.cloud.google.com/welcome")
|
||||
must(cobra.MarkFlagRequired(cmd.Flags(), "projectID"))
|
||||
|
||||
cmd.MarkFlagsMutuallyExclusive([]string{"prefix", "serviceAccountID"}...)
|
||||
must(cmd.Flags().MarkDeprecated("serviceAccountID", "use --prefix instead"))
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
@ -53,6 +59,7 @@ func runIAMCreateGCP(cmd *cobra.Command, _ []string) error {
|
|||
type gcpIAMCreateFlags struct {
|
||||
rootFlags
|
||||
serviceAccountID string
|
||||
namePrefix string
|
||||
zone string
|
||||
region string
|
||||
projectID string
|
||||
|
@ -91,9 +98,18 @@ func (f *gcpIAMCreateFlags) parse(flags *pflag.FlagSet) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("getting 'serviceAccountID' flag: %w", err)
|
||||
}
|
||||
if !gcpIDRegex.MatchString(f.serviceAccountID) {
|
||||
if f.serviceAccountID != "" && !gcpIDRegex.MatchString(f.serviceAccountID) {
|
||||
return fmt.Errorf("serviceAccountID %q doesn't match %s", f.serviceAccountID, gcpIDRegex)
|
||||
}
|
||||
|
||||
f.namePrefix, err = flags.GetString("prefix")
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting 'prefix' flag: %w", err)
|
||||
}
|
||||
if f.namePrefix != "" && !gcpPrefixRegex.MatchString(f.namePrefix) {
|
||||
return fmt.Errorf("prefix %q doesn't match %s", f.namePrefix, gcpIDRegex)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -109,13 +125,19 @@ func (c *gcpIAMCreator) getIAMConfigOptions() *cloudcmd.IAMConfigOptions {
|
|||
Region: c.flags.region,
|
||||
ProjectID: c.flags.projectID,
|
||||
ServiceAccountID: c.flags.serviceAccountID,
|
||||
NamePrefix: c.flags.namePrefix,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *gcpIAMCreator) printConfirmValues(cmd *cobra.Command) {
|
||||
cmd.Printf("Project ID:\t\t%s\n", c.flags.projectID)
|
||||
cmd.Printf("Service Account ID:\t%s\n", c.flags.serviceAccountID)
|
||||
if c.flags.namePrefix != "" {
|
||||
cmd.Printf("Name Prefix:\t\t%s\n", c.flags.namePrefix)
|
||||
}
|
||||
if c.flags.serviceAccountID != "" {
|
||||
cmd.Printf("Service Account ID:\t%s\n", c.flags.serviceAccountID)
|
||||
}
|
||||
cmd.Printf("Region:\t\t\t%s\n", c.flags.region)
|
||||
cmd.Printf("Zone:\t\t\t%s\n\n", c.flags.zone)
|
||||
}
|
||||
|
@ -127,11 +149,12 @@ func (c *gcpIAMCreator) printOutputValues(cmd *cobra.Command, _ cloudcmd.IAMOutp
|
|||
cmd.Printf("serviceAccountKeyPath:\t%s\n\n", c.flags.pathPrefixer.PrefixPrintablePath(constants.GCPServiceAccountKeyFilename))
|
||||
}
|
||||
|
||||
func (c *gcpIAMCreator) writeOutputValuesToConfig(conf *config.Config, _ cloudcmd.IAMOutput) {
|
||||
func (c *gcpIAMCreator) writeOutputValuesToConfig(conf *config.Config, out cloudcmd.IAMOutput) {
|
||||
conf.Provider.GCP.Project = c.flags.projectID
|
||||
conf.Provider.GCP.ServiceAccountKeyPath = constants.GCPServiceAccountKeyFilename // File was created in workspace, so only the filename is needed.
|
||||
conf.Provider.GCP.Region = c.flags.region
|
||||
conf.Provider.GCP.Zone = c.flags.zone
|
||||
conf.Provider.GCP.IAMServiceAccountVM = out.GCPOutput.IAMServiceAccountVM
|
||||
for groupName, group := range conf.NodeGroups {
|
||||
group.Zone = c.flags.zone
|
||||
conf.NodeGroups[groupName] = group
|
||||
|
|
|
@ -539,6 +539,7 @@ func defaultConfigWithExpectedMeasurements(t *testing.T, conf *config.Config, cs
|
|||
conf.Provider.GCP.Project = "test-project"
|
||||
conf.Provider.GCP.Zone = "test-zone"
|
||||
conf.Provider.GCP.ServiceAccountKeyPath = "test-key-path"
|
||||
conf.Provider.GCP.IAMServiceAccountVM = "example@example.com"
|
||||
conf.Attestation.GCPSEVSNP.Measurements[4] = measurements.WithAllBytes(0x44, measurements.Enforce, measurements.PCRMeasurementLength)
|
||||
conf.Attestation.GCPSEVSNP.Measurements[9] = measurements.WithAllBytes(0x11, measurements.Enforce, measurements.PCRMeasurementLength)
|
||||
conf.Attestation.GCPSEVSNP.Measurements[12] = measurements.WithAllBytes(0xcc, measurements.Enforce, measurements.PCRMeasurementLength)
|
||||
|
|
|
@ -103,9 +103,18 @@ func (c *Client) ShowIAM(ctx context.Context, provider cloudprovider.Provider) (
|
|||
if !ok {
|
||||
return IAMOutput{}, errors.New("invalid type in service_account_key output: not a string")
|
||||
}
|
||||
IAMServiceAccountVMOutputRaw, ok := tfState.Values.Outputs["service_account_mail_vm"]
|
||||
if !ok {
|
||||
return IAMOutput{}, errors.New("no service_account_mail_vm output found")
|
||||
}
|
||||
IAMServiceAccountVMOutput, ok := IAMServiceAccountVMOutputRaw.Value.(string)
|
||||
if !ok {
|
||||
return IAMOutput{}, errors.New("invalid type in service_account_mail_vm output: not a string")
|
||||
}
|
||||
return IAMOutput{
|
||||
GCP: GCPIAMOutput{
|
||||
SaKey: saKeyOutput,
|
||||
SaKey: saKeyOutput,
|
||||
ServiceAccountVMMailAddress: IAMServiceAccountVMOutput,
|
||||
},
|
||||
}, nil
|
||||
case cloudprovider.Azure:
|
||||
|
@ -539,7 +548,8 @@ type IAMOutput struct {
|
|||
|
||||
// GCPIAMOutput contains the output information of the Terraform IAM operation on GCP.
|
||||
type GCPIAMOutput struct {
|
||||
SaKey string
|
||||
SaKey string
|
||||
ServiceAccountVMMailAddress string
|
||||
}
|
||||
|
||||
// AzureIAMOutput contains the output information of the Terraform IAM operation on Microsoft Azure.
|
||||
|
|
|
@ -120,6 +120,7 @@ func TestPrepareIAM(t *testing.T) {
|
|||
Region: "europe-west1",
|
||||
Zone: "europe-west1-a",
|
||||
ServiceAccountID: "const-test-case",
|
||||
NamePrefix: "test_iam",
|
||||
}
|
||||
azureVars := &AzureIAMVariables{
|
||||
Location: "westus",
|
||||
|
@ -509,6 +510,9 @@ func TestCreateIAM(t *testing.T) {
|
|||
"service_account_key": {
|
||||
Value: "12345678_abcdefg",
|
||||
},
|
||||
"service_account_mail_vm": {
|
||||
Value: "test_iam_service_account_vm",
|
||||
},
|
||||
"subscription_id": {
|
||||
Value: "test_subscription_id",
|
||||
},
|
||||
|
@ -581,7 +585,7 @@ func TestCreateIAM(t *testing.T) {
|
|||
vars: gcpVars,
|
||||
tf: &stubTerraform{showState: newTestState()},
|
||||
fs: afero.NewMemMapFs(),
|
||||
want: IAMOutput{GCP: GCPIAMOutput{SaKey: "12345678_abcdefg"}},
|
||||
want: IAMOutput{GCP: GCPIAMOutput{SaKey: "12345678_abcdefg", ServiceAccountVMMailAddress: "test_iam_service_account_vm"}},
|
||||
},
|
||||
"gcp init fails": {
|
||||
pathBase: path.Join(constants.TerraformEmbeddedDir, "iam"),
|
||||
|
@ -614,7 +618,25 @@ func TestCreateIAM(t *testing.T) {
|
|||
tf: &stubTerraform{
|
||||
showState: &tfjson.State{
|
||||
Values: &tfjson.StateValues{
|
||||
Outputs: map[string]*tfjson.StateOutput{},
|
||||
Outputs: map[string]*tfjson.StateOutput{
|
||||
"service_account_mail_vm": {Value: "test_iam_service_account_vm"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fs: afero.NewMemMapFs(),
|
||||
wantErr: true,
|
||||
},
|
||||
"gcp no service_account_mail_vm": {
|
||||
pathBase: path.Join(constants.TerraformEmbeddedDir, "iam"),
|
||||
provider: cloudprovider.GCP,
|
||||
vars: gcpVars,
|
||||
tf: &stubTerraform{
|
||||
showState: &tfjson.State{
|
||||
Values: &tfjson.StateValues{
|
||||
Outputs: map[string]*tfjson.StateOutput{
|
||||
"service_account_key": {Value: "12345678_abcdefg"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1129,7 +1151,8 @@ func TestShowIAM(t *testing.T) {
|
|||
"GCP success": {
|
||||
tf: &stubTerraform{
|
||||
showState: getTfjsonState(map[string]any{
|
||||
"service_account_key": "key",
|
||||
"service_account_key": "key",
|
||||
"service_account_mail_vm": "example@example.com",
|
||||
}),
|
||||
},
|
||||
csp: cloudprovider.GCP,
|
||||
|
@ -1137,7 +1160,8 @@ func TestShowIAM(t *testing.T) {
|
|||
"GCP wrong data type": {
|
||||
tf: &stubTerraform{
|
||||
showState: getTfjsonState(map[string]any{
|
||||
"service_account_key": map[string]any{},
|
||||
"service_account_key": map[string]any{},
|
||||
"service_account_mail_vm": "example@example.com",
|
||||
}),
|
||||
},
|
||||
csp: cloudprovider.GCP,
|
||||
|
@ -1145,7 +1169,9 @@ func TestShowIAM(t *testing.T) {
|
|||
},
|
||||
"GCP missing key": {
|
||||
tf: &stubTerraform{
|
||||
showState: getTfjsonState(map[string]any{}),
|
||||
showState: getTfjsonState(map[string]any{
|
||||
"service_account_mail_vm": "example@example.com",
|
||||
}),
|
||||
},
|
||||
csp: cloudprovider.GCP,
|
||||
wantErr: true,
|
||||
|
|
|
@ -141,6 +141,8 @@ type GCPClusterVariables struct {
|
|||
InternalLoadBalancer bool `hcl:"internal_load_balancer" cty:"internal_load_balancer"`
|
||||
// CCTechnology is the confidential computing technology to use on the VMs. (`SEV` or `SEV_SNP`)
|
||||
CCTechnology string `hcl:"cc_technology" cty:"cc_technology"`
|
||||
// IAMServiceAccountControlPlane is the IAM service account mail address to attach to VMs.
|
||||
IAMServiceAccountVM string `hcl:"iam_service_account_vm" cty:"iam_service_account_vm"`
|
||||
// AdditionalLables are (optional) additional labels that should be applied to created resources.
|
||||
AdditionalLabels cloudprovider.Tags `hcl:"additional_labels" cty:"additional_labels"`
|
||||
}
|
||||
|
@ -182,6 +184,9 @@ type GCPIAMVariables struct {
|
|||
Zone string `hcl:"zone" cty:"zone"`
|
||||
// ServiceAccountID is the ID of the service account to use.
|
||||
ServiceAccountID string `hcl:"service_account_id" cty:"service_account_id"`
|
||||
// IAMServiceAccountVM is the ID of the service account to attach to VMs.
|
||||
// TODO(@3u13r): Eventually remove this field after v2.22 has been released.
|
||||
NamePrefix string `hcl:"name_prefix,optional" cty:"name_prefix"`
|
||||
}
|
||||
|
||||
// String returns a string representation of the IAM-specific variables, formatted as Terraform variables.
|
||||
|
|
|
@ -122,8 +122,9 @@ func TestGCPClusterVariables(t *testing.T) {
|
|||
DiskType: "pd-ssd",
|
||||
},
|
||||
},
|
||||
CustomEndpoint: "example.com",
|
||||
CCTechnology: "SEV_SNP",
|
||||
CustomEndpoint: "example.com",
|
||||
CCTechnology: "SEV_SNP",
|
||||
IAMServiceAccountVM: "example@example.com",
|
||||
}
|
||||
|
||||
// test that the variables are correctly rendered
|
||||
|
@ -151,10 +152,11 @@ node_groups = {
|
|||
zone = "eu-central-1b"
|
||||
}
|
||||
}
|
||||
custom_endpoint = "example.com"
|
||||
internal_load_balancer = false
|
||||
cc_technology = "SEV_SNP"
|
||||
additional_labels = null
|
||||
custom_endpoint = "example.com"
|
||||
internal_load_balancer = false
|
||||
cc_technology = "SEV_SNP"
|
||||
iam_service_account_vm = "example@example.com"
|
||||
additional_labels = null
|
||||
`
|
||||
got := vars.String()
|
||||
assert.Equal(t, strings.Fields(want), strings.Fields(got)) // to ignore whitespace differences
|
||||
|
@ -173,9 +175,27 @@ func TestGCPIAMVariables(t *testing.T) {
|
|||
region = "eu-central-1"
|
||||
zone = "eu-central-1a"
|
||||
service_account_id = "my-service-account"
|
||||
name_prefix = ""
|
||||
`
|
||||
got := vars.String()
|
||||
assert.Equal(t, strings.Fields(want), strings.Fields(got)) // to ignore whitespace differences
|
||||
|
||||
vars = GCPIAMVariables{
|
||||
Project: "my-project",
|
||||
Region: "eu-central-1",
|
||||
Zone: "eu-central-1a",
|
||||
NamePrefix: "my-prefix",
|
||||
}
|
||||
|
||||
// test that the variables are correctly rendered
|
||||
want = `project_id = "my-project"
|
||||
region = "eu-central-1"
|
||||
zone = "eu-central-1a"
|
||||
service_account_id = ""
|
||||
name_prefix = "my-prefix"
|
||||
`
|
||||
got = vars.String()
|
||||
assert.Equal(t, strings.Fields(want), strings.Fields(got)) // to ignore whitespace differences
|
||||
}
|
||||
|
||||
func TestAzureClusterVariables(t *testing.T) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue