Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/asset/machines/aws/clusterapi_machinesets.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func ClusterAPIMachineSets(in *MachineSetInput) ([]capa.AWSMachineTemplate, []ca

instanceProfile := mpool.IAMProfile
if len(instanceProfile) == 0 {
instanceProfile = fmt.Sprintf("%s-worker-profile", in.ClusterID)
instanceProfile = fmt.Sprintf("%s-%s-profile", in.ClusterID, in.Role)
}

tags, err := CapaTagsFromUserTags(in.ClusterID, in.InstallConfigPlatformAWS.UserTags)
Expand Down
23 changes: 22 additions & 1 deletion pkg/asset/machines/aws/clusterapi_machinesets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func TestClusterAPIMachineSets(t *testing.T) {
},
},
{
name: "default IAM profile uses cluster ID",
name: "default worker IAM profile uses the worker pool role",
input: func() *MachineSetInput {
in := defaultMachineSetInput()
in.Pool.Platform.AWS.Zones = []string{"us-east-1a"}
Expand All @@ -199,6 +199,26 @@ func TestClusterAPIMachineSets(t *testing.T) {
}
},
},
{
name: "default edge IAM profile uses the edge pool role",
input: func() *MachineSetInput {
in := defaultMachineSetInput()
in.Role = types.MachinePoolEdgeRoleName
in.Pool.Platform.AWS.Zones = []string{"us-east-1a"}
in.Pool.Replicas = ptr.To(int64(1))
return in
}(),
validate: func(t *testing.T, templates []capa.AWSMachineTemplate, _ []capi.MachineSet) {
t.Helper()
if len(templates) != 1 {
t.Fatalf("expected 1 template, got %d", len(templates))
}
got := templates[0].Spec.Template.Spec.IAMInstanceProfile
if got != "test-cluster-edge-profile" {
t.Errorf("IAM profile = %q, want %q", got, "test-cluster-edge-profile")
}
},
},
{
name: "custom IAM profile",
input: func() *MachineSetInput {
Expand Down Expand Up @@ -307,6 +327,7 @@ func defaultMachineSetInput() *MachineSetInput {
InstallConfigPlatformAWS: &awstypes.Platform{
Region: "us-east-1",
},
Role: types.MachinePoolComputeRoleName,
Pool: &types.MachinePool{
Name: types.MachinePoolComputeRoleName,
Replicas: ptr.To(int64(3)),
Expand Down
2 changes: 1 addition & 1 deletion pkg/asset/machines/aws/machinesets.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func MachineSets(in *MachineSetInput) ([]*machineapi.MachineSet, error) {

instanceProfile := mpool.IAMProfile
if len(instanceProfile) == 0 {
instanceProfile = fmt.Sprintf("%s-worker-profile", in.ClusterID)
instanceProfile = fmt.Sprintf("%s-%s-profile", in.ClusterID, in.Role)
Comment thread
tthvo marked this conversation as resolved.
}

dedicatedHost := DedicatedHost(in.Hosts, mpool.HostPlacement, az)
Expand Down
2 changes: 1 addition & 1 deletion pkg/destroy/aws/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ func (o *ClusterUninstaller) RunWithContext(ctx context.Context) ([]string, erro
func (o *ClusterUninstaller) findUntaggableResources(ctx context.Context, deleted sets.Set[string]) (sets.Set[string], error) {
resources := sets.New[string]()
o.Logger.Debug("search for IAM instance profiles")
for _, profileType := range []string{"master", "worker", "bootstrap"} {
for _, profileType := range []string{"master", "worker", "bootstrap", "edge"} {
profile := fmt.Sprintf("%s-%s-profile", o.ClusterID, profileType)
response, err := o.IAMClient.GetInstanceProfile(ctx, &iamv2.GetInstanceProfileInput{InstanceProfileName: &profile})
if err != nil {
Expand Down
65 changes: 57 additions & 8 deletions pkg/infrastructure/aws/clusterapi/iam.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ import (

"github.com/openshift/installer/pkg/asset/installconfig"
awsconfig "github.com/openshift/installer/pkg/asset/installconfig/aws"
"github.com/openshift/installer/pkg/types"
awstypes "github.com/openshift/installer/pkg/types/aws"
)

const (
master = "master"
worker = "worker"
master = types.MachinePoolControlPlaneRoleName
worker = types.MachinePoolComputeRoleName
edge = types.MachinePoolEdgeRoleName
)

var (
Expand Down Expand Up @@ -93,6 +95,19 @@ var (
},
},
},
edge: {
Version: "2012-10-17",
Statement: []iamv1.StatementEntry{
{
Effect: "Allow",
Action: iamv1.Actions{
"ec2:DescribeInstances",
"ec2:DescribeRegions",
},
Resource: iamv1.Resources{"*"},
},
},
},
}
)

Expand Down Expand Up @@ -155,16 +170,28 @@ func createIAMRoles(ctx context.Context, infraID string, ic *installconfig.Insta
defaultProfile = dmp.IAMProfile
}

for _, role := range []string{master, worker} {
// Reconcile a role for the control plane plus every configured compute
// pool. The worker pool is always present; the edge pool is optional and
// only appears here when the user has configured it.
roles := []string{master}
for _, compute := range ic.Config.Compute {
roles = append(roles, compute.Name)
Comment thread
tthvo marked this conversation as resolved.
}

for _, role := range roles {
instanceProfile := defaultProfile
switch role {
case master:
if cp := ic.Config.ControlPlane; cp != nil && cp.Platform.AWS != nil && len(cp.Platform.AWS.IAMProfile) > 0 {
instanceProfile = cp.Platform.AWS.IAMProfile
}
case worker:
if w := ic.Config.Compute; len(w) > 0 && w[0].Platform.AWS != nil && len(w[0].Platform.AWS.IAMProfile) > 0 {
instanceProfile = w[0].Platform.AWS.IAMProfile
if wp := getComputeMachinePoolByName(ic, worker); wp != nil && wp.Platform.AWS != nil && len(wp.Platform.AWS.IAMProfile) > 0 {
instanceProfile = wp.Platform.AWS.IAMProfile
}
case edge:
if ep := getComputeMachinePoolByName(ic, edge); ep != nil && ep.Platform.AWS != nil && len(ep.Platform.AWS.IAMProfile) > 0 {
instanceProfile = ep.Platform.AWS.IAMProfile
}
}

Expand Down Expand Up @@ -228,15 +255,22 @@ func getOrCreateIAMRole(ctx context.Context, nodeRole, infraID, assumePolicy str
}

workerRole := defaultRole
if w := ic.Config.Compute; len(w) > 0 && w[0].Platform.AWS != nil && len(w[0].Platform.AWS.IAMRole) > 0 {
workerRole = w[0].Platform.AWS.IAMRole
if wp := getComputeMachinePoolByName(&ic, worker); wp != nil && wp.Platform.AWS != nil && len(wp.Platform.AWS.IAMRole) > 0 {
workerRole = wp.Platform.AWS.IAMRole
}

edgeRole := defaultRole
if ep := getComputeMachinePoolByName(&ic, edge); ep != nil && ep.Platform.AWS != nil && len(ep.Platform.AWS.IAMRole) > 0 {
edgeRole = ep.Platform.AWS.IAMRole
}

switch {
case nodeRole == master && len(masterRole) > 0:
return masterRole, nil
case nodeRole == worker && len(workerRole) > 0:
return workerRole, nil
case nodeRole == edge && len(edgeRole) > 0:
return edgeRole, nil
}

if _, err := svc.GetRole(ctx, &iam.GetRoleInput{RoleName: roleName}); err != nil {
Expand All @@ -262,8 +296,12 @@ func getOrCreateIAMRole(ctx context.Context, nodeRole, infraID, assumePolicy str
}

// Put the policy inline.
policy, ok := policies[nodeRole]
if !ok {
return "", fmt.Errorf("no IAM policy defined for role %q", nodeRole)
}
policyName := aws.String(fmt.Sprintf("%s-%s-policy", infraID, nodeRole))
b, err := json.Marshal(policies[nodeRole])
b, err := json.Marshal(policy)
if err != nil {
return "", fmt.Errorf("failed to marshal %s policy: %w", nodeRole, err)
}
Expand Down Expand Up @@ -306,3 +344,14 @@ func getEC2ServicePrincipal(region string) (string, error) {
logrus.Debugf("Using domain name: %s for EC2 service principal ID", domain)
return fmt.Sprintf("ec2.%s", domain), nil
}

// getComputeMachinePoolByName returns the machine pool for the compute pool with the
// given role name (worker or edge).
func getComputeMachinePoolByName(ic *installconfig.InstallConfig, name string) *types.MachinePool {
for _, compute := range ic.Config.Compute {
if compute.Name == name {
return &compute
}
}
return nil
}