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  }