# file-share ![CI](https://github.com/Sea-Haven-Industries/file-share/actions/workflows/ci.yaml/badge.svg) ![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?logo=typescript&logoColor=white) ![AWS CDK](https://img.shields.io/badge/AWS-CDK-FF9900?logo=amazonaws&logoColor=white) Personal file share server on AWS — Samba for macOS Finder integration and FileBrowser for web-based file management. Accessible exclusively over the site-to-site VPN. ## Infrastructure The live share is still the management-account CDK stack until cutover proof. The prod replacement is HCP Terraform in `terraform/`, workspace `file-share-prod`, trigger `terraform/**`. CDK deploy on push to main is frozen. | Path | Role | |---|---| | `terraform/` | Prod EC2, subnet in the syslog VPC, DLM, and HCP roles | | `lib/file-share-stack.ts` | Management-account CDK stack, still the live path until decommission | ``` bin/app.ts # CDK app entry point — instantiates the stack lib/file-share-stack.ts # FileShareStack — all resource definitions cdk.json # App command + CDK feature flags / context cdk.context.json # Cached VPC/subnet lookups and the resolved AL2023 AMI ``` `cdk.json` is the CDK app manifest. Its `app` command (`npx tsx bin/app.ts`) runs the TypeScript entry point directly via [tsx](https://github.com/privatenumber/tsx) — no separate compile step is needed for synth or deploy. `bin/app.ts` instantiates `FileShareStack` with an explicit `stackName: "file-share"` (kebab-case, per convention) and the target account/region. `aws-cdk-lib` is pinned to an exact version (`2.261.0`); the `aws-cdk` CLI is available as a dev dependency and via `npx cdk`. Common commands (also exposed as npm scripts): | Command | Purpose | |---|---| | `npx cdk synth` (`npm run synth`) | Synthesize the CloudFormation template to `cdk.out/` | | `npx cdk diff` (`npm run diff`) | Diff the synthesized stack against what is deployed | | `npx cdk deploy` (`npm run deploy`) | Deploy the stack | | `npm run build` | Type-check via `tsc` | ## Architecture - **EC2** — `t4g.small` (ARM64, Amazon Linux 2023) in the private subnet. The AMI is cached in the committed `cdk.context.json` (`cachedInContext: true`), so deploys never pick up a new AL2023 release implicitly — an AMI change forces instance replacement and must be deliberate (`cdk context --reset && cdk synth`). - **Samba** — SMB file share at `/data/share`, optimized for macOS (`vfs_fruit`) - **FileBrowser** — Web UI on port 8080, backed by the same `/data/share` directory - **SFTP** — password auth for user `adam` (`ForceCommand internal-sftp`, same password as SMB); used by Hazel for automated uploads - **EBS data volume** — `vol-04d951cccacc435b5`, 500 GiB gp3 encrypted, mounted at `/data`. **Unmanaged import**: the stack references it by ID (`Volume.fromVolumeAttributes` + `CfnVolumeAttachment`), so CloudFormation can attach it but can never create, replace, or delete it — the data survives instance replacement and even stack deletion. UserData waits for the attachment, then mounts the existing filesystem; a `blkid` guard ensures a disk that already has a filesystem is never formatted. - **DLM** — Daily EBS snapshots at 06:00 UTC, 30-day retention (targets the `file-share-backup=true` tag, set directly on the volume) - **SSM** — Session Manager for instance access (no SSH key) > **History:** the data volume was originally an inline `blockDevice`, which destroyed data on instance replacement (2026-05-27 incident), then a stack-managed standalone volume, which was orphaned when an uncommitted deploy got reverted by CD (2026-06-05 incident). The unmanaged-import design ends that failure class. ## Documentation The canonical map of Sea Haven's AWS infrastructure lives in Confluence. This project's `file-share` stack is represented there as a Mermaid subgraph. - **[AWS Architecture Map](https://seahaven.atlassian.net/wiki/spaces/IT/pages/1540098)** (Confluence, IT space, page 1540098) ## Access Requires VPN connection to the office network (10.10.0.0/16). ### Finder (SMB) 1. Finder > Go > Connect to Server 2. Enter `smb:///files` 3. Authenticate with `adam` and the password from `file-share/smb-password` in Secrets Manager ### FileBrowser (Web) Open `http://:8080` in a browser. ## Secrets Both stored in AWS Secrets Manager: | Secret | Purpose | |---|---| | `file-share/smb-password` | Samba user password | | `file-share/filebrowser-password` | FileBrowser admin password | Create these secrets before deploying the stack: ```bash aws secretsmanager create-secret --name file-share/smb-password --secret-string '' aws secretsmanager create-secret --name file-share/filebrowser-password --secret-string '' ``` ## Deploy Prod changes go through HCP Terraform workspace `file-share-prod` (manual apply until the move is sealed). The bootstrap apply creates the HCP roles and the instance boundary. The following apply, using `hcptf-file-share`, creates the subnet, security group, and DLM policy. `data_volume_id` stays empty until the snapshot copy exists, so those applies do not boot an instance. The management-account CDK workflow no longer runs on push. `workflow_dispatch` remains for an explicit rollback of that stack. The instance has no public IP. Its route table sends `10.10.0.0/16` and `10.30.0.0/16` through the VPN gateway in workspace variable `vpn_gateway_id` and everything else through a NAT gateway in the syslog public subnet. `10.10.0.0/16` is the Ronkonkoma office LAN and `10.30.0.0/16` is the Locust office LAN, the same pair the syslog VPN already routes. `10.20.0.0/16` is the management VPC and is not routed here. Clients use the private IP. Office routing must include `10.40.20.0/24` on the existing syslog IPsec before SMB from the office will work. A check from `10.10.70.0/24` on 2026-09-28 reached the gateway for `10.40.10.254` and got no hop-1 reply for `10.40.20.1`. The nightly DLM policy targets volumes tagged `file-share-backup=true`. Tag the copied volume with that key at cutover. ## Expanding Storage The data volume is **not managed by CloudFormation** (imported by ID), so changing a size in `lib/file-share-stack.ts` has no effect. Expand it directly — no downtime: 1. `aws ec2 modify-volume --volume-id vol-04d951cccacc435b5 --size ` 2. Wait for the modification to leave `modifying`: `aws ec2 describe-volumes-modifications --volume-ids vol-04d951cccacc435b5` 3. Resize the filesystem via an SSM session: ```bash sudo resize2fs /dev/nvme1n1 # xvdf surfaces as nvme1n1 on Nitro instances ```