mirror of
https://github.com/Sea-Haven-Industries/seahaven-org-baseline.git
synced 2026-09-30 03:23:15 +00:00
* [INFRA-96] CMK-encrypt sensitive CloudWatch log groups (M-24) Add a dedicated customer-managed CMK (alias/seahaven-logs) for encrypting the sensitive CloudWatch Logs groups (CloudTrail + finance/PII Lambdas). - lib/logs-key.ts: LogsKey construct. Key policy grants the CloudWatch Logs service principal (logs.us-east-1.amazonaws.com) Encrypt*/Decrypt*/ ReEncrypt*/GenerateDataKey*/DescribeKey, scoped by the kms:EncryptionContext:aws:logs:arn condition (REQUIRED per AWS docs or log delivery breaks). Cross-reviewed (GPT-4.1): tightened Describe* -> DescribeKey; CreateGrant omitted (not needed for plain log-group encryption). - account-baseline-stack.ts: instantiate LogsKey and set KmsKeyId on the L2 Trail's CloudWatch log group in place (escape hatch on the existing AWS::Logs::LogGroup) so it keeps the same logical id + physical name - additive, no replacement, CIS Section-4 metric filters (which import the group by name) keep working, live audit trail not disrupted. Gated by context `encryptTrailLogGroup` so the CMK can be smoke-tested on a low-risk Lambda group before the most-sensitive CloudTrail group. Finance/PII Lambda log groups (exec-aide-*, payments-*, po-email-processor, vendor-reply-processor) are owned by other stacks and associated to this CMK via the CLI for now; codifying KmsKeyId in those repos is tracked as drift. * [INFRA-96] Document sensitive-logs CMK (M-24) in README
69 lines
2.6 KiB
TypeScript
69 lines
2.6 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 { Construct } from "constructs";
|
|
|
|
/**
|
|
* Dedicated customer-managed CMK for encrypting sensitive CloudWatch Logs
|
|
* groups (audit M-24 / INFRA-96).
|
|
*
|
|
* Used by the account CloudTrail log group and the finance/PII Lambda log
|
|
* groups (exec-aide, payments, po/vendor email processors, qbo). This is a
|
|
* SEPARATE key from `alias/seahaven-alarm-topics` (SNS alarm topics) and
|
|
* `alias/cloudtrail-logs` (the CloudTrail S3 log-file CMK) — those have
|
|
* different service principals and encryption contexts.
|
|
*
|
|
* The key policy MUST grant the CloudWatch Logs service principal use of the
|
|
* key, scoped by the `kms:EncryptionContext:aws:logs:arn` condition, or log
|
|
* delivery to any CMK-encrypted group silently stops. (AWS docs: "Encrypt log
|
|
* data in CloudWatch Logs using AWS KMS".) Cross-reviewed 2026-06-08
|
|
* (INFRA-96): dropped `Describe*` to the specific `DescribeKey`; CreateGrant is
|
|
* not required for plain log-group encryption so it is omitted.
|
|
*/
|
|
export class LogsKey extends Construct {
|
|
public readonly key: kms.Key;
|
|
|
|
constructor(scope: Construct, id: string) {
|
|
super(scope, id);
|
|
|
|
const stack = cdk.Stack.of(this);
|
|
|
|
this.key = new kms.Key(this, "Key", {
|
|
alias: "seahaven-logs",
|
|
description:
|
|
"Encrypts sensitive CloudWatch Logs groups (CloudTrail + finance/PII Lambdas) — M-24/INFRA-96",
|
|
enableKeyRotation: true,
|
|
removalPolicy: cdk.RemovalPolicy.RETAIN,
|
|
});
|
|
|
|
// CloudWatch Logs service principal must be able to use the key to deliver
|
|
// (encrypt) and read (decrypt) log events. The encryption-context condition
|
|
// binds the grant to this account's log groups only, so the key cannot be
|
|
// used to decrypt arbitrary data under the logs service principal.
|
|
this.key.addToResourcePolicy(
|
|
new iam.PolicyStatement({
|
|
sid: "AllowCloudWatchLogsUseOfKey",
|
|
effect: iam.Effect.ALLOW,
|
|
principals: [
|
|
new iam.ServicePrincipal(`logs.${stack.region}.amazonaws.com`),
|
|
],
|
|
actions: [
|
|
"kms:Encrypt*",
|
|
"kms:Decrypt*",
|
|
"kms:ReEncrypt*",
|
|
"kms:GenerateDataKey*",
|
|
"kms:DescribeKey",
|
|
],
|
|
resources: ["*"],
|
|
conditions: {
|
|
ArnLike: {
|
|
"kms:EncryptionContext:aws:logs:arn": `arn:${stack.partition}:logs:${stack.region}:${stack.account}:log-group:*`,
|
|
},
|
|
},
|
|
})
|
|
);
|
|
|
|
new cdk.CfnOutput(this, "LogsKeyArn", { value: this.key.keyArn });
|
|
new cdk.CfnOutput(this, "LogsKeyAlias", { value: "alias/seahaven-logs" });
|
|
}
|
|
}
|