Initial file-share stack

CDK stack deploying a t4g.small EC2 instance with Samba and FileBrowser
for personal file storage over the site-to-site VPN. Includes 500 GiB
gp3 data volume with daily DLM snapshots.
This commit is contained in:
Adam Moussa 2026-05-14 15:23:38 -04:00
commit 427242499d
11 changed files with 954 additions and 0 deletions

8
.github/workflows/ci.yaml vendored Normal file
View file

@ -0,0 +1,8 @@
name: CI
on:
pull_request:
branches: [main]
jobs:
ci:
uses: Sea-Haven-Industries/.github/.github/workflows/ci-typescript-cdk.yaml@main

18
.github/workflows/deploy.yaml vendored Normal file
View file

@ -0,0 +1,18 @@
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
secrets:
deploy-role-arn: ${{ secrets.AWS_DEPLOY_ROLE_ARN }}

5
.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
node_modules/
cdk.out/
*.js
*.d.ts
*.js.map

63
README.md Normal file
View file

@ -0,0 +1,63 @@
# file-share
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.
## Architecture
- **EC2** — `t4g.small` (ARM64, Amazon Linux 2023) in the private subnet
- **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
- **EBS** — 500 GiB gp3 data volume (separate from root), encrypted
- **DLM** — Daily EBS snapshots, 30-day retention
- **SSM** — Session Manager for instance access (no SSH key)
## Access
Requires VPN connection to the office network (10.10.0.0/16).
### Finder (SMB)
1. Finder > Go > Connect to Server
2. Enter `smb://<private-ip>/files`
3. Authenticate with `adam` and the password from `file-share/smb-password` in Secrets Manager
### FileBrowser (Web)
Open `http://<private-ip>: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 '<password>'
aws secretsmanager create-secret --name file-share/filebrowser-password --secret-string '<password>'
```
## Deploy
```bash
npm install
npx cdk deploy
```
The stack outputs the instance's private IP for SMB and FileBrowser access.
## Expanding Storage
The 500 GiB data volume can be expanded without downtime:
1. Modify the volume size in `lib/file-share-stack.ts`
2. Deploy: `npx cdk deploy`
3. SSH into the instance via SSM and resize the filesystem:
```bash
sudo growpart /dev/xvdf 1 # if partitioned
sudo resize2fs /dev/xvdf
```

11
bin/app.ts Normal file
View file

@ -0,0 +1,11 @@
#!/usr/bin/env node
import "source-map-support/register";
import * as cdk from "aws-cdk-lib";
import { FileShareStack } from "../lib/file-share-stack";
const app = new cdk.App();
new FileShareStack(app, "file-share", {
stackName: "file-share",
env: { account: "328440206208", region: "us-east-1" },
});

47
cdk.context.json Normal file
View file

@ -0,0 +1,47 @@
{
"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"
}
]
}
]
}
}

21
cdk.json Normal file
View file

@ -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"]
}
}

212
lib/file-share-stack.ts Normal file
View file

