mirror of
https://github.com/Sea-Haven-Industries/forgejo.git
synced 2026-10-07 12:58:53 +00:00
Fires on any Lambda error and on missing data (missed schedule). Catches silent failures where the Slack notification never fires.
110 lines
3.6 KiB
TypeScript
110 lines
3.6 KiB
TypeScript
import * as cdk from "aws-cdk-lib";
|
|
import * as cloudwatch from "aws-cdk-lib/aws-cloudwatch";
|
|
import * as events from "aws-cdk-lib/aws-events";
|
|
import * as events_targets from "aws-cdk-lib/aws-events-targets";
|
|
import * as iam from "aws-cdk-lib/aws-iam";
|
|
import * as lambda from "aws-cdk-lib/aws-lambda";
|
|
import * as logs from "aws-cdk-lib/aws-logs";
|
|
import * as s3 from "aws-cdk-lib/aws-s3";
|
|
import { PythonFunction } from "@aws-cdk/aws-lambda-python-alpha";
|
|
import { Construct } from "constructs";
|
|
|
|
interface BackupVerificationProps {
|
|
sourceBucket: s3.IBucket;
|
|
replicaBucketName: string;
|
|
gcsBucket: string;
|
|
gcsSaSecretName: string;
|
|
slackWebhookSecretName: string;
|
|
}
|
|
|
|
export class BackupVerification extends Construct {
|
|
constructor(scope: Construct, id: string, props: BackupVerificationProps) {
|
|
super(scope, id);
|
|
|
|
const fn = new PythonFunction(this, "Function", {
|
|
functionName: "forgejo-backup-verification",
|
|
entry: "lambda/backup-verification",
|
|
runtime: lambda.Runtime.PYTHON_3_12,
|
|
architecture: lambda.Architecture.ARM_64,
|
|
handler: "handler",
|
|
index: "app.py",
|
|
memorySize: 512,
|
|
ephemeralStorageSize: cdk.Size.gibibytes(4),
|
|
timeout: cdk.Duration.minutes(5),
|
|
environment: {
|
|
SOURCE_BUCKET: props.sourceBucket.bucketName,
|
|
REPLICA_BUCKET: props.replicaBucketName,
|
|
GCS_BUCKET: props.gcsBucket,
|
|
GCS_SA_SECRET_NAME: props.gcsSaSecretName,
|
|
SLACK_WEBHOOK_SECRET_NAME: props.slackWebhookSecretName,
|
|
},
|
|
logRetention: logs.RetentionDays.TWO_MONTHS,
|
|
});
|
|
|
|
props.sourceBucket.grantRead(fn);
|
|
|
|
fn.addToRolePolicy(
|
|
new iam.PolicyStatement({
|
|
actions: ["s3:ListBucket", "s3:GetObject"],
|
|
resources: [
|
|
`arn:aws:s3:::${props.replicaBucketName}`,
|
|
`arn:aws:s3:::${props.replicaBucketName}/*`,
|
|
],
|
|
})
|
|
);
|
|
|
|
const account = cdk.Stack.of(this).account;
|
|
const region = cdk.Stack.of(this).region;
|
|
|
|
fn.addToRolePolicy(
|
|
new iam.PolicyStatement({
|
|
actions: ["secretsmanager:GetSecretValue"],
|
|
resources: [
|
|
`arn:aws:secretsmanager:${region}:${account}:secret:${props.gcsSaSecretName}-*`,
|
|
`arn:aws:secretsmanager:${region}:${account}:secret:${props.slackWebhookSecretName}-*`,
|
|
],
|
|
})
|
|
);
|
|
|
|
fn.addToRolePolicy(
|
|
new iam.PolicyStatement({
|
|
actions: ["ec2:DescribeSnapshots"],
|
|
resources: ["*"],
|
|
})
|
|
);
|
|
|
|
new events.Rule(this, "DailyCheck", {
|
|
ruleName: "forgejo-backup-daily-check",
|
|
schedule: events.Schedule.cron({ hour: "8", minute: "0" }),
|
|
targets: [
|
|
new events_targets.LambdaFunction(fn, {
|
|
event: events.RuleTargetInput.fromObject({ mode: "daily" }),
|
|
}),
|
|
],
|
|
});
|
|
|
|
new events.Rule(this, "MonthlyRestoreTest", {
|
|
ruleName: "forgejo-backup-monthly-restore-test",
|
|
schedule: events.Schedule.cron({
|
|
hour: "9",
|
|
minute: "0",
|
|
day: "1",
|
|
}),
|
|
targets: [
|
|
new events_targets.LambdaFunction(fn, {
|
|
event: events.RuleTargetInput.fromObject({ mode: "restore-test" }),
|
|
}),
|
|
],
|
|
});
|
|
|
|
new cloudwatch.Alarm(this, "ErrorAlarm", {
|
|
alarmName: "forgejo-backup-verification-errors",
|
|
alarmDescription: "Backup verification Lambda is failing — Slack notifications may not be firing",
|
|
metric: fn.metricErrors({ period: cdk.Duration.hours(1) }),
|
|
threshold: 1,
|
|
evaluationPeriods: 1,
|
|
treatMissingData: cloudwatch.TreatMissingData.BREACHING,
|
|
comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD,
|
|
});
|
|
}
|
|
}
|