This commit is contained in:
Adam Moussa 2026-07-06 22:09:50 +00:00 • committed by GitHub
commit 696167a2ff
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 87 additions and 5 deletions

View file

@ -118,6 +118,18 @@ class PoIngestStack(Stack):
), ),
) )
# --- Shared customer-managed CMK for CloudWatch log encryption ---
# alias/seahaven-logs. The po-email-processor log group was already
# associated with this CMK out-of-band; declaring encryption_key on the
# migrated LogGroups below reconciles that drift and hardens the remaining
# groups (INFRA-114, per cross-review). The key policy already permits
# logs.us-east-1.amazonaws.com (verified in use on po-email-processor).
logs_cmk = kms.Key.from_key_arn(
self,
"LogsKey",
"arn:aws:kms:us-east-1:328440206208:key/b748750c-3b26-478d-acfb-d0126cc97f56",
)
# --- Purchase-orders DynamoDB table --- # --- Purchase-orders DynamoDB table ---
# Owned by this stack. Streams enabled for the site-extractor pipeline. # Owned by this stack. Streams enabled for the site-extractor pipeline.
# Other stacks (seahaven-slack-bot) reference this table via fromTableName(). # Other stacks (seahaven-slack-bot) reference this table via fromTableName().
@ -157,6 +169,22 @@ class PoIngestStack(Stack):
enforce_ssl=True, enforce_ssl=True,
) )
# --- Explicit log group (INFRA-114) ---
# Replaces the deprecated log_retention prop, which provisioned a
# LogRetention custom resource whose role held logs:PutRetentionPolicy/
# DeleteRetentionPolicy on Resource "*" (checkov CKV_AWS_111). The name
# matches Lambda's default (/aws/lambda/<function-name>) so the function
# keeps writing to the same group; RETAIN matches the repo convention for
# stateful resources.
email_processor_log_group = logs.LogGroup(
self,
"EmailProcessorLogGroup",
log_group_name="/aws/lambda/po-email-processor",
retention=logs.RetentionDays.TWO_MONTHS,
encryption_key=logs_cmk,
removal_policy=RemovalPolicy.RETAIN,
)
# --- Lambda function --- # --- Lambda function ---
email_processor = lambda_.Function( email_processor = lambda_.Function(
self, self,
@ -180,7 +208,7 @@ class PoIngestStack(Stack):
), ),
timeout=Duration.seconds(60), timeout=Duration.seconds(60),
memory_size=256, memory_size=256,
log_retention=logs.RetentionDays.TWO_MONTHS, log_group=email_processor_log_group,
dead_letter_queue=email_processor_dlq, dead_letter_queue=email_processor_dlq,
environment={ environment={
"PO_TABLE": "purchase-orders", "PO_TABLE": "purchase-orders",
@ -297,6 +325,15 @@ class PoIngestStack(Stack):
) )
# --- Web UI Lambda --- # --- Web UI Lambda ---
web_ui_log_group = logs.LogGroup(
self,
"WebUILogGroup",
log_group_name="/aws/lambda/po-web-ui",
retention=logs.RetentionDays.TWO_MONTHS,
encryption_key=logs_cmk,
removal_policy=RemovalPolicy.RETAIN,
)
web_ui = lambda_.Function( web_ui = lambda_.Function(
self, self,
"WebUI", "WebUI",
@ -307,7 +344,7 @@ class PoIngestStack(Stack):
code=lambda_.Code.from_asset("../lambdas/po/web_ui"), code=lambda_.Code.from_asset("../lambdas/po/web_ui"),
timeout=Duration.seconds(60), timeout=Duration.seconds(60),
memory_size=256, memory_size=256,
log_retention=logs.RetentionDays.TWO_MONTHS, log_group=web_ui_log_group,
environment={ environment={
"PO_TABLE": "purchase-orders", "PO_TABLE": "purchase-orders",
}, },
@ -369,6 +406,15 @@ class PoIngestStack(Stack):
# 518 WCU of write amplification. Re-add if a state-level query path ships. # 518 WCU of write amplification. Re-add if a state-level query path ships.
# --- Site extractor Lambda (DynamoDB Streams → verified-sites) --- # --- Site extractor Lambda (DynamoDB Streams → verified-sites) ---
site_extractor_log_group = logs.LogGroup(
self,
"SiteExtractorLogGroup",
log_group_name="/aws/lambda/po-ingest-site-extractor",
retention=logs.RetentionDays.TWO_MONTHS,
encryption_key=logs_cmk,
removal_policy=RemovalPolicy.RETAIN,
)
site_extractor = lambda_.Function( site_extractor = lambda_.Function(
self, self,
"SiteExtractor", "SiteExtractor",
@ -379,7 +425,7 @@ class PoIngestStack(Stack):
code=lambda_.Code.from_asset("../lambdas/po/site_extractor"), code=lambda_.Code.from_asset("../lambdas/po/site_extractor"),
timeout=Duration.seconds(60), timeout=Duration.seconds(60),
memory_size=256, memory_size=256,
log_retention=logs.RetentionDays.TWO_MONTHS, log_group=site_extractor_log_group,
environment={ environment={
"VERIFIED_SITES_TABLE": verified_sites_table.table_name, "VERIFIED_SITES_TABLE": verified_sites_table.table_name,
"PENDING_REVIEW_TABLE": "pending-site-review", "PENDING_REVIEW_TABLE": "pending-site-review",

View file

@ -156,6 +156,33 @@ class WorkorderIngestStack(Stack):
enforce_ssl=True, enforce_ssl=True,
) )
# --- Shared customer-managed CMK for CloudWatch log encryption ---
# alias/seahaven-logs. Same CMK the po-email-processor log group was
# already associated with out-of-band; declaring encryption_key on the
# migrated LogGroups below hardens these groups (INFRA-114, per
# cross-review). The key policy already permits logs.us-east-1.amazonaws.com.
logs_cmk = kms.Key.from_key_arn(
self,
"LogsKey",
"arn:aws:kms:us-east-1:328440206208:key/b748750c-3b26-478d-acfb-d0126cc97f56",
)
# --- Explicit log group (INFRA-114) ---
# Replaces the deprecated log_retention prop, which provisioned a
# LogRetention custom resource whose role held logs:PutRetentionPolicy/
# DeleteRetentionPolicy on Resource "*" (checkov CKV_AWS_111). The name
# matches Lambda's default (/aws/lambda/<function-name>) so the function
# keeps writing to the same group; RETAIN matches the repo convention for
# stateful resources.
email_processor_log_group = logs.LogGroup(
self,
"EmailProcessorLogGroup",
log_group_name="/aws/lambda/workorder-email-processor",
retention=logs.RetentionDays.TWO_MONTHS,
encryption_key=logs_cmk,
removal_policy=RemovalPolicy.RETAIN,
)
# --- Lambda function --- # --- Lambda function ---
email_processor = lambda_.Function( email_processor = lambda_.Function(
self, self,
@ -179,7 +206,7 @@ class WorkorderIngestStack(Stack):
), ),
timeout=Duration.seconds(60), timeout=Duration.seconds(60),
memory_size=256, memory_size=256,
log_retention=logs.RetentionDays.TWO_MONTHS, log_group=email_processor_log_group,
dead_letter_queue=email_processor_dlq, dead_letter_queue=email_processor_dlq,
environment={ environment={
"WORK_ORDERS_TABLE": work_orders_table.table_name, "WORK_ORDERS_TABLE": work_orders_table.table_name,
@ -311,6 +338,15 @@ class WorkorderIngestStack(Stack):
) )
# --- Web UI Lambda --- # --- Web UI Lambda ---
web_ui_log_group = logs.LogGroup(
self,
"WebUILogGroup",
log_group_name="/aws/lambda/workorder-web-ui",
retention=logs.RetentionDays.TWO_MONTHS,
encryption_key=logs_cmk,
removal_policy=RemovalPolicy.RETAIN,
)
web_ui = lambda_.Function( web_ui = lambda_.Function(
self, self,
"WebUI", "WebUI",
@ -321,7 +357,7 @@ class WorkorderIngestStack(Stack):
code=lambda_.Code.from_asset("../lambdas/wo/web_ui"), code=lambda_.Code.from_asset("../lambdas/wo/web_ui"),
timeout=Duration.seconds(15), timeout=Duration.seconds(15),
memory_size=128, memory_size=128,
log_retention=logs.RetentionDays.TWO_MONTHS, log_group=web_ui_log_group,
environment={ environment={
"WORK_ORDERS_TABLE": work_orders_table.table_name, "WORK_ORDERS_TABLE": work_orders_table.table_name,
"COMMENTS_TABLE": comments_table.table_name, "COMMENTS_TABLE": comments_table.table_name,