@ -0,0 +1,212 @@
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 dlm from "aws-cdk-lib/aws-dlm";
import { Construct } from "constructs";
export class FileShareStack 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",
});
const privateSubnet1 = ec2.Subnet.fromSubnetAttributes(
this, "PrivateSubnet1", {
subnetId: "subnet-04e38c507e96f1926",
availabilityZone: "us-east-1a",
}
);
const sg = new ec2.SecurityGroup(this, "SecurityGroup", {
vpc,
securityGroupName: "file-share",
description: "File share - SMB and FileBrowser via VPN",
allowAllOutbound: true,
});
sg.addIngressRule(ec2.Peer.ipv4("10.10.0.0/16"), ec2.Port.tcp(445), "SMB from office VPN");
sg.addIngressRule(ec2.Peer.ipv4("10.20.0.0/16"), ec2.Port.tcp(445), "SMB from VPC");
sg.addIngressRule(ec2.Peer.ipv4("10.10.0.0/16"), ec2.Port.tcp(8080), "FileBrowser from office VPN");
sg.addIngressRule(ec2.Peer.ipv4("10.20.0.0/16"), ec2.Port.tcp(8080), "FileBrowser from VPC");
const role = new iam.Role(this, "InstanceRole", {
roleName: "file-share-instance",
assumedBy: new iam.ServicePrincipal("ec2.amazonaws.com"),
managedPolicies: [
iam.ManagedPolicy.fromAwsManagedPolicyName("AmazonSSMManagedInstanceCore"),
],
});
role.addToPolicy(new iam.PolicyStatement({
actions: ["secretsmanager:GetSecretValue"],
resources: [
`arn:aws:secretsmanager:us-east-1:328440206208:secret:file-share/*`,
],
}));
const userData = ec2.UserData.forLinux();
userData.addCommands(
"set -euxo pipefail",
"",
"# ── Data volume ──",
"DATA_DEVICE=/dev/$(lsblk -dno NAME | grep -v $(lsblk -no PKNAME $(findmnt -n -o SOURCE /) 2>/dev/null || echo xvda) | head -1)",
"if ! blkid \"$DATA_DEVICE\"; then",
" mkfs.ext4 -L file-share-data \"$DATA_DEVICE\"",
"fi",
"mkdir -p /data",
"echo \"LABEL=file-share-data /data ext4 defaults,nofail 0 2\" >> /etc/fstab",
"mount -a",
"mkdir -p /data/share",
"",
"# ── Samba ──",
"dnf install -y samba samba-common jq",
"",
"useradd --system --no-create-home --shell /sbin/nologin adam || true",
"chown adam:adam /data/share",
"",
"SMB_PASSWORD=$(aws secretsmanager get-secret-value --secret-id file-share/smb-password --query SecretString --output text --region us-east-1)",
"(echo \"$SMB_PASSWORD\"; echo \"$SMB_PASSWORD\") | smbpasswd -s -a adam",
"",
"cat > /etc/samba/smb.conf << 'SMBEOF'",
"[global]",
"workgroup = SEAHAVEN",
"server string = Sea Haven File Share",
"security = user",
"map to guest = never",
"log file = /var/log/samba/log.%m",
"max log size = 1000",
"server min protocol = SMB3",
"",
"# macOS Finder optimizations",
"vfs objects = catia fruit streams_xattr",
"fruit:metadata = stream",
"fruit:model = MacSamba",
"fruit:posix_rename = yes",
"fruit:veto_appledouble = no",
"fruit:nfs_aces = no",
"fruit:wipe_intentionally_left_blank_rfork = yes",
"fruit:delete_empty_adfiles = yes",
"",
"[files]",
"path = /data/share",
"browseable = yes",
"writable = yes",
"valid users = adam",
"create mask = 0644",
"directory mask = 0755",
"SMBEOF",
"",
"systemctl enable --now smb nmb",
"",
"# ── FileBrowser ──",
'FB_VERSION=$(curl -sf "https://api.github.com/repos/filebrowser/filebrowser/releases/latest" | jq -r .tag_name)',
'FB_URL="https://github.com/filebrowser/filebrowser/releases/download/${FB_VERSION}/linux-arm64-filebrowser.tar.gz"',
"curl -sfL \"$FB_URL\" | tar xz -C /usr/local/bin filebrowser",
"chmod +x /usr/local/bin/filebrowser",
"",
"mkdir -p /etc/filebrowser",
"FB_PASSWORD=$(aws secretsmanager get-secret-value --secret-id file-share/filebrowser-password --query SecretString --output text --region us-east-1)",
"FB_HASH=$(filebrowser hash \"$FB_PASSWORD\")",
"",
"cat > /etc/filebrowser/config.json << FBEOF",
"{",
" \"address\": \"0.0.0.0\",",
" \"port\": 8080,",
" \"root\": \"/data/share\",",
" \"database\": \"/etc/filebrowser/filebrowser.db\",",
" \"log\": \"/var/log/filebrowser.log\"",
"}",
"FBEOF",
"",
"filebrowser config init --config /etc/filebrowser/config.json",
"filebrowser users add admin \"$FB_PASSWORD\" --config /etc/filebrowser/config.json --perm.admin",
"",
"cat > /etc/systemd/system/filebrowser.service << 'SVCEOF'",
"[Unit]",
"Description=FileBrowser",
"After=network.target",
"",
"[Service]",
"Type=simple",
"ExecStart=/usr/local/bin/filebrowser --config /etc/filebrowser/config.json",
"Restart=always",
"RestartSec=5",
"",
"[Install]",
"WantedBy=multi-user.target",
"SVCEOF",
"",
"systemctl daemon-reload",
"systemctl enable --now filebrowser",
);
const instance = new ec2.Instance(this, "Instance", {
instanceName: "file-share",
vpc,
vpcSubnets: { subnets: [privateSubnet1] },
instanceType: ec2.InstanceType.of(ec2.InstanceClass.T4G, ec2.InstanceSize.SMALL),
machineImage: ec2.MachineImage.latestAmazonLinux2023({
cpuType: ec2.AmazonLinuxCpuType.ARM_64,
}),
securityGroup: sg,
role,
userData,
blockDevices: [
{
deviceName: "/dev/xvda",
volume: ec2.BlockDeviceVolume.ebs(20, {
volumeType: ec2.EbsDeviceVolumeType.GP3,
encrypted: true,
}),
},
{
deviceName: "/dev/xvdf",
volume: ec2.BlockDeviceVolume.ebs(500, {
volumeType: ec2.EbsDeviceVolumeType.GP3,
encrypted: true,
}),
},
],
});
cdk.Tags.of(instance).add("file-share-backup", "true");
const dlmRole = new iam.Role(this, "DlmRole", {
roleName: "file-share-dlm",
assumedBy: new iam.ServicePrincipal("dlm.amazonaws.com"),
managedPolicies: [
iam.ManagedPolicy.fromAwsManagedPolicyName(
"service-role/AWSDataLifecycleManagerServiceRole"
),
],
});
new dlm.CfnLifecyclePolicy(this, "SnapshotPolicy", {
description: "Nightly EBS snapshots for file share data volume",
state: "ENABLED",
executionRoleArn: dlmRole.roleArn,
policyDetails: {
resourceTypes: ["INSTANCE"],
targetTags: [{ key: "file-share-backup", value: "true" }],
schedules: [{
name: "file-share-nightly",
createRule: { interval: 24, intervalUnit: "HOURS", times: ["06:00"] },
retainRule: { count: 30 },
copyTags: true,
tagsToAdd: [{ key: "file-share-backup", value: "true" }],
}],
},
});
new cdk.CfnOutput(this, "InstanceId", {
value: instance.instanceId,
});
new cdk.CfnOutput(this, "PrivateIp", {
value: instance.instancePrivateIp,
description: "Use for SMB (smb://<ip>/files) and FileBrowser (http://<ip>:8080)",
});
}
}

