From 596cbc146915365be7f48cbb574660a3e1876373 Mon Sep 17 00:00:00 2001 From: Evan Gibler Date: Mon, 30 Oct 2023 16:13:40 -0500 Subject: [PATCH] Add a helper to retrieve the AWS account ID associated with a given access key ID (#920) * Adapt the AWS Key ID decoding blog post to a helper * Appease the linter * Appease the linter again * Move to panther_default; set up default_test.py * We don't need the separate Makefile target --- global_helpers/default_test.py | 16 ++++++++++++++++ global_helpers/panther_default.py | 21 +++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 global_helpers/default_test.py diff --git a/global_helpers/default_test.py b/global_helpers/default_test.py new file mode 100644 index 000000000..69f9736de --- /dev/null +++ b/global_helpers/default_test.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python +# Unit tests for functions inside panther_default + +import os +import sys +import unittest + +sys.path.append(os.path.dirname(__file__)) +import panther_default as p_d # pylint: disable=C0413 + + +class TestAWSKeyAccountID(unittest.TestCase): + def test_aws_key_account_id(self): + aws_key_id = "ASIAY34FZKBOKMUTVV7A" + account_id = p_d.aws_key_account_id(aws_key_id) + self.assertEqual(account_id, "609629065308") diff --git a/global_helpers/panther_default.py b/global_helpers/panther_default.py index 3f2539560..e873eecc8 100644 --- a/global_helpers/panther_default.py +++ b/global_helpers/panther_default.py @@ -8,6 +8,10 @@ # +import base64 +import binascii + + def example_helper(): return True @@ -63,3 +67,20 @@ def aws_event_tense(event_name): return tensed # If the event pattern doesn't exist, return original return event_name + + +# Adapted from https://medium.com/@TalBeerySec/a-short-note-on-aws-key-id-f88cc4317489 +def aws_key_account_id(aws_key: str): + """retrieve the AWS account ID associated with a given access key ID""" + key_no_prefix = aws_key[4:] # remove the four-character prefix + base32_key = base64.b32decode(key_no_prefix) # remainder of the key is base32-encoded + decoded_key = base32_key[0:6] # retrieve the 10-byte string + + # Convert the 10-byte string to an integer + key_id_int = int.from_bytes(decoded_key, byteorder="big", signed=False) + mask = int.from_bytes(binascii.unhexlify(b"7fffffffff80"), byteorder="big", signed=False) + + # Do a bitwise AND with the mask to retrieve the account ID + # (divide the 10-byte key integer by 128 and remove the fractional part(s)) + account_id = (key_id_int & mask) >> 7 + return str(account_id)