diff --git a/lib/syslog-server-stack.ts b/lib/syslog-server-stack.ts index 7262a7d..ae2528d 100644 --- a/lib/syslog-server-stack.ts +++ b/lib/syslog-server-stack.ts @@ -84,6 +84,15 @@ export class SyslogServerStack extends cdk.Stack { userData.addCommands( "set -euxo pipefail", "", + "# ── 1 GiB swap (build headroom + stability on the 512 MiB t4g.nano) ──", + "if [ ! -f /swapfile ]; then", + " fallocate -l 1G /swapfile || dd if=/dev/zero of=/swapfile bs=1M count=1024", + " chmod 600 /swapfile", + " mkswap /swapfile", + " echo '/swapfile none swap sw 0 0' >> /etc/fstab", + "fi", + "swapon -a || true", + "", "# ── rsyslog: listen on UDP/TCP 514 ──", "dnf install -y rsyslog", "cat > /etc/rsyslog.d/10-listen.conf <<'EOF'", @@ -131,6 +140,74 @@ export class SyslogServerStack extends cdk.Stack { " -a fetch-config -m ec2 \\", " -c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json -s", "systemctl enable amazon-cloudwatch-agent", + "", + "# ── NetFlow/IPFIX collectors (nfcapd) ──", + "# nfdump is not packaged for AL2023; build 1.6.23 from source (needs", + "# rrdtool-devel for librrd). Reconstructed under IaC for INFRA-12 — the", + "# original instance ran these as hand-installed systemd units. Captures", + "# are local-only (no consumer/shipping today); 30-day retention enforced.", + "dnf install -y gcc gcc-c++ make automake autoconf libtool flex bison libpcap-devel zlib-devel bzip2-devel rrdtool-devel tar", + "NFVER=1.6.23", + "curl -sfL https://github.com/phaag/nfdump/archive/refs/tags/v${NFVER}.tar.gz | tar xz -C /tmp", + "( cd /tmp/nfdump-${NFVER} && ./autogen.sh && ./configure && make -j1 && make install )", + "ldconfig", + "", + "mkdir -p /var/log/netflow/ronkonkoma /var/log/netflow/locust", + "chown -R ec2-user:ec2-user /var/log/netflow", + "", + "# Ronkonkoma gateway -> UDP 2055", + "cat > /etc/systemd/system/nfcapd.service <<'EOF'", + "[Unit]", + "Description=nfcapd NetFlow collector (Ronkonkoma, udp/2055)", + "After=network.target", + "[Service]", + "Type=simple", + "User=ec2-user", + "ExecStart=/usr/local/bin/nfcapd -p 2055 -l /var/log/netflow/ronkonkoma", + "Restart=always", + "[Install]", + "WantedBy=multi-user.target", + "EOF", + "", + "# Locust Ave gateway -> UDP 2056", + "cat > /etc/systemd/system/nfcapd-locust.service <<'EOF'", + "[Unit]", + "Description=nfcapd NetFlow collector (Locust Ave, udp/2056)", + "After=network.target", + "[Service]", + "Type=simple", + "User=ec2-user", + "ExecStart=/usr/local/bin/nfcapd -p 2056 -l /var/log/netflow/locust", + "Restart=always", + "[Install]", + "WantedBy=multi-user.target", + "EOF", + "", + "# 30-day retention sweep (daily 03:30 UTC)", + "cat > /usr/local/sbin/netflow-retention.sh <<'EOF'", + "#!/bin/bash", + "find /var/log/netflow -type f -name 'nfcapd.*' -mtime +30 -delete", + "EOF", + "chmod +x /usr/local/sbin/netflow-retention.sh", + "cat > /etc/systemd/system/netflow-retention.service <<'EOF'", + "[Unit]", + "Description=Delete NetFlow captures older than 30 days", + "[Service]", + "Type=oneshot", + "ExecStart=/usr/local/sbin/netflow-retention.sh", + "EOF", + "cat > /etc/systemd/system/netflow-retention.timer <<'EOF'", + "[Unit]", + "Description=Daily NetFlow retention sweep", + "[Timer]", + "OnCalendar=*-*-* 03:30:00 UTC", + "Persistent=true", + "[Install]", + "WantedBy=timers.target", + "EOF", + "", + "systemctl daemon-reload", + "systemctl enable --now nfcapd.service nfcapd-locust.service netflow-retention.timer", ); const instance = new ec2.Instance(this, "Instance", { @@ -148,6 +225,9 @@ export class SyslogServerStack extends cdk.Stack { securityGroup: sg, role, userData, + // A user-data change must actually re-run, so force instance replacement + // (the box is stateless — logs live in CloudWatch, the EIP re-associates). + userDataCausesReplacement: true, blockDevices: [ { deviceName: "/dev/xvda",