mirror of
https://github.com/Sea-Haven-Industries/seahaven-org-baseline.git
synced 2026-09-30 05:43:17 +00:00
69 lines
2.9 KiB
TypeScript
69 lines
2.9 KiB
TypeScript
|
|
import * as cdk from "aws-cdk-lib";
|
||
|
|
import * as kms from "aws-cdk-lib/aws-kms";
|
||
|
|
import * as iam from "aws-cdk-lib/aws-iam";
|
||
|
|
import * as sns from "aws-cdk-lib/aws-sns";
|
||
|
|
import { Construct } from "constructs";
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Shared CloudWatch-alarm SNS topic (`site-alerts`) + its CMK for a member
|
||
|
|
* account. First tenant: seahaven-prod, for the procurement-ingest migration
|
||
|
|
* (its stacks import the topic by constructed ARN `site-alerts` in-account).
|
||
|
|
*
|
||
|
|
* mgmt's equivalent topic is unmanaged (created via CLI, acknowledged debt in
|
||
|
|
* cis-monitoring.ts) - this stack codifies the same working pattern instead of
|
||
|
|
* replicating the debt:
|
||
|
|
* - CMK `alias/seahaven-alarm-topics`, NOT alias/aws/sns: the AWS-managed SNS
|
||
|
|
* key's policy cannot grant cloudwatch.amazonaws.com, so alarms silently
|
||
|
|
* fail to publish through it.
|
||
|
|
* - Key policy grants cloudwatch.amazonaws.com only (SourceAccount-scoped).
|
||
|
|
* Subscribers (AWS Chatbot -> Slack) need no KMS grant: SNS decrypts at
|
||
|
|
* delivery. Verified live by mgmt's site-alerts + Chatbot wiring.
|
||
|
|
* - Chatbot workspace auth + channel config are console-only (per-account)
|
||
|
|
* and deliberately out of scope here; verify delivery post-deploy with
|
||
|
|
* `aws sns publish` + a Slack message check.
|
||
|
|
*/
|
||
|
|
export class AlarmTopicStack extends cdk.Stack {
|
||
|
|
public readonly topic: sns.Topic;
|
||
|
|
|
||
|
|
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
|
||
|
|
super(scope, id, props);
|
||
|
|
|
||
|
|
const alarmTopicKey = new kms.Key(this, "AlarmTopicKey", {
|
||
|
|
alias: "seahaven-alarm-topics",
|
||
|
|
description:
|
||
|
|
"SSE for SNS alarm topics; grants CloudWatch alarms publish-side usage",
|
||
|
|
enableKeyRotation: true,
|
||
|
|
removalPolicy: cdk.RemovalPolicy.RETAIN,
|
||
|
|
});
|
||
|
|
// GenerateDataKey* is the publish-side envelope-encryption call CloudWatch
|
||
|
|
// makes when writing to an encrypted topic; Decrypt covers retried
|
||
|
|
// deliveries re-reading its own envelope. Both are required for alarms to
|
||
|
|
// publish at all.
|
||
|
|
alarmTopicKey.addToResourcePolicy(
|
||
|
|
new iam.PolicyStatement({
|
||
|
|
sid: "AllowCloudWatchAlarmsUse",
|
||
|
|
principals: [new iam.ServicePrincipal("cloudwatch.amazonaws.com")],
|
||
|
|
actions: ["kms:GenerateDataKey*", "kms:Decrypt", "kms:DescribeKey"],
|
||
|
|
resources: ["*"],
|
||
|
|
conditions: {
|
||
|
|
StringEquals: { "aws:SourceAccount": this.account },
|
||
|
|
},
|
||
|
|
}),
|
||
|
|
);
|
||
|
|
|
||
|
|
this.topic = new sns.Topic(this, "SiteAlertsTopic", {
|
||
|
|
topicName: "site-alerts",
|
||
|
|
displayName: "Sea Haven operational alarms",
|
||
|
|
masterKey: alarmTopicKey,
|
||
|
|
});
|
||
|
|
|
||
|
|
cdk.Tags.of(this).add("Project", "account-baseline");
|
||
|
|
cdk.Tags.of(this).add("Owner", "adam@seahavenind.com");
|
||
|
|
cdk.Tags.of(this).add("Environment", "prod");
|
||
|
|
cdk.Tags.of(this).add("ManagedBy", "cdk");
|
||
|
|
|
||
|
|
new cdk.CfnOutput(this, "SiteAlertsTopicArn", { value: this.topic.topicArn });
|
||
|
|
new cdk.CfnOutput(this, "AlarmTopicKeyArn", { value: alarmTopicKey.keyArn });
|
||
|
|
}
|
||
|
|
}
|