@@ -288,3 +288,178 @@ func (o *iamUserResourceType) CreateAccount(
288288 IsCreateAccountResult : true ,
289289 }, nil , nil , nil
290290}
291+
292+ func (o * iamUserResourceType ) Delete (ctx context.Context , resourceId * v2.ResourceId , parentResourceID * v2.ResourceId ) (annotations.Annotations , error ) {
293+ var noSuchEntity * iamTypes.NoSuchEntityException
294+ l := ctxzap .Extract (ctx )
295+ if resourceId .ResourceType != resourceTypeIAMUser .Id {
296+ return nil , fmt .Errorf ("aws-connector: only IAM user resources can be deleted" )
297+ }
298+ userName , err := iamUserNameFromARN (resourceId .Resource )
299+ if err != nil {
300+ return nil , err
301+ }
302+ awsStringUserName := awsSdk .String (userName )
303+
304+ iamClient := o .iamClient
305+ if parentResourceID != nil {
306+ iamClient , err = o .awsClientFactory .GetIAMClient (ctx , parentResourceID .Resource )
307+ if err != nil {
308+ return nil , fmt .Errorf ("aws-connector: GetIAMClient failed: %w" , err )
309+ }
310+ }
311+
312+ // try to fetch the user, if not found then the user has already been deleted
313+ user , err := iamClient .GetUser (ctx , & iam.GetUserInput {UserName : awsStringUserName })
314+ if err != nil {
315+ if errors .As (err , & noSuchEntity ) {
316+ l .Info ("User not found, returning success for delete operation" )
317+ return nil , nil
318+ }
319+ return nil , fmt .Errorf ("aws-connector: iam.GetUser failed: %w" , err )
320+ }
321+
322+ if user .User == nil {
323+ return nil , fmt .Errorf ("aws-connector: user not found" )
324+ }
325+
326+ // To delete a user through the API we'll need to manually delete information associated with it,
327+ // which is a 10 step process (9 + delete itself).
328+ // https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_remove.html#id_users_deleting_cli
329+
330+ // Permission needed: iam:DeleteLoginProfile
331+ _ , err = iamClient .DeleteLoginProfile (ctx , & iam.DeleteLoginProfileInput {UserName : awsStringUserName })
332+ if err != nil {
333+ if ! errors .As (err , & noSuchEntity ) {
334+ return nil , fmt .Errorf ("aws-connector: failed to delete login profile: %w" , err )
335+ }
336+ l .Info ("login profile not found, skipping" )
337+ }
338+
339+ // Delete all access keys
340+ // Permission needed: iam:ListAccessKeys, iam:DeleteAccessKey
341+ keys , err := iamClient .ListAccessKeys (ctx , & iam.ListAccessKeysInput {UserName : awsStringUserName })
342+ if err != nil {
343+ return nil , fmt .Errorf ("aws-connector: failed to list access keys: %w" , err )
344+ }
345+
346+ for _ , key := range keys .AccessKeyMetadata {
347+ _ , err = iamClient .DeleteAccessKey (ctx , & iam.DeleteAccessKeyInput {UserName : awsStringUserName , AccessKeyId : awsSdk .String (awsSdk .ToString (key .AccessKeyId ))})
348+ if err != nil {
349+ return nil , fmt .Errorf ("aws-connector: failed to delete access key: %w" , err )
350+ }
351+ }
352+
353+ // Delete all signing certificates
354+ // Permission needed: iam:ListSigningCertificates, iam:DeleteSigningCertificate
355+ certificates , err := iamClient .ListSigningCertificates (ctx , & iam.ListSigningCertificatesInput {UserName : awsStringUserName })
356+ if err != nil {
357+ return nil , fmt .Errorf ("aws-connector: failed to list signing certificates: %w" , err )
358+ }
359+
360+ for _ , certificate := range certificates .Certificates {
361+ _ , err = iamClient .DeleteSigningCertificate (ctx , & iam.DeleteSigningCertificateInput {UserName : awsStringUserName , CertificateId : awsSdk .String (awsSdk .ToString (certificate .CertificateId ))})
362+ if err != nil {
363+ return nil , fmt .Errorf ("aws-connector: failed to delete signing certificate: %w" , err )
364+ }
365+ }
366+
367+ // Delete all SSH public keys
368+ // Permission needed: iam:ListSSHPublicKeys, iam:DeleteSSHPublicKey
369+ sshKeys , err := iamClient .ListSSHPublicKeys (ctx , & iam.ListSSHPublicKeysInput {UserName : awsStringUserName })
370+ if err != nil {
371+ return nil , fmt .Errorf ("aws-connector: failed to list SSH public keys: %w" , err )
372+ }
373+
374+ for _ , key := range sshKeys .SSHPublicKeys {
375+ _ , err = iamClient .DeleteSSHPublicKey (ctx , & iam.DeleteSSHPublicKeyInput {UserName : awsStringUserName , SSHPublicKeyId : awsSdk .String (awsSdk .ToString (key .SSHPublicKeyId ))})
376+ if err != nil {
377+ return nil , fmt .Errorf ("aws-connector: failed to delete SSH public key: %w" , err )
378+ }
379+ }
380+
381+ // Delete all service specific credentials
382+ // Permission needed: iam:ListServiceSpecificCredentials, iam:DeleteServiceSpecificCredential
383+ ssCredentials , err := iamClient .ListServiceSpecificCredentials (ctx , & iam.ListServiceSpecificCredentialsInput {UserName : awsStringUserName })
384+ if err != nil {
385+ return nil , fmt .Errorf ("aws-connector: failed to list service specific credentials: %w" , err )
386+ }
387+
388+ for _ , credential := range ssCredentials .ServiceSpecificCredentials {
389+ _ , err = iamClient .DeleteServiceSpecificCredential (
390+ ctx ,
391+ & iam.DeleteServiceSpecificCredentialInput {
392+ UserName : awsStringUserName ,
393+ ServiceSpecificCredentialId : awsSdk .String (awsSdk .ToString (credential .ServiceSpecificCredentialId )),
394+ },
395+ )
396+ if err != nil {
397+ return nil , fmt .Errorf ("aws-connector: failed to delete service specific credential: %w" , err )
398+ }
399+ }
400+
401+ // If user has MFA, deactivate them
402+ // Permission needed: iam:ListMFADevices, iam:DeactivateMFADevice
403+ mfaDevices , err := iamClient .ListMFADevices (ctx , & iam.ListMFADevicesInput {UserName : awsStringUserName })
404+ if err != nil {
405+ return nil , fmt .Errorf ("aws-connector: failed to list MFA devices: %w" , err )
406+ }
407+
408+ for _ , device := range mfaDevices .MFADevices {
409+ _ , err = iamClient .DeactivateMFADevice (ctx , & iam.DeactivateMFADeviceInput {UserName : awsStringUserName , SerialNumber : awsSdk .String (awsSdk .ToString (device .SerialNumber ))})
410+ if err != nil {
411+ return nil , fmt .Errorf ("aws-connector: failed to deactivate MFA device: %w" , err )
412+ }
413+ }
414+
415+ // Delete users inline policies
416+ // Permission needed: iam:ListUserPolicies, iam:DeleteUserPolicy
417+ userPolicies , err := iamClient .ListUserPolicies (ctx , & iam.ListUserPoliciesInput {UserName : awsStringUserName })
418+ if err != nil {
419+ return nil , fmt .Errorf ("aws-connector: failed to list user policies: %w" , err )
420+ }
421+
422+ for _ , policy := range userPolicies .PolicyNames {
423+ _ , err = iamClient .DeleteUserPolicy (ctx , & iam.DeleteUserPolicyInput {UserName : awsStringUserName , PolicyName : awsSdk .String (policy )})
424+ if err != nil {
425+ return nil , fmt .Errorf ("aws-connector: failed to delete user policy: %w" , err )
426+ }
427+ }
428+
429+ // List and detach all attached policies
430+ // Permission needed: iam:ListAttachedUserPolicies, iam:DetachUserPolicy
431+ attachedPolicies , err := iamClient .ListAttachedUserPolicies (ctx , & iam.ListAttachedUserPoliciesInput {UserName : awsStringUserName })
432+ if err != nil {
433+ return nil , fmt .Errorf ("aws-connector: failed to list attached user policies: %w" , err )
434+ }
435+
436+ for _ , policy := range attachedPolicies .AttachedPolicies {
437+ _ , err = iamClient .DetachUserPolicy (ctx , & iam.DetachUserPolicyInput {UserName : awsStringUserName , PolicyArn : awsSdk .String (awsSdk .ToString (policy .PolicyArn ))})
438+ if err != nil {
439+ return nil , fmt .Errorf ("aws-connector: failed to detach user policy: %w" , err )
440+ }
441+ }
442+
443+ // Remove the user from any IAM groups
444+ // Permission needed: iam:ListGroupsForUser, iam:RemoveUserFromGroup
445+ userGroups , err := iamClient .ListGroupsForUser (ctx , & iam.ListGroupsForUserInput {UserName : awsStringUserName })
446+ if err != nil {
447+ return nil , fmt .Errorf ("aws-connector: failed to list groups for user: %w" , err )
448+ }
449+
450+ for _ , group := range userGroups .Groups {
451+ _ , err = iamClient .RemoveUserFromGroup (ctx , & iam.RemoveUserFromGroupInput {UserName : awsStringUserName , GroupName : awsSdk .String (awsSdk .ToString (group .GroupName ))})
452+ if err != nil {
453+ return nil , fmt .Errorf ("aws-connector: failed to remove user from group: %w" , err )
454+ }
455+ }
456+
457+ // Proceed to delete the user
458+ // Permission needed: iam:DeleteUser
459+ _ , err = iamClient .DeleteUser (ctx , & iam.DeleteUserInput {UserName : awsStringUserName })
460+ if err != nil {
461+ return nil , fmt .Errorf ("aws-connector: failed to delete user: %w" , err )
462+ }
463+
464+ return nil , nil
465+ }
0 commit comments