commit a8276b44fd31ae0f3ba0358b7cb9da18decb7ae7 Author: Adam Moussa Date: Tue Jun 9 13:51:17 2026 -0400 feat: syslog-server under IaC (INFRA-12) CDK stack for the EC2 syslog collector (rsyslog 514 -> CloudWatch agent -> unifi-syslog), mirroring the file-share/forgejo pattern. Recreated from the captured console config; EIP 184.72.154.32 imported + re-associated so the UniFi forwarding target is unchanged. Deployed + verified 2026-06-09. Note: deploy role can assume cdk-hnb659fds-* (account-admin via CDK bootstrap) — same exposure as every org CDK deploy role; per-app qualifier is a known org-wide follow-up. diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..89a077f --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,10 @@ +name: CI +on: + pull_request: + branches: [main] + +jobs: + ci: + uses: Sea-Haven-Industries/.github/.github/workflows/ci-typescript-cdk.yaml@main + with: + node-version: "24" diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000..2c5d47c --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,6 @@ +name: Dependency Review +on: + pull_request: +jobs: + review: + uses: Sea-Haven-Industries/.github/.github/workflows/callable-dependency-review.yaml@main diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml new file mode 100644 index 0000000..90d3497 --- /dev/null +++ b/.github/workflows/deploy.yaml @@ -0,0 +1,20 @@ +name: Deploy +on: + push: + branches: [main] + +permissions: + id-token: write + contents: read + +concurrency: + group: deploy + cancel-in-progress: false + +jobs: + deploy: + uses: Sea-Haven-Industries/.github/.github/workflows/cd-cdk.yaml@main + with: + node-version: "24" + secrets: + deploy-role-arn: ${{ secrets.AWS_DEPLOY_ROLE_ARN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1b323b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +node_modules/ +cdk.out/ +*.js +*.d.ts +*.js.map +.env diff --git a/README.md b/README.md new file mode 100644 index 0000000..6551dbd --- /dev/null +++ b/README.md @@ -0,0 +1,57 @@ +# syslog-server + +CDK stack for the **syslog-server** EC2 collector: receives remote syslog +(UDP/TCP 514) from the office UniFi fleet over its Elastic IP and ships it to +the `unifi-syslog` CloudWatch Logs group via the CloudWatch agent. + +Brought under IaC for **INFRA-12** (AWS audit L-6). Previously a console/CLI +instance with no drift detection. + +## Architecture + +``` +office UniFi devices ──syslog/514──▶ EIP 184.72.154.32 ──▶ EC2 (rsyslog) + │ + /var/log/remote//*.log + │ + CloudWatch agent ──▶ unifi-syslog (90d) + │ + Syslog-NoIncomingLogs alarm ──▶ site-alerts +``` + +| Resource | Value | +|---|---| +| Instance | `syslog-server`, t4g.nano, Amazon Linux 2023 (arm64), 30 GiB encrypted gp3 | +| Subnet | `subnet-0eea820effe1b3ae5` (public, us-east-1a, `vpc-0d3d4b67bd0cf8a68`) | +| Elastic IP | `184.72.154.32` (`eipalloc-006bdefc9802f3285`) — **unmanaged**, re-associated by ID | +| Security group | `syslog-server` — 514 tcp/udp + 22 from office IPs + VPC/VPN CIDRs; 2055/2056 udp reserved (netflow/sflow) | +| IAM role | `syslog-server-role` — `AmazonSSMManagedInstanceCore` + `CloudWatchAgentServerPolicy` | +| Log group | `unifi-syslog` (90-day retention) — created/retained by the CW agent, **not** a CFN resource (holds history; see stack comment) | +| Alarm | `Syslog-NoIncomingLogs` — `IncomingLogEvents` Sum < 1 over 2×1-day, ALARM-only → `site-alerts` | + +## Access + +SSM Session Manager (no key pair). SSH 22 is open from office/VPC for +break-glass only. + +## Deploy + +CI/CD via the org reusable workflows (`ci-typescript-cdk.yaml`, +`cd-cdk.yaml`); merges to `main` deploy through the `githubdeploy-syslog-server` +OIDC role. No Docker assets, so a local `cdk deploy` is also safe. + +``` +npm ci +npm run diff +npm run deploy +``` + +## Notes + +- **EIP is unmanaged.** CloudFormation associates it but never releases it, so + the public forwarding target survives any instance replacement. +- **AMI is pinned in `cdk.context.json`** (`cachedInContext`). An AL2023 AMI + change forces instance replacement — refresh deliberately with + `cdk context --reset && cdk synth`. +- To widen device coverage of the forwarded syslog feed, see **INFRA-11** + (UniFi controller remote-logging config). diff --git a/bin/app.ts b/bin/app.ts new file mode 100644 index 0000000..c5b42f8 --- /dev/null +++ b/bin/app.ts @@ -0,0 +1,11 @@ +#!/usr/bin/env node +import "source-map-support/register"; +import * as cdk from "aws-cdk-lib"; +import { SyslogServerStack } from "../lib/syslog-server-stack"; + +const app = new cdk.App(); + +new SyslogServerStack(app, "syslog-server", { + stackName: "syslog-server", + env: { account: "328440206208", region: "us-east-1" }, +}); diff --git a/cdk.context.json b/cdk.context.json new file mode 100644 index 0000000..05f2824 --- /dev/null +++ b/cdk.context.json @@ -0,0 +1,48 @@ +{ + "vpc-provider:account=328440206208:filter.vpc-id=vpc-0d3d4b67bd0cf8a68:region=us-east-1:returnAsymmetricSubnets=true": { + "vpcId": "vpc-0d3d4b67bd0cf8a68", + "vpcCidrBlock": "10.20.0.0/16", + "ownerAccountId": "328440206208", + "availabilityZones": [], + "vpnGatewayId": "vgw-073737d44762dffc2", + "subnetGroups": [ + { + "name": "Private", + "type": "Private", + "subnets": [ + { + "subnetId": "subnet-04e38c507e96f1926", + "cidr": "10.20.30.0/24", + "availabilityZone": "us-east-1a", + "routeTableId": "rtb-06a2f56f492b9b4de" + }, + { + "subnetId": "subnet-0a0b4fc6f296dfba5", + "cidr": "10.20.40.0/24", + "availabilityZone": "us-east-1b", + "routeTableId": "rtb-01e152fe5cabca7d6" + } + ] + }, + { + "name": "Public", + "type": "Public", + "subnets": [ + { + "subnetId": "subnet-0eea820effe1b3ae5", + "cidr": "10.20.10.0/24", + "availabilityZone": "us-east-1a", + "routeTableId": "rtb-0f2232493a5c43fe8" + }, + { + "subnetId": "subnet-0012f5895182c1580", + "cidr": "10.20.20.0/24", + "availabilityZone": "us-east-1b", + "routeTableId": "rtb-0f2232493a5c43fe8" + } + ] + } + ] + }, + "ssm:account=328440206208:parameterName=/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-arm64:region=us-east-1": "ami-02c114835b4e7739f" +} diff --git a/cdk.json b/cdk.json new file mode 100644 index 0000000..4070f75 --- /dev/null +++ b/cdk.json @@ -0,0 +1,21 @@ +{ + "app": "npx ts-node bin/app.ts", + "watch": { + "include": ["**"], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "node_modules", + "cdk.out" + ] + }, + "context": { + "@aws-cdk/aws-lambda:recognizeLayerVersion": true, + "@aws-cdk/core:checkSecretUsage": true, + "@aws-cdk/core:target-partitions": ["aws"] + } +} diff --git a/lib/syslog-server-stack.ts b/lib/syslog-server-stack.ts new file mode 100644 index 0000000..7262a7d --- /dev/null +++ b/lib/syslog-server-stack.ts @@ -0,0 +1,202 @@ +import * as cdk from "aws-cdk-lib"; +import * as ec2 from "aws-cdk-lib/aws-ec2"; +import * as iam from "aws-cdk-lib/aws-iam"; +import * as cloudwatch from "aws-cdk-lib/aws-cloudwatch"; +import * as cwactions from "aws-cdk-lib/aws-cloudwatch-actions"; +import * as sns from "aws-cdk-lib/aws-sns"; +import { Construct } from "constructs"; + +/** + * syslog-server — EC2 collector that receives remote syslog (UDP/TCP 514) from + * the office UniFi fleet over the EIP and ships it to the `unifi-syslog` + * CloudWatch Logs group via the CloudWatch agent. + * + * Brought under IaC for INFRA-12 (AWS audit L-6). Recreated to mirror the + * file-share/forgejo CDK pattern; the existing EIP (184.72.154.32) is imported + * by allocation ID and re-associated so the forwarding target is unchanged. + * + * The `unifi-syslog` log group is intentionally NOT a CloudFormation resource: + * it holds 90 days of history and is created/retained by the CloudWatch agent + * per the user-data config below (log_group_name + retention_in_days). Managing + * it as a CFN resource would either collide with the live group on create or + * risk deleting the history on a future replacement. The agent owns it; this + * stack owns the instance that runs the agent. + */ +export class SyslogServerStack extends cdk.Stack { + constructor(scope: Construct, id: string, props?: cdk.StackProps) { + super(scope, id, props); + + const vpc = ec2.Vpc.fromLookup(this, "SeaHavenVpc", { + vpcId: "vpc-0d3d4b67bd0cf8a68", + }); + + // Public subnet (IGW route present) — the instance must be internet-facing + // so the office gateways can forward syslog to the EIP. + const publicSubnet = ec2.Subnet.fromSubnetAttributes(this, "PublicSubnet", { + subnetId: "subnet-0eea820effe1b3ae5", + availabilityZone: "us-east-1a", + }); + + // Office public IPs that forward syslog (see reference_office_ips). + const OFFICE_1 = "47.21.61.4/32"; + const OFFICE_2 = "96.250.164.146/32"; + + const sg = new ec2.SecurityGroup(this, "SecurityGroup", { + vpc, + securityGroupName: "syslog-server", + description: "Syslog collector - rsyslog 514 from office + VPC", + allowAllOutbound: true, + }); + + // Remote syslog (UDP + TCP 514) from the office public IPs and the internal + // VPC / VPN CIDRs. + for (const proto of [ec2.Port.tcp(514), ec2.Port.udp(514)]) { + sg.addIngressRule(ec2.Peer.ipv4(OFFICE_1), proto, "syslog from office-1"); + sg.addIngressRule(ec2.Peer.ipv4(OFFICE_2), proto, "syslog from office-2"); + sg.addIngressRule(ec2.Peer.ipv4("10.10.0.0/16"), proto, "syslog from office VPN"); + sg.addIngressRule(ec2.Peer.ipv4("10.20.0.0/16"), proto, "syslog from VPC"); + sg.addIngressRule(ec2.Peer.ipv4("10.30.0.0/16"), proto, "syslog from VPN pool"); + } + + // SSH (SSM is the primary access path; 22 kept for break-glass from office/VPC). + sg.addIngressRule(ec2.Peer.ipv4(OFFICE_1), ec2.Port.tcp(22), "SSH from office-1"); + sg.addIngressRule(ec2.Peer.ipv4(OFFICE_2), ec2.Port.tcp(22), "SSH from office-2"); + sg.addIngressRule(ec2.Peer.ipv4("10.10.0.0/16"), ec2.Port.tcp(22), "SSH from office VPN"); + sg.addIngressRule(ec2.Peer.ipv4("10.20.0.0/16"), ec2.Port.tcp(22), "SSH from VPC"); + + // NetFlow / sFlow ingress reserved from the office IPs. No collector is + // configured in user-data yet; kept to preserve the prior capability. + for (const port of [ec2.Port.udp(2055), ec2.Port.udp(2056)]) { + sg.addIngressRule(ec2.Peer.ipv4(OFFICE_1), port, "netflow/sflow from office-1"); + sg.addIngressRule(ec2.Peer.ipv4(OFFICE_2), port, "netflow/sflow from office-2"); + } + + const role = new iam.Role(this, "InstanceRole", { + roleName: "syslog-server-role", + assumedBy: new iam.ServicePrincipal("ec2.amazonaws.com"), + managedPolicies: [ + iam.ManagedPolicy.fromAwsManagedPolicyName("AmazonSSMManagedInstanceCore"), + iam.ManagedPolicy.fromAwsManagedPolicyName("CloudWatchAgentServerPolicy"), + ], + }); + + const userData = ec2.UserData.forLinux(); + userData.addCommands( + "set -euxo pipefail", + "", + "# ── rsyslog: listen on UDP/TCP 514 ──", + "dnf install -y rsyslog", + "cat > /etc/rsyslog.d/10-listen.conf <<'EOF'", + 'module(load="imudp")', + 'input(type="imudp" port="514")', + 'module(load="imtcp")', + 'input(type="imtcp" port="514")', + "EOF", + "", + "# ── Write remote syslog to /var/log/remote//.log ──", + "cat > /etc/rsyslog.d/20-remote.conf <<'EOF'", + 'template(name="RemoteHost" type="string" string="/var/log/remote/%HOSTNAME%/%PROGRAMNAME%.log")', + "if $fromhost-ip != '127.0.0.1' then {", + ' action(type="omfile" dynaFile="RemoteHost" createDirs="on")', + " stop", + "}", + "EOF", + "", + "mkdir -p /var/log/remote", + "systemctl enable rsyslog", + "systemctl restart rsyslog", + "", + "# ── CloudWatch agent: ship /var/log/remote/**/*.log to unifi-syslog ──", + "dnf install -y amazon-cloudwatch-agent", + "cat > /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json <<'EOF'", + "{", + ' "logs": {', + ' "logs_collected": {', + ' "files": {', + ' "collect_list": [', + " {", + ' "file_path": "/var/log/remote/**/*.log",', + ' "log_group_name": "unifi-syslog",', + ' "log_stream_name": "{hostname}/{file_name}",', + ' "retention_in_days": 90', + " }", + " ]", + " }", + " }", + " }", + "}", + "EOF", + "", + "/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \\", + " -a fetch-config -m ec2 \\", + " -c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json -s", + "systemctl enable amazon-cloudwatch-agent", + ); + + const instance = new ec2.Instance(this, "Instance", { + instanceName: "syslog-server", + vpc, + vpcSubnets: { subnets: [publicSubnet] }, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.T4G, ec2.InstanceSize.NANO), + machineImage: ec2.MachineImage.latestAmazonLinux2023({ + cpuType: ec2.AmazonLinuxCpuType.ARM_64, + // Cache the resolved AMI in cdk.context.json so deploys don't implicitly + // pick up new AL2023 releases (AMI change forces instance replacement). + // Refresh deliberately: cdk context --reset && cdk synth + cachedInContext: true, + }), + securityGroup: sg, + role, + userData, + blockDevices: [ + { + deviceName: "/dev/xvda", + volume: ec2.BlockDeviceVolume.ebs(30, { + volumeType: ec2.EbsDeviceVolumeType.GP3, + encrypted: true, + }), + }, + ], + }); + + // Re-associate the existing Elastic IP (184.72.154.32) so the UniFi fleet's + // forwarding target is unchanged. The allocation is UNMANAGED (referenced by + // ID) — CloudFormation can associate it but never release it. + new ec2.CfnEIPAssociation(this, "EipAssociation", { + allocationId: "eipalloc-006bdefc9802f3285", + instanceId: instance.instanceId, + }); + + // ALARM-only "no incoming logs" alarm to the shared site-alerts topic + // (alias/seahaven-alarm-topics CMK). Mirrors the prior standalone alarm: + // IncomingLogEvents (Sum) < 1 over two 1-day periods. 2-day window tolerates + // quiet weekends; treatMissingData=breaching catches a dead pipeline. + const alarmTopic = sns.Topic.fromTopicArn( + this, "SiteAlerts", "arn:aws:sns:us-east-1:328440206208:site-alerts", + ); + + const noLogsAlarm = new cloudwatch.Alarm(this, "NoIncomingLogsAlarm", { + alarmName: "Syslog-NoIncomingLogs", + alarmDescription: + "No log events delivered to unifi-syslog for 2 days — syslog pipeline may be down.", + metric: new cloudwatch.Metric({ + namespace: "AWS/Logs", + metricName: "IncomingLogEvents", + dimensionsMap: { LogGroupName: "unifi-syslog" }, + statistic: "Sum", + period: cdk.Duration.days(1), + }), + threshold: 1, + comparisonOperator: cloudwatch.ComparisonOperator.LESS_THAN_THRESHOLD, + evaluationPeriods: 2, + treatMissingData: cloudwatch.TreatMissingData.BREACHING, + }); + noLogsAlarm.addAlarmAction(new cwactions.SnsAction(alarmTopic)); + + new cdk.CfnOutput(this, "InstanceId", { value: instance.instanceId }); + new cdk.CfnOutput(this, "PublicIp", { + value: "184.72.154.32", + description: "Elastic IP — UniFi remote-syslog forwarding target", + }); + } +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..6ec5351 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,532 @@ +{ + "name": "syslog-server", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "syslog-server", + "version": "1.0.0", + "dependencies": { + "aws-cdk-lib": "2.257.0", + "constructs": "^10.0.0" + }, + "bin": { + "app": "bin/app.js" + }, + "devDependencies": { + "@types/node": "^22.0.0", + "aws-cdk": "^2.252.0", + "source-map-support": "^0.5.21", + "typescript": "~5.7.0" + } + }, + "node_modules/@aws-cdk/asset-awscli-v1": { + "version": "2.2.273", + "resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.273.tgz", + "integrity": "sha512-X57HYUtHt9BQrlrzUNcMyRsDUCoakYNnY6qh5lNwRCHPtQoTfXmuISkfLk0AjLkcbS5lw1LLTQFiQhTDXfiTvg==", + "license": "Apache-2.0" + }, + "node_modules/@aws-cdk/asset-node-proxy-agent-v6": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@aws-cdk/asset-node-proxy-agent-v6/-/asset-node-proxy-agent-v6-2.1.2.tgz", + "integrity": "sha512-pDiuqH+qY3zM9lhhLjbKJ1tnKOHzQ2V4Wr/3qsxyKeKAkuPMI/BVGvZG1PbrikUw949cGVTfVEt4ETKKYnrj0Q==", + "license": "Apache-2.0" + }, + "node_modules/@aws-cdk/cloud-assembly-schema": { + "version": "53.28.0", + "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-53.28.0.tgz", + "integrity": "sha512-pZS+9bLGv2tCqcgxfA0WD3XjcqT3yE4ICvKeJEicw6aTdCxBl8FQ/AUsorY/6f2JrMS3kUQgvhXxA30MWcji0A==", + "bundleDependencies": [ + "jsonschema", + "semver" + ], + "license": "Apache-2.0", + "dependencies": { + "jsonschema": "^1.5.0", + "semver": "^7.8.0" + }, + "engines": { + "node": ">= 18.0.0" + } + }, + "node_modules/@aws-cdk/cloud-assembly-schema/node_modules/jsonschema": { + "version": "1.5.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/@aws-cdk/cloud-assembly-schema/node_modules/semver": { + "version": "7.8.0", + "inBundle": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@types/node": { + "version": "22.19.20", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.20.tgz", + "integrity": "sha512-6tELRwSDYWW9EdZhbeZmYGZ1/7Djkt+Ah3/ScEYT9cDord7UJzasR/4D3VONg9tQI5CDp+/CZC1AXj2pCFOvpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/aws-cdk": { + "version": "2.1126.0", + "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1126.0.tgz", + "integrity": "sha512-uNoocb3vCPiAT3j9+SwL6pn/VVggHWBsgC2XpxyhNvYQYt6cE9BM/149GWwtdcwnLrPjnwW1+CV/5nSSh5dV+w==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "cdk": "bin/cdk" + }, + "engines": { + "node": ">= 18.0.0" + } + }, + "node_modules/aws-cdk-lib": { + "version": "2.257.0", + "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.257.0.tgz", + "integrity": "sha512-GoHfWklrBJcMwLtDlY64pvaT7cD2KyDXC8sik89DR6jHl6nQsBtYTKSJCM+C/k4jgXaecbv8myNX75FySejq0A==", + "bundleDependencies": [ + "@balena/dockerignore", + "@aws-cdk/cloud-assembly-api", + "case", + "fs-extra", + "ignore", + "jsonschema", + "minimatch", + "punycode", + "semver", + "table", + "yaml", + "mime-types" + ], + "license": "Apache-2.0", + "dependencies": { + "@aws-cdk/asset-awscli-v1": "2.2.273", + "@aws-cdk/asset-node-proxy-agent-v6": "^2.1.1", + "@aws-cdk/cloud-assembly-api": "^2.2.4", + "@aws-cdk/cloud-assembly-schema": "^53.25.0", + "@balena/dockerignore": "^1.0.2", + "case": "1.6.3", + "fs-extra": "^11.3.3", + "ignore": "^5.3.2", + "jsonschema": "^1.5.0", + "mime-types": "^2.1.35", + "minimatch": "^10.2.3", + "punycode": "^2.3.1", + "semver": "^7.7.4", + "table": "^6.9.0", + "yaml": "1.10.3" + }, + "engines": { + "node": ">= 20.0.0" + }, + "peerDependencies": { + "constructs": "^10.5.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/@aws-cdk/cloud-assembly-api": { + "version": "2.2.4", + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "jsonschema": "^1.5.0", + "semver": "^7.8.0" + }, + "engines": { + "node": ">= 18.0.0" + }, + "peerDependencies": { + "@aws-cdk/cloud-assembly-schema": ">=53.25.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/@aws-cdk/cloud-assembly-api/node_modules/semver": { + "version": "7.8.0", + "inBundle": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/aws-cdk-lib/node_modules/@balena/dockerignore": { + "version": "1.0.2", + "inBundle": true, + "license": "Apache-2.0" + }, + "node_modules/aws-cdk-lib/node_modules/ajv": { + "version": "8.18.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/aws-cdk-lib/node_modules/ansi-regex": { + "version": "5.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/aws-cdk-lib/node_modules/ansi-styles": { + "version": "4.3.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/aws-cdk-lib/node_modules/astral-regex": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/aws-cdk-lib/node_modules/balanced-match": { + "version": "4.0.4", + "inBundle": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/aws-cdk-lib/node_modules/brace-expansion": { + "version": "5.0.5", + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/aws-cdk-lib/node_modules/case": { + "version": "1.6.3", + "inBundle": true, + "license": "(MIT OR GPL-3.0-or-later)", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/color-convert": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/color-name": { + "version": "1.1.4", + "inBundle": true, + "license": "MIT" + }, + "node_modules/aws-cdk-lib/node_modules/emoji-regex": { + "version": "8.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/aws-cdk-lib/node_modules/fast-deep-equal": { + "version": "3.1.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/aws-cdk-lib/node_modules/fast-uri": { + "version": "3.1.2", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "inBundle": true, + "license": "BSD-3-Clause" + }, + "node_modules/aws-cdk-lib/node_modules/fs-extra": { + "version": "11.3.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/aws-cdk-lib/node_modules/graceful-fs": { + "version": "4.2.11", + "inBundle": true, + "license": "ISC" + }, + "node_modules/aws-cdk-lib/node_modules/ignore": { + "version": "5.3.2", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/aws-cdk-lib/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/aws-cdk-lib/node_modules/json-schema-traverse": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/aws-cdk-lib/node_modules/jsonfile": { + "version": "6.2.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/aws-cdk-lib/node_modules/jsonschema": { + "version": "1.5.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/aws-cdk-lib/node_modules/lodash.truncate": { + "version": "4.4.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/aws-cdk-lib/node_modules/mime-db": { + "version": "1.52.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/aws-cdk-lib/node_modules/mime-types": { + "version": "2.1.35", + "inBundle": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/aws-cdk-lib/node_modules/minimatch": { + "version": "10.2.5", + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/aws-cdk-lib/node_modules/punycode": { + "version": "2.3.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/aws-cdk-lib/node_modules/require-from-string": { + "version": "2.0.2", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/semver": { + "version": "7.7.4", + "inBundle": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/aws-cdk-lib/node_modules/slice-ansi": { + "version": "4.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/aws-cdk-lib/node_modules/string-width": { + "version": "4.2.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/aws-cdk-lib/node_modules/strip-ansi": { + "version": "6.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/aws-cdk-lib/node_modules/table": { + "version": "6.9.0", + "inBundle": true, + "license": "BSD-3-Clause", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/universalify": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/yaml": { + "version": "1.10.3", + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/constructs": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/constructs/-/constructs-10.6.0.tgz", + "integrity": "sha512-TxHOnBO5zMo/G76ykzGF/wMpEHu257TbWiIxP9K0Yv/+t70UzgBQiTqjkAsWOPC6jW91DzJI0+ehQV6xDRNBuQ==", + "license": "Apache-2.0" + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/typescript": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", + "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..d3514ab --- /dev/null +++ b/package.json @@ -0,0 +1,24 @@ +{ + "name": "syslog-server", + "version": "1.0.0", + "bin": { + "app": "bin/app.js" + }, + "scripts": { + "build": "tsc", + "cdk": "cdk", + "synth": "cdk synth", + "deploy": "cdk deploy", + "diff": "cdk diff" + }, + "devDependencies": { + "@types/node": "^22.0.0", + "aws-cdk": "^2.252.0", + "source-map-support": "^0.5.21", + "typescript": "~5.7.0" + }, + "dependencies": { + "aws-cdk-lib": "2.257.0", + "constructs": "^10.0.0" + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..2b2e2de --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "commonjs", + "lib": ["ES2022"], + "types": ["node"], + "declaration": true, + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "inlineSourceMap": true, + "inlineSources": true, + "strictPropertyInitialization": false, + "outDir": "./cdk.out", + "rootDir": ".", + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "esModuleInterop": true + }, + "exclude": ["node_modules", "cdk.out"] +}