@@ -16,9 +16,14 @@ import (
1616 "github.com/openshift/installer/pkg/asset/installconfig"
1717)
1818
19+ const (
20+ master = "master"
21+ worker = "worker"
22+ )
23+
1924var (
2025 policies = map [string ]* iamv1.PolicyDocument {
21- " master" : {
26+ master : {
2227 Version : "2012-10-17" ,
2328 Statement : []iamv1.StatementEntry {
2429 {
6974 },
7075 },
7176 },
72- " worker" : {
77+ worker : {
7378 Version : "2012-10-17" ,
7479 Statement : []iamv1.StatementEntry {
7580 {
8590 }
8691)
8792
88- // putIAMRoles creates the roles used by control-plane and compute nodes.
89- func putIAMRoles (ctx context.Context , clusterID string , ic * installconfig.InstallConfig ) error {
93+ // createIAMRoles creates the roles used by control-plane and compute nodes.
94+ func createIAMRoles (ctx context.Context , infraID string , ic * installconfig.InstallConfig ) error {
9095 logrus .Infoln ("Creating IAM roles for control-plane and compute nodes" )
9196 // Create the IAM Role with the aws sdk.
9297 // https://docs.aws.amazon.com/sdk-for-go/api/service/iam/#IAM.CreateRole
@@ -97,9 +102,18 @@ func putIAMRoles(ctx context.Context, clusterID string, ic *installconfig.Instal
97102 svc := iam .New (session )
98103
99104 // Create the IAM Roles for master and workers.
100- clusterOwnedIAMTag := & iam.Tag {
101- Key : aws .String (fmt .Sprintf ("kubernetes.io/cluster/%s" , clusterID )),
102- Value : aws .String ("owned" ),
105+ tags := []* iam.Tag {
106+ {
107+ Key : aws .String (fmt .Sprintf ("kubernetes.io/cluster/%s" , infraID )),
108+ Value : aws .String ("owned" ),
109+ },
110+ }
111+
112+ for k , v := range ic .Config .AWS .UserTags {
113+ tags = append (tags , & iam.Tag {
114+ Key : aws .String (k ),
115+ Value : aws .String (v ),
116+ })
103117 }
104118
105119 assumePolicy := & iamv1.PolicyDocument {
@@ -123,43 +137,27 @@ func putIAMRoles(ctx context.Context, clusterID string, ic *installconfig.Instal
123137 return fmt .Errorf ("failed to marshal assume policy: %w" , err )
124138 }
125139
126- for _ , role := range []string {"master" , "worker" } {
127- roleName := aws .String (fmt .Sprintf ("%s-%s-role" , clusterID , role ))
128- if _ , err := svc .GetRoleWithContext (ctx , & iam.GetRoleInput {RoleName : roleName }); err != nil {
129- var awsErr awserr.Error
130- if errors .As (err , & awsErr ) && awsErr .Code () != iam .ErrCodeNoSuchEntityException {
131- return fmt .Errorf ("failed to get %s role: %w" , role , err )
132- }
133- // If the role does not exist, create it.
134- createRoleInput := & iam.CreateRoleInput {
135- RoleName : roleName ,
136- AssumeRolePolicyDocument : aws .String (string (assumePolicyBytes )),
137- Tags : []* iam.Tag {clusterOwnedIAMTag },
138- }
139- if _ , err := svc .CreateRoleWithContext (ctx , createRoleInput ); err != nil {
140- return fmt .Errorf ("failed to create %s role: %w" , role , err )
141- }
142-
143- if err := svc .WaitUntilRoleExistsWithContext (ctx , & iam.GetRoleInput {RoleName : roleName }); err != nil {
144- return fmt .Errorf ("failed to wait for %s role to exist: %w" , role , err )
145- }
140+ for _ , role := range []string {master , worker } {
141+ roleName , err := getOrCreateIAMRole (ctx , role , infraID , string (assumePolicyBytes ), * ic , tags , svc )
142+ if err != nil {
143+ return fmt .Errorf ("failed to create IAM roles: %w" , err )
146144 }
147145
148146 // Put the policy inline.
149- policyName := aws .String (fmt .Sprintf ("%s-%s-policy" , clusterID , role ))
147+ policyName := aws .String (fmt .Sprintf ("%s-%s-policy" , infraID , role ))
150148 b , err := json .Marshal (policies [role ])
151149 if err != nil {
152150 return fmt .Errorf ("failed to marshal %s policy: %w" , role , err )
153151 }
154152 if _ , err := svc .PutRolePolicyWithContext (ctx , & iam.PutRolePolicyInput {
155153 PolicyDocument : aws .String (string (b )),
156154 PolicyName : policyName ,
157- RoleName : roleName ,
155+ RoleName : aws . String ( roleName ) ,
158156 }); err != nil {
159157 return fmt .Errorf ("failed to create inline policy for role %s: %w" , role , err )
160158 }
161159
162- profileName := aws .String (fmt .Sprintf ("%s-%s-profile" , clusterID , role ))
160+ profileName := aws .String (fmt .Sprintf ("%s-%s-profile" , infraID , role ))
163161 if _ , err := svc .GetInstanceProfileWithContext (ctx , & iam.GetInstanceProfileInput {InstanceProfileName : profileName }); err != nil {
164162 var awsErr awserr.Error
165163 if errors .As (err , & awsErr ) && awsErr .Code () != iam .ErrCodeNoSuchEntityException {
@@ -168,7 +166,7 @@ func putIAMRoles(ctx context.Context, clusterID string, ic *installconfig.Instal
168166 // If the profile does not exist, create it.
169167 if _ , err := svc .CreateInstanceProfileWithContext (ctx , & iam.CreateInstanceProfileInput {
170168 InstanceProfileName : profileName ,
171- Tags : [] * iam. Tag { clusterOwnedIAMTag } ,
169+ Tags : tags ,
172170 }); err != nil {
173171 return fmt .Errorf ("failed to create %s instance profile: %w" , role , err )
174172 }
@@ -179,7 +177,7 @@ func putIAMRoles(ctx context.Context, clusterID string, ic *installconfig.Instal
179177 // Finally, attach the role to the profile.
180178 if _ , err := svc .AddRoleToInstanceProfileWithContext (ctx , & iam.AddRoleToInstanceProfileInput {
181179 InstanceProfileName : profileName ,
182- RoleName : roleName ,
180+ RoleName : aws . String ( roleName ) ,
183181 }); err != nil {
184182 return fmt .Errorf ("failed to add %s role to instance profile: %w" , role , err )
185183 }
@@ -189,6 +187,55 @@ func putIAMRoles(ctx context.Context, clusterID string, ic *installconfig.Instal
189187 return nil
190188}
191189
190+ // getOrCreateRole returns the name of the IAM role to be used,
191+ // creating it when not specified by the user in the install config.
192+ func getOrCreateIAMRole (ctx context.Context , nodeRole , infraID , assumePolicy string , ic installconfig.InstallConfig , tags []* iam.Tag , svc * iam.IAM ) (string , error ) {
193+ roleName := aws .String (fmt .Sprintf ("%s-%s-role" , infraID , nodeRole ))
194+
195+ var defaultRole string
196+ if dmp := ic .Config .AWS .DefaultMachinePlatform ; dmp != nil && len (dmp .IAMRole ) > 0 {
197+ defaultRole = dmp .IAMRole
198+ }
199+
200+ masterRole := defaultRole
201+ if cp := ic .Config .ControlPlane ; cp != nil && cp .Platform .AWS != nil && len (cp .Platform .AWS .IAMRole ) > 0 {
202+ masterRole = cp .Platform .AWS .IAMRole
203+ }
204+
205+ workerRole := defaultRole
206+ if w := ic .Config .Compute ; len (w ) > 0 && w [0 ].Platform .AWS != nil && len (w [0 ].Platform .AWS .IAMRole ) > 0 {
207+ workerRole = w [0 ].Platform .AWS .IAMRole
208+ }
209+
210+ switch {
211+ case nodeRole == master && len (masterRole ) > 0 :
212+ return masterRole , nil
213+ case nodeRole == worker && len (workerRole ) > 0 :
214+ return workerRole , nil
215+ }
216+
217+ if _ , err := svc .GetRoleWithContext (ctx , & iam.GetRoleInput {RoleName : roleName }); err != nil {
218+ var awsErr awserr.Error
219+ if errors .As (err , & awsErr ) && awsErr .Code () != iam .ErrCodeNoSuchEntityException {
220+ return "" , fmt .Errorf ("failed to get %s role: %w" , nodeRole , err )
221+ }
222+ // If the role does not exist, create it.
223+ createRoleInput := & iam.CreateRoleInput {
224+ RoleName : roleName ,
225+ AssumeRolePolicyDocument : aws .String (assumePolicy ),
226+ Tags : tags ,
227+ }
228+ if _ , err := svc .CreateRoleWithContext (ctx , createRoleInput ); err != nil {
229+ return "" , fmt .Errorf ("failed to create %s role: %w" , nodeRole , err )
230+ }
231+
232+ if err := svc .WaitUntilRoleExistsWithContext (ctx , & iam.GetRoleInput {RoleName : roleName }); err != nil {
233+ return "" , fmt .Errorf ("failed to wait for %s role to exist: %w" , nodeRole , err )
234+ }
235+ }
236+ return * roleName , nil
237+ }
238+
192239func getPartitionService (region string ) string {
193240 partitionDNSSuffix := "amazonaws.com"
194241 if ps , found := endpoints .PartitionForRegion (endpoints .DefaultPartitions (), region ); found {
0 commit comments