521
package-lock.json generated Normal file
View file

@ -0,0 +1,521 @@
{
"name": "file-share",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "file-share",
"version": "1.0.0",
"dependencies": {
"aws-cdk-lib": "^2.252.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.1",
"resolved": "https://registry.npmjs.org/@aws-cdk/asset-node-proxy-agent-v6/-/asset-node-proxy-agent-v6-2.1.1.tgz",
"integrity": "sha512-We4bmHaowOPHr+IQR4/FyTGjRfjgBj4ICMjtqmJeBDWad3Q/6St12NT07leNtyuukv2qMhtSZJQorD8KpKTwRA==",
"license": "Apache-2.0"
},
"node_modules/@aws-cdk/cloud-assembly-schema": {
"version": "53.24.0",
"resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-53.24.0.tgz",
"integrity": "sha512-rCwsd0Y9z4CUmV5FhzjbO2MprXjKG0rxCACuLEY40lD+wInvgcHer0lSDo7Xq9Sxe/IoNe/Wxb2YP3GgxvT3GA==",
"bundleDependencies": [
"jsonschema",
"semver"
],
"license": "Apache-2.0",
"dependencies": {
"jsonschema": "~1.4.1",
"semver": "^7.8.0"
},
"engines": {
"node": ">= 18.0.0"
}
},
"node_modules/@aws-cdk/cloud-assembly-schema/node_modules/jsonschema": {
"version": "1.4.1",
"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.19",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz",
"integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
}
},
"node_modules/aws-cdk": {
"version": "2.1122.0",
"resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1122.0.tgz",
"integrity": "sha512-AI2Ks9qioWLvBPD4IoEtTet3wUG/o/q6U3WR3VCQKH5sNYLLPALo8o9sermNpMnfd1OQkqhL20tp4cEyojrIZg==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"cdk": "bin/cdk"
},
"engines": {
"node": ">= 18.0.0"
}
},
"node_modules/aws-cdk-lib": {
"version": "2.254.0",
"resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.254.0.tgz",
"integrity": "sha512-O7fn6fu1FXb0BgoO/+WeiBXZ16H/q6z4fOndjdG62c9bPU7Z/UeW5gz7qBiwLm4ERvTObobLCqv7wjd8bp+v3A==",
"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.3",
"@aws-cdk/cloud-assembly-schema": "^53.21.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.3",
"inBundle": true,
"license": "Apache-2.0",
"dependencies": {
"jsonschema": "~1.4.1",
"semver": "^7.7.4"
},
"engines": {
"node": ">= 18.0.0"
},
"peerDependencies": {
"@aws-cdk/cloud-assembly-schema": ">=53.21.0"
}
},
"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"
}
}
}

24
package.json Normal file
View file

@ -0,0 +1,24 @@
{
"name": "file-share",
"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.252.0",
"constructs": "^10.0.0"
}
}

24
tsconfig.json Normal file
View file

@ -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"]
}