Skip to content

chiberry/serverless-iam-key-sentry

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 

Repository files navigation

Serverless IAM Old Key Sentry

Changing access keys (which consist of an access key ID and a secret access key) on a regular schedule is a well-known security best practice because it shortens the period an access key is active and therefore reduces the business impact if they are compromised. Having an established process that is run regularly also ensures the operational steps around key rotation are verified, so changing a key is never a scary step.

Identifying applications and services with old keys become imperative in those case. We are going to use Lambda Functions to periodically check our account for old keys and notify our Security Operations Team using SNS

Fig : Valaxy-Serverless-Security-Group-Sentry You can also follow this article in Youtube

Pre-Requisities

We will need the following pre-requisites to successfully complete this activity,

  • Few IAM Users with one or two Access Key created in the AWS Region where the solution is deployed
  • Security Operations SNS Topic ARN - If you need assistance, follow this article
  • IAM Role - i.e Lambda Service Role - with
    • IAMReadOnlyAccess permissions
    • AmazonSNSFullAccess permissions
    • You may use an Inline policy with more restrictive permissions

The image above shows the execution order, that should not be confused with the numbering of steps given here

Step 1 - Configure Lambda Function- Serverless-IAM-Sentry

The below script is written in Python 2.7. Remember to choose the same in AWS Lambda Functions.

Customisations

  • globalVars['key_age'] - Set the key_age to any value you desire, by default it is set to 90 days
  • globalVars['SecOpsTopicArn'] - Update the ARN of your SNS Topic

Change the global variables at the top of the script to suit your needs.

# List IAM users having 90 days older Access keys

import datetime, boto3, os, json
from botocore.exceptions import ClientError

# Set the global variables
globalVars  = {}
globalVars['Owner']                 = "Miztiik"
globalVars['Environment']           = "Test"
globalVars['REGION_NAME']           = "ap-south-1"
globalVars['tagName']               = "Valaxy-Serverless-IAM-Key-Sentry"
globalVars['key_age']               = "90"
globalVars['SecOpsTopicArn']        = ""

def get_usr_old_keys( keyAge ):
    client = boto3.client('iam',region_name = globalVars['REGION_NAME'])
    snsClient = boto3.client('sns',region_name = globalVars['REGION_NAME'])
    usersList=client.list_users()
   
    timeLimit=datetime.datetime.now() - datetime.timedelta( days = int(keyAge) )
    usrsWithOldKeys = {'Users':[],'Description':'List of users with Key Age greater than (>=) {} days'.format(keyAge),'KeyAgeCutOff':keyAge}

    # Iterate through list of users and compare with `key_age` to flag old key owners
    for k in usersList['Users']:
        accessKeys=client.list_access_keys(UserName=k['UserName'])
    
        # Iterate for all users
        for key in accessKeys['AccessKeyMetadata']:
            if key['CreateDate'].date() <= timeLimit.date():
                usrsWithOldKeys['Users'].append({ 'UserName': k['UserName'], 'KeyAgeInDays': (datetime.date.today() - key['CreateDate'].date()).days })

        # If no users found with older keys, add message in response
        if not usrsWithOldKeys['Users']:
            usrsWithOldKeys['OldKeyCount'] = 'Found 0 Keys that are older than {} days'.format(keyAge)
        else:
            usrsWithOldKeys['OldKeyCount'] = 'Found {0} Keys that are older than {1} days'.format(len(usrsWithOldKeys['Users']), keyAge)

    try:
        snsClient.get_topic_attributes( TopicArn= globalVars['SecOpsTopicArn'] )
        snsClient.publish(TopicArn = globalVars['SecOpsTopicArn'], Message = json.dumps(usrsWithOldKeys, indent=4) )
        usrsWithOldKeys['SecOpsEmailed']="Yes"
    except ClientError as e:
        usrsWithOldKeys['SecOpsEmailed']="No - SecOpsTopicArn is Incorrect"

    return usrsWithOldKeys


def lambda_handler(event, context):   
    # Set the default cutoff if env variable is not set
    globalVars['key_age'] = int(os.getenv('key_age',90))
    globalVars['SecOpsTopicArn']=str(os.getenv('SecOpsTopicArn'))

    return get_usr_old_keys( globalVars['key_age'] )

After pasting the code, Scroll down to create a environment variable Key,

  1. Key as key_age_cutoff_in_days and Value as 90
  2. Key SecOpsTopicArn and Value as YOUR-SNS-TOPIC-ARN

Save the lambda function

Step 2 - Configure Lambda Triggers

We are going to use Cloudwatch Scheduled Events to take backup everyday.

rate(1 minute)
or
rate(5 minutes)
or
rate(1 day)
# The below example creates a rule that is triggered every day at 12:00pm UTC.
cron(0 12 * * ? *)

If you want to learn more about the above Scheduled expressions, Ref: CloudWatch - Schedule Expressions for Rules

Step 3 - Testing the solution

If you already have IAM Users with Access Keys, then set the key_age to appropirate values. If not, Create multiple IAM Users and create Access Key for each of them and set the key_age to 1.

Rotate access keys

After you have identified old keys, You should follow these steps to rotate the keys

  1. Create a second access key in addition to the one in use.
  2. Update all your applications to use the new access key and validate that the applications are working.
  3. Change the state of the previous access key to inactive.
  4. Validate that your applications are still working as expected.
  5. Delete the inactive access key.

Summary

We have demonstrated how you can automatically identify users with old Access/Secret Keys.

About

Find and list Access Keys older than certain date

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Python 100.0%