Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pulling in latest updates from the Ghost of Christmas past #18

Open
wants to merge 26 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
863208f
Wrap regional loop in a try/except in case there is an issue with reg…
Oct 23, 2020
92f5ee4
Enable support to create a CMK rather than use AWS Default
jchrisfarris Apr 14, 2021
5d31704
Adding Shield Advanced Fast-Fix
Jun 3, 2021
9b72cc6
Adding Shield Advanced Fast-Fix
Jun 3, 2021
b3d89ff
Merge branch 'Shield'
Jun 3, 2021
b7d827b
Small Fix to adhere to Shield Naming conventions for CloudFront
Jun 29, 2021
7cbc3f3
Improve Pagination of the Shield Enable Fast Fix
Jul 7, 2021
f62c032
Adding requirements.txt
Jul 26, 2021
b493c5b
New FastFix to delete IAM Users w/o MFA
Aug 13, 2021
a94ccd1
Forgot to remove the safety
Aug 17, 2021
066d41a
Spell check
Nov 4, 2021
42fd548
It's not woke to assume someone's region
Nov 4, 2021
94e6e24
Support disabling keys that are older than threshold and have never b…
Nov 4, 2021
654b6de
Root Email Marketing Unsubscribe for all org accounts
Nov 11, 2021
fe61a5a
Script to update alternate contacts across the org
Nov 12, 2021
cbe8a34
close dependapot alerts, support for latest boto3
Nov 16, 2021
797f0b4
Delete Pipfile.lock
jchrisfarris Nov 16, 2021
f89ac1c
Change dry run info messages to not indicate deletion is happening
Nov 16, 2021
df2a9e8
Bug fix for Regional issues
Nov 17, 2021
5764112
added support for Custom CMK with PrincipalOrgID permissions to allow…
Jan 3, 2022
4d53c91
Merge pull request #2 from jchrisfarris/ebs-default-encryption-for-am…
jchrisfarris Jan 3, 2022
fe68868
Better Error handling, handle setting contact in the payer which must…
jchrisfarris Jan 15, 2022
9f11d8d
Bug fixes and better logging
Apr 25, 2022
137fe70
Error handlings on disabled regions
Sep 6, 2022
4a85c1f
Added error handling for disabled regions and flag to deploy to empty…
jchrisfarris Feb 26, 2023
b732af1
Create FastFix to enable EBS Block Public Access in all regions
jchrisfarris Nov 22, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 0 additions & 92 deletions Pipfile.lock

This file was deleted.

28 changes: 21 additions & 7 deletions delete-default-vpc/delete-default-vpcs.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python3

import boto3
from botocore.exceptions import ClientError
from botocore.exceptions import ClientError, ProfileNotFound
import logging
import os

Expand All @@ -10,14 +10,24 @@
def main(args, logger):
'''Executes the Primary Logic'''

session = boto3.Session(profile_name=args.profile, region_name=args.boto_region)
try:
session = boto3.Session(profile_name=args.profile, region_name=args.boto_region)
except ProfileNotFound as e:
logger.critical(f"Profile {args.profile} was not found: {e}")
exit(1)

# Get all the Regions for this account
all_regions = get_regions(session, args)

# processiong regions
for region in all_regions:
process_region(args, region, session, logger)
try:
process_region(args, region, session, logger)
except ClientError as e:
if e.response['Error']['Code'] == "RegionDisabledException":
logger.critical(f"Region {region} is not enabled. Skipping...")
else:
raise

return

