github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/internal/adapters/cloud/aws/iam/user.go (about) 1 package iam 2 3 import ( 4 "fmt" 5 "strings" 6 "time" 7 8 "github.com/khulnasoft-lab/defsec/pkg/concurrency" 9 defsecTypes "github.com/khulnasoft-lab/defsec/pkg/types" 10 11 iamapi "github.com/aws/aws-sdk-go-v2/service/iam" 12 iamtypes "github.com/aws/aws-sdk-go-v2/service/iam/types" 13 "github.com/khulnasoft-lab/defsec/pkg/providers/aws/iam" 14 "github.com/khulnasoft-lab/defsec/pkg/state" 15 ) 16 17 func (a *adapter) adaptUsers(state *state.State) error { 18 19 a.Tracker().SetServiceLabel("Discovering users...") 20 21 var nativeUsers []iamtypes.User 22 23 input := &iamapi.ListUsersInput{} 24 for { 25 usersOutput, err := a.api.ListUsers(a.Context(), input) 26 if err != nil { 27 return err 28 } 29 nativeUsers = append(nativeUsers, usersOutput.Users...) 30 a.Tracker().SetTotalResources(len(nativeUsers)) 31 if !usersOutput.IsTruncated { 32 break 33 } 34 input.Marker = usersOutput.Marker 35 } 36 37 a.Tracker().SetServiceLabel("Adapting users...") 38 39 state.AWS.IAM.Users = concurrency.Adapt(nativeUsers, a.RootAdapter, a.adaptUser) 40 return nil 41 } 42 43 func (a *adapter) getMFADevices(user iamtypes.User) ([]iam.MFADevice, error) { 44 input := &iamapi.ListMFADevicesInput{ 45 Marker: nil, 46 UserName: user.UserName, 47 } 48 var apiDevices []iamtypes.MFADevice 49 for { 50 output, err := a.api.ListMFADevices(a.Context(), input) 51 if err != nil { 52 return nil, err 53 } 54 apiDevices = append(apiDevices, output.MFADevices...) 55 if !output.IsTruncated { 56 break 57 } 58 input.Marker = output.Marker 59 } 60 61 var devices []iam.MFADevice 62 for _, apiDevice := range apiDevices { 63 isVirtual := true 64 metadata := a.CreateMetadataFromARN(*apiDevice.SerialNumber) 65 if !strings.HasPrefix(*apiDevice.SerialNumber, "arn:") { 66 metadata = a.CreateMetadataFromARN(*user.Arn) 67 isVirtual = false 68 } 69 devices = append(devices, iam.MFADevice{ 70 Metadata: metadata, 71 IsVirtual: defsecTypes.Bool(isVirtual, metadata), 72 }) 73 } 74 75 return devices, nil 76 } 77 78 func (a *adapter) getUserGroups(apiUser iamtypes.User) []iam.Group { 79 var groups []iam.Group 80 81 input := &iamapi.ListGroupsForUserInput{ 82 UserName: apiUser.UserName, 83 } 84 for { 85 output, err := a.api.ListGroupsForUser(a.Context(), input) 86 if err != nil { 87 a.Debug("Failed to locate groups attached to user '%s': %s", *apiUser.UserName, err) 88 break 89 } 90 for _, apiGroup := range output.Groups { 91 group, err := a.adaptGroup(apiGroup, nil) 92 if err != nil { 93 a.Debug("Failed to adapt group attached to user '%s': %s", *apiUser.UserName, err) 94 continue 95 } 96 groups = append(groups, *group) 97 } 98 if !output.IsTruncated { 99 break 100 } 101 input.Marker = output.Marker 102 } 103 return groups 104 } 105 106 func (a *adapter) getUserPolicies(apiUser iamtypes.User) []iam.Policy { 107 var policies []iam.Policy 108 input := &iamapi.ListAttachedUserPoliciesInput{ 109 UserName: apiUser.UserName, 110 } 111 for { 112 policiesOutput, err := a.api.ListAttachedUserPolicies(a.Context(), input) 113 if err != nil { 114 a.Debug("Failed to locate policies attached to user '%s': %s", *apiUser.UserName, err) 115 break 116 } 117 118 for _, apiPolicy := range policiesOutput.AttachedPolicies { 119 policy, err := a.adaptAttachedPolicy(apiPolicy) 120 if err != nil { 121 a.Debug("Failed to adapt policy attached to user '%s': %s", *apiUser.UserName, err) 122 continue 123 } 124 policies = append(policies, *policy) 125 } 126 127 if !policiesOutput.IsTruncated { 128 break 129 } 130 input.Marker = policiesOutput.Marker 131 } 132 return policies 133 } 134 135 func (a *adapter) getUserKeys(apiUser iamtypes.User) ([]iam.AccessKey, error) { 136 137 var keys []iam.AccessKey 138 metadata := a.CreateMetadataFromARN(*apiUser.Arn) 139 input := iamapi.ListAccessKeysInput{ 140 UserName: apiUser.UserName, 141 } 142 for { 143 output, err := a.api.ListAccessKeys(a.Context(), &input) 144 if err != nil { 145 return nil, err 146 } 147 for _, apiAccessKey := range output.AccessKeyMetadata { 148 149 lastUsed := defsecTypes.TimeUnresolvable(metadata) 150 if output, err := a.api.GetAccessKeyLastUsed(a.Context(), &iamapi.GetAccessKeyLastUsedInput{ 151 AccessKeyId: apiAccessKey.AccessKeyId, 152 }); err == nil { 153 if output.AccessKeyLastUsed != nil && output.AccessKeyLastUsed.LastUsedDate != nil { 154 lastUsed = defsecTypes.Time(*output.AccessKeyLastUsed.LastUsedDate, metadata) 155 } 156 } 157 158 accessKeyId := defsecTypes.StringDefault("", metadata) 159 if apiAccessKey.AccessKeyId != nil { 160 accessKeyId = defsecTypes.String(*apiAccessKey.AccessKeyId, metadata) 161 } 162 163 creationDate := defsecTypes.TimeDefault(time.Now(), metadata) 164 if apiAccessKey.CreateDate != nil { 165 creationDate = defsecTypes.Time(*apiAccessKey.CreateDate, metadata) 166 } 167 168 keys = append(keys, iam.AccessKey{ 169 Metadata: metadata, 170 AccessKeyId: accessKeyId, 171 Active: defsecTypes.Bool(apiAccessKey.Status == iamtypes.StatusTypeActive, metadata), 172 CreationDate: creationDate, 173 LastAccess: lastUsed, 174 }) 175 } 176 if !output.IsTruncated { 177 break 178 } 179 input.Marker = output.Marker 180 } 181 return keys, nil 182 } 183 184 func (a *adapter) adaptUser(apiUser iamtypes.User) (*iam.User, error) { 185 186 if apiUser.Arn == nil { 187 return nil, fmt.Errorf("user arn not specified") 188 } 189 if apiUser.UserName == nil { 190 return nil, fmt.Errorf("user name not specified") 191 } 192 193 metadata := a.CreateMetadataFromARN(*apiUser.Arn) 194 195 groups := a.getUserGroups(apiUser) 196 197 policies := a.getUserPolicies(apiUser) 198 199 keys, err := a.getUserKeys(apiUser) 200 if err != nil { 201 return nil, err 202 } 203 204 mfaDevices, err := a.getMFADevices(apiUser) 205 if err != nil { 206 return nil, err 207 } 208 209 lastAccess := defsecTypes.TimeUnresolvable(metadata) 210 if apiUser.PasswordLastUsed != nil { 211 lastAccess = defsecTypes.Time(*apiUser.PasswordLastUsed, metadata) 212 } 213 214 username := defsecTypes.StringDefault("", metadata) 215 if apiUser.UserName != nil { 216 username = defsecTypes.String(*apiUser.UserName, metadata) 217 } 218 219 return &iam.User{ 220 Metadata: metadata, 221 Name: username, 222 Groups: groups, 223 Policies: policies, 224 AccessKeys: keys, 225 MFADevices: mfaDevices, 226 LastAccess: lastAccess, 227 }, nil 228 }