apm-wo-analysis/cdk/stacks/pipeline_stack.py

68 lines
2.5 KiB
Python
Raw Normal View History

"""Pipeline stack: S3, classifier + slack-post Lambdas, Glue, Athena, IAM.
Scaffold — the exports bucket (Phase 1 of docs/BUILD.md) is included so the
stack synthesizes to something real. The classifier Lambda (Phase 2), Glue
database + Athena workgroup with partition projection (Phase 3), and the
slack-post Lambda + IAM (Phase 4) are added in their respective phases.
Lambda defaults when added: Python 3.12, ARM64, explicit LogGroup with 60-day
retention. No DynamoDB — this is an S3 + Athena analytics workload (see CLAUDE.md).
"""
from aws_cdk import (
Duration,
RemovalPolicy,
Stack,
)
from aws_cdk import (
aws_iam as iam,
)
from aws_cdk import (
aws_s3 as s3,
)
from constructs import Construct
class PipelineStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
# Phase 1 — single exports bucket.
# Prefixes: raw/ (incoming), analytics/ (per-WO snapshots), athena-results/.
self.exports_bucket = s3.Bucket(
self,
"Exports",
bucket_name=f"apm-wo-analysis-exports-{self.account}",
encryption=s3.BucketEncryption.S3_MANAGED,
block_public_access=s3.BlockPublicAccess.BLOCK_ALL,
enforce_ssl=True,
removal_policy=RemovalPolicy.RETAIN,
lifecycle_rules=[
s3.LifecycleRule(
id="expire-raw-exports",
prefix="raw/",
expiration=Duration.days(90),
)
],
)
# Phase 1 — least-privilege identity for the local drop-folder uploader.
# Scoped to s3:PutObject on raw/* only. The access key is created
# out-of-band (aws iam create-access-key) and stored in the local
# ~/.aws/credentials profile `apm-wo-drop` — never in CloudFormation.
self.drop_uploader = iam.User(
self, "DropUploader", user_name="apm-wo-drop-uploader"
)
self.drop_uploader.add_to_policy(
iam.PolicyStatement(
sid="PutRawExportsOnly",
actions=["s3:PutObject"],
resources=[self.exports_bucket.arn_for_objects("raw/*")],
)
)
# Phase 2 — classifier Lambda, S3-triggered on the raw/ prefix. TODO
# Phase 3 — Glue database `apm_wo_analysis` + Athena workgroup
# (partition projection on dt; no crawler). TODO
# Phase 4 — slack-post Lambda + scoped IAM. TODO