Expand Down Expand Up @@ -127,8 +137,8 @@ def delete_vpc(vpc,logger,region,debug):
logger.debug("Interface:{} attached to {}, VPC:{}, region:{}".format(eni.id,eni.attachment,vpc.id,region))
return
else:
logger.info("Deleting default VPC:{}, region:{}".format(vpc.id,region))
if args.actually_do_it:
logger.info("Deleting default VPC:{}, region:{}".format(vpc.id,region))
try:
vpc_resources = {
# dependency order from https://aws.amazon.com/premiumsupport/knowledge-center/troubleshoot-dependency-error-delete-vpc/
Expand Down Expand Up @@ -156,9 +166,8 @@ def delete_vpc(vpc,logger,region,debug):
logger.error("VPC:{} can't be delete due to dependency, {}".format(vpc.id, e))
else:
raise

logger.info("Successfully deleted default VPC:{}, region:{}".format(vpc.id,region))
if not args.actually_do_it:
else:
logger.info("Would delete default VPC:{}, region:{}".format(vpc.id,region))

def process_region(args, region, session, logger):
Expand Down Expand Up @@ -242,10 +251,15 @@ def do_args():
logging.getLogger('urllib3').setLevel(logging.WARNING)

# create formatter
if args.timestamp:
if args.timestamp and args.profile:
formatter = logging.Formatter(f"%(asctime)s - %(name)s - %(levelname)s - {args.profile} - %(message)s")
elif args.timestamp:
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
elif args.profile:
formatter = logging.Formatter(f"%(levelname)s - {args.profile} - %(message)s")
else:
formatter = logging.Formatter('%(levelname)s - %(message)s')

# add formatter to ch (console handler)
ch.setFormatter(formatter)
# add ch to logger
Expand Down
42 changes: 42 additions & 0 deletions ebs-block-public-access/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# EBS Block Public Access

This script will enable Block Public Access for EBS in all regions in your account.

## Why?

While there are a few valid use-cases for sharing a hard drive to every AWS customer, those probably don't apply to you. But it is easy to accidentally share an EBS Snapshot and threat actors scan for those regularly. AWS recently accounts [Block Public Access](https://aws.amazon.com/about-aws/whats-new/2023/11/amazon-elastic-block-store-public-access-ebs-snapshots/) for EBS. This script will enable that feature in all regions.

## What the script does.

This script iterates through all the regions returned by ec2:DescribeRegions and if get_snapshot_block_public_access_state() is `unblocked` calls enable_snapshot_block_public_access() to enable blocking _all_ sharing.

## Usage

```bash
usage: ebs-block-public-access.py [-h] [--debug] [--error] [--timestamp]
[--region REGION] [--profile PROFILE]
[--actually-do-it] [--disable]

options:
-h, --help show this help message and exit
--debug print debugging info
--error print error info only
--timestamp Output log with timestamp and toolname
--region REGION Only Process Specified Region
--profile PROFILE Use this CLI profile (instead of default or env credentials)
--actually-do-it Actually Perform the action
--disable Disable Block Public Access rather than enable it.

```

You must specify `--actually-do-it` for the changes to be made. Otherwise the script runs in dry-run mode only.


## AWS Docs

* [Feature Announcement](https://aws.amazon.com/about-aws/whats-new/2023/11/amazon-elastic-block-store-public-access-ebs-snapshots/)
* [EnableSnapshotBlockPublicAccess API](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_EnableSnapshotBlockPublicAccess.html)
* [boto3 get_snapshot_block_public_access_state()](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2/client/get_snapshot_block_public_access_state.html)
* [boto3 enable_snapshot_block_public_access()](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2/client/enable_snapshot_block_public_access.html)


136 changes: 136 additions & 0 deletions ebs-block-public-access/ebs-block-public-access.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#!/usr/bin/env python3

import boto3
from botocore.exceptions import ClientError
import os
import logging
import json
# logger = logging.getLogger()


def main(args, logger):
'''Executes the Primary Logic of the Fast Fix'''

# If they specify a profile use it. Otherwise do the normal thing
if args.profile:
session = boto3.Session(profile_name=args.profile)
else:
session = boto3.Session()

# Get all the Regions for this account
for region in get_regions(session, args):
ec2_client = session.client("ec2", region_name=region)


# Then ensure the EBS Encryption is set correctly
status_response = ec2_client.get_snapshot_block_public_access_state()
if status_response['State'] == 'unblocked' and not args.disable:
# Make it true
if args.actually_do_it is True:
logger.info(f"Enabling EBS Block Public Access in {region}")
enable_bpa(ec2_client, region)

else:
logger.info(f"You Need To Enable EBS Block Public Access in {region}")
elif status_response['State'] != 'unblocked' and args.disable:
# Make it false
if args.actually_do_it is True:
logger.info(f"Disabling EBS Block Public Access in {region}")
disable_bpa(ec2_client, region)

else:
logger.info(f"Would Disable EBS Block Public Access in {region}")
else:
logger.debug(f"EBS Block Public Access is enabled in {region}")


def enable_bpa(ec2_client, region):
'''Actually perform the enabling of block public access'''
response = ec2_client.enable_snapshot_block_public_access(State='block-all-sharing')
if response['State'] == 'block-all-sharing':
return(True)
else:
logger.error(f"Attempt to enable EBS Block Public Access in {region} returned {response}")
return(False)


def disable_bpa(ec2_client, region):
'''Actually perform the enabling of default ebs encryption'''
response = ec2_client.disable_snapshot_block_public_access()
if response['State'] == 'unblocked':
return(True)
else:
logger.error(f"Attempt to disable EBS Block Public Access in {region} returned {response}")
return(False)


def get_regions(session, args):
'''Return a list of regions with us-east-1 first. If --region was specified, return a list wth just that'''

# If we specifed a region on the CLI, return a list of just that
if args.region:
return([args.region])

# otherwise return all the regions, us-east-1 first
ec2 = session.client('ec2', region_name="us-east-1")
response = ec2.describe_regions()
output = ['us-east-1']
for r in response['Regions']:
# return us-east-1 first, but dont return it twice
if r['RegionName'] == "us-east-1":
continue
output.append(r['RegionName'])
return(output)


def do_args():
import argparse

parser = argparse.ArgumentParser()

parser.add_argument("--debug", help="print debugging info", action='store_true')
parser.add_argument("--error", help="print error info only", action='store_true')
parser.add_argument("--timestamp", help="Output log with timestamp and toolname", action='store_true')
parser.add_argument("--region", help="Only Process Specified Region")
parser.add_argument("--profile", help="Use this CLI profile (instead of default or env credentials)")
parser.add_argument("--actually-do-it", help="Actually Perform the action", action='store_true')
parser.add_argument("--disable", help="Disable Block Public Access rather than enable it.", action='store_true')

args = parser.parse_args()

return(args)

if __name__ == '__main__':

args = do_args()

# Logging idea stolen from: https://docs.python.org/3/howto/logging.html#configuring-logging
# create console handler and set level to debug
logger = logging.getLogger('enable-ebs-default-encryption')
ch = logging.StreamHandler()
if args.debug:
logger.setLevel(logging.DEBUG)
elif args.error:
logger.setLevel(logging.ERROR)
else:
logger.setLevel(logging.INFO)

# Silence Boto3 & Friends
logging.getLogger('botocore').setLevel(logging.WARNING)
logging.getLogger('boto3').setLevel(logging.WARNING)
logging.getLogger('urllib3').setLevel(logging.WARNING)

# create formatter
if args.timestamp:
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
else:
formatter = logging.Formatter('%(levelname)s - %(message)s')
# add formatter to ch
ch.setFormatter(formatter)
# add ch to logger
logger.addHandler(ch)

try:
main(args, logger)
except KeyboardInterrupt:
exit(1)
Loading