Skip to content

Commit

Permalink
mantle/kola: add test flag to skip passing credentials to instance
Browse files Browse the repository at this point in the history
We want to be able to test that anonymous fetches S3 -> EC2 and
GCS -> GCE work without instance credentials.  This has been a
problem in the past: coreos/ignition#1363
  • Loading branch information
bgilbert committed May 16, 2022
1 parent 0b3b301 commit 4a464b6
Show file tree
Hide file tree
Showing 7 changed files with 38 additions and 22 deletions.
8 changes: 8 additions & 0 deletions mantle/kola/harness.go
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,7 @@ type externalTestMeta struct {
TimeoutMin int `json:"timeoutMin"`
Conflicts []string `json:"conflicts"`
AllowConfigWarnings bool `json:"allowConfigWarnings"`
NoInstanceCreds bool `json:"noInstanceCreds"`
}

// metadataFromTestBinary extracts JSON-in-comment like:
Expand Down Expand Up @@ -990,6 +991,9 @@ ExecStart=%s
} else {
t.Distros = strings.Fields(targetMeta.Distros)
}
if targetMeta.NoInstanceCreds {
t.Flags = append(t.Flags, register.NoInstanceCreds)
}
t.Tags = append(t.Tags, strings.Fields(targetMeta.Tags)...)
// TODO validate tags here
t.RequiredTag = targetMeta.RequiredTag
Expand Down Expand Up @@ -1250,6 +1254,9 @@ func makeNonExclusiveTest(bucket int, tests []*register.Test, flight platform.Fl
if test.HasFlag(register.NoSSHKeyInMetadata) || test.HasFlag(register.NoSSHKeyInUserData) {
plog.Fatalf("Non-exclusive test %v cannot have NoSSHKeyIn* flag", test.Name)
}
if test.HasFlag(register.NoInstanceCreds) {
plog.Fatalf("Non-exclusive test %v cannot have NoInstanceCreds flag", test.Name)
}
if test.HasFlag(register.AllowConfigWarnings) {
plog.Fatalf("Non-exclusive test %v cannot have AllowConfigWarnings flag", test.Name)
}
Expand Down Expand Up @@ -1336,6 +1343,7 @@ func runTest(h *harness.H, t *register.Test, pltfrm string, flight platform.Flig
OutputDir: h.OutputDir(),
NoSSHKeyInUserData: t.HasFlag(register.NoSSHKeyInUserData),
NoSSHKeyInMetadata: t.HasFlag(register.NoSSHKeyInMetadata),
NoInstanceCreds: t.HasFlag(register.NoInstanceCreds),
WarningsAction: conf.FailWarnings,
InternetAccess: testRequiresInternet(t),
}
Expand Down
1 change: 1 addition & 0 deletions mantle/kola/register/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type Flag int
const (
NoSSHKeyInUserData Flag = iota // don't inject SSH key into Ignition/cloud-config
NoSSHKeyInMetadata // don't add SSH key to platform metadata
NoInstanceCreds // don't grant credentials (AWS instance profile, GCP service account) to the instance
NoEmergencyShellCheck // don't check console output for emergency shell invocation
RequiresInternetAccess // run the test only if the platform supports Internet access
AllowConfigWarnings // ignore Ignition and Butane warnings instead of failing
Expand Down
34 changes: 19 additions & 15 deletions mantle/platform/api/aws/ec2.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func (a *API) DeleteKey(name string) error {
}

// CreateInstances creates EC2 instances with a given name tag, optional ssh key name, user data. The image ID, instance type, and security group set in the API will be used. CreateInstances will block until all instances are running and have an IP address.
func (a *API) CreateInstances(name, keyname, userdata string, count uint64, minDiskSize int64) ([]*ec2.Instance, error) {
func (a *API) CreateInstances(name, keyname, userdata string, count uint64, minDiskSize int64, useInstanceProfile bool) ([]*ec2.Instance, error) {
cnt := int64(count)

var ud *string
Expand All @@ -91,9 +91,11 @@ func (a *API) CreateInstances(name, keyname, userdata string, count uint64, minD
ud = &tud
}

err := a.ensureInstanceProfile(a.opts.IAMInstanceProfile)
if err != nil {
return nil, fmt.Errorf("error verifying IAM instance profile: %v", err)
if useInstanceProfile {
err := a.ensureInstanceProfile(a.opts.IAMInstanceProfile)
if err != nil {
return nil, fmt.Errorf("error verifying IAM instance profile: %v", err)
}
}

sgId, err := a.getSecurityGroupID(a.opts.SecurityGroup)
Expand Down Expand Up @@ -131,17 +133,14 @@ func (a *API) CreateInstances(name, keyname, userdata string, count uint64, minD
})
}
inst := ec2.RunInstancesInput{
ImageId: &a.opts.AMI,
MinCount: &cnt,
MaxCount: &cnt,
KeyName: key,
InstanceType: &a.opts.InstanceType,
SecurityGroupIds: []*string{&sgId},
SubnetId: &subnetId,
UserData: ud,
IamInstanceProfile: &ec2.IamInstanceProfileSpecification{
Name: &a.opts.IAMInstanceProfile,
},
ImageId: &a.opts.AMI,
MinCount: &cnt,
MaxCount: &cnt,
KeyName: key,
InstanceType: &a.opts.InstanceType,
SecurityGroupIds: []*string{&sgId},
SubnetId: &subnetId,
UserData: ud,
BlockDeviceMappings: rootBlockDev,
TagSpecifications: []*ec2.TagSpecification{
&ec2.TagSpecification{
Expand All @@ -159,6 +158,11 @@ func (a *API) CreateInstances(name, keyname, userdata string, count uint64, minD
},
},
}
if useInstanceProfile {
inst.IamInstanceProfile = &ec2.IamInstanceProfileSpecification{
Name: &a.opts.IAMInstanceProfile,
}
}

var reservations *ec2.Reservation
err = util.RetryConditional(5, 5*time.Second, func(err error) bool {
Expand Down
12 changes: 7 additions & 5 deletions mantle/platform/api/gcloud/compute.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func (a *API) vmname() string {
}

// Taken from: https://github.com/golang/build/blob/master/buildlet/gce.go
func (a *API) mkinstance(userdata, name string, keys []*agent.Key) *compute.Instance {
func (a *API) mkinstance(userdata, name string, keys []*agent.Key, useServiceAcct bool) *compute.Instance {
mantle := "mantle"
metadataItems := []*compute.MetadataItems{
&compute.MetadataItems{
Expand Down Expand Up @@ -94,13 +94,15 @@ func (a *API) mkinstance(userdata, name string, keys []*agent.Key) *compute.Inst
Network: instancePrefix + "/global/networks/" + a.options.Network,
},
},
}
if useServiceAcct {
// allow the instance to perform authenticated GCS fetches
ServiceAccounts: []*compute.ServiceAccount{
instance.ServiceAccounts = []*compute.ServiceAccount{
&compute.ServiceAccount{
Email: a.options.ServiceAcct,
Scopes: []string{"https://www.googleapis.com/auth/devstorage.read_only"},
},
},
}
}
// add cloud config
if userdata != "" {
Expand All @@ -115,9 +117,9 @@ func (a *API) mkinstance(userdata, name string, keys []*agent.Key) *compute.Inst
}

// CreateInstance creates a Google Compute Engine instance.
func (a *API) CreateInstance(userdata string, keys []*agent.Key) (*compute.Instance, error) {
func (a *API) CreateInstance(userdata string, keys []*agent.Key, useServiceAcct bool) (*compute.Instance, error) {
name := a.vmname()
inst := a.mkinstance(userdata, name, keys)
inst := a.mkinstance(userdata, name, keys, useServiceAcct)

plog.Debugf("Creating instance %q", name)

Expand Down
2 changes: 1 addition & 1 deletion mantle/platform/machine/aws/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func (ac *cluster) NewMachineWithOptions(userdata *conf.UserData, options platfo
fmt.Printf("WARNING: compressed userdata exceeds expected limit of %d\n", MaxUserDataSize)
}
}
instances, err := ac.flight.api.CreateInstances(ac.Name(), keyname, ud, 1, int64(options.MinDiskSize))
instances, err := ac.flight.api.CreateInstances(ac.Name(), keyname, ud, 1, int64(options.MinDiskSize), !ac.RuntimeConf().NoInstanceCreds)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion mantle/platform/machine/gcloud/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func (gc *cluster) NewMachineWithOptions(userdata *conf.UserData, options platfo
}
}

instance, err := gc.flight.api.CreateInstance(conf.String(), keys)
instance, err := gc.flight.api.CreateInstance(conf.String(), keys, !gc.RuntimeConf().NoInstanceCreds)
if err != nil {
return nil, err
}
Expand Down
1 change: 1 addition & 0 deletions mantle/platform/platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ type RuntimeConfig struct {

NoSSHKeyInUserData bool // don't inject SSH key into Ignition/cloud-config
NoSSHKeyInMetadata bool // don't add SSH key to platform metadata
NoInstanceCreds bool // don't grant credentials (AWS instance profile, GCP service account) to the instance
AllowFailedUnits bool // don't fail CheckMachine if a systemd unit has failed
WarningsAction conf.WarningsAction // what to do on Ignition or Butane validation warnings

Expand Down

0 comments on commit 4a464b6

Please sign in to comment.