diff --git a/aws-exposed-key-checker-infra/.gitignore b/aws-exposed-key-checker-infra/.gitignore new file mode 100644 index 000000000..7f3825b85 --- /dev/null +++ b/aws-exposed-key-checker-infra/.gitignore @@ -0,0 +1,6 @@ +.terraform +.tfvars +*.zip +*.tfstate +*.tfstate.backup +test_ticket_data.json diff --git a/aws-exposed-key-checker-infra/.terraform.lock.hcl b/aws-exposed-key-checker-infra/.terraform.lock.hcl new file mode 100644 index 000000000..10597a99c --- /dev/null +++ b/aws-exposed-key-checker-infra/.terraform.lock.hcl @@ -0,0 +1,62 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/archive" { + version = "2.6.0" + hashes = [ + "h1:upAbF0KeKLAs3UImwwp5veC7jRcLnpKWVjkbd4ziWhM=", + "zh:29273484f7423b7c5b3f5df34ccfc53e52bb5e3d7f46a81b65908e7a8fd69072", + "zh:3cba58ec3aea5f301caf2acc31e184c55d994cc648126cac39c63ae509a14179", + "zh:55170cd17dbfdea842852c6ae2416d057fec631ba49f3bb6466a7268cd39130e", + "zh:7197db402ba35631930c3a4814520f0ebe980ae3acb7f8b5a6f70ec90dc4a388", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:8bf7fe0915d7fb152a3a6b9162614d2ec82749a06dba13fab3f98d33c020ec4f", + "zh:8ce811844fd53adb0dabc9a541f8cb43aacfa7d8e39324e4bd3592b3428f5bfb", + "zh:bca795bca815b8ac90e3054c0a9ab1ccfb16eedbb3418f8ad473fc5ad6bf0ef7", + "zh:d9355a18df5a36cf19580748b23249de2eb445c231c36a353709f8f40a6c8432", + "zh:dc32cc32cfd8abf8752d34f2a783de0d3f7200c573b885ecb64ece5acea173b4", + "zh:ef498e20391bf7a280d0fd6fd6675621c85fbe4e92f0f517ae4394747db89bde", + "zh:f2bc5226c765b0c8055a7b6207d0fe1eb9484e3ec8880649d158827ac6ed3b22", + ] +} + +provider "registry.terraform.io/hashicorp/aws" { + version = "5.73.0" + hashes = [ + "h1:hyOg38/ifG8Jf/b4GC6ydR8ClyRRdsAF3SmMHL6qbes=", + "zh:0d24edc51ab6600f56d759831658a9d7a8f69b53900546b75038fc8e3f312406", + "zh:1f8b8414f710a8c5a8777cb1ef1cad1cb4293bc035deb804734a8ec698b0850d", + "zh:2cf76b03564051ee86ef5fbdaea1949e3af549f8836e56371fe94335cf795e1c", + "zh:2ffe05c62b4ae6292dda66cd3a3cbe3e290a1a04369f3e6f74812e885cf3f2f0", + "zh:3564069d9bc918e5bded252d65b6a8758d08b309e1ac54bf7c8e5947a94cdadc", + "zh:4eb5395d52cfcb3c78e86c4ca3759bf9736e0e8dfa6955b0e1a59d9a7f41d805", + "zh:6cd14cbabbcf8b1c15fa73f9ebba4d4df41215ef92bf8d14a3780a7cb571e5c4", + "zh:6f7dc212dee1be2edb4620d352d9b0ea759744b5be08b84012a7621efa262052", + "zh:7468a490d6df04a401f49422c86b46ef91eba00878cc9a5ec3ee4a12fe9447d0", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:b440ff1be9fc62235b2dcb522dd922cefe751065ba4a601415130462e79fb68e", + "zh:d53dfd7311d8f130f0ce3184ed50461c34086d3490913a0d80d63574dac104a6", + "zh:de9a130dd684aed5b89edc7ce44aef37fa38eca06549035cf387cde9d3937432", + "zh:e0922d81fbed02062a74ea126d3cc6830fa0c8eac92108825d1120a262980831", + "zh:fdd6cdabcf5e9bedb3a419ac18bd12b5b02d8371ba0fb2a6123420937354c8e1", + ] +} + +provider "registry.terraform.io/hashicorp/null" { + version = "3.2.3" + hashes = [ + "h1:I0Um8UkrMUb81Fxq/dxbr3HLP2cecTH2WMJiwKSrwQY=", + "zh:22d062e5278d872fe7aed834f5577ba0a5afe34a3bdac2b81f828d8d3e6706d2", + "zh:23dead00493ad863729495dc212fd6c29b8293e707b055ce5ba21ee453ce552d", + "zh:28299accf21763ca1ca144d8f660688d7c2ad0b105b7202554ca60b02a3856d3", + "zh:55c9e8a9ac25a7652df8c51a8a9a422bd67d784061b1de2dc9fe6c3cb4e77f2f", + "zh:756586535d11698a216291c06b9ed8a5cc6a4ec43eee1ee09ecd5c6a9e297ac1", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:9d5eea62fdb587eeb96a8c4d782459f4e6b73baeece4d04b4a40e44faaee9301", + "zh:a6355f596a3fb8fc85c2fb054ab14e722991533f87f928e7169a486462c74670", + "zh:b5a65a789cff4ada58a5baffc76cb9767dc26ec6b45c00d2ec8b1b027f6db4ed", + "zh:db5ab669cf11d0e9f81dc380a6fdfcac437aea3d69109c7aef1a5426639d2d65", + "zh:de655d251c470197bcbb5ac45d289595295acb8f829f6c781d4a75c8c8b7c7dd", + "zh:f5c68199f2e6076bce92a12230434782bf768103a427e9bb9abee99b116af7b5", + ] +} diff --git a/aws-exposed-key-checker-infra/lambda_outputs/.gitignore b/aws-exposed-key-checker-infra/lambda_outputs/.gitignore new file mode 100644 index 000000000..654617bb0 --- /dev/null +++ b/aws-exposed-key-checker-infra/lambda_outputs/.gitignore @@ -0,0 +1,2 @@ +**/* +!.gitignore diff --git a/aws-exposed-key-checker-infra/lambda_source/exposed_key_checker/database.py b/aws-exposed-key-checker-infra/lambda_source/exposed_key_checker/database.py new file mode 100644 index 000000000..6aa8b744e --- /dev/null +++ b/aws-exposed-key-checker-infra/lambda_source/exposed_key_checker/database.py @@ -0,0 +1,39 @@ +from typing import TYPE_CHECKING +import boto3 +from botocore.config import Config +from exposed_key_checker.util import create_support_ticket + +if TYPE_CHECKING: + from exposed_keys import ExposedKeyData + +DB_TABLE_NAME = "ExposedKeyCheckerProcessed" +BOTO_CONFIG = Config(region_name="us-east-1") + + +class Database: + def __init__(self): + self._db = boto3.client("dynamodb", config=BOTO_CONFIG) + + def mark_key_as_processed(self, key_data: "ExposedKeyData"): + try: + self._db.put_item(TableName=DB_TABLE_NAME, Item=key_data.to_db_item()) + except Exception as e: + text = f"The key checker could not save the following item as processed in DynamoDB: {key_data}. The exception was {e}." + create_support_ticket( + "Exposed AWS Key Checker could not save processed state", + text, + "exposed-aws-key-checker-save-error", + ) + + def has_key_been_processed(self, key_data: "ExposedKeyData") -> bool: + res = self._db.query( + TableName=DB_TABLE_NAME, + Select="COUNT", + ExpressionAttributeValues={ + ":v1": { + "S": key_data.iam_user, + }, + }, + KeyConditionExpression="IamUser = :v1", + ) + return res.get("Count", 0) > 0 diff --git a/aws-exposed-key-checker-infra/lambda_source/exposed_key_checker/exposed_keys.py b/aws-exposed-key-checker-infra/lambda_source/exposed_key_checker/exposed_keys.py new file mode 100644 index 000000000..0f1e93c54 --- /dev/null +++ b/aws-exposed-key-checker-infra/lambda_source/exposed_key_checker/exposed_keys.py @@ -0,0 +1,109 @@ +from dataclasses import dataclass +from datetime import datetime +import re +from exposed_key_checker.ticket_manager import TicketData + + +def parse_tickets( + tickets: "list[TicketData]", +) -> "tuple[list[ExposedKeyData], list[int]]": + exposed_data: list[ExposedKeyData] = [] + parse_error_ids: list[int] = [] + for ticket in tickets: + data = ExposedKeyData.from_ticket(ticket) + if data is None and not _should_ignore_ticket_parse_failure(ticket): + parse_error_ids.append(ticket.id) + elif data is not None: + exposed_data.append(data) + + return exposed_data, parse_error_ids + + +def _should_ignore_ticket_parse_failure(ticket: TicketData) -> bool: + """ + Ignore ticket parse failures if we don't expect the email to have iam_user / key details + + There are a few different types of emails, like follow up emails, case resolved emails, etc. + """ + ignore_strs = [ + "correspondence was added to case", + "following up", + "following-up", + "follow up", + "follow-up", + "previous notice", + "we have not heard back from you", + "duplicate of case", + "case has been resolved", + ] + + text = ticket.description.lower() + for match_str in ignore_strs: + if match_str in text: + return True + else: + return False + + +@dataclass +class ExposedKeyData: + ticket: TicketData + iam_user: str + access_key: str + public_location: str + case_no: str + + @property + def tokens_server(self) -> str: + return self.iam_user.split("@@")[0] + + @property + def token(self) -> str: + return self.iam_user.split("@@")[1] + + def to_db_item(self) -> dict: + return { + "IamUser": {"S": self.iam_user.lower()}, + "AccessKey": {"S": self.access_key.lower()}, + "PublicLocation": {"S": self.public_location}, + "ProcessedAt": {"N": f"{datetime.now().timestamp():.0f}"}, + "ZendeskTicketId": {"N": str(self.ticket.id)}, + "TicketCreatedAt": {"N": f"{self.ticket.created_dt.timestamp():.0f}"}, + } + + @classmethod + def from_ticket(cls, ticket: TicketData) -> "ExposedKeyData | None": + iam_user = "" + access_key = "" + location = "" + case_no = "" + + account_details_match = re.search( + r"access key * (\w+).*user *([\w-]+\.(?:com|net|org)@@\w+)", + ticket.description, + re.IGNORECASE, + ) + if account_details_match is None: + return None + + access_key, iam_user = account_details_match.groups() + + case_match = re.search(r"case (\d+)", ticket.subject, re.IGNORECASE) + if case_match is not None: + case_no = case_match.group(1) + + location_match = re.search( + r"online at *(http[s]?://[\w%./#-]+) *\. *(?:to)?", + ticket.description, + re.IGNORECASE, + ) + if location_match is not None: + location = location_match.group(1) + + return cls(ticket, iam_user.lower(), access_key.lower(), location, case_no) + + def __str__(self) -> str: + return f"" + + def __repr__(self) -> str: + return self.__str__() diff --git a/aws-exposed-key-checker-infra/lambda_source/exposed_key_checker/lambda_handler.py b/aws-exposed-key-checker-infra/lambda_source/exposed_key_checker/lambda_handler.py new file mode 100644 index 000000000..dac6d6d86 --- /dev/null +++ b/aws-exposed-key-checker-infra/lambda_source/exposed_key_checker/lambda_handler.py @@ -0,0 +1,123 @@ +import json +import os +from datetime import datetime, timedelta +import requests +import boto3 +from botocore.config import Config + +from exposed_key_checker.database import Database +from exposed_key_checker.ticket_manager import ZendeskTicketManager +from exposed_key_checker.util import create_support_ticket +from exposed_key_checker.exposed_keys import ExposedKeyData, parse_tickets + +DB_TABLE_NAME = "ExposedKeyCheckerProcessed" +MAX_PROCESS_AGE_DAYS = 7 +ZENDESK_EXPOSED_TICKET_TAG = os.environ["ZENDESK_EXPOSED_TICKET_TAG"] +ZENDESK_AUTH_SECRET_ID = os.environ["ZENDESK_AUTH_SECRET_ID"] +TOKENS_SERVERS_ALLOW_LIST = [ + s.strip() for s in os.environ["TOKENS_SERVERS_ALLOW_LIST"].split(",") +] +TOKENS_POST_URL_OVERRIDE = os.getenv("TOKENS_POST_URL_OVERRIDE") + +BOTO_CONFIG = Config(region_name="us-east-1") + + +def lambda_handler(_event, _context): + db = Database() + + try: + ticket_manager = ZendeskTicketManager(*get_zendesk_auth()) + key_data, failed_ids = gather_data(ticket_manager) + except Exception as e: + text = f"The key checker could not query the Zendesk API for tickets.\nThe exception was {e}." + create_support_ticket( + "Exposed AWS Key Checker could not query the Zendesk API", + text, + "exposed-aws-key-checker-zendesk-api-error", + ) + return + + process_data(db, key_data) + + if failed_ids: + text = f"The key checker could not parse the following Zendesk ticket IDs: {failed_ids}" + create_support_ticket( + "Exposed AWS Key Checker could not parse Zendesk tickets", + text, + "exposed-aws-key-checker-parse-error", + ) + + +def process_data(db: Database, data: "list[ExposedKeyData]"): + unprocessed_items = [d for d in data if not db.has_key_been_processed(d)] + processed_count = len(data) - len(unprocessed_items) + print(f"Skipping {processed_count} items that were already processed.") + + items_to_process = [] + for item in unprocessed_items: + if item.tokens_server not in TOKENS_SERVERS_ALLOW_LIST: + print( + f"Ignoring the following item because its server is not in the allow list: {item}" + ) + continue + + items_to_process.append(item) + + print(f"Processing {len(items_to_process)} unprocessed items: {items_to_process}.") + + for item in items_to_process: + try: + send_to_tokens_server(item) + except Exception as e: + text = f"The key checker could not post the exposed event to the tokens server for the following item: {item}\nThe exception was: {e}.\n\nThis post will be retried automatically on the next run of the lambda. This only needs to be investigated if the failures continue." + create_support_ticket( + "Exposed AWS Key Checker could not post to tokens server", + text, + "exposed-aws-key-checker-post-error", + ) + else: + db.mark_key_as_processed(item) + + +def gather_data( + ticket_manager: "ZendeskTicketManager", +) -> "tuple[list[ExposedKeyData], list[int]]": + data: list[ExposedKeyData] = [] + error_ids: list[int] = [] + + num_tickets = 0 + for tickets in ticket_manager.read_all_tickets_in_batches(): + num_tickets += len(tickets) + key_data, eids = parse_tickets(tickets) + data.extend(key_data) + error_ids.extend(eids) + + age = datetime.now() - key_data[-1].ticket.created_dt + if age > timedelta(days=MAX_PROCESS_AGE_DAYS): + # Only check the last week's data + break + + print(f"Got {len(data)} exposed keys from {num_tickets} tickets.") + + return data, error_ids + + +def send_to_tokens_server(data: "ExposedKeyData"): + post_url = TOKENS_POST_URL_OVERRIDE or data.tokens_server + print(f"Sending key exposed event to {post_url} for token {data.token}") + + post_data = { + "token_exposed": True, + "exposed_time": int(data.ticket.created_dt.strftime("%s")), + "public_location": data.public_location, + } + + res = requests.post(post_url, data=post_data) + res.raise_for_status() + + +def get_zendesk_auth(): + client = boto3.client("secretsmanager", config=BOTO_CONFIG) + res = client.get_secret_value(SecretId=ZENDESK_AUTH_SECRET_ID) + data = json.loads(res.get("SecretString")) + return data["api_token"], data["user"], data["search_endpoint"] diff --git a/aws-exposed-key-checker-infra/lambda_source/exposed_key_checker/ticket_manager.py b/aws-exposed-key-checker-infra/lambda_source/exposed_key_checker/ticket_manager.py new file mode 100644 index 000000000..3e7114aa3 --- /dev/null +++ b/aws-exposed-key-checker-infra/lambda_source/exposed_key_checker/ticket_manager.py @@ -0,0 +1,71 @@ +from typing import Generator +from dataclasses import dataclass +from datetime import datetime +import os +import requests + +ZENDESK_EXPOSED_TICKET_TAG = os.environ["ZENDESK_EXPOSED_TICKET_TAG"] + + +class ZendeskTicketManager: + ZENDESK_SEARCH_LAST_PAGE = ( + 10 # the search endpoint has a maximum number of pages that it allows + ) + + def __init__(self, api_token: str, user: str, search_endpoint: str): + self._auth = (user, api_token) + self._search_endpoint = search_endpoint + + def read_all_tickets_in_batches(self) -> "Generator[list[TicketData], None, None]": + next_url = self._search_endpoint + for _ in range(self.ZENDESK_SEARCH_LAST_PAGE): + if next_url is None: + break + + tickets, next_url = self.get_tickets_from_api(next_url) + yield tickets + + def get_tickets_from_api( + self, + url: str | None = None, + ) -> "tuple[list[TicketData], str | None]": + r = requests.get( + url or self._search_endpoint, + auth=self._auth, + data={ + "query": f'tags:"{ZENDESK_EXPOSED_TICKET_TAG}"', + "sort_by": "created_at", + "sort_order": "desc", + }, + ) + + r.raise_for_status() + res = r.json() + + tickets = [TicketData.from_dict(t) for t in res["results"]] + return tickets, res["next_page"] + + +@dataclass +class TicketData: + url: str + id: int + created_at: str + updated_at: str + subject: str + description: str + + @classmethod + def from_dict(cls, data: dict) -> "TicketData": + return cls( + data["url"], + data["id"], + data["created_at"], + data["updated_at"], + data["subject"], + "".join(data["description"].splitlines()), + ) + + @property + def created_dt(self) -> datetime: + return datetime.strptime(self.created_at, "%Y-%m-%dT%H:%M:%SZ") diff --git a/aws-exposed-key-checker-infra/lambda_source/exposed_key_checker/util.py b/aws-exposed-key-checker-infra/lambda_source/exposed_key_checker/util.py new file mode 100644 index 000000000..a2581072a --- /dev/null +++ b/aws-exposed-key-checker-infra/lambda_source/exposed_key_checker/util.py @@ -0,0 +1,23 @@ +import os +import requests + + +def create_support_ticket(subject: str, text: str, dedupe_key: str): + ticket_service_url = os.getenv("TICKET_SERVICE_URL") + ticket_service_recipient = os.getenv("TICKET_SERVICE_RECIPIENT") + + data = { + "subject": subject, + "team": ticket_service_recipient, + "text": text, + "dedupe_key": dedupe_key, + } + + print(f"Creating support ticket with data: {data}.") + + if not ticket_service_url or not ticket_service_recipient: + print("Ticket service not configured, skipping actual ticket request.") + return + + res = requests.post(ticket_service_url, json=data) + res.raise_for_status() diff --git a/aws-exposed-key-checker-infra/layer/python/.gitignore b/aws-exposed-key-checker-infra/layer/python/.gitignore new file mode 100644 index 000000000..654617bb0 --- /dev/null +++ b/aws-exposed-key-checker-infra/layer/python/.gitignore @@ -0,0 +1,2 @@ +**/* +!.gitignore diff --git a/aws-exposed-key-checker-infra/main.tf b/aws-exposed-key-checker-infra/main.tf new file mode 100644 index 000000000..803037432 --- /dev/null +++ b/aws-exposed-key-checker-infra/main.tf @@ -0,0 +1,224 @@ +locals { + lambda_timeout = 120 + lambda_runtime = "python3.10" +} + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.58" + } + } + + required_version = ">= 1.2.0" + + backend "s3" { + bucket = "aws-exposed-key-checker-infra-tfstate-frcebvb1wabk" + key = "terraform/state.tfstate" + region = "us-east-1" + dynamodb_table = "aws-exposed-key-checker-tf-locks" + encrypt = true + } +} + +provider "aws" { + region = "us-east-1" +} + +# DB +resource "aws_dynamodb_table" "processed_table" { + name = "ExposedKeyCheckerProcessed" + billing_mode = "PAY_PER_REQUEST" + hash_key = "IamUser" + deletion_protection_enabled = true + + attribute { + name = "IamUser" + type = "S" + } +} + +# Lambda +resource "null_resource" "pip_install" { + triggers = { + shell_hash = "${sha256(file("${path.module}/requirements.txt"))}" + } + + provisioner "local-exec" { + command = "python3 -m pip install -r requirements.txt -t ${path.module}/layer/python" + } +} + +data "archive_file" "dependencies_layer_archive" { + type = "zip" + source_dir = "${path.module}/layer" + output_path = "${path.module}/lambda_outputs/layer.zip" + depends_on = [null_resource.pip_install] +} + +resource "aws_lambda_layer_version" "dependencies_layer" { + layer_name = "exposed-key-checker-dependencies" + filename = data.archive_file.dependencies_layer_archive.output_path + source_code_hash = data.archive_file.dependencies_layer_archive.output_base64sha256 + compatible_runtimes = ["python3.10"] +} + +data "archive_file" "code_archive" { + type = "zip" + source_dir = "${path.module}/lambda_source" + output_path = "${path.module}/lambda_outputs/lambda_exposed_aws_key_checker_payload.zip" +} + +resource "aws_lambda_function" "key_checker_lambda" { + function_name = "exposed_key_checker_lambda" + handler = "exposed_key_checker.lambda_handler.lambda_handler" + runtime = local.lambda_runtime + timeout = local.lambda_timeout + filename = data.archive_file.code_archive.output_path + source_code_hash = data.archive_file.code_archive.output_base64sha256 + role = aws_iam_role.key_checker_lambda_exec.arn + layers = [aws_lambda_layer_version.dependencies_layer.arn] + + environment { + variables = merge( + { + TICKET_SERVICE_URL = "${var.ticket_service_url}" + TICKET_SERVICE_RECIPIENT = "${var.ticket_service_recipient}" + ZENDESK_EXPOSED_TICKET_TAG = "${var.zendesk_exposed_ticket_tag}" + ZENDESK_AUTH_SECRET_ID = "${var.zendesk_auth_secret_id}" + TOKENS_SERVERS_ALLOW_LIST = "${var.tokens_servers_allow_list}" + }, + var.tokens_post_url_override != null ? { TOKENS_POST_URL_OVERRIDE = var.tokens_post_url_override } : {} + ) + } +} + +# IAM +resource "aws_iam_role" "key_checker_lambda_exec" { + name = "exposed_key_checker_lambda_exec_role" + assume_role_policy = jsonencode({ + Version = "2012-10-17", + Statement : [{ + Action = "sts:AssumeRole", + Effect = "Allow", + Principal = { + Service = "lambda.amazonaws.com" + } + }] + }) +} + +resource "aws_iam_policy" "key_checker_lambda_exec_policy" { + name = "exposed_key_checker_lambda_exec_role_policy" + description = "AWS IAM Policy for the Exposed Key Checker" + + policy = jsonencode({ + "Version" : "2012-10-17", + "Statement" : [ + { + "Action" : [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Resource" : "arn:aws:logs:*:*:*", + "Effect" : "Allow" + }, + { + "Effect" : "Allow", + "Action" : [ + "secretsmanager:GetSecretValue" + ], + "Resource" : [ + "${aws_secretsmanager_secret.zendesk_auth_data_secret.id}" + ] + }, + { + "Effect" : "Allow", + "Action" : [ + "dynamodb:PutItem", + "dynamodb:Query", + ], + "Resource" : [ + "${aws_dynamodb_table.processed_table.arn}" + ] + } + ] + }) +} + +resource "aws_iam_role_policy_attachment" "console_event_dispatcher_lambda_basic_execution" { + role = aws_iam_role.key_checker_lambda_exec.name + policy_arn = aws_iam_policy.key_checker_lambda_exec_policy.arn +} + +# Schedule lambda run +resource "aws_cloudwatch_event_rule" "periodic_run" { + name = "run_exposed_key_checker_periodically" + schedule_expression = "rate(12 hours)" +} + +resource "aws_cloudwatch_event_target" "lambda_target" { + rule = aws_cloudwatch_event_rule.periodic_run.name + target_id = "SendToLambda" + arn = aws_lambda_function.key_checker_lambda.arn +} + +resource "aws_lambda_permission" "allow_eventbridge_periodic" { + statement_id = "AllowExecutionFromEventBridge" + action = "lambda:InvokeFunction" + function_name = aws_lambda_function.key_checker_lambda.function_name + principal = "events.amazonaws.com" + source_arn = aws_cloudwatch_event_rule.periodic_run.arn +} + +# Secrets + +# This secret value is added manually +resource "aws_secretsmanager_secret" "zendesk_auth_data_secret" { + name = var.zendesk_auth_secret_id +} + +# TF state +resource "aws_s3_bucket" "terraform_state" { + bucket = "aws-exposed-key-checker-infra-tfstate-frcebvb1wabk" + tags = { + Name = "Terraform State Bucket for aws-exposed-key-checker" + } + lifecycle { + prevent_destroy = true + } +} + +resource "aws_s3_bucket_versioning" "terraform_state" { + bucket = aws_s3_bucket.terraform_state.id + + versioning_configuration { + status = "Enabled" + } +} + +resource "aws_s3_bucket_public_access_block" "terraform_state" { + bucket = aws_s3_bucket.terraform_state.id + + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} + +resource "aws_dynamodb_table" "terraform_state_lock" { + name = "aws-exposed-key-checker-tf-locks" + billing_mode = "PAY_PER_REQUEST" + hash_key = "LockID" + + attribute { + name = "LockID" + type = "S" + } + + tags = { + Name = "Terraform Lock Table for aws-exposed-key-checker" + } +} diff --git a/aws-exposed-key-checker-infra/requirements.txt b/aws-exposed-key-checker-infra/requirements.txt new file mode 100644 index 000000000..e1b8c7342 --- /dev/null +++ b/aws-exposed-key-checker-infra/requirements.txt @@ -0,0 +1,2 @@ +boto3==1.35.48 +requests==2.31.0 diff --git a/aws-exposed-key-checker-infra/tests/test_data_to_ignore.json b/aws-exposed-key-checker-infra/tests/test_data_to_ignore.json new file mode 100644 index 000000000..1f7d0244b --- /dev/null +++ b/aws-exposed-key-checker-infra/tests/test_data_to_ignore.json @@ -0,0 +1,168 @@ +{ + "following up": [ + { + "url": "https://example.com/api/data/1.json", + "id": 1, + "created_at": "2023-12-13T23:14:58Z", + "updated_at": "2023-12-14T00:01:40Z", + "subject": "RE:[CASE 12345678911] ACTION REQUIRED: Your AWS Access Key is Exposed for AWS Account 000000000000", + "description": "Dear AWS Customer,We are following up with you, as your AWS Account may still be compromised. Please review the previous notice we have sent and take immediate action to secure your account. If you believe that your account is secured and there is no unauthorized access or usage, please contact us immediately by responding to this Support case.This account compromise poses a security risk to your account (including other account users), and could lead to excessive charges from unauthorized activity. To protect your account from excessive charges, we have temporarily limited your ability to use some AWS services. To remove the limits, please follow the instructions provided in our initial notice.If the unauthorized usage is not stopped we may suspend your AWS account. To further protect your account from excessive charges, we may terminate any suspected unauthorized resources on your account.If you have any questions, please contact us by responding through this Support case. =============================================================== To share your experience or contact us again about this case, please return to the AWS Support Center using the following URL: https://console.aws.amazon.com/support/home#/case/?displayId=14460360771&language=en Note, this e-mail was sent from an address that cannot accept incoming e-mails. To respond to this case, please follow the link above to respond from your AWS Support Center. =============================================================== Don\u2019t miss messages from AWS Support when you need help! Update your contact information: https://console.aws.amazon.com/billing/home#/account If you receive an error message when visiting the contact information page, visit: https://aws.amazon.com/premiumsupport/knowledge-center/iam-billing-access/ AWS Support: https://aws.amazon.com/premiumsupport/knowledge-center/ AWS Documentation: https://docs.aws.amazon.com/ AWS Cost Management: https://aws.amazon.com/aws-cost-management/ AWS Training: http://aws.amazon.com/training/ AWS Managed Services: https://aws.amazon.com/managed-services/ Amazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com.This message was produced and distributed by Amazon Web Services, Inc. or its affiliates 410 Terry Ave. North, Seattle, WA 98109.\u00a9 [2023], Amazon Web Services, Inc. or its affiliates. All rights reserved. Read our Privacy Notice." + }, + { + "url": "https://example.com/api/data/2.json", + "id": 2, + "created_at": "2024-07-11T11:06:04Z", + "updated_at": "2024-07-11T12:02:20Z", + "subject": "RE:[CASE 123456789101112] [Action Required] Your AWS Access Key is Exposed for AWS Account 111111111111", + "description": "Dear AWS Customer,We are following up with you, as your AWS Account may still be compromised. Please review the previous notice we have sent and take immediate action to secure your account. If you believe that your account is secured and there is no unauthorized access or usage, please contact us immediately by responding to this Support case.This account compromise poses a security risk to your account (including other account users), and could lead to excessive charges from unauthorized activity. To protect your account from excessive charges, we have temporarily limited your ability to use some AWS services. To remove the limits, please follow the instructions provided in our initial notice.If the unauthorized usage is not stopped we may suspend your AWS account. To further protect your account from excessive charges, we may terminate any suspected unauthorized resources on your account.If you have any questions, please contact us by responding through this Support case. =============================================================== To share your experience or contact us again about this case, please return to the AWS Support Center using the following URL: https://console.aws.amazon.com/support/home#/case/?displayId=172052312200561&language=en Note, this e-mail was sent from an address that cannot accept incoming e-mails. To respond to this case, please follow the link above to respond from your AWS Support Center. =============================================================== Don\u2019t miss messages from AWS Support when you need help! Update your contact information: https://console.aws.amazon.com/billing/home#/account If you receive an error message when visiting the contact information page, visit: https://repost.aws/knowledge-center/iam-billing-access/ AWS Support: https://repost.aws/knowledge-center/ AWS Documentation: https://docs.aws.amazon.com/ AWS Cost Management: https://aws.amazon.com/aws-cost-management/ AWS Training: http://aws.amazon.com/training/ AWS Managed Services: https://aws.amazon.com/managed-services/ Amazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com.This message was produced and distributed by Amazon Web Services, Inc. or its affiliates 410 Terry Ave. North, Seattle, WA 98109.\u00a9 [2024], Amazon Web Services, Inc. or its affiliates. All rights reserved. Read our Privacy Notice." + }, + { + "url": "https://example.com/api/data/3.json", + "id": 3, + "created_at": "2024-07-23T02:36:13Z", + "updated_at": "2024-07-23T03:01:16Z", + "subject": "RE:[CASE 123456789101113] ACTION REQUIRED: Your AWS Access Key is Exposed for AWS Account 222222222222", + "description": "Dear AWS Customer,We are following up with you, as your AWS Account may still be compromised. Please review the previous notice we have sent and take immediate action to secure your account. If you believe that your account is secured and there is no unauthorized access or usage, please contact us immediately by responding to this Support case.This account compromise poses a security risk to your account (including other account users), and could lead to excessive charges from unauthorized activity. To protect your account from excessive charges, we have temporarily limited your ability to use some AWS services. To remove the limits, please follow the instructions provided in our initial notice.If the unauthorized usage is not stopped we may suspend your AWS account. To further protect your account from excessive charges, we may terminate any suspected unauthorized resources on your account.If you have any questions, please contact us by responding through this Support case. =============================================================== To share your experience or contact us again about this case, please return to the AWS Support Center using the following URL: https://console.aws.amazon.com/support/home#/case/?displayId=172152931200751&language=en Note, this e-mail was sent from an address that cannot accept incoming e-mails. To respond to this case, please follow the link above to respond from your AWS Support Center. =============================================================== Don\u2019t miss messages from AWS Support when you need help! Update your contact information: https://console.aws.amazon.com/billing/home#/account If you receive an error message when visiting the contact information page, visit: https://repost.aws/knowledge-center/iam-billing-access/ AWS Support: https://repost.aws/knowledge-center/ AWS Documentation: https://docs.aws.amazon.com/ AWS Cost Management: https://aws.amazon.com/aws-cost-management/ AWS Training: http://aws.amazon.com/training/ AWS Managed Services: https://aws.amazon.com/managed-services/ Amazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com.This message was produced and distributed by Amazon Web Services, Inc. or its affiliates 410 Terry Ave. North, Seattle, WA 98109.\u00a9 [2024], Amazon Web Services, Inc. or its affiliates. All rights reserved. Read our Privacy Notice." + } + ], + "we have not heard back from you": [ + { + "url": "https://example.com/api/data/4.json", + "id": 4, + "created_at": "2024-09-13T20:58:18Z", + "updated_at": "2024-09-13T21:01:40Z", + "subject": "Attention required on case 123456789101112: ACTION REQUIRED: Your AWS Access Key is Exposed for AWS Account 333333333333", + "description": "We have not heard back from you regarding case 123456789101112 in the last 7 days. We hope this means you have resolved your issue or question. If you need continued support, please contact us using the following URL:https://console.aws.amazon.com/support/home?#/case/?caseId=172548235900600&displayId=172548235900600&language=en(If you will connect by federation, log in before following the link.)Best Regards,Amazon Web Services*Please note: this e-mail was sent from an address that cannot accept incoming e-mail. Please use the link above if you need to contact us about this same issue.Amazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com, Inc." + }, + { + "url": "https://example.com/api/data/5.json", + "id": 5, + "created_at": "2024-07-30T03:48:09Z", + "updated_at": "2024-07-30T04:01:27Z", + "subject": "Resolved 103456789101112: ACTION REQUIRED: Your AWS Access Key is Exposed for AWS Account 444444444444", + "description": "We have not heard back from you regarding case 103456789101112 in the last 10 days. We hope this means you have resolved your issue or question. If this is not the case, please re-open case 172127105300711 using the following URL and we will continue to support you:https://console.aws.amazon.com/support/home?#/case/?caseId=172127105300711&displayId=172127105300711&language=en(If you will connect by federation, log in before following the link.)Please let us know if we helped address your issue:If YES, click here:https://console.aws.amazon.com/support/feedback?eventId=172127105300711&language=en&questionnaireId=Support-HMD-YesIf NO, click here:https://console.aws.amazon.com/support/feedback?eventId=172127105300711&language=en&questionnaireId=Support-HMD-No*Please note: this e-mail was sent from an address that cannot accept incoming e-mail. Please use the link above if you need to contact us about this same issue.Amazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com, Inc." + }, + { + "url": "https://example.com/api/data/6.json", + "id": 6, + "created_at": "2024-10-18T15:24:52Z", + "updated_at": "2024-10-18T16:02:25Z", + "subject": "Attention required on case 133456789101112: ACTION REQUIRED: Your AWS Access Key is Exposed for AWS Account 555555555555", + "description": "We have not heard back from you regarding case 133456789101112 in the last 7 days. We hope this means you have resolved your issue or question. If you need continued support, please contact us using the following URL:https://console.aws.amazon.com/support/home?#/case/?caseId=172848682200937&displayId=172848682200937&language=en(If you will connect by federation, log in before following the link.)Best Regards,Amazon Web Services*Please note: this e-mail was sent from an address that cannot accept incoming e-mail. Please use the link above if you need to contact us about this same issue.Amazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com, Inc." + } + ], + "follow-up": [ + { + "url": "https://example.com/api/data/7.json", + "id": 7, + "created_at": "2024-05-10T18:02:01Z", + "updated_at": "2024-05-10T19:02:05Z", + "subject": "Re: Attention required on case 111111111111111: ACTION REQUIRED: Your AWS Access Key is Exposed for AWS Account 666666666666", + "description": "This is a follow-up to your previous request #76510 \"Attention required on case ...\"

