From f61cb9a088fd0682e498cf4b7f47a16147422342 Mon Sep 17 00:00:00 2001 From: John Lukach Date: Sat, 22 Jun 2024 13:12:45 +0000 Subject: [PATCH] 2024.06.21 --- README.md | 53 +-- botoplus.ipynb | 177 --------- botoplus/__init__.py | 2 +- botoplus/deflation.py | 146 +++++++ botoplus/identity.py | 151 ++++++++ botoplus/{botoplus.py => organization.py} | 120 +++--- notebooks/analysis/deflation.ipynb | 88 +++++ notebooks/cdk/identify-cdk-bootstraps.ipynb | 15 +- .../cdk/remove-bootstrap-everywhere.ipynb | 158 -------- ...=> periodic-daily-config-recordings.ipynb} | 124 +++++- .../disable-serial-console-access.ipynb} | 29 +- .../enable-image-block-public-access.ipynb} | 30 +- .../enable-snapshot-block-public-access.ipynb | 66 ++++ .../ec2/public-amazon-machine-images.ipynb | 67 ---- .../identify-privileged-accounts.ipynb | 6 +- .../minimal-cost-configuration.ipynb | 157 -------- .../deregister-delegated-administrator.ipynb | 48 --- .../securitylake/resolver-query-logs.ipynb | 281 -------------- notebooks/securitylake/searching.ipynb | 362 ------------------ notebooks/vpc/delete-default-vpcs.ipynb | 100 ----- notebooks/vpc/identify-default-vpcs.ipynb | 68 ++++ notebooks/vpc/ip-address-conflicts.ipynb | 117 ------ setup.py | 12 +- start.ipynb | 103 +++++ 24 files changed, 844 insertions(+), 1636 deletions(-) delete mode 100644 botoplus.ipynb create mode 100644 botoplus/deflation.py create mode 100644 botoplus/identity.py rename botoplus/{botoplus.py => organization.py} (51%) create mode 100644 notebooks/analysis/deflation.ipynb delete mode 100644 notebooks/cdk/remove-bootstrap-everywhere.ipynb rename notebooks/controltower/{periodic-daily-donfig-recordings.ipynb => periodic-daily-config-recordings.ipynb} (55%) rename notebooks/{s3/public-cors-configuration.ipynb => ec2/disable-serial-console-access.ipynb} (53%) rename notebooks/{cloudformation/delete-stack-everywhere.ipynb => ec2/enable-image-block-public-access.ipynb} (55%) create mode 100644 notebooks/ec2/enable-snapshot-block-public-access.ipynb delete mode 100644 notebooks/ec2/public-amazon-machine-images.ipynb delete mode 100644 notebooks/securityhub/minimal-cost-configuration.ipynb delete mode 100644 notebooks/securitylake/deregister-delegated-administrator.ipynb delete mode 100644 notebooks/securitylake/resolver-query-logs.ipynb delete mode 100644 notebooks/securitylake/searching.ipynb delete mode 100644 notebooks/vpc/delete-default-vpcs.ipynb create mode 100644 notebooks/vpc/identify-default-vpcs.ipynb delete mode 100644 notebooks/vpc/ip-address-conflicts.ipynb create mode 100644 start.ipynb diff --git a/README.md b/README.md index 16cca75..c493684 100644 --- a/README.md +++ b/README.md @@ -4,41 +4,15 @@ | Notebook | Description | | -------- | ----------- | -| [botoplus](botoplus.ipynb) | Authentication & Dependencies | -| [searching](notebooks/securitylake/searching.ipynb) | Searching the Security Lake Logs | +| [start](start.ipynb) | IAM Identity Center (SSO) Login & Logout | -### Security Lake - -| Notebook | Description | -| -------- | ----------- | -| [resolver-query-logs](notebooks/securitylake/resolver-query-logs.ipynb) | Amazon Route53 Resolver Query Logs | - -## More Notebooks +## Threat Detection ### Cloud Development Kit (CDK) | Notebook | Description | | -------- | ----------- | | [identify-cdk-bootstraps](notebooks/cdk/identify-cdk-bootstraps.ipynb) | Identify CDK Bootstraps with Versions for All Accounts & Regions | -| [remove-bootstrap-everywhere](notebooks/cdk/remove-bootstrap-everywhere.ipynb) | Remove CDK Bootstraps with provided Qualifier from Everywhere | - -### CloudFormation - -| Notebook | Description | -| -------- | ----------- | -| [delete-stack-everywhere](notebooks/cloudformation/delete-stack-everywhere.ipynb) | Delete CloudFormation Stack Everywhere | - -### Control Tower - -| Notebook | Description | -| -------- | ----------- | -| [periodic-daily-donfig-recordings](notebooks/controltower/periodic-daily-donfig-recordings.ipynb) | Setup Config Daily Recordings | - -### Elastic Compute Cloud (EC2) - -| Notebook | Description | -| -------- | ----------- | -| [public-amazon-machine-images](notebooks/ec2/public-amazon-machine-images.ipynb) | Find Public Amazon Machine Images | ### Organizations @@ -46,27 +20,32 @@ | -------- | ----------- | | [identify-privileged-accounts](notebooks/organizations/identify-privileged-accounts.ipynb) | List of Delegated Administration Accounts & Services | -### Security Hub +### Virtual Private Cloud (VPC) | Notebook | Description | | -------- | ----------- | -| [minimal-cost-configuration](notebooks/securityhub/minimal-cost-configuration.ipynb) | Disable All Standards & Limit Subscriptions | +| [identify-default-vpcs](notebooks/vpc/identify-default-vpcs.ipynb) | Identify Default VPCs Across All Regions | + +## Threat Response -### Security Lake +### Elastic Compute Cloud (EC2) | Notebook | Description | | -------- | ----------- | -| [deregister-delegated-administrator](notebooks/securitylake/deregister-delegated-administrator.ipynb) | Deregister Delegated Administrator | +| [disable-serial-console-access](notebooks/ec2/disable-serial-console-access.ipynb) | Disable Serial Console Access | +| [enable-image-block-public-access](notebooks/ec2/enable-image-block-public-access.ipynb) | Enable Image Block Public Access | +| [enable-snapshot-block-public-access](notebooks/ec2/enable-snapshot-block-public-access.ipynb) | Enable Snapshot Block Public Access | -### Simple Storage Service (S3) +## Threat Utilities + +### Analysis | Notebook | Description | | -------- | ----------- | -| [public-cors-configuration](notebooks/s3/public-cors-configuration.ipynb) | Find potentially public S3 Buckets with CORS Configured | +| [deflation](notebooks/analysis/deflation.ipynb) | Deflation of Data Structures | -### Virtual Private Cloud (VPC) +### Control Tower | Notebook | Description | | -------- | ----------- | -| [delete-default-vpcs](notebooks/vpc/delete-default-vpcs.ipynb) | Delete Default VPCs Across All Regions | -| [ip-address-conflicts](notebooks/vpc/ip-address-conflicts.ipynb) | Identify IP address conflicts, default VPCs, & IPv6 configs | +| [periodic-daily-config-recordings](notebooks/controltower/periodic-daily-config-recordings.ipynb) | Setup or Stop Config Periodic Daily Recordings | diff --git a/botoplus.ipynb b/botoplus.ipynb deleted file mode 100644 index 5979b9f..0000000 --- a/botoplus.ipynb +++ /dev/null @@ -1,177 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### AWS IAM Identity Center (SSO)\n", - "##### AWS Command Line Interface (AWS CLI) Version 2 Requirement\n", - "https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "\n", - "os.system('curl \"https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip\" -o \"../awscliv2.zip\"')\n", - "os.system('unzip -o ../awscliv2.zip -d ../')\n", - "os.system('cd .. && sudo ./aws/install --update')\n", - "os.system('aws --version')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Python Library for Jupyter Notebooks\n", - "https://github.com/botoplus/botoplus" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import sys\n", - "\n", - "!{sys.executable} -m pip install botoplus --upgrade" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Aqueduct Utility for IAM Identity Center (SSO) Authenication\n", - "https://github.com/jblukach/aqueduct" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import sys\n", - "\n", - "!{sys.executable} -m pip install aqueduct-utility --upgrade" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Login Example\n", - "\n", - "```\n", - "Identity Store: portal\n", - "SSO Region: us-east-2\n", - "SSO Role: AWSAdministratorAccess\n", - "CLI Region: us-east-2\n", - "CLI Output: json\n", - "Authenticated!!\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import aqueduct.identity as _idp\n", - "\n", - "_idp.login()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Logout Example\n", - "\n", - "```\n", - "Logged Out!!\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import aqueduct.identity as _idp\n", - "\n", - "_idp.logout()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Local Development" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "\n", - "os.system('python setup.py install --user')" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Build Test" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import botoplus.botoplus as botoplus\n", - "\n", - "botoplus.hello()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "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.13" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/botoplus/__init__.py b/botoplus/__init__.py index 49399d7..4cd34b3 100644 --- a/botoplus/__init__.py +++ b/botoplus/__init__.py @@ -1 +1 @@ -__version__ = VERSION = '2023.12.1' \ No newline at end of file +__version__ = VERSION = '2024.06.21' \ No newline at end of file diff --git a/botoplus/deflation.py b/botoplus/deflation.py new file mode 100644 index 0000000..8efbcee --- /dev/null +++ b/botoplus/deflation.py @@ -0,0 +1,146 @@ +import uuid + +def _dict(count,data,key): + + count += 1 + indent = _indent(count) + + for k,v in data[key].items(): + + print(indent+k+' '+str(type(v))) + + if type(v) is dict: + _dict(count,data[key],k) + + if type(v) is list: + _list(count,data[key],k) + +def _dictdeflate(count,data,key,deflated,dupe): + + count += 1 + + for k,v in data[key].items(): + + if type(v) is not dict and type(v) is not list: + + name = k+'_'+str(count) + + if name in dupe: + name = name+'_'+str(uuid.uuid1()) + + dupe.append(name) + deflated[name] = v + + if type(v) is dict: + _dictdeflate(count,data[key],k,deflated,dupe) + + if type(v) is list: + _listdeflate(count,data[key],k,deflated,dupe) + +def _indent(count): + return '\t' * count + +def _list(count,data,key): + + count += 1 + indent = _indent(count) + index = 0 + + for item in data[key]: + + print(indent+str(index)+' '+str(type(item))) + + if type(item) is dict: + _dict(count,data[key],index) + + if type(item) is list: + _list(count,data[key],index) + + index += 1 + +def _listdeflate(count,data,key,deflated,dupe): + + count += 1 + index = 0 + + for item in data[key]: + + if type(item) is not dict and type(item) is not list: + + name = key+'_'+str(count)+'_'+str(index) + + if name in dupe: + name = name+'_'+str(uuid.uuid1()) + + dupe.append(name) + deflated[name] = item + + if type(item) is dict: + _dictdeflate(count,data[key],index,deflated,dupe) + + if type(item) is list: + _listdeflate(count,data[key],index,deflated,dupe) + + index += 1 + +def deflation(data,dupe): + + deflated = {} + + count = 0 + + if type(data) is dict: + + for k,v in data.items(): + + if type(v) is not dict and type(v) is not list: + + name = k + + if name in dupe: + name = name+'_'+str(uuid.uuid1()) + + deflated[name] = v + + if type(v) is dict: + _dictdeflate(count,data,k,deflated,dupe) + + if type(v) is list: + _listdeflate(count,data,k,deflated,dupe) + + return deflated + +def strturuce(data): + + if type(data) is dict: + + for key, value in data.items(): + + count = 0 + indent = _indent(count) + + print(indent+key+' '+str(type(value))) + + if type(value) is dict: + _dict(count,data,key) + + if type(value) is list: + _list(count,data,key) + + if type(data) is list: + + for item in data: + + count = 0 + indent = _indent(count) + index = 0 + + print(indent+str(index)+' '+str(type(item))) + + if type(item) is dict: + _dict(count,data,index) + + if type(item) is list: + _list(count,data,index) + + index += 1 diff --git a/botoplus/identity.py b/botoplus/identity.py new file mode 100644 index 0000000..6189a51 --- /dev/null +++ b/botoplus/identity.py @@ -0,0 +1,151 @@ +import aws_sso_lib +import pathlib +import typer + +def login(): + + ### previous login ### + + idp = pathlib.Path.joinpath(pathlib.Path.home(),'.botoplus_idp') + sso = pathlib.Path.joinpath(pathlib.Path.home(),'.botoplus_sso') + role = pathlib.Path.joinpath(pathlib.Path.home(),'.botoplus_role') + cli = pathlib.Path.joinpath(pathlib.Path.home(),'.botoplus_cli') + out = pathlib.Path.joinpath(pathlib.Path.home(),'.botoplus_output') + + ### identity provider ### + + if idp.is_file() == False: + + identity_store = typer.prompt("Identity Store").strip() + pathlib.Path(idp).write_text(identity_store) + + else: + + identity_store = pathlib.Path(idp).read_text() + correct = typer.confirm("Identity Store {"+identity_store+"}") + + if not correct: + + identity_store = typer.prompt("Identity Store").strip() + pathlib.Path(idp).write_text(identity_store) + + ### sso region ### + + if sso.is_file() == False: + + sso_region = typer.prompt("SSO Region").strip() + pathlib.Path(sso).write_text(sso_region) + + else: + + sso_region = pathlib.Path(sso).read_text() + correct = typer.confirm("SSO Region {"+sso_region+"}") + + if not correct: + + sso_region = typer.prompt("SSO Region").strip() + pathlib.Path(sso).write_text(sso_region) + + ### sso login ### + + login = aws_sso_lib.login( + start_url = 'https://'+identity_store+'.awsapps.com/start', + sso_region = sso_region + ) + + ### sso role ### + + if role.is_file() == False: + + sso_role = typer.prompt("SSO Role").strip() + pathlib.Path(role).write_text(sso_role) + + else: + + sso_role = pathlib.Path(role).read_text() + correct = typer.confirm("SSO Role {"+sso_role+"}") + + if not correct: + + sso_role = typer.prompt("SSO Role").strip() + pathlib.Path(role).write_text(sso_role) + + ### cli region ### + + if cli.is_file() == False: + + cli_region = typer.prompt("CLI Region").strip() + pathlib.Path(cli).write_text(cli_region) + + else: + + cli_region = pathlib.Path(cli).read_text() + correct = typer.confirm("CLI Region {"+cli_region+"}") + + if not correct: + + cli_region = typer.prompt("CLI Region").strip() + pathlib.Path(cli).write_text(cli_region) + + ### cli output ### + + if out.is_file() == False: + + cli_output = typer.prompt("CLI Output").strip() + pathlib.Path(out).write_text(cli_output) + + else: + + cli_output = pathlib.Path(out).read_text() + correct = typer.confirm("CLI Output {"+cli_output+"}") + + if not correct: + + cli_output = typer.prompt("CLI Output").strip() + pathlib.Path(out).write_text(cli_output) + + ### configuration ### + + config = pathlib.Path.joinpath(pathlib.Path.home(),'.aws','config') + pathlib.Path(config).parents[0].mkdir(parents = True, exist_ok = True) + + accounts = aws_sso_lib.list_available_accounts( + start_url = 'https://'+identity_store+'.awsapps.com/start', + sso_region = sso_region, + login = True + ) + + f = pathlib.Path(config).open('w') + + for account in accounts: + + alias = account[1].replace(' ','') + + f.write('[profile '+alias+']\n') + f.write('credential_process = aws-sso-util credential-process --profile '+alias+'\n') + f.write('sso_start_url = https://'+identity_store+'.awsapps.com/start\n') + f.write('sso_region = '+sso_region+'\n') + f.write('sso_account_id = '+account[0]+'\n') + f.write('sso_role_name = '+sso_role+'\n') + f.write('region = '+cli_region+'\n') + f.write('output = '+cli_output+'\n\n') + + f.close() + + print('Logged In!!') + +def logout(): + + identity = pathlib.Path.joinpath(pathlib.Path.home(),'.botoplus_idp') + identity_store = pathlib.Path(identity).read_text() + + sso = pathlib.Path.joinpath(pathlib.Path.home(),'.botoplus_sso') + sso_region = pathlib.Path(sso).read_text() + + aws_sso_lib.sso.logout( + start_url = 'https://'+identity_store+'.awsapps.com/start', + sso_region = sso_region, + sso_cache = None + ) + + print('Logged Out!!') diff --git a/botoplus/botoplus.py b/botoplus/organization.py similarity index 51% rename from botoplus/botoplus.py rename to botoplus/organization.py index e058c76..5053230 100644 --- a/botoplus/botoplus.py +++ b/botoplus/organization.py @@ -4,30 +4,30 @@ def account(selected_account,identity_store,sso_region): - accounts = aws_sso_lib.list_available_accounts( + awsaccounts = aws_sso_lib.list_available_accounts( start_url = 'https://'+identity_store+'.awsapps.com/start', sso_region = sso_region, login = True ) - for account in accounts: - if account[0] == selected_account: + for acct in awsaccounts: + if acct[0] == selected_account: item = {} - item['awsaccount'] = account[0] - item['awsalias'] = account[1] + item['awsaccount'] = acct[0] + item['awsalias'] = acct[1] return item raise typer.Abort() def accounts(): - identity = pathlib.Path.joinpath(pathlib.Path.home(),'.aqueduct_idp') + identity = pathlib.Path.joinpath(pathlib.Path.home(),'.botoplus_idp') identity_store = pathlib.Path(identity).read_text() - sso = pathlib.Path.joinpath(pathlib.Path.home(),'.aqueduct_sso') + sso = pathlib.Path.joinpath(pathlib.Path.home(),'.botoplus_sso') sso_region = pathlib.Path(sso).read_text() - accounts = aws_sso_lib.list_available_accounts( + awsaccounts = aws_sso_lib.list_available_accounts( start_url = 'https://'+identity_store+'.awsapps.com/start', sso_region = sso_region, login = True @@ -35,74 +35,56 @@ def accounts(): acctlist = [] - for account in accounts: - acct = {} - acct['awsaccount'] = account[0] - acct['awsalias'] = account[1] - acctlist.append(acct) + for acct in awsaccounts: + + item = {} + item['awsaccount'] = acct[0] + item['awsalias'] = acct[1] + acctlist.append(item) return acctlist def alias(selected_account,identity_store,sso_region): - accounts = aws_sso_lib.list_available_accounts( + awsaccounts = aws_sso_lib.list_available_accounts( start_url = 'https://'+identity_store+'.awsapps.com/start', sso_region = sso_region, login = True ) - for account in accounts: - if account[1].lower() == selected_account.lower(): + for acct in awsaccounts: + if acct[1].lower() == selected_account.lower(): item = {} - item['awsaccount'] = account[0] - item['awsalias'] = account[1] + item['awsaccount'] = acct[0] + item['awsalias'] = acct[1] return item raise typer.Abort() -def convert(selected_account): +def selected(): - identity = pathlib.Path.joinpath(pathlib.Path.home(),'.aqueduct_idp') + identity = pathlib.Path.joinpath(pathlib.Path.home(),'.botoplus_idp') identity_store = pathlib.Path(identity).read_text() - sso = pathlib.Path.joinpath(pathlib.Path.home(),'.aqueduct_sso') + sso = pathlib.Path.joinpath(pathlib.Path.home(),'.botoplus_sso') sso_region = pathlib.Path(sso).read_text() - accounts = aws_sso_lib.list_available_accounts( - start_url = 'https://'+identity_store+'.awsapps.com/start', - sso_region = sso_region, - login = True - ) - - for account in accounts: - if account[1].lower() == selected_account.lower(): - item = {} - item['awsaccount'] = account[0] - item['awsalias'] = account[1] - return item - - raise typer.Abort() - -def default(): - - identity = pathlib.Path.joinpath(pathlib.Path.home(),'.aqueduct_idp') - identity_store = pathlib.Path(identity).read_text() - - sso = pathlib.Path.joinpath(pathlib.Path.home(),'.aqueduct_sso') - sso_region = pathlib.Path(sso).read_text() - - role = pathlib.Path.joinpath(pathlib.Path.home(),'.aqueduct_role') + role = pathlib.Path.joinpath(pathlib.Path.home(),'.botoplus_role') sso_role = pathlib.Path(role).read_text() selected_account = typer.prompt("Selected Account").strip() print(' '+selected_account+'\n') if len(selected_account) == 12 and selected_account.isdigit(): + selected_account = account(selected_account,identity_store,sso_region) - else: + + else: + selected_account = alias(selected_account,identity_store,sso_region) try: + session = aws_sso_lib.get_boto3_session( start_url = 'https://'+identity_store+'.awsapps.com/start', sso_region = sso_region, @@ -111,28 +93,35 @@ def default(): region = sso_region, login = True ) + return session + except: + print('\n** '+selected_account['awsaccount']+' {'+selected_account['awsalias']+'} - DENIED **') pass -def defaults(selected_account): +def sessions(selected_account): - identity = pathlib.Path.joinpath(pathlib.Path.home(),'.aqueduct_idp') + identity = pathlib.Path.joinpath(pathlib.Path.home(),'.botoplus_idp') identity_store = pathlib.Path(identity).read_text() - sso = pathlib.Path.joinpath(pathlib.Path.home(),'.aqueduct_sso') + sso = pathlib.Path.joinpath(pathlib.Path.home(),'.botoplus_sso') sso_region = pathlib.Path(sso).read_text() - role = pathlib.Path.joinpath(pathlib.Path.home(),'.aqueduct_role') + role = pathlib.Path.joinpath(pathlib.Path.home(),'.botoplus_role') sso_role = pathlib.Path(role).read_text() if len(selected_account) == 12 and selected_account.isdigit(): + selected_account = account(selected_account,identity_store,sso_region) - else: + + else: + selected_account = alias(selected_account,identity_store,sso_region) try: + session = aws_sso_lib.get_boto3_session( start_url = 'https://'+identity_store+'.awsapps.com/start', sso_region = sso_region, @@ -141,33 +130,10 @@ def defaults(selected_account): region = sso_region, login = True ) + return session + except: + print('\n** '+selected_account['awsaccount']+' {'+selected_account['awsalias']+'} - DENIED **') pass - -def deletebootstrap(): - qualifier = typer.prompt("Delete CDK Qualifier Bootstrap").strip() - print(' '+qualifier) - confirm = typer.confirm("Destroy") - if not confirm: - raise typer.Abort() - else: - return qualifier - -def deletestack(): - stackname = typer.prompt("Delete Stack Name").strip() - print(' '+stackname) - confirm = typer.confirm("Destroy") - if not confirm: - raise typer.Abort() - else: - return stackname - -def execution(): - query_execution_id = typer.prompt("Query Execution Id").strip() - print(' '+query_execution_id+'\n') - return query_execution_id - -def hello(): - print('Hello, World!') diff --git a/notebooks/analysis/deflation.ipynb b/notebooks/analysis/deflation.ipynb new file mode 100644 index 0000000..d2506d6 --- /dev/null +++ b/notebooks/analysis/deflation.ipynb @@ -0,0 +1,88 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Deflation\n", + "##### Data Structures" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import botoplus.organization as _org\n", + "import botoplus.deflation as _defalte\n", + "\n", + "selected = _org.selected()\n", + "client = selected.client('lambda')\n", + "paginator = client.get_paginator('list_functions')\n", + "pages = paginator.paginate()\n", + "\n", + "for page in pages:\n", + " for item in page['Functions']:\n", + "\n", + " _defalte.strturuce(item)\n", + "\n", + " break\n", + " break" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##### Flatten Structures" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import botoplus.organization as _org\n", + "import botoplus.deflation as _defalte\n", + "\n", + "selected = _org.selected()\n", + "client = selected.client('lambda')\n", + "paginator = client.get_paginator('list_functions')\n", + "pages = paginator.paginate()\n", + "\n", + "for page in pages:\n", + " for item in page['Functions']:\n", + "\n", + " dupe = []\n", + " out = _defalte.deflation(item, dupe)\n", + " print(out)\n", + "\n", + " break\n", + " break" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "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.13" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/notebooks/cdk/identify-cdk-bootstraps.ipynb b/notebooks/cdk/identify-cdk-bootstraps.ipynb index cbd3fb4..1395e3e 100644 --- a/notebooks/cdk/identify-cdk-bootstraps.ipynb +++ b/notebooks/cdk/identify-cdk-bootstraps.ipynb @@ -18,20 +18,22 @@ "metadata": {}, "outputs": [], "source": [ - "import botoplus.botoplus as botoplus\n", + "import botoplus.organization as _org\n", "\n", - "accounts = botoplus.accounts()\n", + "display_denied = False\n", + "\n", + "accounts = _org.accounts()\n", "\n", "for account in accounts:\n", "\n", " print(str(account['awsaccount'])+' '+account['awsalias'])\n", - " session = botoplus.defaults(account['awsaccount'])\n", - " ec2 = session.client('ec2')\n", + " sessions = _org.sessions(account['awsaccount'])\n", + " ec2 = sessions.client('ec2')\n", " regions = ec2.describe_regions()\n", "\n", " for region in regions['Regions']:\n", " try:\n", - " ssm = session.client('ssm', region_name = region['RegionName'])\n", + " ssm = sessions.client('ssm', region_name = region['RegionName'])\n", " paginator = ssm.get_paginator('get_parameters_by_path')\n", " pages = paginator.paginate(\n", " Path = '/cdk-bootstrap',\n", @@ -41,7 +43,8 @@ " for parameters in page['Parameters']:\n", " print(' - '+region['RegionName']+' '+parameters['Name']+': '+parameters['Value'])\n", " except:\n", - " print(' - '+region['RegionName']+' DENIED')\n", + " if display_denied == True:\n", + " print(' - '+region['RegionName']+' DENIED')\n", " pass" ] } diff --git a/notebooks/cdk/remove-bootstrap-everywhere.ipynb b/notebooks/cdk/remove-bootstrap-everywhere.ipynb deleted file mode 100644 index 9d554f6..0000000 --- a/notebooks/cdk/remove-bootstrap-everywhere.ipynb +++ /dev/null @@ -1,158 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Cloud Development Kit (CDK)\n", - "##### Remove Bootstrap Everywhere" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import botoplus.botoplus as botoplus\n", - "\n", - "qualifier = botoplus.deletebootstrap()\n", - "\n", - "accounts = botoplus.accounts()\n", - "\n", - "for account in accounts:\n", - "\n", - " print(str(account['awsaccount'])+' '+account['awsalias'])\n", - " session = botoplus.defaults(account['awsaccount'])\n", - " ec2 = session.client('ec2')\n", - " regions = ec2.describe_regions()\n", - "\n", - " for region in regions['Regions']:\n", - " \n", - " print(' - '+region['RegionName'])\n", - " \n", - " try: \n", - "\n", - " ecr = 'cdk-'+qualifier+'-container-assets-'+account['awsaccount']+'-'+region['RegionName']\n", - "\n", - " ecr_client = session.client('ecr', region_name = region['RegionName'])\n", - "\n", - " paginator = ecr_client.get_paginator('list_images')\n", - "\n", - " pages = paginator.paginate(\n", - " repositoryName = ecr\n", - " )\n", - "\n", - " for page in pages:\n", - " for image in page['imageIds']:\n", - " ecr_client.batch_delete_image(\n", - " repositoryName = ecr,\n", - " imageIds = [\n", - " {\n", - " 'imageDigest': image['imageDigest'],\n", - " 'imageTag': image['imageTag']\n", - " }\n", - " ]\n", - " )\n", - "\n", - " except:\n", - " pass\n", - "\n", - " bucket = 'cdk-'+qualifier+'-assets-'+account['awsaccount']+'-'+region['RegionName']\n", - "\n", - " s3_client = session.client('s3')\n", - "\n", - " try:\n", - "\n", - " paginator = s3_client.get_paginator('list_objects_v2')\n", - "\n", - " pages = paginator.paginate(\n", - " Bucket = bucket\n", - " )\n", - "\n", - " for page in pages:\n", - " for object in page['Contents']:\n", - " s3_client.delete_object(\n", - " Bucket = bucket,\n", - " Key = object['Key']\n", - " )\n", - "\n", - " except:\n", - " pass\n", - "\n", - " try:\n", - "\n", - " paginator = s3_client.get_paginator('list_object_versions')\n", - "\n", - " pages = paginator.paginate(\n", - " Bucket = bucket\n", - " )\n", - "\n", - " for page in pages:\n", - " for object in page['Versions']:\n", - " s3_client.delete_object(\n", - " Bucket = bucket,\n", - " Key = object['Key'],\n", - " VersionId = object['VersionId']\n", - " )\n", - "\n", - " for page in pages:\n", - " for object in page['DeleteMarkers']:\n", - " s3_client.delete_object(\n", - " Bucket = bucket,\n", - " Key = object['Key'],\n", - " VersionId = object['VersionId']\n", - " )\n", - "\n", - " except:\n", - " pass\n", - "\n", - " try:\n", - " s3_client.delete_bucket(\n", - " Bucket = bucket\n", - " )\n", - " except:\n", - " pass\n", - "\n", - " try:\n", - "\n", - " cfn = 'cdk-bootstrap-'+qualifier+'-'+account['awsaccount']+'-'+region['RegionName']\n", - "\n", - " cfn_client = session.client('cloudformation', region_name = region['RegionName'])\n", - "\n", - " cfn_client.update_termination_protection(\n", - " EnableTerminationProtection = False,\n", - " StackName = cfn\n", - " )\n", - "\n", - " cfn_client.delete_stack(\n", - " StackName = cfn\n", - " )\n", - "\n", - " except:\n", - " pass" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "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.13" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/notebooks/controltower/periodic-daily-donfig-recordings.ipynb b/notebooks/controltower/periodic-daily-config-recordings.ipynb similarity index 55% rename from notebooks/controltower/periodic-daily-donfig-recordings.ipynb rename to notebooks/controltower/periodic-daily-config-recordings.ipynb index d04ea74..f8a55d1 100644 --- a/notebooks/controltower/periodic-daily-donfig-recordings.ipynb +++ b/notebooks/controltower/periodic-daily-config-recordings.ipynb @@ -15,10 +15,10 @@ "outputs": [], "source": [ "import boto3\n", - "import botoplus.botoplus as botoplus\n", + "import botoplus.organization as _org\n", "\n", - "sessions = botoplus.default()\n", - "accounts = botoplus.accounts()\n", + "accounts = _org.accounts()\n", + "selected = _org.selected()\n", "\n", "home = 'us-east-2' # Define Management Region\n", "\n", @@ -28,7 +28,7 @@ "\n", " print(str(account['awsaccount'])+' '+account['awsalias'])\n", "\n", - " sts = sessions.client('sts')\n", + " sts = selected.client('sts')\n", "\n", " assumed = sts.assume_role(\n", " RoleArn = 'arn:aws:iam::'+account['awsaccount']+':role/AWSControlTowerExecution',\n", @@ -47,7 +47,7 @@ "\n", " print(' - '+region['RegionName'])\n", "\n", - " sts = sessions.client('sts', region_name=region['RegionName'])\n", + " sts = selected.client('sts', region_name=region['RegionName'])\n", "\n", " assumed = sts.assume_role(\n", " RoleArn = 'arn:aws:iam::'+account['awsaccount']+':role/AWSControlTowerExecution',\n", @@ -114,23 +114,127 @@ "metadata": {}, "outputs": [], "source": [ - "import botoplus.botoplus as botoplus\n", + "import botoplus.organization as _org\n", "\n", - "accounts = botoplus.accounts()\n", + "accounts = _org.accounts()\n", "\n", "for account in accounts:\n", "\n", " print(str(account['awsaccount'])+' '+account['awsalias'])\n", - " session = botoplus.defaults(account['awsaccount'])\n", - " ec2 = session.client('ec2')\n", + " sessions = _org.sessions(account['awsaccount'])\n", + " ec2 = sessions.client('ec2')\n", " regions = ec2.describe_regions()\n", "\n", " for region in regions['Regions']:\n", - " config = session.client('config', region_name = region['RegionName'])\n", + " config = sessions.client('config', region_name = region['RegionName'])\n", " response = config.describe_configuration_recorders()\n", " for record in response['ConfigurationRecorders']:\n", " print(' - '+region['RegionName']+': '+record['name']+' '+record['recordingMode']['recordingFrequency'])" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##### Stop All Config Recordings" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import boto3\n", + "import botoplus.organization as _org\n", + "\n", + "accounts = _org.accounts()\n", + "selected = _org.selected()\n", + "\n", + "home = 'us-east-2' # Define Management Region\n", + "\n", + "for account in accounts:\n", + "\n", + " if account['awsalias'] != 'Portal': # Exclude Management Account\n", + "\n", + " print(str(account['awsaccount'])+' '+account['awsalias'])\n", + "\n", + " sts = selected.client('sts')\n", + "\n", + " assumed = sts.assume_role(\n", + " RoleArn = 'arn:aws:iam::'+account['awsaccount']+':role/AWSControlTowerExecution',\n", + " RoleSessionName = 'ControlTowerBreakGlass'\n", + " )\n", + " session = boto3.Session(\n", + " aws_access_key_id = assumed['Credentials']['AccessKeyId'],\n", + " aws_secret_access_key = assumed['Credentials']['SecretAccessKey'],\n", + " aws_session_token = assumed['Credentials']['SessionToken']\n", + " )\n", + "\n", + " ec2 = session.client('ec2', region_name=home)\n", + " regions = ec2.describe_regions()\n", + " \n", + " for region in regions['Regions']:\n", + "\n", + " print(' - '+region['RegionName'])\n", + "\n", + " sts = selected.client('sts', region_name=region['RegionName'])\n", + "\n", + " assumed = sts.assume_role(\n", + " RoleArn = 'arn:aws:iam::'+account['awsaccount']+':role/AWSControlTowerExecution',\n", + " RoleSessionName = 'CTBreakGlass-'+region['RegionName']\n", + " )\n", + " session = boto3.Session(\n", + " aws_access_key_id = assumed['Credentials']['AccessKeyId'],\n", + " aws_secret_access_key = assumed['Credentials']['SecretAccessKey'],\n", + " aws_session_token = assumed['Credentials']['SessionToken']\n", + " )\n", + "\n", + " config = session.client('config', region_name=region['RegionName'])\n", + " recorders = config.describe_configuration_recorders()\n", + "\n", + " if len(recorders['ConfigurationRecorders']) != 0:\n", + " for record in recorders['ConfigurationRecorders']:\n", + " config.stop_configuration_recorder(\n", + " ConfigurationRecorderName = record['name']\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##### Validate Config Recorder Status" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import botoplus.organization as _org\n", + "\n", + "accounts = _org.accounts()\n", + "\n", + "for account in accounts:\n", + "\n", + " print(str(account['awsaccount'])+' '+account['awsalias'])\n", + " sessions = _org.sessions(account['awsaccount'])\n", + " ec2 = sessions.client('ec2')\n", + " regions = ec2.describe_regions()\n", + "\n", + " for region in regions['Regions']:\n", + " config = sessions.client('config', region_name = region['RegionName'])\n", + " response = config.describe_configuration_recorders()\n", + " for record in response['ConfigurationRecorders']:\n", + " output = config.describe_configuration_recorder_status(\n", + " ConfigurationRecorderNames = [\n", + " record['name']\n", + " ]\n", + " )\n", + " print(' - '+region['RegionName']+': '+record['name']+' '+str(output['ConfigurationRecordersStatus'][0]['recording'])+' '+output['ConfigurationRecordersStatus'][0]['lastStatus'])" + ] } ], "metadata": { diff --git a/notebooks/s3/public-cors-configuration.ipynb b/notebooks/ec2/disable-serial-console-access.ipynb similarity index 53% rename from notebooks/s3/public-cors-configuration.ipynb rename to notebooks/ec2/disable-serial-console-access.ipynb index af08f76..3bb6716 100644 --- a/notebooks/s3/public-cors-configuration.ipynb +++ b/notebooks/ec2/disable-serial-console-access.ipynb @@ -4,8 +4,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Simple Storage Service (S3)\n", - "##### Public CORS Configuration" + "### Elastic Compute Cloud (EC2)\n", + "##### Disable Serial Console Access" ] }, { @@ -14,25 +14,28 @@ "metadata": {}, "outputs": [], "source": [ - "import botoplus.botoplus as botoplus\n", + "import botoplus.organization as _org\n", "\n", - "accounts = botoplus.accounts()\n", + "display_denied = False\n", + "\n", + "accounts = _org.accounts()\n", "\n", "for account in accounts:\n", "\n", " print(str(account['awsaccount'])+' '+account['awsalias'])\n", - " session = botoplus.defaults(account['awsaccount'])\n", - " s3 = session.client('s3')\n", - " buckets = s3.list_buckets()\n", + " sessions = _org.sessions(account['awsaccount'])\n", + " ec2 = sessions.client('ec2')\n", + " regions = ec2.describe_regions()\n", + "\n", + " for region in regions['Regions']:\n", "\n", - " for bucket in buckets['Buckets']:\n", " try:\n", - " response = s3.get_bucket_cors(\n", - " Bucket = bucket['Name']\n", - " )\n", - " if len(response['CORSRules']) != 0:\n", - " print(' - '+bucket['Name'])\n", + " ec2_region = sessions.client('ec2', region_name = region['RegionName'])\n", + " ec2_region.disable_serial_console_access()\n", + " print(' - '+region['RegionName']+' DISABLED')\n", " except:\n", + " if display_denied == True:\n", + " print(' - '+region['RegionName']+' DENIED')\n", " pass" ] } diff --git a/notebooks/cloudformation/delete-stack-everywhere.ipynb b/notebooks/ec2/enable-image-block-public-access.ipynb similarity index 55% rename from notebooks/cloudformation/delete-stack-everywhere.ipynb rename to notebooks/ec2/enable-image-block-public-access.ipynb index 786c1d5..136f6ca 100644 --- a/notebooks/cloudformation/delete-stack-everywhere.ipynb +++ b/notebooks/ec2/enable-image-block-public-access.ipynb @@ -4,8 +4,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### CloudFormation\n", - "##### Delete Stack Everywhere" + "### Elastic Compute Cloud (EC2)\n", + "##### Enable Image Block Public Access" ] }, { @@ -14,32 +14,30 @@ "metadata": {}, "outputs": [], "source": [ - "import botoplus.botoplus as botoplus\n", + "import botoplus.organization as _org\n", "\n", - "stackname = botoplus.deletestack()\n", + "display_denied = False\n", "\n", - "accounts = botoplus.accounts()\n", + "accounts = _org.accounts()\n", "\n", "for account in accounts:\n", "\n", " print(str(account['awsaccount'])+' '+account['awsalias'])\n", - " session = botoplus.defaults(account['awsaccount'])\n", - " ec2 = session.client('ec2')\n", + " sessions = _org.sessions(account['awsaccount'])\n", + " ec2 = sessions.client('ec2')\n", " regions = ec2.describe_regions()\n", "\n", " for region in regions['Regions']:\n", + "\n", " try:\n", - " cfn = session.client('cloudformation', region_name = region['RegionName'])\n", - " cfn.update_termination_protection(\n", - " EnableTerminationProtection = False,\n", - " StackName = stackname\n", - " )\n", - " cfn.delete_stack(\n", - " StackName = stackname\n", + " ec2_region = sessions.client('ec2', region_name = region['RegionName'])\n", + " ec2_region.enable_image_block_public_access(\n", + " ImageBlockPublicAccessState = 'block-new-sharing'\n", " )\n", - " print(' - '+region['RegionName']+' SUCCESS')\n", + " print(' - '+region['RegionName']+' BLOCKED')\n", " except:\n", - " print(' - '+region['RegionName']+' DENIED')\n", + " if display_denied == True:\n", + " print(' - '+region['RegionName']+' DENIED')\n", " pass" ] } diff --git a/notebooks/ec2/enable-snapshot-block-public-access.ipynb b/notebooks/ec2/enable-snapshot-block-public-access.ipynb new file mode 100644 index 0000000..ff21c63 --- /dev/null +++ b/notebooks/ec2/enable-snapshot-block-public-access.ipynb @@ -0,0 +1,66 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Elastic Compute Cloud (EC2)\n", + "##### Enable Snapshot Block Public Access" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import botoplus.organization as _org\n", + "\n", + "display_denied = False\n", + "\n", + "accounts = _org.accounts()\n", + "\n", + "for account in accounts:\n", + "\n", + " print(str(account['awsaccount'])+' '+account['awsalias'])\n", + " sessions = _org.sessions(account['awsaccount'])\n", + " ec2 = sessions.client('ec2')\n", + " regions = ec2.describe_regions()\n", + "\n", + " for region in regions['Regions']:\n", + "\n", + " try:\n", + " ec2_region = sessions.client('ec2', region_name = region['RegionName'])\n", + " ec2_region.enable_snapshot_block_public_access(\n", + " State = 'block-all-sharing'\n", + " )\n", + " print(' - '+region['RegionName']+' BLOCKED')\n", + " except:\n", + " if display_denied == True:\n", + " print(' - '+region['RegionName']+' DENIED')\n", + " pass" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "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.13" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/notebooks/ec2/public-amazon-machine-images.ipynb b/notebooks/ec2/public-amazon-machine-images.ipynb deleted file mode 100644 index 5f470c9..0000000 --- a/notebooks/ec2/public-amazon-machine-images.ipynb +++ /dev/null @@ -1,67 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Elastic Compute Cloud (EC2)\n", - "##### Public Amazon Machine Images" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import hashlib\n", - "import requests\n", - "import botoplus.botoplus as botoplus\n", - "\n", - "def calculate(account):\n", - " hasher = hashlib.sha256()\n", - " hasher.update(account.encode())\n", - " sha256 = hasher.hexdigest().upper()\n", - " return sha256\n", - "\n", - "response = requests.get('https://static.matchmeta.info/publicami.json')\n", - "data = response.json()\n", - "\n", - "accounts = botoplus.accounts()\n", - "\n", - "for account in accounts:\n", - "\n", - " print(str(account['awsaccount'])+' '+account['awsalias'])\n", - "\n", - " sha256 = calculate(account['awsaccount'])\n", - "\n", - " for region in data['regions']:\n", - " for value in region['sha256']:\n", - " if value == sha256:\n", - " print(' - '+region['region'])\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "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.13" - }, - "orig_nbformat": 4 - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/notebooks/organizations/identify-privileged-accounts.ipynb b/notebooks/organizations/identify-privileged-accounts.ipynb index 140ea28..73bf3b5 100644 --- a/notebooks/organizations/identify-privileged-accounts.ipynb +++ b/notebooks/organizations/identify-privileged-accounts.ipynb @@ -16,10 +16,10 @@ "metadata": {}, "outputs": [], "source": [ - "import botoplus.botoplus as botoplus\n", + "import botoplus.organization as _org\n", "\n", - "session = botoplus.default()\n", - "client = session.client('organizations')\n", + "selected = _org.selected()\n", + "client = selected.client('organizations')\n", "paginator = client.get_paginator('list_delegated_administrators')\n", "pages = paginator.paginate()\n", "\n", diff --git a/notebooks/securityhub/minimal-cost-configuration.ipynb b/notebooks/securityhub/minimal-cost-configuration.ipynb deleted file mode 100644 index 48d98a4..0000000 --- a/notebooks/securityhub/minimal-cost-configuration.ipynb +++ /dev/null @@ -1,157 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Security Hub\n", - "##### Minimal Cost Configuration" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import botoplus.botoplus as botoplus\n", - "\n", - "accounts = botoplus.accounts()\n", - "\n", - "for account in accounts:\n", - "\n", - " print(str(account['awsaccount'])+' '+account['awsalias'])\n", - " session = botoplus.defaults(account['awsaccount'])\n", - " ec2 = session.client('ec2')\n", - " regions = ec2.describe_regions()\n", - "\n", - " for region in regions['Regions']:\n", - " try:\n", - " ### STANDARDS ###\n", - " securityhub = session.client('securityhub', region_name = region['RegionName'])\n", - " paginator = securityhub.get_paginator('get_enabled_standards')\n", - " pages = paginator.paginate()\n", - " for page in pages:\n", - " for subscriptions in page['StandardsSubscriptions']:\n", - " securityhub.batch_disable_standards(\n", - " StandardsSubscriptionArns = [\n", - " subscriptions['StandardsSubscriptionArn']\n", - " ]\n", - " )\n", - " ### SUBSCRIPTIONS ###\n", - " paginator = securityhub.get_paginator('list_enabled_products_for_import')\n", - " pages = paginator.paginate()\n", - " for page in pages:\n", - " for products in page['ProductSubscriptions']:\n", - " parsed = products.split('/')\n", - " if parsed[2] != 'access-analyzer' and parsed[2] != 'config' and parsed[2] != 'guardduty' and parsed[2] != 'health' and parsed[2] != 'inspector' and parsed[2] != 'securityhub':\n", - " securityhub.disable_import_findings_for_product(\n", - " ProductSubscriptionArn = products\n", - " )\n", - " print(' - '+region['RegionName'])\n", - " except:\n", - " print(' - '+region['RegionName']+' DENIED')\n", - " pass" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### List Enabled Region Integrations" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import botoplus.botoplus as botoplus\n", - "\n", - "accounts = botoplus.accounts()\n", - "\n", - "for account in accounts:\n", - "\n", - " print(str(account['awsaccount'])+' '+account['awsalias'])\n", - " session = botoplus.defaults(account['awsaccount'])\n", - " ec2 = session.client('ec2')\n", - " regions = ec2.describe_regions()\n", - "\n", - " for region in regions['Regions']:\n", - " print(' - '+region['RegionName'])\n", - " securityhub = session.client('securityhub', region_name=region['RegionName'])\n", - " paginator = securityhub.get_paginator('list_enabled_products_for_import')\n", - " pages = paginator.paginate()\n", - "\n", - " for page in pages:\n", - " for products in page['ProductSubscriptions']:\n", - " print(products)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Enable Region Integrations" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import botoplus.botoplus as botoplus\n", - "\n", - "accounts = botoplus.accounts()\n", - "\n", - "for account in accounts:\n", - "\n", - " print(str(account['awsaccount'])+' '+account['awsalias'])\n", - " session = botoplus.defaults(account['awsaccount'])\n", - " ec2 = session.client('ec2')\n", - " regions = ec2.describe_regions()\n", - "\n", - " for region in regions['Regions']:\n", - " print(' - '+region['RegionName'])\n", - " securityhub = session.client('securityhub', region_name=region['RegionName'])\n", - " paginator = securityhub.get_paginator('describe_products')\n", - " pages = paginator.paginate()\n", - "\n", - " for page in pages:\n", - " for products in page['Products']:\n", - " if products['CompanyName'] == 'AWS':\n", - " if products['ProductName'] == 'Config' or products['ProductName'] == 'GuardDuty' or products['ProductName'] == 'Health' or products['ProductName'] == 'IAM Access Analyzer' or products['ProductName'] == 'Inspector':\n", - " try:\n", - " securityhub.enable_import_findings_for_product(\n", - " ProductArn = products['ProductArn']\n", - " )\n", - " except:\n", - " pass" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "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.13" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/notebooks/securitylake/deregister-delegated-administrator.ipynb b/notebooks/securitylake/deregister-delegated-administrator.ipynb deleted file mode 100644 index e7d384d..0000000 --- a/notebooks/securitylake/deregister-delegated-administrator.ipynb +++ /dev/null @@ -1,48 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Amazon Security Lake\n", - "##### Deregister Delegated Administrator" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import botoplus.botoplus as botoplus\n", - "\n", - "session = botoplus.default()\n", - "client = session.client('securitylake')\n", - "\n", - "response = client.deregister_data_lake_delegated_administrator()\n", - "print(response)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "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.13" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/notebooks/securitylake/resolver-query-logs.ipynb b/notebooks/securitylake/resolver-query-logs.ipynb deleted file mode 100644 index b62a22d..0000000 --- a/notebooks/securitylake/resolver-query-logs.ipynb +++ /dev/null @@ -1,281 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Amazon Route53 Resolver Query Logs\n", - "\n", - "##### DNS RCODEs\n", - "\n", - "https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6\n", - "\n", - "##### Read CSV to DataFrame" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "\n", - "df = pd.read_csv('/tmp/68eff94b-a283-48e7-93af-42edfbda8e2a.csv', sep=',')\n", - "\n", - "pd.set_option('display.max_columns', None)\n", - "pd.set_option('display.max_rows', None)\n", - "\n", - "df.head(1)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Identify Query Source" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "pd.crosstab(\n", - " index = [\n", - " df[\"query_hostname\"],\n", - " df[\"query_type\"],\n", - " df[\"accountid\"],\n", - " df[\"region\"],\n", - " df[\"src_vpc_uid\"],\n", - " df[\"src_instance_uid\"],\n", - " df[\"src_ip\"]\n", - " ], \n", - " columns = [\n", - " df[\"rcode\"]\n", - " ], \n", - " margins = True\n", - ").sort_index(\n", - " axis = 1,\n", - " ascending = False\n", - ").sort_values(\n", - " by = [\n", - " 'All'\n", - " ],\n", - " ascending = False\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Identify Host Source" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "pd.crosstab(\n", - " index = [\n", - " df[\"src_ip\"],\n", - " df[\"src_instance_uid\"],\n", - " df[\"src_vpc_uid\"],\n", - " df[\"region\"],\n", - " df[\"accountid\"],\n", - " df[\"query_type\"],\n", - " df[\"query_hostname\"]\n", - " ], \n", - " columns = [\n", - " df[\"rcode\"]\n", - " ], \n", - " margins = True\n", - ").sort_index(\n", - " axis = 1,\n", - " ascending = False\n", - ").sort_values(\n", - " by = [\n", - " 'All'\n", - " ],\n", - " ascending = False\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Query Times" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "\n", - "df1 = df['time'].value_counts().rename_axis('time').reset_index(name='counts')\n", - "df1 = df1.sort_values(by=['time'], ascending=True)\n", - "\n", - "plt.figure(figsize=(20,10))\n", - "plt.scatter(df1['time'], df1['counts'])\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Query Deviations" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "\n", - "df2 = df['query_hostname'].value_counts().rename_axis('query_hostname').reset_index(name='counts')\n", - "\n", - "records = df2.loc[:,'counts'].to_numpy()\n", - "mean = records.mean()\n", - "median = np.median(records)\n", - "stddev = np.std(records)\n", - "\n", - "plt.figure(figsize=(20,10))\n", - "plt.hist(df2.loc[:,'counts'], log=True)\n", - "plt.plot([mean, mean],[0,15**4], label=\"Mean\")\n", - "plt.plot([median,median],[0,15**4],label=\"Median\")\n", - "plt.plot([mean+stddev,mean+stddev],[0,15**4], label=\"+1 Std\")\n", - "plt.plot([mean+(stddev*2),mean+(stddev*2)],[0,15**4], label=\"+2 Std\")\n", - "plt.plot([mean-stddev,mean-stddev],[0,15**4], label=\"-1 Std\")\n", - "plt.plot([mean-(stddev*2),mean-(stddev*2)],[0,15**4], label=\"-2 Std\")\n", - "\n", - "plt.legend()\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Identify Query Answers" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df3 = df[['query_hostname', 'rcode', 'answers']]\n", - "df3 = df3.dropna()\n", - "\n", - "items = []\n", - "number = 0\n", - "\n", - "for index, row in df3.iterrows():\n", - " try:\n", - " answers = row['answers'].split('}, {')\n", - " for answer in answers:\n", - " answer = answer.replace('[','').replace(']','').replace('{','').replace('}','')\n", - " item = answer.split(', ')\n", - " items.append([row['query_hostname'],row['rcode'],item[1][6:]])\n", - " except:\n", - " number += 1\n", - " pass\n", - "\n", - "print('Query Answers: '+str(len(items)))\n", - "print('No Query Answers: '+str(number))\n", - "\n", - "df4 = pd.DataFrame(items, columns = ['query_hostname', 'rcode', 'answer'])\n", - "\n", - "pd.crosstab(\n", - " index = [\n", - " df4[\"answer\"],\n", - " df4[\"query_hostname\"]\n", - " \n", - " ], \n", - " columns = [\n", - " df4[\"rcode\"]\n", - " ], \n", - " margins = True\n", - ").sort_index(\n", - " axis = 1,\n", - " ascending = False\n", - ").sort_values(\n", - " by = [\n", - " 'All'\n", - " ],\n", - " ascending = False\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Answer Deviations" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "\n", - "df5 = df4['answer'].value_counts().rename_axis('answer').reset_index(name='counts')\n", - "\n", - "records = df5.loc[:,'counts'].to_numpy()\n", - "mean = records.mean()\n", - "median = np.median(records)\n", - "stddev = np.std(records)\n", - "\n", - "plt.figure(figsize=(20,10))\n", - "plt.hist(df5.loc[:,'counts'], log=True)\n", - "plt.plot([mean, mean],[0,15**4], label=\"Mean\")\n", - "plt.plot([median,median],[0,15**4],label=\"Median\")\n", - "plt.plot([mean+stddev,mean+stddev],[0,15**4], label=\"+1 Std\")\n", - "plt.plot([mean+(stddev*2),mean+(stddev*2)],[0,15**4], label=\"+2 Std\")\n", - "plt.plot([mean-stddev,mean-stddev],[0,15**4], label=\"-1 Std\")\n", - "plt.plot([mean-(stddev*2),mean-(stddev*2)],[0,15**4], label=\"-2 Std\")\n", - "\n", - "plt.legend()\n", - "plt.show()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "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": 2 -} diff --git a/notebooks/securitylake/searching.ipynb b/notebooks/securitylake/searching.ipynb deleted file mode 100644 index 17eeca3..0000000 --- a/notebooks/securitylake/searching.ipynb +++ /dev/null @@ -1,362 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Amazon Security Lake\n", - "##### Identify Delegated Administrator" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import botoplus.botoplus as botoplus\n", - "\n", - "selected_account = 'Unavailable'\n", - "\n", - "session = botoplus.default()\n", - "client = session.client('organizations')\n", - "paginator = client.get_paginator('list_delegated_administrators')\n", - "pages = paginator.paginate()\n", - "\n", - "for page in pages:\n", - " for item in page['DelegatedAdministrators']:\n", - "\n", - " paginator2 = client.get_paginator('list_delegated_services_for_account')\n", - " pages2 = paginator2.paginate(\n", - " AccountId = item['Id']\n", - " )\n", - "\n", - " for page2 in pages2:\n", - " for item2 in page2['DelegatedServices']:\n", - " if item2['ServicePrincipal'] == 'securitylake.amazonaws.com':\n", - " selected_account = item['Name']\n", - "\n", - "print('Amazon Security Lake Delegated Administrator: '+selected_account)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Regions Ingesting Data" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import botoplus.botoplus as botoplus\n", - "\n", - "ingestion = []\n", - "\n", - "try:\n", - "\n", - " session = botoplus.defaults(selected_account)\n", - " securitylake = session.client('securitylake')\n", - " regions = securitylake.get_data_lake_organization_configuration()\n", - "\n", - " for region in regions['autoEnableNewAccount']:\n", - " print(region['region'])\n", - " ingestion.append(region['region'])\n", - " for source in region['sources']:\n", - " print(' * '+source['sourceVersion']+' '+source['sourceName'])\n", - "\n", - "except:\n", - " print('Amazon Security Lake Delegated Administrator: Unidentified')\n", - " pass" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Identify Replication Region" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import botoplus.botoplus as botoplus\n", - "\n", - "replication = []\n", - "\n", - "try:\n", - "\n", - " session = botoplus.defaults(selected_account)\n", - " securitylake = session.client('securitylake')\n", - " lakes = securitylake.list_data_lakes(\n", - " regions = ingestion\n", - " )\n", - "\n", - " for lake in lakes['dataLakes']:\n", - " try:\n", - " for region in lake['replicationConfiguration']['regions']:\n", - " replication.append(region)\n", - " except:\n", - " pass\n", - "\n", - "except:\n", - " print('Amazon Security Ingestion Region(s): Unidentified')\n", - " pass\n", - "\n", - "try:\n", - " replication = list(set(replication))\n", - " replication = replication[0]\n", - " print('Amazon Security Lake Replication Region: '+str(replication))\n", - "except:\n", - " pass" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Lifecycle Configuration" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import json\n", - "import botoplus.botoplus as botoplus\n", - "\n", - "try:\n", - "\n", - " session = botoplus.defaults(selected_account)\n", - " securitylake = session.client('securitylake')\n", - " lakes = securitylake.list_data_lakes(\n", - " regions = ingestion\n", - " )\n", - "\n", - " for lake in lakes['dataLakes']:\n", - " if lake['region'] == replication:\n", - " print(json.dumps(lake['lifecycleConfiguration'], indent=4, sort_keys=True))\n", - "\n", - "except:\n", - " print('Amazon Security Ingestion Region(s): Unidentified')\n", - " pass" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Amazon Athena\n", - "##### List Query Executions" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import time\n", - "import botoplus.botoplus as botoplus\n", - "\n", - "try:\n", - "\n", - " session = botoplus.defaults(selected_account)\n", - " athena = session.client('athena', region_name=replication)\n", - " paginator = athena.get_paginator('list_query_executions')\n", - " pages = paginator.paginate()\n", - "\n", - " for page in pages:\n", - " for item in page['QueryExecutionIds']:\n", - " execution = athena.get_query_execution(\n", - " QueryExecutionId = item\n", - " )\n", - " if execution['QueryExecution']['Status']['SubmissionDateTime'].timestamp() > (time.time() - 604800):\n", - " if execution['QueryExecution']['Status']['State'] == 'SUCCEEDED':\n", - " if execution['QueryExecution']['Statistics']['DataScannedInBytes'] > 0:\n", - " print(execution['QueryExecution']['Query'])\n", - " print(' * Date: '+str(execution['QueryExecution']['Status']['CompletionDateTime']))\n", - " print(' * Execution: '+execution['QueryExecution']['QueryExecutionId'])\n", - " print(' * Megabytes: '+str(execution['QueryExecution']['Statistics']['DataScannedInBytes']/1000000))\n", - " print(' * Minutes: '+str(execution['QueryExecution']['Statistics']['EngineExecutionTimeInMillis']/60000)+'\\n')\n", - "\n", - "except:\n", - " print('Amazon Security Ingestion Region(s): Unidentified')\n", - " pass" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Query Execution Output" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import botoplus.botoplus as botoplus\n", - "\n", - "query_execution_id = botoplus.execution()\n", - "\n", - "try:\n", - "\n", - " session = botoplus.defaults(selected_account)\n", - " athena = session.client('athena', region_name=replication)\n", - " output = athena.get_query_runtime_statistics(\n", - " QueryExecutionId = query_execution_id\n", - " )\n", - " print(' * Megabytes: '+str(output['QueryRuntimeStatistics']['OutputStage']['OutputBytes']/1000000))\n", - " print(' * Output Rows: '+str(output['QueryRuntimeStatistics']['OutputStage']['OutputRows']))\n", - "\n", - "except:\n", - " print('Amazon Security Ingestion Region(s): Unidentified')\n", - " pass" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Query Execution Output" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import botoplus.botoplus as botoplus\n", - "import pandas as pd\n", - "\n", - "session = botoplus.defaults(selected_account)\n", - "athena = session.client('athena', region_name=replication)\n", - "output = athena.get_query_execution(\n", - " QueryExecutionId = query_execution_id\n", - ")\n", - "\n", - "bucket = output['QueryExecution']['ResultConfiguration']['OutputLocation']\n", - "out = bucket[5:].split('/')\n", - "print(bucket)\n", - "\n", - "s3 = session.resource('s3')\n", - "s3.Object(out[0], out[1]).download_file('/tmp/'+out[1])\n", - "\n", - "df = pd.read_csv('/tmp/'+out[1], sep=',')\n", - "\n", - "pd.set_option('display.max_columns', None)\n", - "pd.set_option('display.max_rows', None)\n", - "\n", - "df.head(1)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Amazon Route 53 Resolver Query Logs\n", - "##### Start Query Execution" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import botoplus.botoplus as botoplus\n", - "\n", - "query = \"\"\"\n", - "SELECT time,\n", - "\tmetadata.product.version,\n", - "\tmetadata.product.name AS service,\n", - "\tmetadata.product.feature.name,\n", - "\tmetadata.product.vendor_name,\n", - "\tmetadata.profiles,\n", - "\tmetadata.version AS securitylake,\n", - "\tsrc_endpoint.vpc_uid AS src_vpc_uid,\n", - "\tsrc_endpoint.ip AS src_ip,\n", - "\tsrc_endpoint.port AS src_port,\n", - "\tsrc_endpoint.instance_uid AS src_instance_uid,\n", - "\tquery.hostname AS query_hostname,\n", - "\tquery.type AS query_type,\n", - "\tquery.class AS query_class,\n", - "\tconnection_info.protocol_name,\n", - "\tconnection_info.direction,\n", - "\tconnection_info.direction_id,\n", - "\tdst_endpoint.instance_uid AS dst_instance_uid,\n", - "\tdst_endpoint.interface_uid AS dst_inaterface_uid,\n", - "\tseverity_id,\n", - "\tseverity,\n", - "\tclass_name,\n", - "\tclass_uid,\n", - "\tdisposition,\n", - "\tdisposition_id,\n", - "\trcode_id,\n", - "\trcode,\n", - "\tactivity_id,\n", - "\tactivity_name,\n", - "\ttype_name,\n", - "\ttype_uid,\n", - "\tunmapped,\n", - "\tregion,\n", - "\taccountid,\n", - "\teventday,\n", - "\tanswers\n", - "FROM amazon_security_lake_glue_db_us_east_2.amazon_security_lake_table_us_east_2_route53_1_0\n", - "WHERE eventDay BETWEEN cast(\n", - "\t\tdate_format(current_timestamp - INTERVAL '7' day, '%Y%m%d%H') as varchar\n", - "\t)\n", - "\tand cast(\n", - "\t\tdate_format(current_timestamp - INTERVAL '0' day, '%Y%m%d%H') as varchar\n", - "\t)\n", - "ORDER BY time DESC\n", - "\"\"\"\n", - "\n", - "converted = botoplus.convert(selected_account)\n", - "\n", - "session = botoplus.defaults(selected_account)\n", - "athena = session.client('athena', region_name=replication)\n", - "athena.start_query_execution(\n", - " QueryString = query,\n", - " ResultConfiguration = {\n", - " 'OutputLocation': 's3://temp-athena-results-'+converted['awsaccount']+'-'+replication+'/'\n", - " }\n", - ")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "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": 2 -} diff --git a/notebooks/vpc/delete-default-vpcs.ipynb b/notebooks/vpc/delete-default-vpcs.ipynb deleted file mode 100644 index e0180f2..0000000 --- a/notebooks/vpc/delete-default-vpcs.ipynb +++ /dev/null @@ -1,100 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Virtual Private Cloud (VPC)\n", - "##### Delete Default VPCs" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import botoplus.botoplus as botoplus\n", - "\n", - "accounts = botoplus.accounts()\n", - "\n", - "for account in accounts:\n", - "\n", - " print(str(account['awsaccount'])+' '+account['awsalias'])\n", - " session = botoplus.defaults(account['awsaccount'])\n", - " ec2 = session.client('ec2')\n", - " regions = ec2.describe_regions()\n", - "\n", - " for region in regions['Regions']:\n", - "\n", - " print(' - '+region['RegionName'])\n", - " ec2_region = session.client('ec2', region_name = region['RegionName'])\n", - " paginator = ec2_region.get_paginator('describe_vpcs')\n", - " response_iterator = paginator.paginate()\n", - " for page in response_iterator:\n", - " if len(page['Vpcs']) > 0:\n", - " for item in page['Vpcs']:\n", - " if item['IsDefault'] is True:\n", - "\n", - " paginator2 = ec2_region.get_paginator('describe_internet_gateways')\n", - " response_iterator2 = paginator2.paginate()\n", - " for page2 in response_iterator2:\n", - " for item2 in page2['InternetGateways']:\n", - " if len(page2['InternetGateways']) > 0:\n", - " if item2['Attachments'][0]['VpcId'] == item['VpcId']:\n", - " try:\n", - " ec2_region.detach_internet_gateway(\n", - " InternetGatewayId=item2['InternetGatewayId'],\n", - " VpcId=item['VpcId']\n", - " )\n", - " ec2_region.delete_internet_gateway(\n", - " InternetGatewayId=item2['InternetGatewayId']\n", - " )\n", - " except:\n", - " print('ERROR '+str(item2))\n", - "\n", - " paginator3 = ec2_region.get_paginator('describe_subnets')\n", - " response_iterator3 = paginator3.paginate()\n", - " for page3 in response_iterator3:\n", - " for item3 in page3['Subnets']:\n", - " if len(page3['Subnets']) > 0:\n", - " if item3['VpcId'] == item['VpcId']:\n", - " try:\n", - " ec2_region.delete_subnet(\n", - " SubnetId=item3['SubnetId']\n", - " )\n", - " except:\n", - " print('ERROR '+str(item3))\n", - "\n", - " try:\n", - " ec2_region.delete_vpc(\n", - " VpcId=item['VpcId']\n", - " )\n", - " except:\n", - " print('ERROR '+str(item))\n", - " pass" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "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.13" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/notebooks/vpc/identify-default-vpcs.ipynb b/notebooks/vpc/identify-default-vpcs.ipynb new file mode 100644 index 0000000..49d1da5 --- /dev/null +++ b/notebooks/vpc/identify-default-vpcs.ipynb @@ -0,0 +1,68 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Virtual Private Cloud (VPC)\n", + "##### Identify Default VPCs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import botoplus.organization as _org\n", + "\n", + "display_denied = False\n", + "\n", + "accounts = _org.accounts()\n", + "\n", + "for account in accounts:\n", + "\n", + " print(str(account['awsaccount'])+' '+account['awsalias'])\n", + " sessions = _org.sessions(account['awsaccount'])\n", + " ec2 = sessions.client('ec2')\n", + " regions = ec2.describe_regions()\n", + "\n", + " for region in regions['Regions']:\n", + " try:\n", + " ec2_region = sessions.client('ec2', region_name = region['RegionName'])\n", + " paginator = ec2_region.get_paginator('describe_vpcs')\n", + " response_iterator = paginator.paginate()\n", + " for page in response_iterator:\n", + " if len(page['Vpcs']) > 0:\n", + " for item in page['Vpcs']:\n", + " if item['IsDefault'] is True:\n", + " print(' - '+region['RegionName']+' DEFAULT: '+item['VpcId'])\n", + " except:\n", + " if display_denied == True:\n", + " print(' - '+region['RegionName']+' DENIED')\n", + " pass" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "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.13" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/notebooks/vpc/ip-address-conflicts.ipynb b/notebooks/vpc/ip-address-conflicts.ipynb deleted file mode 100644 index 324b8db..0000000 --- a/notebooks/vpc/ip-address-conflicts.ipynb +++ /dev/null @@ -1,117 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Virtual Private Cloud (VPC)\n", - "##### Detect IP Address Conflicts" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import ipaddress\n", - "import botoplus.botoplus as botoplus\n", - "\n", - "networks = []\n", - "\n", - "accounts = botoplus.accounts()\n", - "\n", - "for account in accounts:\n", - "\n", - " print(str(account['awsaccount'])+' '+account['awsalias'])\n", - " session = botoplus.defaults(account['awsaccount'])\n", - " ec2 = session.client('ec2')\n", - " regions = ec2.describe_regions()\n", - "\n", - " for region in regions['Regions']:\n", - " try:\n", - " ec2_region = session.client('ec2', region_name = region['RegionName'])\n", - " paginator = ec2_region.get_paginator('describe_vpcs')\n", - " pages = paginator.paginate()\n", - " for page in pages:\n", - " for vpcs in page['Vpcs']:\n", - " # Resource Access Manager (RAM) Shared VPC Test\n", - " if account['awsaccount'] == vpcs['OwnerId']:\n", - " # Default VPC Test\n", - " if vpcs['IsDefault'] == True:\n", - " default = 'Default'\n", - " else:\n", - " default = ''\n", - " # IPv6 Test\n", - " try:\n", - " if len(vpcs['Ipv6CidrBlockAssociationSet']) > 0:\n", - " ipv6 = 'IPv6'\n", - " else:\n", - " ipv6 = ''\n", - " except:\n", - " ipv6 = ''\n", - " pass\n", - " print(' - '+region['RegionName']+' '+vpcs['VpcId']+' '+vpcs['CidrBlock']+' '+default+' '+ipv6)\n", - " # Convert CIDR to Integer\n", - " netrange = ipaddress.IPv4Network(vpcs['CidrBlock'])\n", - " first, last = netrange[0], netrange[-1]\n", - " firstip = int(ipaddress.IPv4Address(first))\n", - " lastip = int(ipaddress.IPv4Address(last))\n", - " networks.append({'vpcid':vpcs['VpcId'],'cidrblock':vpcs['CidrBlock'],'firstip':firstip,'lastip':lastip})\n", - " except:\n", - " print(' - '+region['RegionName']+' DENIED')\n", - " pass" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Validate IP Address Conflicts" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "for network in networks:\n", - " for network2 in networks:\n", - " if network['vpcid'] != network2['vpcid']:\n", - " if network['firstip'] >= network2['firstip'] and network['firstip'] <= network2['lastip']:\n", - " print(' - '+network['vpcid']+' '+network['cidrblock']+' overlaps with '+network2['vpcid']+' '+network2['cidrblock'])\n", - " elif network['lastip'] >= network2['firstip'] and network['lastip'] <= network2['lastip']:\n", - " print(' - '+network['vpcid']+' '+network['cidrblock']+' overlaps with '+network2['vpcid']+' '+network2['cidrblock'])\n", - " elif network['firstip'] <= network2['firstip'] and network['lastip'] >= network2['lastip']:\n", - " print(' - '+network['vpcid']+' '+network['cidrblock']+' overlaps with '+network2['vpcid']+' '+network2['cidrblock'])\n", - " else:\n", - " pass\n", - " else:\n", - " pass" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "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.13" - }, - "orig_nbformat": 4 - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/setup.py b/setup.py index 388181b..35ff980 100644 --- a/setup.py +++ b/setup.py @@ -8,18 +8,18 @@ setup( name = "botoplus", version = __version__, - description = "Python Library for Jupyter Notebooks", + description = "Python Library for Jupyter Notebooks that provides Security Operations the Threat Detection and Response capabilities needed during an Amazon Web Services (AWS) investigation.", long_description = long_description, long_description_content_type = "text/markdown", - url = "https://github.com/botoplus/botoplus", - author = "botoplus", - author_email = "hello@botoplus.com", + url = "https://github.com/jblukach/botoplus", + author = "John Lukach", + author_email = "hello@lukach.io", license = "Apache-2.0", packages = ["botoplus"], install_requires = [ "aws-sso-lib", "boto3", - "typer[all]" + "typer" ], - python_requires = ">=3.7", + python_requires = ">=3.8", ) \ No newline at end of file diff --git a/start.ipynb b/start.ipynb new file mode 100644 index 0000000..8218dda --- /dev/null +++ b/start.ipynb @@ -0,0 +1,103 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Start\n", + "### Requirement\n", + "##### Installation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "\n", + "!{sys.executable} -m pip install botoplus --upgrade" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##### Development" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "\n", + "os.system('rm /home/codespace/.local/lib/python3.10/site-packages/botoplus-*')\n", + "os.system('python setup.py install --user')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### IAM Identity Center\n", + "##### Login" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import botoplus.identity as _idp\n", + "\n", + "_idp.login()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##### Logout" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import botoplus.identity as _idp\n", + "\n", + "_idp.logout()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "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.13" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}