From 8fde87d896007fe8379ac7b71439479004c7c168 Mon Sep 17 00:00:00 2001 From: Nithin Chandran R Date: Mon, 10 Aug 2026 11:40:28 +0000 Subject: [PATCH] feat(macie-sfn-s3-quarantine-cdk): Add Macie sensitive data auto-quarantine pattern Amazon Macie detects sensitive data in S3, publishes findings to EventBridge, which triggers a Step Functions state machine to classify severity and automatically quarantine high-severity objects to a separate S3 bucket. Medium-severity objects are tagged, all findings notify via SNS. --- macie-sfn-s3-quarantine-cdk/README.md | 105 +++++++++ macie-sfn-s3-quarantine-cdk/cdk/.gitignore | 7 + macie-sfn-s3-quarantine-cdk/cdk/bin/app.ts | 15 ++ macie-sfn-s3-quarantine-cdk/cdk/cdk.json | 6 + .../cdk/lib/macie-sfn-s3-quarantine-stack.ts | 219 ++++++++++++++++++ macie-sfn-s3-quarantine-cdk/cdk/package.json | 24 ++ .../cdk/src/quarantine-handler/index.py | 101 ++++++++ macie-sfn-s3-quarantine-cdk/cdk/tsconfig.json | 25 ++ .../example-pattern.json | 99 ++++++++ 9 files changed, 601 insertions(+) create mode 100644 macie-sfn-s3-quarantine-cdk/README.md create mode 100644 macie-sfn-s3-quarantine-cdk/cdk/.gitignore create mode 100644 macie-sfn-s3-quarantine-cdk/cdk/bin/app.ts create mode 100644 macie-sfn-s3-quarantine-cdk/cdk/cdk.json create mode 100644 macie-sfn-s3-quarantine-cdk/cdk/lib/macie-sfn-s3-quarantine-stack.ts create mode 100644 macie-sfn-s3-quarantine-cdk/cdk/package.json create mode 100644 macie-sfn-s3-quarantine-cdk/cdk/src/quarantine-handler/index.py create mode 100644 macie-sfn-s3-quarantine-cdk/cdk/tsconfig.json create mode 100644 macie-sfn-s3-quarantine-cdk/example-pattern.json diff --git a/macie-sfn-s3-quarantine-cdk/README.md b/macie-sfn-s3-quarantine-cdk/README.md new file mode 100644 index 000000000..e47a26b0f --- /dev/null +++ b/macie-sfn-s3-quarantine-cdk/README.md @@ -0,0 +1,105 @@ +# Amazon Macie to AWS Step Functions to Amazon S3 Quarantine + +This pattern deploys an automated sensitive data response pipeline that uses Amazon Macie to detect sensitive data in Amazon S3, routes findings through Amazon EventBridge to AWS Step Functions for severity-based classification, and automatically quarantines high-severity objects to a separate Amazon S3 bucket while notifying security teams via Amazon SNS. + +Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/macie-sfn-s3-quarantine-cdk + +Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the [AWS Pricing page](https://aws.amazon.com/pricing/) for details. You are responsible for any AWS costs incurred. No warranty is implied in this example. + +## Requirements + +* [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls and manage AWS resources. +* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured +* [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) +* [Node.js 18+](https://nodejs.org/en/download/) installed +* [AWS CDK v2](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html) installed and bootstrapped + +## Deployment Instructions + +1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository: + ```bash + git clone https://github.com/aws-samples/serverless-patterns + ``` +2. Change directory to the pattern directory: + ```bash + cd serverless-patterns/macie-sfn-s3-quarantine-cdk/cdk + ``` +3. Install dependencies: + ```bash + npm install + ``` +4. Deploy the stack: + ```bash + npx cdk deploy --parameters NotificationEmail=your-email@example.com + ``` +5. Confirm the SNS subscription email you receive. + +## How it works + +This pattern creates an automated security response pipeline for sensitive data detected by Amazon Macie: + +1. **Amazon Macie** continuously scans objects in the monitored Amazon S3 bucket for sensitive data (PII, credentials, financial data). +2. When sensitive data is found, Macie publishes a finding to **Amazon EventBridge**. +3. The Amazon EventBridge rule matches `SensitiveData` finding types and triggers the **AWS Step Functions** state machine. +4. The state machine classifies the finding by severity score: + - **HIGH (score ≥ 7)**: Quarantine the object (copy to quarantine bucket, delete from source) + notify + - **MEDIUM (score 4-6)**: Tag the object with finding metadata + notify + - **LOW (score < 4)**: Notify only (no remediation action) +5. **Amazon SNS** delivers notifications to the security team with finding details. + +## Architecture + +``` +Amazon Macie (scan) --> Amazon EventBridge (finding) --> AWS Step Functions (classify + quarantine) + | + +--> AWS Lambda (move/tag object) --> Amazon S3 (quarantine) + | + +--> Amazon SNS (alert) +``` + +## Testing + +1. Upload a file containing sensitive data (e.g., credit card numbers, SSNs) to the monitored bucket: + ```bash + # Create a test file with sample sensitive data + echo "Name: John Doe, SSN: 123-45-6789, Card: 4111-1111-1111-1111" > /tmp/sensitive-test.txt + + # Upload to the monitored bucket + aws s3 cp /tmp/sensitive-test.txt s3://macie-monitored--/test/sensitive-test.txt + ``` + +2. Wait for Amazon Macie to scan the object (findings are published every 15 minutes by default, or trigger a one-time classification job): + ```bash + # Create a one-time classification job for faster testing + aws macie2 create-classification-job \ + --job-type ONE_TIME \ + --name "test-scan" \ + --s3-job-definition '{"bucketDefinitions": [{"accountId": "", "buckets": ["macie-monitored--"]}]}' + ``` + +3. Monitor the Step Functions execution: + ```bash + aws stepfunctions list-executions \ + --state-machine-arn \ + --status-filter SUCCEEDED + ``` + +4. Verify quarantine (for high-severity findings): + ```bash + aws s3 ls s3://macie-quarantine--/quarantined/ --recursive + ``` + +## Cleanup + +> **Warning**: Destroying this stack will delete all objects in both the monitored and quarantine buckets. Ensure you have backed up any data you need before proceeding. + +```bash +npx cdk destroy +``` + +## Resources + +- [Amazon Macie documentation](https://docs.aws.amazon.com/macie/latest/user/) +- [Amazon Macie finding types](https://docs.aws.amazon.com/macie/latest/user/findings-types.html) +- [AWS Step Functions documentation](https://docs.aws.amazon.com/step-functions/latest/dg/welcome.html) +- [Amazon EventBridge event patterns](https://docs.aws.amazon.com/eventbridge/latest/userguide/filtering-examples-structure.html) diff --git a/macie-sfn-s3-quarantine-cdk/cdk/.gitignore b/macie-sfn-s3-quarantine-cdk/cdk/.gitignore new file mode 100644 index 000000000..c6e6f7a14 --- /dev/null +++ b/macie-sfn-s3-quarantine-cdk/cdk/.gitignore @@ -0,0 +1,7 @@ +node_modules +cdk.out +cdk.context.json +build +*.js +*.d.ts +!jest.config.js diff --git a/macie-sfn-s3-quarantine-cdk/cdk/bin/app.ts b/macie-sfn-s3-quarantine-cdk/cdk/bin/app.ts new file mode 100644 index 000000000..68b3599ab --- /dev/null +++ b/macie-sfn-s3-quarantine-cdk/cdk/bin/app.ts @@ -0,0 +1,15 @@ +#!/usr/bin/env node +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT-0 +// 2026 + +import * as cdk from 'aws-cdk-lib'; +import { MacieSfnS3QuarantineStack } from '../lib/macie-sfn-s3-quarantine-stack'; + +const app = new cdk.App(); +new MacieSfnS3QuarantineStack(app, 'MacieSfnS3QuarantineStack', { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT, + region: process.env.CDK_DEFAULT_REGION, + }, +}); diff --git a/macie-sfn-s3-quarantine-cdk/cdk/cdk.json b/macie-sfn-s3-quarantine-cdk/cdk/cdk.json new file mode 100644 index 000000000..56ed0cad7 --- /dev/null +++ b/macie-sfn-s3-quarantine-cdk/cdk/cdk.json @@ -0,0 +1,6 @@ +{ + "app": "npx ts-node --prefer-ts-exts bin/app.ts", + "context": { + "@aws-cdk/customresources:installLatestAwsSdkDefault": false + } +} diff --git a/macie-sfn-s3-quarantine-cdk/cdk/lib/macie-sfn-s3-quarantine-stack.ts b/macie-sfn-s3-quarantine-cdk/cdk/lib/macie-sfn-s3-quarantine-stack.ts new file mode 100644 index 000000000..e45d9561e --- /dev/null +++ b/macie-sfn-s3-quarantine-cdk/cdk/lib/macie-sfn-s3-quarantine-stack.ts @@ -0,0 +1,219 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT-0 +// 2026 + +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as sns from 'aws-cdk-lib/aws-sns'; +import * as sns_subscriptions from 'aws-cdk-lib/aws-sns-subscriptions'; +import * as events from 'aws-cdk-lib/aws-events'; +import * as events_targets from 'aws-cdk-lib/aws-events-targets'; +import * as sfn from 'aws-cdk-lib/aws-stepfunctions'; +import * as tasks from 'aws-cdk-lib/aws-stepfunctions-tasks'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as path from 'path'; + +export class MacieSfnS3QuarantineStack extends cdk.Stack { + constructor(scope: Construct, id: string, props?: cdk.StackProps) { + super(scope, id, props); + + // Email parameter for SNS notifications + const notificationEmail = new cdk.CfnParameter(this, 'NotificationEmail', { + type: 'String', + description: 'Email address to receive sensitive data finding notifications', + default: 'security-team@example.com', + }); + + // Source bucket (monitored by Amazon Macie) + const sourceBucket = new s3.Bucket(this, 'MonitoredBucket', { + bucketName: `macie-monitored-${cdk.Aws.ACCOUNT_ID}-${cdk.Aws.REGION}`, + removalPolicy: cdk.RemovalPolicy.DESTROY, + autoDeleteObjects: true, + encryption: s3.BucketEncryption.S3_MANAGED, + versioned: true, + }); + + // Quarantine bucket (where sensitive objects are moved) + const quarantineBucket = new s3.Bucket(this, 'QuarantineBucket', { + bucketName: `macie-quarantine-${cdk.Aws.ACCOUNT_ID}-${cdk.Aws.REGION}`, + removalPolicy: cdk.RemovalPolicy.DESTROY, + autoDeleteObjects: true, + encryption: s3.BucketEncryption.S3_MANAGED, + versioned: true, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + }); + + // SNS topic for notifications + const notificationTopic = new sns.Topic(this, 'FindingNotificationTopic', { + topicName: 'MacieSensitiveDataFindings', + displayName: 'Amazon Macie Sensitive Data Findings', + }); + + notificationTopic.addSubscription( + new sns_subscriptions.EmailSubscription(notificationEmail.valueAsString) + ); + + // Lambda function to quarantine S3 objects + const quarantineFunction = new lambda.Function(this, 'QuarantineFunction', { + runtime: lambda.Runtime.PYTHON_3_12, + handler: 'index.handler', + code: lambda.Code.fromAsset(path.join(__dirname, '../src/quarantine-handler')), + timeout: cdk.Duration.seconds(60), + environment: { + QUARANTINE_BUCKET: quarantineBucket.bucketName, + }, + }); + + // Grant the Lambda function read from source and write to quarantine + sourceBucket.grantRead(quarantineFunction); + sourceBucket.grantDelete(quarantineFunction); + quarantineBucket.grantWrite(quarantineFunction); + + // Also allow tagging the source object + quarantineFunction.addToRolePolicy(new iam.PolicyStatement({ + actions: ['s3:PutObjectTagging'], + resources: [sourceBucket.arnForObjects('*')], + })); + + // Step Functions state machine + // Step 1: Classify severity + const classifySeverity = new sfn.Choice(this, 'ClassifySeverity') + .when( + sfn.Condition.numberGreaterThanEquals('$.detail.severity.score', 7), + new sfn.Pass(this, 'HighSeverity', { + result: sfn.Result.fromObject({ action: 'quarantine', severity: 'HIGH' }), + resultPath: '$.classification', + }) + ) + .when( + sfn.Condition.numberGreaterThanEquals('$.detail.severity.score', 4), + new sfn.Pass(this, 'MediumSeverity', { + result: sfn.Result.fromObject({ action: 'tag_and_notify', severity: 'MEDIUM' }), + resultPath: '$.classification', + }) + ) + .otherwise( + new sfn.Pass(this, 'LowSeverity', { + result: sfn.Result.fromObject({ action: 'notify_only', severity: 'LOW' }), + resultPath: '$.classification', + }) + ); + + // Step 2: Quarantine the object (move to quarantine bucket) + const quarantineObject = new tasks.LambdaInvoke(this, 'QuarantineObject', { + lambdaFunction: quarantineFunction, + payload: sfn.TaskInput.fromObject({ + 'bucketName.$': '$.detail.resourcesAffected.s3Bucket.name', + 'objectKey.$': '$.detail.resourcesAffected.s3Object.key', + 'findingId.$': '$.detail.id', + 'severity.$': '$.detail.severity.description', + }), + resultPath: '$.quarantineResult', + }); + + // Step 3: Send SNS notification + const sendNotification = new tasks.SnsPublish(this, 'SendNotification', { + topic: notificationTopic, + subject: sfn.JsonPath.format( + 'Macie Finding: Sensitive data detected [{}]', + sfn.JsonPath.stringAt('$.detail.severity.description') + ), + message: sfn.TaskInput.fromObject({ + 'findingId.$': '$.detail.id', + 'findingType.$': '$.detail.type', + 'severity.$': '$.detail.severity.description', + 'bucket.$': '$.detail.resourcesAffected.s3Bucket.name', + 'objectKey.$': '$.detail.resourcesAffected.s3Object.key', + 'detectedDataTypes.$': '$.detail.classificationDetails.result.sensitiveData[*].category', + 'action.$': '$.classification.action', + }), + resultPath: '$.notificationResult', + }); + + // Step 4: Tag source object (for medium severity - don't quarantine but mark it) + const tagObject = new tasks.LambdaInvoke(this, 'TagObject', { + lambdaFunction: quarantineFunction, + payload: sfn.TaskInput.fromObject({ + 'bucketName.$': '$.detail.resourcesAffected.s3Bucket.name', + 'objectKey.$': '$.detail.resourcesAffected.s3Object.key', + 'findingId.$': '$.detail.id', + 'severity.$': '$.detail.severity.description', + 'tagOnly': true, + }), + resultPath: '$.tagResult', + }); + + // Wire the state machine + const highSeverityChain = quarantineObject.next(sendNotification); + const mediumSeverityChain = tagObject.next(sendNotification); + const lowSeverityChain = sendNotification; + + // After classification, route to appropriate action + const routeAction = new sfn.Choice(this, 'RouteAction') + .when( + sfn.Condition.stringEquals('$.classification.action', 'quarantine'), + highSeverityChain + ) + .when( + sfn.Condition.stringEquals('$.classification.action', 'tag_and_notify'), + mediumSeverityChain + ) + .otherwise(lowSeverityChain); + + // Build the full definition + const definition = classifySeverity.afterwards().next(routeAction); + + const stateMachine = new sfn.StateMachine(this, 'MacieResponseStateMachine', { + stateMachineName: 'MacieSensitiveDataResponse', + definitionBody: sfn.DefinitionBody.fromChainable(definition), + timeout: cdk.Duration.minutes(5), + }); + + // EventBridge rule: Macie finding published + const macieRule = new events.Rule(this, 'MacieFindingRule', { + ruleName: 'MacieSensitiveDataFinding', + description: 'Routes Amazon Macie sensitive data findings to Step Functions for automated response', + eventPattern: { + source: ['aws.macie'], + detailType: ['Macie Finding'], + detail: { + type: [{ prefix: 'SensitiveData' }], + }, + }, + }); + + macieRule.addTarget(new events_targets.SfnStateMachine(stateMachine)); + + // Enable Macie (creates a session if not already enabled) + const macieSession = new cdk.CfnResource(this, 'MacieSession', { + type: 'AWS::Macie::Session', + properties: { + FindingPublishingFrequency: 'FIFTEEN_MINUTES', + Status: 'ENABLED', + }, + }); + + // Outputs + new cdk.CfnOutput(this, 'MonitoredBucketName', { + value: sourceBucket.bucketName, + description: 'Upload files here to be scanned by Amazon Macie', + }); + + new cdk.CfnOutput(this, 'QuarantineBucketName', { + value: quarantineBucket.bucketName, + description: 'High-severity sensitive data objects are moved here', + }); + + new cdk.CfnOutput(this, 'StateMachineArn', { + value: stateMachine.stateMachineArn, + description: 'Step Functions state machine ARN for Macie response automation', + }); + + new cdk.CfnOutput(this, 'NotificationTopicArn', { + value: notificationTopic.topicArn, + description: 'SNS topic for finding notifications', + }); + } +} diff --git a/macie-sfn-s3-quarantine-cdk/cdk/package.json b/macie-sfn-s3-quarantine-cdk/cdk/package.json new file mode 100644 index 000000000..4d1a90b6f --- /dev/null +++ b/macie-sfn-s3-quarantine-cdk/cdk/package.json @@ -0,0 +1,24 @@ +{ + "name": "macie-sfn-s3-quarantine-cdk", + "version": "1.0.0", + "description": "Amazon Macie sensitive data finding triggers AWS Step Functions to quarantine objects in Amazon S3", + "bin": { + "app": "bin/app.ts" + }, + "scripts": { + "build": "tsc", + "synth": "cdk synth", + "deploy": "cdk deploy", + "destroy": "cdk destroy" + }, + "dependencies": { + "aws-cdk-lib": "^2.185.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + "typescript": "~5.4.0", + "@types/node": "^20.0.0", + "ts-node": "^10.9.0", + "aws-cdk": "^2.185.0" + } +} diff --git a/macie-sfn-s3-quarantine-cdk/cdk/src/quarantine-handler/index.py b/macie-sfn-s3-quarantine-cdk/cdk/src/quarantine-handler/index.py new file mode 100644 index 000000000..5cfd61990 --- /dev/null +++ b/macie-sfn-s3-quarantine-cdk/cdk/src/quarantine-handler/index.py @@ -0,0 +1,101 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +# 2026 + +""" +Lambda handler for Amazon Macie sensitive data quarantine operations. +Supports two modes: + - quarantine: Copy object to quarantine bucket, delete from source, tag + - tag_only: Tag the source object with finding metadata without moving it +""" + +import os +import json +import boto3 +from datetime import datetime, timezone + + +s3 = boto3.client('s3') +QUARANTINE_BUCKET = os.environ['QUARANTINE_BUCKET'] + + +def handler(event, context): + """Handle quarantine or tag-only operations for sensitive data objects.""" + bucket_name = event['bucketName'] + object_key = event['objectKey'] + finding_id = event['findingId'] + severity = event['severity'] + tag_only = event.get('tagOnly', False) + + timestamp = datetime.now(timezone.utc).isoformat() + + tags = [ + {'Key': 'MacieFinding', 'Value': finding_id}, + {'Key': 'MacieSeverity', 'Value': severity}, + {'Key': 'QuarantineDate', 'Value': timestamp}, + ] + + if tag_only: + return tag_object(bucket_name, object_key, tags) + else: + return quarantine_object(bucket_name, object_key, tags, finding_id) + + +def tag_object(bucket_name, object_key, tags): + """Tag the source object with Macie finding metadata.""" + try: + s3.put_object_tagging( + Bucket=bucket_name, + Key=object_key, + Tagging={'TagSet': tags} + ) + return { + 'status': 'TAGGED', + 'bucket': bucket_name, + 'key': object_key, + 'tags': tags, + } + except Exception as e: + print(f'Error tagging object: {e}') + raise + + +def quarantine_object(bucket_name, object_key, tags, finding_id): + """Move object to quarantine bucket with metadata preservation.""" + quarantine_key = f'quarantined/{finding_id}/{object_key}' + + try: + # Copy to quarantine bucket with finding metadata + s3.copy_object( + Bucket=QUARANTINE_BUCKET, + Key=quarantine_key, + CopySource={'Bucket': bucket_name, 'Key': object_key}, + MetadataDirective='COPY', + TaggingDirective='REPLACE', + Tagging='&'.join([f"{t['Key']}={t['Value']}" for t in tags]), + ) + + # Tag source object to indicate it was quarantined + quarantine_tags = tags + [{'Key': 'QuarantineStatus', 'Value': 'MOVED'}] + s3.put_object_tagging( + Bucket=bucket_name, + Key=object_key, + Tagging={'TagSet': quarantine_tags} + ) + + # Delete from source bucket + s3.delete_object( + Bucket=bucket_name, + Key=object_key + ) + + return { + 'status': 'QUARANTINED', + 'sourceBucket': bucket_name, + 'sourceKey': object_key, + 'quarantineBucket': QUARANTINE_BUCKET, + 'quarantineKey': quarantine_key, + } + except Exception as e: + print(f'Error quarantining object: {e}') + raise diff --git a/macie-sfn-s3-quarantine-cdk/cdk/tsconfig.json b/macie-sfn-s3-quarantine-cdk/cdk/tsconfig.json new file mode 100644 index 000000000..bd6d3bc33 --- /dev/null +++ b/macie-sfn-s3-quarantine-cdk/cdk/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "declaration": true, + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "noImplicitThis": true, + "alwaysStrict": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": false, + "inlineSourceMap": true, + "inlineSources": true, + "experimentalDecorators": true, + "strictPropertyInitialization": false, + "typeRoots": ["./node_modules/@types"], + "outDir": "./build", + "rootDir": "." + }, + "exclude": ["node_modules", "build"] +} diff --git a/macie-sfn-s3-quarantine-cdk/example-pattern.json b/macie-sfn-s3-quarantine-cdk/example-pattern.json new file mode 100644 index 000000000..1cc1bd3aa --- /dev/null +++ b/macie-sfn-s3-quarantine-cdk/example-pattern.json @@ -0,0 +1,99 @@ +{ + "title": "Amazon Macie to AWS Step Functions to Amazon S3 Quarantine", + "description": "Automated sensitive data response: Amazon Macie findings trigger AWS Step Functions to classify severity and quarantine objects in Amazon S3", + "language": "TypeScript", + "level": "300", + "framework": "AWS CDK", + "introBox": { + "headline": "How it works", + "text": [ + "This pattern deploys an automated sensitive data response pipeline.", + "Amazon Macie scans Amazon S3 objects for sensitive data and publishes findings to Amazon EventBridge.", + "An Amazon EventBridge rule triggers an AWS Step Functions state machine that classifies findings by severity.", + "High-severity findings result in automatic object quarantine (moved to a separate Amazon S3 bucket).", + "Medium-severity findings result in object tagging with finding metadata.", + "All findings trigger Amazon SNS notifications to the security team." + ] + }, + "gitHub": { + "template": { + "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/macie-sfn-s3-quarantine-cdk", + "templateURL": "serverless-patterns/macie-sfn-s3-quarantine-cdk", + "projectFolder": "macie-sfn-s3-quarantine-cdk", + "templateFile": "cdk/lib/macie-sfn-s3-quarantine-stack.ts" + } + }, + "resources": { + "bullets": [ + { + "text": "Amazon Macie - Sensitive data discovery", + "link": "https://docs.aws.amazon.com/macie/latest/user/" + }, + { + "text": "AWS Step Functions - Serverless workflow orchestration", + "link": "https://docs.aws.amazon.com/step-functions/latest/dg/welcome.html" + }, + { + "text": "Amazon EventBridge - Serverless event bus", + "link": "https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-what-is.html" + } + ] + }, + "deploy": { + "text": [ + "cd macie-sfn-s3-quarantine-cdk/cdk", + "npm install", + "npx cdk deploy --parameters NotificationEmail=your-email@example.com" + ] + }, + "cleanup": { + "text": [ + "npx cdk destroy" + ] + }, + "authors": [ + { + "name": "Nithin Chandran R", + "bio": "Technical Account Manager at AWS", + "linkedin": "nithin-chandran-r" + } + ], + "patternArch": { + "icon1": { + "x": 20, + "y": 50, + "service": "macie", + "label": "Amazon Macie" + }, + "icon2": { + "x": 40, + "y": 50, + "service": "eventbridge", + "label": "Amazon EventBridge" + }, + "icon3": { + "x": 60, + "y": 50, + "service": "sfn", + "label": "AWS Step Functions" + }, + "icon4": { + "x": 80, + "y": 50, + "service": "s3", + "label": "Amazon S3" + }, + "line1": { + "from": "icon1", + "to": "icon2" + }, + "line2": { + "from": "icon2", + "to": "icon3" + }, + "line3": { + "from": "icon3", + "to": "icon4" + } + } +}