Greetings from Amazon Web Services.

We're sorry. You've written to an address that cannot accept incoming
e-mail.

If you need to contact us, please visit http://www.aws.amazon.com/contact-us .

Thank you for your business.

Best regards,
Amazon Web Services
http://www.aws.amazon.com/

P.S. You received this message because Amazon.com received the following
message:

Access Key is Exposed for AWS Account 777777777777

" + }, + { + "url": "https://example.com/api/data/8.json", + "id": 8, + "created_at": "2024-10-06T01:01:36Z", + "updated_at": "2024-10-06T02:01:40Z", + "subject": "Re: RE:[CASE 222222222222222] ACTION REQUIRED: Your AWS Access Key is Exposed for AWS Account 888888888888", + "description": "This is a follow-up to your previous request #99318 \"RE:[CASE 222222222222222] A...\"

Greetings from Amazon Web Services.

We're sorry. You've written to an address that cannot accept incoming
e-mail.

If you need to contact us, please visit http://www.aws.amazon.com/contact-us .

Thank you for your business.

Best regards,
Amazon Web Services
http://www.aws.amazon.com/

P.S. You received this message because Amazon.com received the following
message:

Exposed for AWS Account 888888888888

" + }, + { + "url": "https://example.com/api/data/9.json", + "id": 9, + "created_at": "2024-07-01T22:01:59Z", + "updated_at": "2024-07-01T23:01:33Z", + "subject": "Re: RE:[CASE 333333333333333] [Action Required] Your AWS Access Key is Exposed for AWS Account 999999999999", + "description": "This is a follow-up to your previous request #84523 \"RE:[CASE 333333333333333] [...\"

