{ "cells": [ { "cell_type": "markdown", "id": "394caeb2", "metadata": {}, "source": [ "# IAM Credential Compromise - Containment\n", "This notebook is to be used in case of malicious activity inside your AWS Account.\n", "We will query CloudTrail logs using Athena in order to detect and contain malicious account activity.\n", "\n", "We are following best practices from the AWS Incident Response guide as we execute our processes:\n", "\n", "https://docs.aws.amazon.com/whitepapers/latest/aws-security-incident-response-guide/aws-security-incident-response-guide.html" ] }, { "cell_type": "markdown", "id": "6a9f5f5a", "metadata": {}, "source": [ "# Setup" ] }, { "cell_type": "markdown", "id": "e3c4bf4d", "metadata": {}, "source": [ "## Load Libraries\n", "\n", "In order to query CloudTrail and interact with AWS, we need to load several libraries and configure our environment." ] }, { "cell_type": "code", "execution_count": null, "id": "ad09e1c1", "metadata": { "tags": [] }, "outputs": [], "source": [ "pip install pyathena --quiet" ] }, { "cell_type": "code", "execution_count": null, "id": "89920512", "metadata": { "tags": [] }, "outputs": [], "source": [ "import boto3 # the Python SDK for AWS\n", "import pandas as pd # Pandas is a data analysis tool for Python\n", "from pyathena import connect # Python API client for Amazon Athena\n", "region='us-east-1' # Set region variable to us-east-1 for API commands\n", "athena_bucket = 's3:// ENTER BUCKET NAME HERE /' # S3 bucket that is configured to store your Athena queries\n", "db_name = 'security_analysis' # database used by Athena. Choose 'default' if your CloudTrail was created via the Athena console and 'security_analysis' if you are using the AWS Security Analytics Bootstrap" ] }, { "cell_type": "markdown", "id": "7b274378-f99b-4cb3-a8ee-044e8e1e239e", "metadata": {}, "source": [ "## 1.0 Set up helper function for Athena" ] }, { "cell_type": "markdown", "id": "dedf4f39-ee24-4abe-8624-2be862c0d904", "metadata": {}, "source": [ "The Python query_results function shown below will help you query Athena tables." ] }, { "cell_type": "code", "execution_count": null, "id": "99ea6040-0508-4269-bc3f-190825d9580b", "metadata": { "tags": [] }, "outputs": [], "source": [ "def query_results(sql):\n", " \n", " cursor = connect(s3_staging_dir=athena_bucket, region_name=region).cursor()\n", " cursor.execute(sql)\n", " \n", " columns = cursor.description\n", " data = cursor.fetchall()\n", "\n", " column_names = [column[0] for column in columns]\n", " rows = [dict(zip(column_names, data_row)) for data_row in data]\n", "\n", " df = pd.DataFrame(rows, columns=column_names)\n", " df1 = df.style.set_table_styles([dict(selector='th', props=[('text-align', 'center')])])\n", " \n", " return df1.set_properties(**{'text-align': 'center'})" ] }, { "cell_type": "markdown", "id": "7005432a", "metadata": { "tags": [] }, "source": [ "## 3. IAM Containment\n", "Now that you have identified the potential IAM entity which has been compromised you need to perform containment activities. The first of these will be to find out what the Access Key ID is being used by the account.\n" ] }, { "cell_type": "markdown", "id": "48b1bde6", "metadata": {}, "source": [ "### 3.1 Identify Access Key ID" ] }, { "cell_type": "code", "execution_count": null, "id": "251269e2", "metadata": {}, "outputs": [], "source": [ "keyid = f\"\"\"\n", "\n", "select useridentity.accesskeyid, count(*) as total\n", "from \"{db_name}\".\"cloudtrail\" \n", "where userIdentity.arn='insert ARN of IAM Credential from query in 2.2'\n", "group by useridentity.accesskeyid\n", "order by total desc\n", "\n", "\"\"\"" ] }, { "cell_type": "code", "execution_count": null, "id": "f076dbb3", "metadata": {}, "outputs": [], "source": [ "results = query_results(keyid)\n", "results" ] }, { "cell_type": "markdown", "id": "18fc0d0e", "metadata": {}, "source": [ "### 3.2 Deactivate Access Key" ] }, { "cell_type": "code", "execution_count": null, "id": "b7c2b6d8", "metadata": {}, "outputs": [], "source": [ "access_key_to_deactivate='ENTER ACCESS KEY ID HERE'\n", "username='ENTER USERNAME HERE'\n", "iam = boto3.resource('iam', region_name=region)\n", "access_key = iam.AccessKey(username,access_key_to_deactivate)\n", "response_status = access_key.deactivate()\n", "status_code = response_status['ResponseMetadata']['HTTPStatusCode']\n", "if status_code == 200:\n", " print('Key Disabled Successfully')\n", "else:\n", " print('Key deactivation failed')" ] }, { "cell_type": "markdown", "id": "8d8f0c1d", "metadata": {}, "source": [ "### 3.3 Attach Deny All Actions Policy" ] }, { "cell_type": "code", "execution_count": null, "id": "1084109d", "metadata": {}, "outputs": [], "source": [ "username='ENTER USERNAME HERE'\n", "iam = boto3.client('iam', region_name=region)\n", "response = iam.put_user_policy(UserName=username,PolicyName='Block',PolicyDocument='{\"Version\":\"2012-10-17\",\"Statement\":{\"Effect\":\"Deny\",\"Action\":\"*\",\"Resource\":\"*\"}}')\n", "status_code = response['ResponseMetadata']['HTTPStatusCode']\n", "if status_code == 200:\n", " print('Policy attached successfully')\n", "else:\n", " print('Policy attachment failed')\n" ] }, { "cell_type": "markdown", "id": "15d37785-3ed5-41a9-af1f-6f4d99137f3b", "metadata": {}, "source": [ "## [Credential Compromise Detection Notebook](./credential-compromise-detection.ipynb)" ] } ], "metadata": { "kernelspec": { "display_name": "conda_python3", "language": "python", "name": "conda_python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.8" } }, "nbformat": 4, "nbformat_minor": 5 }