Thursday, May 11, 2017

Auditing AWS IAM Users

Like any other company with sensitive data we go through audits pretty regularly. The latest one included some questions about accounts that have access to sensitive data, and the number of auth factors required to log into them.

As usual I started digging around in the AWS Powershell Tools to find a way to make this job easier than just manually looking through accounts, and I quickly found Request-IAMCredentialReport and Get-IAMCredentialReport.

These two commands are a pretty interesting combination. The first tells AWS to generate a credential report. Request-IAMCredentialReport is the step required to generate the report on AWS's end. There's some pretty good documentation on how that section works. The most interesting point to me is that AWS will only generate a report every 4 hours. This is important to note if you're making changes, and re-running reports to double check they fixed an issue.

The second command, Get-IAMCredentialReport actually downloads the report that's generated. From what I've seen, if you haven't run Request-IAMCredentialReport in the last 4 hours to have a fresh report, this command will fail.

I found the output of this command to be the most useful when I included the -AsTextArray option. That returns an array of lines of the report with the columns separated by columns. I won't include an sample output from our accounts for obvious reasons, but check the documentation for an example of what that looks like.

Now that we've got all of the components to download this report, it's pretty trivial powershell work to do some parsing and logic.

The script example below creates an array of maps for each line of the report, letting you iterate over it and check for different conditions.

The one I'm testing for now is IAM accounts that have passwords enabled, but do not have an MFA device activated, but you can see it would be pretty easy to add additional criteria that would be tested against the report.

$awsProfiles = @("FirstProfileName","SecondProfileName");
set-DefaultAWSRegion us-east-1;
foreach ($awsProfile in $awsProfiles) {
    write-host "Running audit on $awsProfile";
    Set-AWSCredentials -ProfileName $awsProfile;
    # Attempt to get an IAM credential report, if one does not exist, sleep to let one generate
    $reportResult = Request-IAMCredentialReport -Force;

    # Sleep for 15 seconds to allow the report to generate
    start-sleep -s 15

    try {

        # Get IAM Credential report
        $credReports = Get-IAMCredentialReport -AsTextArray;
    } catch {
        write-host "No credential report exists for this account, please run script again in a few minutes to let one generate";
    # Empty list that will contain parsed, formatted credential reports
    $credReportList = @();

    # Get the headings from the report
    $headings = $credReports[0].split(",");

    # Start processing the report, starting after the headings
    for ($i = 1; $i -lt $credReports.length; $i++) {

        # Break up the line of the report by commas
        $splitLine = $credReports[$i].split(",");
        $lineMap = @{};

        # Go through the line of the report and set a map key of the header for that column
        for ($j = 0; $j -lt $headings.length; $j++) {
            $lineMap[$headings[$j]] = $splitLine[$j];

        # Add the formatted line to the final list
        $credReportList += , $lineMap;

    # Iterate over the report, using rules to evaluate the contents
    foreach($credReport in  $credReportList) {
        # Check for users that have an active password, but not an active MFA device
        if($credReport['password_enabled'] -eq "TRUE" -and $credReport['mfa_active'] -eq "FALSE") {
            write-host "ALERT: User: $($credReport['user']) has a password enabled, but no MFA device"
    write-host "";

This script assumes you have created AWS Powershell tools profiles that match the array on the first line.

And here is some example output of users I had to go have a chat with today to activate their MFA devices.

NOTE: You may need to run this script a couple times, if you haven't generated an IAM Credential Report in a while.