Greetings from Amazon Web Services.

We're sorry. You've written to an address that cannot accept incoming
e-mail.

If you need to contact us, please visit http://www.aws.amazon.com/contact-us .

Thank you for your business.

Best regards,
Amazon Web Services
http://www.aws.amazon.com/

P.S. You received this message because Amazon.com received the following
message:

Exposed for AWS Account 999999999999

" + } + ], + "case has been resolved": [ + { + "url": "https://example.com/api/data/10.json", + "id": 10, + "created_at": "2024-10-02T06:32:29Z", + "updated_at": "2024-10-02T07:01:56Z", + "subject": "RE:[CASE 444444444444444] ACTION REQUIRED: Your AWS Access Key is Exposed for AWS Account 211111111111", + "description": "This case has been resolved. Please contact us again if you need further assistance. =============================================================== To share your experience or contact us again about this case, please return to the AWS Support Center using the following URL: https://console.aws.amazon.com/support/home#/case/?displayId=172777775700841&language=en Note, this e-mail was sent from an address that cannot accept incoming e-mails. To respond to this case, please follow the link above to respond from your AWS Support Center. =============================================================== Don\u2019t miss messages from AWS Support when you need help! Update your contact information: https://console.aws.amazon.com/billing/home#/account If you receive an error message when visiting the contact information page, visit: https://repost.aws/knowledge-center/iam-billing-access/ AWS Support: https://repost.aws/knowledge-center/ AWS Documentation: https://docs.aws.amazon.com/ AWS Cost Management: https://aws.amazon.com/aws-cost-management/ AWS Training: http://aws.amazon.com/training/ AWS Managed Services: https://aws.amazon.com/managed-services/ Amazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com.This message was produced and distributed by Amazon Web Services, Inc. or its affiliates 410 Terry Ave. North, Seattle, WA 98109.\u00a9 [2024], Amazon Web Services, Inc. or its affiliates. All rights reserved. Read our Privacy Notice." + }, + { + "url": "https://example.com/api/data/11.json", + "id": 11, + "created_at": "2024-10-04T05:09:44Z", + "updated_at": "2024-10-04T06:01:59Z", + "subject": "RE:[CASE 555555555555555] ACTION REQUIRED: Your AWS Access Key is Exposed for AWS Account 311111111111", + "description": "This case has been resolved. Please contact us again if you need further assistance. =============================================================== To share your experience or contact us again about this case, please return to the AWS Support Center using the following URL: https://console.aws.amazon.com/support/home#/case/?displayId=172795967700417&language=en Note, this e-mail was sent from an address that cannot accept incoming e-mails. To respond to this case, please follow the link above to respond from your AWS Support Center. =============================================================== Don\u2019t miss messages from AWS Support when you need help! Update your contact information: https://console.aws.amazon.com/billing/home#/account If you receive an error message when visiting the contact information page, visit: https://repost.aws/knowledge-center/iam-billing-access/ AWS Support: https://repost.aws/knowledge-center/ AWS Documentation: https://docs.aws.amazon.com/ AWS Cost Management: https://aws.amazon.com/aws-cost-management/ AWS Training: http://aws.amazon.com/training/ AWS Managed Services: https://aws.amazon.com/managed-services/ Amazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com.This message was produced and distributed by Amazon Web Services, Inc. or its affiliates 410 Terry Ave. North, Seattle, WA 98109.\u00a9 [2024], Amazon Web Services, Inc. or its affiliates. All rights reserved. Read our Privacy Notice." + }, + { + "url": "https://example.com/api/data/12.json", + "id": 12, + "created_at": "2024-10-02T06:32:30Z", + "updated_at": "2024-10-02T07:01:56Z", + "subject": "RE:[CASE 666666666666666] ACTION REQUIRED: Your AWS Access Key is Exposed for AWS Account 411111111111", + "description": "This case has been resolved. Please contact us again if you need further assistance. =============================================================== To share your experience or contact us again about this case, please return to the AWS Support Center using the following URL: https://console.aws.amazon.com/support/home#/case/?displayId=172778753000580&language=en Note, this e-mail was sent from an address that cannot accept incoming e-mails. To respond to this case, please follow the link above to respond from your AWS Support Center. =============================================================== Don\u2019t miss messages from AWS Support when you need help! Update your contact information: https://console.aws.amazon.com/billing/home#/account If you receive an error message when visiting the contact information page, visit: https://repost.aws/knowledge-center/iam-billing-access/ AWS Support: https://repost.aws/knowledge-center/ AWS Documentation: https://docs.aws.amazon.com/ AWS Cost Management: https://aws.amazon.com/aws-cost-management/ AWS Training: http://aws.amazon.com/training/ AWS Managed Services: https://aws.amazon.com/managed-services/ Amazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com.This message was produced and distributed by Amazon Web Services, Inc. or its affiliates 410 Terry Ave. North, Seattle, WA 98109.\u00a9 [2024], Amazon Web Services, Inc. or its affiliates. All rights reserved. Read our Privacy Notice." + } + ], + "duplicate of case": [ + { + "url": "https://example.com/api/data/13.json", + "id": 13, + "created_at": "2024-08-29T15:37:49Z", + "updated_at": "2024-08-29T16:01:15Z", + "subject": "RE:[CASE 723456789101112] ACTION REQUIRED: Your AWS Access Key is Exposed for AWS Account 511111111111", + "description": "Hi there, I trust this email finds you well. This case appears to be a duplicate of case 515151515151515. In order to avoid any confusion or potential delays, I am going to resolve this case for you. Please refer to the other case for any further correspondence on this issue. You can follow the next link to get directly to that case: https://console.aws.amazon.com/support/home?#/case/?displayId=172464183600472&language=en Have a wonderful rest of your day. We value your feedback. Please share your experience by rating this and other correspondences in the AWS Support Center. You can rate a correspondence by selecting the stars in the top right corner of the correspondence.Best regards,Jhosua M.Amazon Web Services =============================================================== To share your experience or contact us again about this case, please return to the AWS Support Center using the following URL: https://console.aws.amazon.com/support/home#/case/?displayId=172460995000982&language=en Note, this e-mail was sent from an address that cannot accept incoming e-mails. To respond to this case, please follow the link above to respond from your AWS Support Center. =============================================================== Don\u2019t miss messages from AWS Support when you need help! Update your contact information: https://console.aws.amazon.com/billing/home#/account If you receive an error message when visiting the contact information page, visit: https://repost.aws/knowledge-center/iam-billing-access/ AWS Support: https://repost.aws/knowledge-center/ AWS Documentation: https://docs.aws.amazon.com/ AWS Cost Management: https://aws.amazon.com/aws-cost-management/ AWS Training: http://aws.amazon.com/training/ AWS Managed Services: https://aws.amazon.com/managed-services/ Amazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com.This message was produced and distributed by Amazon Web Services, Inc. or its affiliates 410 Terry Ave. North, Seattle, WA 98109.\u00a9 [2024], Amazon Web Services, Inc. or its affiliates. All rights reserved. Read our Privacy Notice." + } + ], + "correspondence was added to case": [ + { + "url": "https://example.com/api/data/14.json", + "id": 14, + "created_at": "2024-08-29T14:44:31Z", + "updated_at": "2024-08-29T15:01:44Z", + "subject": "[Case 123456789100000] New correspondence added", + "description": "A new correspondence was added to case 123456789100000 To view this correspondence, please visit the AWS Support Center using the following URL: https://console.aws.amazon.com/support/home#/case/?displayId=172460995000982&language=en ======================================= (If you will connect by federation, log in before following the link.) *Please note: this e-mail was sent from an address that cannot receive incoming e-mail. Please use the link above if you need to contact us again about this same issue. Amazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com.This message was produced and distributed by Amazon Web Services, Inc. or its affiliates 410 Terry Ave. North, Seattle, WA 98109.\u00a9 [2024], Amazon Web Services, Inc. or its affiliates. All rights reserved. Read our Privacy Notice. Some of the content and links in this email may have been generated by an Amazon customer. Amazon is not responsible for the contents or links within." + }, + { + "url": "https://example.com/api/data/15.json", + "id": 15, + "created_at": "2024-08-26T05:42:03Z", + "updated_at": "2024-08-26T06:01:45Z", + "subject": "[Case 223456789100000] New correspondence added", + "description": "A new correspondence was added to case 223456789100000 To view this correspondence, please visit the AWS Support Center using the following URL: https://console.aws.amazon.com/support/home#/case/?displayId=172434550000219&language=en ======================================= (If you will connect by federation, log in before following the link.) *Please note: this e-mail was sent from an address that cannot receive incoming e-mail. Please use the link above if you need to contact us again about this same issue. Amazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com.This message was produced and distributed by Amazon Web Services, Inc. or its affiliates 410 Terry Ave. North, Seattle, WA 98109.\u00a9 [2024], Amazon Web Services, Inc. or its affiliates. All rights reserved. Read our Privacy Notice. Some of the content and links in this email may have been generated by an Amazon customer. Amazon is not responsible for the contents or links within." + }, + { + "url": "https://example.com/api/data/16.json", + "id": 16, + "created_at": "2024-08-29T14:48:31Z", + "updated_at": "2024-08-29T15:01:44Z", + "subject": "[Case 323456789100000] New correspondence added", + "description": "A new correspondence was added to case 323456789100000 To view this correspondence, please visit the AWS Support Center using the following URL: https://console.aws.amazon.com/support/home#/case/?displayId=172464183600472&language=en ======================================= (If you will connect by federation, log in before following the link.) *Please note: this e-mail was sent from an address that cannot receive incoming e-mail. Please use the link above if you need to contact us again about this same issue. Amazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com.This message was produced and distributed by Amazon Web Services, Inc. or its affiliates 410 Terry Ave. North, Seattle, WA 98109.\u00a9 [2024], Amazon Web Services, Inc. or its affiliates. All rights reserved. Read our Privacy Notice. Some of the content and links in this email may have been generated by an Amazon customer. Amazon is not responsible for the contents or links within." + } + ], + "following-up": [ + { + "url": "https://example.com/api/data/17.json", + "id": 17, + "created_at": "2023-10-26T07:38:17Z", + "updated_at": "2023-10-26T08:02:00Z", + "subject": "RE:[CASE 823456789101112] ACTION REQUIRED: Your AWS Access Key is Exposed for AWS Account 611111111111", + "description": "Hello,We are following-up regarding re-securing your account.I see that this case appears to be a duplicate of case 123456789100000. In order to avoid any confusion or potential delays, I'm going to resolve this case for you.Please refer to the other case for any further correspondence on this issue here: - https://console.aws.amazon.com/support/home?#/case/?caseId=14087663201We value your feedback. Please share your experience by rating this and other correspondences in the AWS Support Center. You can rate a correspondence by selecting the stars in the top right corner of the correspondence.Best regards,KevinAmazon Web Services =============================================================== To share your experience or contact us again about this case, please return to the AWS Support Center using the following URL: https://console.aws.amazon.com/support/home#/case/?displayId=14149244261&language=en Note, this e-mail was sent from an address that cannot accept incoming e-mails. To respond to this case, please follow the link above to respond from your AWS Support Center. =============================================================== Don\u2019t miss messages from AWS Support when you need help! Update your contact information: https://console.aws.amazon.com/billing/home#/account If you receive an error message when visiting the contact information page, visit: https://aws.amazon.com/premiumsupport/knowledge-center/iam-billing-access/ AWS Support: https://aws.amazon.com/premiumsupport/knowledge-center/ AWS Documentation: https://docs.aws.amazon.com/ AWS Cost Management: https://aws.amazon.com/aws-cost-management/ AWS Training: http://aws.amazon.com/training/ AWS Managed Services: https://aws.amazon.com/managed-services/ Amazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com.This message was produced and distributed by Amazon Web Services, Inc. or its affiliates 410 Terry Ave. North, Seattle, WA 98109.\u00a9 [2023], Amazon Web Services, Inc. or its affiliates. All rights reserved. Read our Privacy Notice." + }, + { + "url": "https://example.com/api/data/18.json", + "id": 18, + "created_at": "2023-10-26T07:37:40Z", + "updated_at": "2023-10-26T08:02:01Z", + "subject": "RE:[CASE 923456789101112] ACTION REQUIRED: Your AWS Access Key is Exposed for AWS Account 711111111111", + "description": "Hello,We are following-up regarding re-securing your account.I see that this case appears to be a duplicate of case 123456789100000. In order to avoid any confusion or potential delays, I'm going to resolve this case for you.Please refer to the other case for any further correspondence on this issue here: - https://console.aws.amazon.com/support/home?#/case/?caseId=14087663201We value your feedback. Please share your experience by rating this and other correspondences in the AWS Support Center. You can rate a correspondence by selecting the stars in the top right corner of the correspondence.Best regards,KevinAmazon Web Services =============================================================== To share your experience or contact us again about this case, please return to the AWS Support Center using the following URL: https://console.aws.amazon.com/support/home#/case/?displayId=14088338691&language=en Note, this e-mail was sent from an address that cannot accept incoming e-mails. To respond to this case, please follow the link above to respond from your AWS Support Center. =============================================================== Don\u2019t miss messages from AWS Support when you need help! Update your contact information: https://console.aws.amazon.com/billing/home#/account If you receive an error message when visiting the contact information page, visit: https://aws.amazon.com/premiumsupport/knowledge-center/iam-billing-access/ AWS Support: https://aws.amazon.com/premiumsupport/knowledge-center/ AWS Documentation: https://docs.aws.amazon.com/ AWS Cost Management: https://aws.amazon.com/aws-cost-management/ AWS Training: http://aws.amazon.com/training/ AWS Managed Services: https://aws.amazon.com/managed-services/ Amazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com.This message was produced and distributed by Amazon Web Services, Inc. or its affiliates 410 Terry Ave. North, Seattle, WA 98109.\u00a9 [2023], Amazon Web Services, Inc. or its affiliates. All rights reserved. Read our Privacy Notice." + }, + { + "url": "https://example.com/api/data/19.json", + "id": 19, + "created_at": "2023-10-26T07:38:45Z", + "updated_at": "2023-10-26T08:01:59Z", + "subject": "RE:[CASE 023456789101112] ACTION REQUIRED: Your AWS Access Key is Exposed for AWS Account 811111111111", + "description": "Hello,We are following-up regarding re-securing your account.I see that this case appears to be a duplicate of case 123456789100000. In order to avoid any confusion or potential delays, I'm going to resolve this case for you.Please refer to the other case for any further correspondence on this issue here: - https://console.aws.amazon.com/support/home?#/case/?caseId=14087663201We value your feedback. Please share your experience by rating this and other correspondences in the AWS Support Center. You can rate a correspondence by selecting the stars in the top right corner of the correspondence.Best regards,KevinAmazon Web Services =============================================================== To share your experience or contact us again about this case, please return to the AWS Support Center using the following URL: https://console.aws.amazon.com/support/home#/case/?displayId=14157718111&language=en Note, this e-mail was sent from an address that cannot accept incoming e-mails. To respond to this case, please follow the link above to respond from your AWS Support Center. =============================================================== Don\u2019t miss messages from AWS Support when you need help! Update your contact information: https://console.aws.amazon.com/billing/home#/account If you receive an error message when visiting the contact information page, visit: https://aws.amazon.com/premiumsupport/knowledge-center/iam-billing-access/ AWS Support: https://aws.amazon.com/premiumsupport/knowledge-center/ AWS Documentation: https://docs.aws.amazon.com/ AWS Cost Management: https://aws.amazon.com/aws-cost-management/ AWS Training: http://aws.amazon.com/training/ AWS Managed Services: https://aws.amazon.com/managed-services/ Amazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com.This message was produced and distributed by Amazon Web Services, Inc. or its affiliates 410 Terry Ave. North, Seattle, WA 98109.\u00a9 [2023], Amazon Web Services, Inc. or its affiliates. All rights reserved. Read our Privacy Notice." + } + ] +} diff --git a/aws-exposed-key-checker-infra/tests/test_data_to_parse.json b/aws-exposed-key-checker-infra/tests/test_data_to_parse.json new file mode 100644 index 000000000..4b356b8e0 --- /dev/null +++ b/aws-exposed-key-checker-infra/tests/test_data_to_parse.json @@ -0,0 +1,50 @@ +[ + { + "url": "https://example.com/api/data/100.json", + "id": 100, + "created_at": "2024-10-06T13:53:31Z", + "updated_at": "2024-10-06T14:02:35Z", + "subject": "RE:[CASE 111111111111111] ACTION REQUIRED: Your AWS Access Key is Exposed for AWS Account 100000000000", + "description": "Hello,We have become aware that the AWS access key AKA1B2C3D4E5F6G7H8I1, belonging to IAM User example.com@@abcdefghijklmnopqrstuvwx1, along with the corresponding secret key is publicly available online at https://github.com/testorg/test-project/blob/abcdefg123450572a58f802fa79f84321983d332/folder1/file.js.To protect your account, we have temporarily limited your ability to use some AWS services.To protect your account from unwanted activity, we have applied the \"AWSCompromisedKeyQuarantineV2\" AWS Managed Policy (\"Quarantine Policy\") to the IAM User [user_id]. The Quarantine Policy applied to the IAM User [user_id] protects your account by denying access to high risk actions like iam:CreateAccessKey and ec2:RunInstances. Please refer to tehe \"AWSCompromisedKeyQuarantineV2 Permissions\" [1] to review all of the actions denied by the policy.Please do not remove the Quarantine Policy before following the instructions below. However, in cases where the Quarantine Policy is causing production issues you may choose to detach the policy from the user. Only users with admin privileges or with access to iam:DetachUserPolicy may remove the policy. Refer to the IAM User Guide [2] on how to remove managed policies.As a security best practice, we recommend that you enable multi-factor authentication (MFA) [3].Follow the instructions below to secure and restore your account:For more detailed instructions, please refer to the \u201cWhat do I do if I notice unauthorized activity in my AWS account?\u201d user guide [4].Step 1:If your application uses the exposed access key, you need to replace the key. To replace the key, first create a second key (at that point both keys will be active). Then, modify your application to use the new key.Next, disable (do not delete) the exposed key by clicking on the \u201cMake inactive\u201d option in the console. If there are any problems with your application, you can reactivate the exposed key. When your application is fully functional using the new key, please delete the exposed access key AKA1B2C3D4E5F6G7H8I1.To delete IAM User Keys, go to your AWS Management Console - Users [5].To delete Root User Keys, go to your AWS Management Console - Security Credential [6].Please note, only rotating and deleting the exposed key may not be sufficient to protect your account, see Step 2.Step 2: Check your CloudTrail log for unwanted activity.Check your account for any unwanted activity such as creation of unapproved IAM users, and/or associated passwords (login profile), access keys, policies, roles or temporary security credentials by checking your CloudTrail log, and immediately delete them.To delete IAM users, go to your AWS Management Console - Users [7].To delete policies, go to your AWS Management Console - Policies [8].To delete roles, go to your AWS Management Console - Roles [9].Please note, deleting IAM users may impact production workloads and should be done carefully.Step 3: Review your AWS account for any unwanted AWS usage.Check your account for any unwanted usage such as EC2 instances, Lambda functions, or EC2 Spot bids by logging into your AWS Management Console and reviewing each service page. You can also do this by checking the \"Bills\" page in the Billing console [10].Please keep in mind that unwanted usage can occur in any region and that your console displays only one region at a time. To switch regions, use the drop-down menu in the top-right corner of the console.Step 4: You must respond to the existing Support Case or create a new one [11] to confirm completion of steps 1-3 in order to restore access to your account, prevent suspension, and apply for a billing adjustment, if applicable.If you need help completing the steps to secure your account, let us know through the Support Case where you can request a phone call or chat session for immediate assistance.If you believe that your account is secured and there is no unwanted access or usage, please contact us immediately via the Support Case to confirm this in writing.Any billing adjustment related to unwanted charges will be considered after the account is secured.[1] https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/AWSCompromisedKeyQuarantineV2$jsonEditor?section=permissions[2] https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_manage-attach-detach.html#remove-policies-console[3] https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable.html[4] https://aws.amazon.com/premiumsupport/knowledge-center/potential-account-compromise/[5] https://console.aws.amazon.com/iam/home#users[6] https://console.aws.amazon.com/iam/home#security_credential[7] https://console.aws.amazon.com/iamv2/home#/users[8] https://console.aws.amazon.com/iam/home#/policies[9] https://console.aws.amazon.com/iam/home#/roles[10] https://console.aws.amazon.com/billing/home#/bill[11] https://console.aws.amazon.com/support/home?#/Sincerely,Amazon Web ServicesAmazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com, Inc. This message was produced and distributed by Amazon Web Services Inc., 410 Terry Ave. North, Seattle, WA 98109-5210 =============================================================== To share your experience or contact us again about this case, please return to the AWS Support Center using the following URL: https://console.aws.amazon.com/support/home#/case/?displayId=172822279300614&language=en Note, this e-mail was sent from an address that cannot accept incoming e-mails. To respond to this case, please follow the link above to respond from your AWS Support Center. =============================================================== Don\u2019t miss messages from AWS Support when you need help! Update your contact information: https://console.aws.amazon.com/billing/home#/account If you receive an error message when visiting the contact information page, visit: https://repost.aws/knowledge-center/iam-billing-access/ AWS Support: https://repost.aws/knowledge-center/ AWS Documentation: https://docs.aws.amazon.com/ AWS Cost Management: https://aws.amazon.com/aws-cost-management/ AWS Training: http://aws.amazon.com/training/ AWS Managed Services: https://aws.amazon.com/managed-services/ Amazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com.This message was produced and distributed by Amazon Web Services, Inc. or its affiliates 410 Terry Ave. North, Seattle, WA 98109.\u00a9 [2024], Amazon Web Services, Inc. or its affiliates. All rights reserved. Read our Privacy Notice." + }, + { + "url": "https://example.com/api/data/200.json", + "id": 200, + "created_at": "2024-03-22T16:07:15Z", + "updated_at": "2024-03-22T17:01:35Z", + "subject": "RE:[CASE 222222222222222] ACTION REQUIRED: Your AWS Access Key is Exposed for AWS Account 200000000000", + "description": "Hello,We have become aware that the AWS Access Key AKA1B2C3D4E5F6G7H8I2 , belonging to IAM User example.net@@abcdefghijklmnopqrstuvwx2 , along with the corresponding Secret Key is publicly available online at https://github.com/testorg/test-project/blob/abcdefg123450572a58f802fa79f84321983d332/folder1/random-file. Your security is important to us and this exposure of your account\u2019s IAM credentials poses a security risk to your AWS account, could lead to excessive charges from unauthorized activity, and violates the AWS Customer Agreement or other agreement with us governing your use of our Services.To protect your account from excessive charges and unauthorized activity, we have applied the \"AWSCompromisedKeyQuarantineV2\" AWS Managed Policy (\"Quarantine Policy\") to the IAM User listed above. The Quarantine Policy applied to the User protects your account by denying access to high risk actions like iam:CreateAccessKey and ec2:RunInstances. You can view all the actions denied by the policy by going here: https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/AWSCompromisedKeyQuarantineV2$jsonEditor?section=permissions.For your security, DO NOT remove the Quarantine Policy before following the instructions below. In cases where the Quarantine Policy is causing production issues you may detach the policy from the user. NOTE: Only users with admin privileges or with access to iam:DetachUserPolicy may remove the policy. For instructions on how to remove managed policies go here: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_manage-attach-detach.html#remove-policies-console. In the event of the unauthorized use of your AWS account, we may, at our sole discretion, provide you with concessions. However, a failure to follow the instructions below may jeopardize your ability to receive a concession.FOLLOW THE INSTRUCTIONS BELOW TO SECURE AND RESTORE YOUR ACCOUNT. More detailed instructions for each item can be found in the \u201cWhat do I do if I notice unauthorized activity in my AWS account?\u201d guide in AWS public documentation: https://aws.amazon.com/premiumsupport/knowledge-center/potential-account-compromise/ Step 1: Rotate and delete the exposed AWS Access Key AKA1B2C3D4E5F6G7H8I2. To delete IAM User Keys go to your AWS Management Console here: https://console.aws.amazon.com/iam/home#users. To delete Root User Keys go here: https://console.aws.amazon.com/iam/home#security_credential.If your application uses the exposed Access Key, you need to replace the Key. To replace the Key, first create a second Key (at that point both Keys will be active) and then modify your application to use the new Key.Then disable (but do not delete) the exposed Key by clicking on the \u201cMake inactive\u201d option in the console. If there are any problems with your application, you can reactivate the exposed Key. When your application is fully functional using the new Key, please delete the exposed Key.NOTE: Only rotating and deleting the exposed Key may not be sufficient to protect your account, see Step 2.We also recommend enabling multi-factor authentication (MFA) on your AWS account for increased security. You can find more information here: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable.html Step 2: Check your CloudTrail log for unsanctioned activity. Check your account for any unsanctioned activity such as creation of unauthorized IAM users and/or associated passwords (login profile), access keys, policies, roles or temporary security credentials by checking your CloudTrail log, and immediately delete them.NOTE: Deleting IAM users may impact production workloads and should be done carefully. Step 3: Review your AWS account for any unauthorized AWS usage.Check your account for any unauthorized usage such as EC2 instances, Lambda functions or EC2 Spot bids by logging into your AWS Management Console and reviewing each service page. You can also do this by checking the \"Bills\" page in the Billing console by going here: https://console.aws.amazon.com/billing/home#/bill Please keep in mind that unauthorized usage can occur in any region and that your console displays only one region at a time. To switch regions, use the drop-down menu in the top-right corner of the console.Step 4: [IMPORTANT] You must respond to the existing Support Case or create a new one to confirm completion of the steps above in order to restore access to your account, prevent suspension, and apply for a billing adjustment, if applicable. While logged in to your account, access the Support Center and reply to the existing Support Case to confirm completion of steps 1-3. If you cannot find an existing Support Case, please create a new one by going here: https://console.aws.amazon.com/support/home?#/ If you need help completing the steps to secure your account, let us know through the Support Case. You can request a phone call or chat session for immediate assistance. If you believe that your account is secured and there is no unauthorized access or usage, please contact us immediately via the Support Case to confirm this in writing. Any billing adjustment related to unauthorized charges will be considered after the account is secured.Thank you for your immediate attention to this matter. Sincerely,Amazon Web ServicesAmazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com, Inc. This message was produced and distributed by Amazon Web Services Inc., 410 Terry Ave. North, Seattle, WA 98109-5210 =============================================================== To share your experience or contact us again about this case, please return to the AWS Support Center using the following URL: https://console.aws.amazon.com/support/home#/case/?displayId=171112361901658&language=en Note, this e-mail was sent from an address that cannot accept incoming e-mails. To respond to this case, please follow the link above to respond from your AWS Support Center. =============================================================== Don\u2019t miss messages from AWS Support when you need help! Update your contact information: https://console.aws.amazon.com/billing/home#/account If you receive an error message when visiting the contact information page, visit: https://repost.aws/knowledge-center/iam-billing-access/ AWS Support: https://repost.aws/knowledge-center/ AWS Documentation: https://docs.aws.amazon.com/ AWS Cost Management: https://aws.amazon.com/aws-cost-management/ AWS Training: http://aws.amazon.com/training/ AWS Managed Services: https://aws.amazon.com/managed-services/ Amazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com.This message was produced and distributed by Amazon Web Services, Inc. or its affiliates 410 Terry Ave. North, Seattle, WA 98109.\u00a9 [2024], Amazon Web Services, Inc. or its affiliates. All rights reserved. Read our Privacy Notice." + }, + { + "url": "https://example.com/api/data/300.json", + "id": 300, + "created_at": "2024-07-08T07:50:44Z", + "updated_at": "2024-07-08T08:02:30Z", + "subject": "RE:[CASE 333333333333333] [Action Required] Your AWS Access Key is Exposed for AWS Account 300000000000", + "description": "Hello,We have become aware that the AWS access key AKA1B2C3D4E5F6G7H8I3, belonging to User example-test.org@@abcdefghijklmnopqrstuvwx3 along with the corresponding secret key is publicly available online at https://github.com/testorg/test-project/blob/abcdefg123450572a58f802fa79f84321983d332/folder1/creds.To protect your account, we have temporarily limited your ability to use some AWS services.To restore access, you must contact AWS by and follow the instructions below. If you do not contact AWS by , we may suspend your account. We may terminate any suspicious resources on your account, and some resources may not be recoverable once terminated.As a security best practice, we recommend that you enable multi-factor authentication (MFA) [1].Follow the instructions below and for further detailed instructions, please refer to the \u201cWhat do I do if I notice unwanted activity in my AWS account?\u201d user guide [2].Step 1: If your application uses the exposed access key, you need to replace the key. To replace the key, first create a second key (at that point both keys will be active). Then, modify your application to use the new key.Next, disable (do not delete) the exposed key by clicking on the \u201cMake inactive\u201d option in the console. If there are any problems with your application, you can reactivate the exposed key. When your application is fully functional using the new key, please delete the exposed access key AKA1B2C3D4E5F6G7H8I3.To delete IAM user keys, go to your AWS Management Console - Users [3].To delete Root user keys, go to your AWS Management Console - Security Credential [4].If your application uses the exposed access key, you need to replace the key. To replace the key, first create a second key (at that point both keys will be active). Then, modify your application to use the new key.Please note, only rotating and deleting the exposed key may not be sufficient to protect your account, continue to Step 2.Step 2: Check your CloudTrail log for unwanted activity.Check your account for any unwanted activity, such as creation of unapproved IAM users and/or associated passwords (login profile), access keys, policies, roles or temporary security credentials by checking your CloudTrail log, and immediately delete them.To delete IAM users, go to your AWS Management Console - Users [5].To delete policies, go to your AWS Management Console - Policies [6].To delete roles, go to your AWS Management Console - Roles [7].Please note, deleting IAM users may impact production workloads and should be done carefully. Step 3: Review your AWS account for any unwanted AWS usage.Check your account for any unwanted usage, such as EC2 instances, Lambda functions, or EC2 Spot bids by logging into your AWS Management Console and reviewing each service page. You can also do this by checking the \"Bills\" page in the Billing console [8].Please note, unwanted usage can occur in any region and your console only displays one region at a time. To switch regions, use the drop-down menu in the top-right corner of the console.Step 4: You must respond to the existing Support Case or create a new one [9] to confirm completion of steps 1-3 in order to restore access to your account, prevent suspension, and apply for a billing adjustment, if applicable. If you need help completing the steps to secure your account, let us know through the Support Case where you can request a phone call or chat session for immediate assistance. If you believe your account is secured and there is no unwanted access or usage, please contact us immediately via the Support Case to confirm this in writing.Any billing adjustment related to unwanted charges will be considered after the account is secured.[1] https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable.html [2] https://aws.amazon.com/premiumsupport/knowledge-center/potential-account-compromise/[3] https://console.aws.amazon.com/iam/home#users[4] https://console.aws.amazon.com/iam/home#security_credential[5] https://console.aws.amazon.com/iamv2/home#/users[6] https://console.aws.amazon.com/iam/home#/policies[7] https://console.aws.amazon.com/iam/home#/roles[8] https://console.aws.amazon.com/billing/home#/bill[9] https://console.aws.amazon.com/support/home?#/Sincerely,Amazon Web ServicesAmazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com, Inc. This message was produced and distributed by Amazon Web Services Inc., 410 Terry Ave. North, Seattle, WA 98109-5210. =============================================================== To share your experience or contact us again about this case, please return to the AWS Support Center using the following URL: https://console.aws.amazon.com/support/home#/case/?displayId=172042502800075&language=en Note, this e-mail was sent from an address that cannot accept incoming e-mails. To respond to this case, please follow the link above to respond from your AWS Support Center. =============================================================== Don\u2019t miss messages from AWS Support when you need help! Update your contact information: https://console.aws.amazon.com/billing/home#/account If you receive an error message when visiting the contact information page, visit: https://repost.aws/knowledge-center/iam-billing-access/ AWS Support: https://repost.aws/knowledge-center/ AWS Documentation: https://docs.aws.amazon.com/ AWS Cost Management: https://aws.amazon.com/aws-cost-management/ AWS Training: http://aws.amazon.com/training/ AWS Managed Services: https://aws.amazon.com/managed-services/ Amazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com.This message was produced and distributed by Amazon Web Services, Inc. or its affiliates 410 Terry Ave. North, Seattle, WA 98109.\u00a9 [2024], Amazon Web Services, Inc. or its affiliates. All rights reserved. Read our Privacy Notice." + }, + { + "url": "https://example.com/api/data/400.json", + "id": 400, + "created_at": "2024-01-16T16:07:08Z", + "updated_at": "2024-01-16T17:03:00Z", + "subject": "RE:[CASE 444444444444444] ACTION REQUIRED: Your AWS Access Key is Exposed for AWS Account 400000000000", + "description": "Hello,We have become aware that the AWS Access Key AKA1B2C3D4E5F6G7H8I4 , belonging to IAM User example2.com@@abcdefghijklmnopqrstuvwx4 , along with the corresponding Secret Key is publicly available online at https://github.com/testorg/test-project/blob/abcdefg123450572a58f802fa79f84321983d332/folder1/aws_test. Your security is important to us and this exposure of your account\u2019s IAM credentials poses a security risk to your AWS account, could lead to excessive charges from unauthorized activity, and violates the AWS Customer Agreement or other agreement with us governing your use of our Services.To protect your account from excessive charges and unauthorized activity, we have applied the \"AWSCompromisedKeyQuarantineV2\" AWS Managed Policy (\"Quarantine Policy\") to the IAM User listed above. The Quarantine Policy applied to the User protects your account by denying access to high risk actions like iam:CreateAccessKey and ec2:RunInstances. You can view all the actions denied by the policy by going here: https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/AWSCompromisedKeyQuarantineV2$jsonEditor?section=permissions.For your security, DO NOT remove the Quarantine Policy before following the instructions below. In cases where the Quarantine Policy is causing production issues you may detach the policy from the user. NOTE: Only users with admin privileges or with access to iam:DetachUserPolicy may remove the policy. For instructions on how to remove managed policies go here: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_manage-attach-detach.html#remove-policies-console. In the event of the unauthorized use of your AWS account, we may, at our sole discretion, provide you with concessions. However, a failure to follow the instructions below may jeopardize your ability to receive a concession.FOLLOW THE INSTRUCTIONS BELOW TO SECURE AND RESTORE YOUR ACCOUNT. More detailed instructions for each item can be found in the \u201cWhat do I do if I notice unauthorized activity in my AWS account?\u201d guide in AWS public documentation: https://aws.amazon.com/premiumsupport/knowledge-center/potential-account-compromise/ Step 1: Rotate and delete the exposed AWS Access Key AKA1B2C3D4E5F6G7H8I4. To delete IAM User Keys go to your AWS Management Console here: https://console.aws.amazon.com/iam/home#users. To delete Root User Keys go here: https://console.aws.amazon.com/iam/home#security_credential.If your application uses the exposed Access Key, you need to replace the Key. To replace the Key, first create a second Key (at that point both Keys will be active) and then modify your application to use the new Key.Then disable (but do not delete) the exposed Key by clicking on the \u201cMake inactive\u201d option in the console. If there are any problems with your application, you can reactivate the exposed Key. When your application is fully functional using the new Key, please delete the exposed Key.NOTE: Only rotating and deleting the exposed Key may not be sufficient to protect your account, see Step 2.We also recommend enabling multi-factor authentication (MFA) on your AWS account for increased security. You can find more information here: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable.html Step 2: Check your CloudTrail log for unsanctioned activity. Check your account for any unsanctioned activity such as creation of unauthorized IAM users and/or associated passwords (login profile), access keys, policies, roles or temporary security credentials by checking your CloudTrail log, and immediately delete them.NOTE: Deleting IAM users may impact production workloads and should be done carefully. Step 3: Review your AWS account for any unauthorized AWS usage.Check your account for any unauthorized usage such as EC2 instances, Lambda functions or EC2 Spot bids by logging into your AWS Management Console and reviewing each service page. You can also do this by checking the \"Bills\" page in the Billing console by going here: https://console.aws.amazon.com/billing/home#/bill Please keep in mind that unauthorized usage can occur in any region and that your console displays only one region at a time. To switch regions, use the drop-down menu in the top-right corner of the console.Step 4: [IMPORTANT] You must respond to the existing Support Case or create a new one to confirm completion of the steps above in order to restore access to your account, prevent suspension, and apply for a billing adjustment, if applicable. While logged in to your account, access the Support Center and reply to the existing Support Case to confirm completion of steps 1-3. If you cannot find an existing Support Case, please create a new one by going here: https://console.aws.amazon.com/support/home?#/ If you need help completing the steps to secure your account, let us know through the Support Case. You can request a phone call or chat session for immediate assistance. If you believe that your account is secured and there is no unauthorized access or usage, please contact us immediately via the Support Case to confirm this in writing. Any billing adjustment related to unauthorized charges will be considered after the account is secured.Thank you for your immediate attention to this matter. Sincerely,Amazon Web ServicesAmazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com, Inc. This message was produced and distributed by Amazon Web Services Inc., 410 Terry Ave. North, Seattle, WA 98109-5210 =============================================================== To share your experience or contact us again about this case, please return to the AWS Support Center using the following URL: https://console.aws.amazon.com/support/home#/case/?displayId=170542120001114&language=en Note, this e-mail was sent from an address that cannot accept incoming e-mails. To respond to this case, please follow the link above to respond from your AWS Support Center. =============================================================== Don\u2019t miss messages from AWS Support when you need help! Update your contact information: https://console.aws.amazon.com/billing/home#/account If you receive an error message when visiting the contact information page, visit: https://repost.aws/knowledge-center/iam-billing-access/ AWS Support: https://repost.aws/knowledge-center/ AWS Documentation: https://docs.aws.amazon.com/ AWS Cost Management: https://aws.amazon.com/aws-cost-management/ AWS Training: http://aws.amazon.com/training/ AWS Managed Services: https://aws.amazon.com/managed-services/ Amazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com.This message was produced and distributed by Amazon Web Services, Inc. or its affiliates 410 Terry Ave. North, Seattle, WA 98109.\u00a9 [2024], Amazon Web Services, Inc. or its affiliates. All rights reserved. Read our Privacy Notice." + }, + { + "url": "https://example.com/api/data/500.json", + "id": 500, + "created_at": "2024-05-14T14:25:56Z", + "updated_at": "2024-05-14T15:02:23Z", + "subject": "RE:[CASE 555555555555555] ACTION REQUIRED: Your AWS Access Key is Exposed for AWS Account 500000000000", + "description": "Hello,We have become aware that the AWS access key AKA1B2C3D4E5F6G7H8I5, belonging to IAM User example2.net@@abcdefghijklmnopqrstuvwx5, along with the corresponding secret key is publicly available online at https://github.com/testorg/test-project/blob/abcdefg123450572a58f802fa79f84321983d332/folder1/README.md.To protect your account, we have temporarily limited your ability to use some AWS services.To protect your account from unwanted activity, we have applied the \"AWSCompromisedKeyQuarantineV2\" AWS Managed Policy (\"Quarantine Policy\") to the IAM User [user_id]. The Quarantine Policy applied to the IAM User [user_id] protects your account by denying access to high risk actions like iam:CreateAccessKey and ec2:RunInstances. Please refer to tehe \"AWSCompromisedKeyQuarantineV2 Permissions\" [1] to review all of the actions denied by the policy.Please do not remove the Quarantine Policy before following the instructions below. However, in cases where the Quarantine Policy is causing production issues you may choose to detach the policy from the user. Only users with admin privileges or with access to iam:DetachUserPolicy may remove the policy. Refer to the IAM User Guide [2] on how to remove managed policies.As a security best practice, we recommend that you enable multi-factor authentication (MFA) [3].Follow the instructions below to secure and restore your account:For more detailed instructions, please refer to the \u201cWhat do I do if I notice unauthorized activity in my AWS account?\u201d user guide [4].Step 1:If your application uses the exposed access key, you need to replace the key. To replace the key, first create a second key (at that point both keys will be active). Then, modify your application to use the new key.Next, disable (do not delete) the exposed key by clicking on the \u201cMake inactive\u201d option in the console. If there are any problems with your application, you can reactivate the exposed key. When your application is fully functional using the new key, please delete the exposed access key AKA1B2C3D4E5F6G7H8I5.To delete IAM User Keys, go to your AWS Management Console - Users [5].To delete Root User Keys, go to your AWS Management Console - Security Credential [6].Please note, only rotating and deleting the exposed key may not be sufficient to protect your account, see Step 2.Step 2: Check your CloudTrail log for unwanted activity.Check your account for any unwanted activity such as creation of unapproved IAM users, and/or associated passwords (login profile), access keys, policies, roles or temporary security credentials by checking your CloudTrail log, and immediately delete them.To delete IAM users, go to your AWS Management Console - Users [7].To delete policies, go to your AWS Management Console - Policies [8].To delete roles, go to your AWS Management Console - Roles [9].Please note, deleting IAM users may impact production workloads and should be done carefully.Step 3: Review your AWS account for any unwanted AWS usage.Check your account for any unwanted usage such as EC2 instances, Lambda functions, or EC2 Spot bids by logging into your AWS Management Console and reviewing each service page. You can also do this by checking the \"Bills\" page in the Billing console [10].Please keep in mind that unwanted usage can occur in any region and that your console displays only one region at a time. To switch regions, use the drop-down menu in the top-right corner of the console.Step 4: You must respond to the existing Support Case or create a new one [11] to confirm completion of steps 1-3 in order to restore access to your account, prevent suspension, and apply for a billing adjustment, if applicable.If you need help completing the steps to secure your account, let us know through the Support Case where you can request a phone call or chat session for immediate assistance.If you believe that your account is secured and there is no unwanted access or usage, please contact us immediately via the Support Case to confirm this in writing.Any billing adjustment related to unwanted charges will be considered after the account is secured.[1] https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/AWSCompromisedKeyQuarantineV2$jsonEditor?section=permissions[2] https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_manage-attach-detach.html#remove-policies-console[3] https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable.html[4] https://aws.amazon.com/premiumsupport/knowledge-center/potential-account-compromise/[5] https://console.aws.amazon.com/iam/home#users[6] https://console.aws.amazon.com/iam/home#security_credential[7] https://console.aws.amazon.com/iamv2/home#/users[8] https://console.aws.amazon.com/iam/home#/policies[9] https://console.aws.amazon.com/iam/home#/roles[10] https://console.aws.amazon.com/billing/home#/bill[11] https://console.aws.amazon.com/support/home?#/Sincerely,Amazon Web ServicesAmazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com, Inc. This message was produced and distributed by Amazon Web Services Inc., 410 Terry Ave. North, Seattle, WA 98109-5210 =============================================================== To share your experience or contact us again about this case, please return to the AWS Support Center using the following URL: https://console.aws.amazon.com/support/home#/case/?displayId=171569673800749&language=en Note, this e-mail was sent from an address that cannot accept incoming e-mails. To respond to this case, please follow the link above to respond from your AWS Support Center. =============================================================== Don\u2019t miss messages from AWS Support when you need help! Update your contact information: https://console.aws.amazon.com/billing/home#/account If you receive an error message when visiting the contact information page, visit: https://repost.aws/knowledge-center/iam-billing-access/ AWS Support: https://repost.aws/knowledge-center/ AWS Documentation: https://docs.aws.amazon.com/ AWS Cost Management: https://aws.amazon.com/aws-cost-management/ AWS Training: http://aws.amazon.com/training/ AWS Managed Services: https://aws.amazon.com/managed-services/ Amazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com.This message was produced and distributed by Amazon Web Services, Inc. or its affiliates 410 Terry Ave. North, Seattle, WA 98109.\u00a9 [2024], Amazon Web Services, Inc. or its affiliates. All rights reserved. Read our Privacy Notice." + }, + { + "url": "https://example.com/api/data/600.json", + "id": 600, + "created_at": "2024-03-13T17:18:40Z", + "updated_at": "2024-03-13T18:01:52Z", + "subject": "RE:[CASE 666666666666666] ACTION REQUIRED: Your AWS Access Key is Exposed for AWS Account 600000000000", + "description": "Hello,We have become aware that the AWS Access Key AKA1B2C3D4E5F6G7H8I6 , belonging to IAM User example-test-domain.org@@abcdefghijklmnopqrstuvwx6 , along with the corresponding Secret Key is publicly available online at https://github.com/testorg/test-project/blob/abcdefg123450572a58f802fa79f84321983d332/folder1/.aws/credentials. Your security is important to us and this exposure of your account\u2019s IAM credentials poses a security risk to your AWS account, could lead to excessive charges from unauthorized activity, and violates the AWS Customer Agreement or other agreement with us governing your use of our Services.To protect your account from excessive charges and unauthorized activity, we have applied the \"AWSCompromisedKeyQuarantineV2\" AWS Managed Policy (\"Quarantine Policy\") to the IAM User listed above. The Quarantine Policy applied to the User protects your account by denying access to high risk actions like iam:CreateAccessKey and ec2:RunInstances. You can view all the actions denied by the policy by going here: https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/AWSCompromisedKeyQuarantineV2$jsonEditor?section=permissions.For your security, DO NOT remove the Quarantine Policy before following the instructions below. In cases where the Quarantine Policy is causing production issues you may detach the policy from the user. NOTE: Only users with admin privileges or with access to iam:DetachUserPolicy may remove the policy. For instructions on how to remove managed policies go here: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_manage-attach-detach.html#remove-policies-console. In the event of the unauthorized use of your AWS account, we may, at our sole discretion, provide you with concessions. However, a failure to follow the instructions below may jeopardize your ability to receive a concession.FOLLOW THE INSTRUCTIONS BELOW TO SECURE AND RESTORE YOUR ACCOUNT. More detailed instructions for each item can be found in the \u201cWhat do I do if I notice unauthorized activity in my AWS account?\u201d guide in AWS public documentation: https://aws.amazon.com/premiumsupport/knowledge-center/potential-account-compromise/ Step 1: Rotate and delete the exposed AWS Access Key AKA1B2C3D4E5F6G7H8I6. To delete IAM User Keys go to your AWS Management Console here: https://console.aws.amazon.com/iam/home#users. To delete Root User Keys go here: https://console.aws.amazon.com/iam/home#security_credential.If your application uses the exposed Access Key, you need to replace the Key. To replace the Key, first create a second Key (at that point both Keys will be active) and then modify your application to use the new Key.Then disable (but do not delete) the exposed Key by clicking on the \u201cMake inactive\u201d option in the console. If there are any problems with your application, you can reactivate the exposed Key. When your application is fully functional using the new Key, please delete the exposed Key.NOTE: Only rotating and deleting the exposed Key may not be sufficient to protect your account, see Step 2.We also recommend enabling multi-factor authentication (MFA) on your AWS account for increased security. You can find more information here: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable.html Step 2: Check your CloudTrail log for unsanctioned activity. Check your account for any unsanctioned activity such as creation of unauthorized IAM users and/or associated passwords (login profile), access keys, policies, roles or temporary security credentials by checking your CloudTrail log, and immediately delete them.NOTE: Deleting IAM users may impact production workloads and should be done carefully. Step 3: Review your AWS account for any unauthorized AWS usage.Check your account for any unauthorized usage such as EC2 instances, Lambda functions or EC2 Spot bids by logging into your AWS Management Console and reviewing each service page. You can also do this by checking the \"Bills\" page in the Billing console by going here: https://console.aws.amazon.com/billing/home#/bill Please keep in mind that unauthorized usage can occur in any region and that your console displays only one region at a time. To switch regions, use the drop-down menu in the top-right corner of the console.Step 4: [IMPORTANT] You must respond to the existing Support Case or create a new one to confirm completion of the steps above in order to restore access to your account, prevent suspension, and apply for a billing adjustment, if applicable. While logged in to your account, access the Support Center and reply to the existing Support Case to confirm completion of steps 1-3. If you cannot find an existing Support Case, please create a new one by going here: https://console.aws.amazon.com/support/home?#/ If you need help completing the steps to secure your account, let us know through the Support Case. You can request a phone call or chat session for immediate assistance. If you believe that your account is secured and there is no unauthorized access or usage, please contact us immediately via the Support Case to confirm this in writing. Any billing adjustment related to unauthorized charges will be considered after the account is secured.Thank you for your immediate attention to this matter. Sincerely,Amazon Web ServicesAmazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com, Inc. This message was produced and distributed by Amazon Web Services Inc., 410 Terry Ave. North, Seattle, WA 98109-5210 =============================================================== To share your experience or contact us again about this case, please return to the AWS Support Center using the following URL: https://console.aws.amazon.com/support/home#/case/?displayId=171035030501810&language=en Note, this e-mail was sent from an address that cannot accept incoming e-mails. To respond to this case, please follow the link above to respond from your AWS Support Center. =============================================================== Don\u2019t miss messages from AWS Support when you need help! Update your contact information: https://console.aws.amazon.com/billing/home#/account If you receive an error message when visiting the contact information page, visit: https://repost.aws/knowledge-center/iam-billing-access/ AWS Support: https://repost.aws/knowledge-center/ AWS Documentation: https://docs.aws.amazon.com/ AWS Cost Management: https://aws.amazon.com/aws-cost-management/ AWS Training: http://aws.amazon.com/training/ AWS Managed Services: https://aws.amazon.com/managed-services/ Amazon Web Services, Inc. is a subsidiary of Amazon.com, Inc. Amazon.com is a registered trademark of Amazon.com.This message was produced and distributed by Amazon Web Services, Inc. or its affiliates 410 Terry Ave. North, Seattle, WA 98109.\u00a9 [2024], Amazon Web Services, Inc. or its affiliates. All rights reserved. Read our Privacy Notice." + } +] diff --git a/aws-exposed-key-checker-infra/tests/test_lambda.py b/aws-exposed-key-checker-infra/tests/test_lambda.py new file mode 100644 index 000000000..a832a6c02 --- /dev/null +++ b/aws-exposed-key-checker-infra/tests/test_lambda.py @@ -0,0 +1,143 @@ +import os +import pytest +import json +from pathlib import Path + +import sys + +sys.path.insert(0, "lambda_source") +os.environ["ZENDESK_EXPOSED_TICKET_TAG"] = "test_tag" +os.environ[ + "TOKENS_SERVERS_ALLOW_LIST" +] = "example.com,example.net,example-test.org,example2.com,example2.net,example-test-domain.org" + +from exposed_key_checker.ticket_manager import TicketData # noqa: E402 +from exposed_key_checker.exposed_keys import parse_tickets # noqa: E402 + + +def test_parsing(all_tickets: list[TicketData]): + """ + Tickets should be successfully parsed + """ + data, error_ids = parse_tickets(all_tickets) + + assert error_ids == [] + assert len(data) == 6 + + iam_users = [d.iam_user for d in data] + access_keys = [d.access_key for d in data] + public_locations = [d.public_location for d in data] + case_numbers = [d.case_no for d in data] + + assert iam_users == [ + "example.com@@abcdefghijklmnopqrstuvwx1", + "example.net@@abcdefghijklmnopqrstuvwx2", + "example-test.org@@abcdefghijklmnopqrstuvwx3", + "example2.com@@abcdefghijklmnopqrstuvwx4", + "example2.net@@abcdefghijklmnopqrstuvwx5", + "example-test-domain.org@@abcdefghijklmnopqrstuvwx6", + ] + + assert access_keys == [ + "aka1b2c3d4e5f6g7h8i1", + "aka1b2c3d4e5f6g7h8i2", + "aka1b2c3d4e5f6g7h8i3", + "aka1b2c3d4e5f6g7h8i4", + "aka1b2c3d4e5f6g7h8i5", + "aka1b2c3d4e5f6g7h8i6", + ] + + assert public_locations == [ + "https://github.com/testorg/test-project/blob/abcdefg123450572a58f802fa79f84321983d332/folder1/file.js", + "https://github.com/testorg/test-project/blob/abcdefg123450572a58f802fa79f84321983d332/folder1/random-file", + "https://github.com/testorg/test-project/blob/abcdefg123450572a58f802fa79f84321983d332/folder1/creds", + "https://github.com/testorg/test-project/blob/abcdefg123450572a58f802fa79f84321983d332/folder1/aws_test", + "https://github.com/testorg/test-project/blob/abcdefg123450572a58f802fa79f84321983d332/folder1/README.md", + "https://github.com/testorg/test-project/blob/abcdefg123450572a58f802fa79f84321983d332/folder1/.aws/credentials", + ] + + assert case_numbers == [ + "111111111111111", + "222222222222222", + "333333333333333", + "444444444444444", + "555555555555555", + "666666666666666", + ] + + +def test_ignore_keywords(ignore_tickets: list[TicketData]): + """ + The ignored tickets should not be parsed, but shouldn't error either (this is for emails like AWS following up on a case.) + """ + data, error_ids = parse_tickets(ignore_tickets) + assert data == [] + assert error_ids == [] + + +def test_parse_failure(): + """ + Tickets that cannot be parsed and are not ignored should be added to the list of error IDs. + """ + tickets = [ + TicketData( + url="http://example.com", + id=512, + created_at="2024-07-11T11:06:04Z", + updated_at="2024-07-11T11:06:04Z", + subject="invalid", + description="invalid", + ) + ] + data, error_ids = parse_tickets(tickets) + + assert data == [] + assert error_ids == [512] + + +def test_url_parsing(all_tickets: list[TicketData]): + """ + Each URL should be at least 10 chars long and have a TLD + """ + data, _ = parse_tickets(all_tickets) + tickets_with_short_locations = { + d.ticket.id for d in data if len(d.public_location) <= 20 + } + tickets_without_tlds = { + d.ticket.id for d in data if not _has_tld(d.public_location) + } + + assert tickets_with_short_locations == set() + assert tickets_without_tlds == set() + + +@pytest.fixture() +def valid_tickets() -> list[TicketData]: + path = Path.cwd() / "tests" / "test_data_to_parse.json" + data = json.loads(path.read_text()) + + return [TicketData(**d) for d in data] + + +@pytest.fixture() +def ignore_tickets() -> list[TicketData]: + path = Path.cwd() / "tests" / "test_data_to_ignore.json" + data = json.loads(path.read_text()) + + tickets = [] + for k in data: + tickets.extend([TicketData(**d) for d in data[k]]) + + return tickets + + +@pytest.fixture() +def all_tickets( + valid_tickets: list[TicketData], ignore_tickets: list[TicketData] +) -> list[TicketData]: + return valid_tickets + ignore_tickets + + +def _has_tld(location: str) -> bool: + tld_list = [".com", ".net", ".org"] + return any(tld in location for tld in tld_list) diff --git a/aws-exposed-key-checker-infra/variables.tf b/aws-exposed-key-checker-infra/variables.tf new file mode 100644 index 000000000..5685cf785 --- /dev/null +++ b/aws-exposed-key-checker-infra/variables.tf @@ -0,0 +1,24 @@ +variable "ticket_service_url" { + type = string +} + +variable "ticket_service_recipient" { + type = string +} + +variable "zendesk_exposed_ticket_tag" { + type = string +} + +variable "zendesk_auth_secret_id" { + type = string +} + +variable "tokens_servers_allow_list" { + type = string +} + +variable "tokens_post_url_override" { + type = string + default = null +}