diff --git a/docker-compose.yml b/docker-compose.yml index 68395f6..76ee0f2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,29 +1,20 @@ services: localstack: - container_name: lambda-starter-localstack - image: localstack/localstack:4.12 + container_name: '${LOCALSTACK_DOCKER_NAME:-localstack-main}' + image: localstack/localstack:2026.03 ports: - '4566:4566' environment: # LocalStack configuration - SERVICES=s3,dynamodb,sns,lambda,apigateway,logs,iam,sts,cloudformation,ssm + # Enable debug mode (optional - set to 1 to enable) - DEBUG=${DEBUG:-0} - - LAMBDA_EXECUTOR=docker - - DOCKER_HOST=unix:///var/run/docker.sock - - AWS_DEFAULT_REGION=us-east-1 - # Configure Lambda to access LocalStack from within containers - - LAMBDA_DOCKER_NETWORK=lambda-starter_lambda-starter-network - - LOCALSTACK_HOSTNAME=localstack # Enable persistence (optional - comment out to disable) - PERSISTENCE=${PERSISTENCE:-0} + # LocalStack Auth Token required for 2026.03 and later + - LOCALSTACK_AUTH_TOKEN=${LOCALSTACK_AUTH_TOKEN:?} volumes: # Mount docker socket for Lambda execution - /var/run/docker.sock:/var/run/docker.sock # Optional: Persist data between restarts - ./localstack-data:/var/lib/localstack - networks: - - lambda-starter-network - -networks: - lambda-starter-network: - driver: bridge diff --git a/docs/LocalStackGuide.md b/docs/LocalStackGuide.md index feda7ba..c23fbfa 100644 --- a/docs/LocalStackGuide.md +++ b/docs/LocalStackGuide.md @@ -48,21 +48,30 @@ Before using LocalStack with this project, ensure you have the following install docker-compose --version ``` -3. **LocalStack CLI** (optional but recommended) +3. **LocalStack Auth Token** (required) - See the [LocalStack Getting Started Guide](https://docs.localstack.cloud/aws/getting-started/) for free account setup, installation instructions, and how to obtain an auth token. + Starting with LocalStack 2026.03, an Auth Token is required to activate LocalStack for AWS. You can get a free Auth Token by: + - Signing up for a free account at [LocalStack Web Application](https://app.localstack.cloud/sign-up) + - Obtaining your Auth Token from the [Auth Tokens page](https://app.localstack.cloud/workspace/auth-tokens) + - Setting the `LOCALSTACK_AUTH_TOKEN` environment variable in your shell or `.env` file + + For more information, see the [LocalStack Auth Token Documentation](https://docs.localstack.cloud/aws/getting-started/auth-token/). + +4. **LocalStack CLI** (optional but recommended) + + See the [LocalStack Getting Started Guide](https://docs.localstack.cloud/aws/getting-started/) for installation instructions. ```bash localstack --version ``` -4. **AWS CLI** (optional, for manual testing) +5. **AWS CLI** (optional, for manual testing) ```bash aws --version ``` -5. **Node.js 24+** and **npm** +6. **Node.js 24+** and **npm** ```bash node --version npm --version @@ -72,7 +81,24 @@ Before using LocalStack with this project, ensure you have the following install Follow these steps to get the Task microservice running locally with LocalStack: -### 1. Start LocalStack +### 1. Set the LocalStack Auth Token + +Before starting LocalStack, set your Auth Token in your environment: + +```bash +export LOCALSTACK_AUTH_TOKEN=your-auth-token-here +``` + +Replace `your-auth-token-here` with your actual Auth Token from the [LocalStack Web Application](https://app.localstack.cloud/workspace/auth-tokens). + +Alternatively, you can add this to your shell profile (`.bashrc`, `.zshrc`, etc.) or create a `.env.local` file in the project root: + +```bash +echo "export LOCALSTACK_AUTH_TOKEN=your-auth-token-here" >> ~/.bashrc +source ~/.bashrc +``` + +### 2. Start LocalStack From the project root directory: @@ -92,7 +118,7 @@ View LocalStack logs: docker-compose logs -f localstack ``` -### 2. Install Dependencies +### 3. Install Dependencies Install CDK infrastructure dependencies: @@ -101,7 +127,7 @@ cd infrastructure npm install ``` -### 3. Configure Environment +### 4. Configure Environment Copy the LocalStack environment configuration: @@ -121,7 +147,7 @@ CDK_USE_LOCALSTACK=true CDK_LOCALSTACK_ENDPOINT=http://localstack:4566 ``` -### 4. Build the Infrastructure +### 5. Build the Infrastructure Compile the CDK TypeScript code: @@ -129,7 +155,7 @@ Compile the CDK TypeScript code: npm run build ``` -### 5. Bootstrap CDK (First Time Only) +### 6. Bootstrap CDK (First Time Only) Bootstrap the CDK environment in LocalStack: @@ -139,7 +165,7 @@ npm run local:bootstrap This creates the necessary S3 buckets and resources for CDK deployments. -### 6. Deploy to LocalStack +### 7. Deploy to LocalStack Deploy all stacks to LocalStack: @@ -155,7 +181,7 @@ This deploys: The deployment typically takes 2-5 minutes. -### 7. Get the API Endpoint +### 8. Get the API Endpoint After deployment, the CloudFormation outputs will show the API Gateway endpoint: @@ -173,7 +199,7 @@ aws --endpoint-url=http://localhost:4566 cloudformation describe-stacks \ --output text ``` -### 8. Test the API +### 9. Test the API Test the API using curl or your favorite HTTP client: @@ -227,23 +253,36 @@ The `docker-compose.yml` file in the project root configures the LocalStack cont ```yaml services: localstack: - image: localstack/localstack:4.12 + container_name: '${LOCALSTACK_DOCKER_NAME:-localstack-main}' + image: localstack/localstack:2026.03 ports: - '4566:4566' environment: + # LocalStack configuration - SERVICES=s3,dynamodb,sns,lambda,apigateway,logs,iam,sts,cloudformation,ssm - - LAMBDA_EXECUTOR=docker + # LocalStack Auth Token (required as of 2026.03) + - LOCALSTACK_AUTH_TOKEN=${LOCALSTACK_AUTH_TOKEN:?} + # Enable debug mode (optional - set to 1 to enable) + - DEBUG=${DEBUG:-0} + # Enable persistence (optional - comment out to disable) + - PERSISTENCE=${PERSISTENCE:-0} volumes: - /var/run/docker.sock:/var/run/docker.sock + - ./localstack-data:/var/lib/localstack ``` -You can customize this configuration by editing the file. For example, to enable data persistence: +Key points: -```yaml -environment: - - PERSISTENCE=1 -volumes: - - ./localstack-data:/var/lib/localstack +- **LOCALSTACK_AUTH_TOKEN** - Required environment variable. Must be set before starting the container. +- **SERVICES** - Specifies which AWS services to emulate. Adjust as needed for your project. +- **DEBUG** - Optional flag for debug mode (set to 1 to enable verbose logging). +- **PERSISTENCE** - Optional flag to persist data between container restarts. + +You can customize the `PERSISTENCE` setting by uncommenting or adding it to enable data persistence: + +```bash +export PERSISTENCE=1 +docker-compose up -d ``` ## Usage @@ -462,6 +501,31 @@ Check available disk space and memory. LocalStack requires at least: - 2 GB RAM - 5 GB disk space +**Missing Auth Token error:** + +If you see an error like "License activation failed", ensure your `LOCALSTACK_AUTH_TOKEN` environment variable is set: + +```bash +export LOCALSTACK_AUTH_TOKEN=your-auth-token +docker-compose up -d +``` + +Verify the token is correctly set: + +```bash +echo $LOCALSTACK_AUTH_TOKEN +``` + +**Invalid Auth Token error:** + +If you receive an "invalid credentials" error: + +1. Verify your Auth Token is correct - check it on the [Auth Tokens page](https://app.localstack.cloud/workspace/auth-tokens) +2. Ensure you have an active license assigned to your account +3. Rotate your Auth Token if you suspect it may have been compromised + +For more troubleshooting steps, see the [LocalStack Auth Token Troubleshooting Guide](https://docs.localstack.cloud/aws/getting-started/auth-token/#troubleshooting) + ### Deployment Issues **CDK bootstrap fails:** @@ -597,6 +661,8 @@ jobs: - uses: actions/checkout@v6 - name: Start LocalStack + env: + LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }} run: docker-compose up -d - name: Setup Node.js @@ -624,6 +690,8 @@ jobs: run: docker-compose down ``` +**Important:** Store your `LOCALSTACK_AUTH_TOKEN` as a GitHub repository secret (`secrets.LOCALSTACK_AUTH_TOKEN`). Never commit your Auth Token to version control. + ### Cost Savings Using LocalStack for development and testing can significantly reduce AWS costs: @@ -635,10 +703,21 @@ Using LocalStack for development and testing can significantly reduce AWS costs: ### Security Considerations -1. **Never commit** the `.env` file with real AWS credentials -2. **Use dummy credentials** for LocalStack (already configured) -3. **Don't expose** LocalStack port (4566) to the internet -4. **Keep LocalStack updated** for security patches: +1. **Protect your Auth Token** - It provides access to your LocalStack workspace and license + - Never commit the `LOCALSTACK_AUTH_TOKEN` to source control + - Use environment variables or a `.env.local` file (not committed to version control) + - If accidentally exposed, immediately rotate it on the [Auth Tokens page](https://app.localstack.cloud/workspace/auth-tokens) + +2. **Secure the `.env` file** + - Add `.env.local` to `.gitignore` to prevent accidental commits + - Never commit files containing real AWS credentials or Auth Tokens + +3. **Network Security** + - Don't expose LocalStack port (4566) to the internet + - Use it only for local development + +4. **Keep LocalStack Updated** + - Regularly update to the latest version for security patches: ```bash docker-compose pull docker-compose up -d diff --git a/infrastructure/package-lock.json b/infrastructure/package-lock.json index 9b8e4dd..428e6e8 100644 --- a/infrastructure/package-lock.json +++ b/infrastructure/package-lock.json @@ -16,8 +16,8 @@ }, "devDependencies": { "@types/jest": "30.0.0", - "@types/node": "25.5.2", - "aws-cdk": "2.1117.0", + "@types/node": "25.6.0", + "aws-cdk": "2.1118.0", "aws-cdk-local": "3.0.4", "esbuild": "0.28.0", "jest": "30.3.0", @@ -1693,13 +1693,13 @@ } }, "node_modules/@types/node": { - "version": "25.5.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.2.tgz", - "integrity": "sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg==", + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.18.0" + "undici-types": "~7.19.0" } }, "node_modules/@types/stack-utils": { @@ -2105,9 +2105,9 @@ } }, "node_modules/aws-cdk": { - "version": "2.1117.0", - "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1117.0.tgz", - "integrity": "sha512-2NbSDDw8LTkGv0uhEDffttmNvgyTAWV5EkLkyPUGAGECzBdwCmbgmRxSoUhbzxZ0XEd1eaqbdVTFRWgtsbj31g==", + "version": "2.1118.0", + "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1118.0.tgz", + "integrity": "sha512-Tfd865GRewDTXIbTVtix/l+v8t3rZENvdHcQQZS2wXYVXfHzljULFXe9JKkgZUNDPB1zo9tSBUu8jjiHRm7nWg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -5484,9 +5484,9 @@ } }, "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", "dev": true, "license": "MIT" }, diff --git a/infrastructure/package.json b/infrastructure/package.json index ec61999..e6d2ab0 100644 --- a/infrastructure/package.json +++ b/infrastructure/package.json @@ -29,8 +29,8 @@ }, "devDependencies": { "@types/jest": "30.0.0", - "@types/node": "25.5.2", - "aws-cdk": "2.1117.0", + "@types/node": "25.6.0", + "aws-cdk": "2.1118.0", "aws-cdk-local": "3.0.4", "esbuild": "0.28.0", "jest": "30.3.0", diff --git a/package-lock.json b/package-lock.json index 93d88e8..fe086b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,10 +9,10 @@ "version": "1.3.0-alpha.1", "license": "MIT", "dependencies": { - "@aws-sdk/client-dynamodb": "3.1026.0", - "@aws-sdk/client-lambda": "3.1026.0", - "@aws-sdk/client-sns": "3.1026.0", - "@aws-sdk/lib-dynamodb": "3.1026.0", + "@aws-sdk/client-dynamodb": "3.1028.0", + "@aws-sdk/client-lambda": "3.1028.0", + "@aws-sdk/client-sns": "3.1028.0", + "@aws-sdk/lib-dynamodb": "3.1028.0", "@leanstacks/lambda-utils": "0.9.0", "zod": "4.3.6" }, @@ -20,7 +20,7 @@ "@eslint/js": "10.0.1", "@types/aws-lambda": "8.10.161", "@types/jest": "30.0.0", - "@types/node": "25.5.2", + "@types/node": "25.6.0", "@typescript-eslint/eslint-plugin": "8.58.1", "@typescript-eslint/parser": "8.58.1", "eslint": "10.2.0", @@ -28,7 +28,7 @@ "globals": "17.4.0", "husky": "9.1.7", "jest": "30.3.0", - "prettier": "3.8.1", + "prettier": "3.8.2", "rimraf": "6.1.3", "ts-jest": "29.4.9", "ts-node": "10.9.2", @@ -176,9 +176,9 @@ } }, "node_modules/@aws-sdk/client-dynamodb": { - "version": "3.1026.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.1026.0.tgz", - "integrity": "sha512-IcguKvv47nFTH14AxrHFmF86hV35HA0KNEbKXMdWZav5leLfd/nkG28UP/tGht70NTOKQ6+oVlsmSSRbyubm3A==", + "version": "3.1028.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.1028.0.tgz", + "integrity": "sha512-OkO2p9Wm+6CccOfQcdYjvCAJdUfBSWbmrIKXGh/qbBjp0B8d1MsYl1Exps5OzRSzqLVuTUVjPJCkgSMJF/mPqg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -229,9 +229,9 @@ } }, "node_modules/@aws-sdk/client-lambda": { - "version": "3.1026.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.1026.0.tgz", - "integrity": "sha512-JjSAWJ73BSDxFjWTibpU5VHrPZzRkVOsrjSZFVzugSDHMEXXOOkJsQurhFeqku5Kd2auOJozV7X/sfv2O7Lk4A==", + "version": "3.1028.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.1028.0.tgz", + "integrity": "sha512-wAJT/1M5UT5d0Nw/7XTWzVO3nJpvghGxoiiKxR3KKIbOEIGPEY2FJpw5xZHFaLS7Du5sr9rCyqJ+0fiejID/gA==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -284,9 +284,9 @@ } }, "node_modules/@aws-sdk/client-sns": { - "version": "3.1026.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sns/-/client-sns-3.1026.0.tgz", - "integrity": "sha512-9KglTCPyGbviaympjq2BioFhAxdMJYP8vu6Hqgerv4yKd7N6B/i7+xB3m5ucRfNUYKGHeT5R3Ak/U1l2roQDGQ==", + "version": "3.1028.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sns/-/client-sns-3.1028.0.tgz", + "integrity": "sha512-izYwsbiPwCQxmGAl2KAT2ZWcZd6Gg2+ylw51zOblwxRZIJ0xXHiltDr5gXadXaa3B5h02oW3TNe8Qq/PNK7iBg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -599,9 +599,9 @@ } }, "node_modules/@aws-sdk/lib-dynamodb": { - "version": "3.1026.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/lib-dynamodb/-/lib-dynamodb-3.1026.0.tgz", - "integrity": "sha512-cM4Ueigue372gdnqPCiVt0lWLI8xUZyYkJ3SLIQKxRcQHUYnT+hMEUoEdgjZQ6zwL345vQOa09iwCFxnAgLV1w==", + "version": "3.1028.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/lib-dynamodb/-/lib-dynamodb-3.1028.0.tgz", + "integrity": "sha512-/DRWE5DPlM74xrSf6AqT8mxNo+ZSUiegwTVdZAVxa9iaQqZn4ZVgv8gP8fPrhG7LA8Twr9uuUlVz2B8tb0pSAA==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.973.27", @@ -615,7 +615,7 @@ "node": ">=20.0.0" }, "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.1026.0" + "@aws-sdk/client-dynamodb": "^3.1028.0" } }, "node_modules/@aws-sdk/middleware-endpoint-discovery": { @@ -3052,13 +3052,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.5.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.2.tgz", - "integrity": "sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg==", + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.18.0" + "undici-types": "~7.19.0" } }, "node_modules/@types/stack-utils": { @@ -6448,9 +6448,9 @@ } }, "node_modules/prettier": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", - "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.2.tgz", + "integrity": "sha512-8c3mgTe0ASwWAJK+78dpviD+A8EqhndQPUBpNUIPt6+xWlIigCwfN01lWr9MAede4uqXGTEKeQWTvzb3vjia0Q==", "dev": true, "license": "MIT", "bin": { @@ -7335,9 +7335,9 @@ } }, "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", "dev": true, "license": "MIT" }, diff --git a/package.json b/package.json index f7ee2eb..bc8dbfb 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "@eslint/js": "10.0.1", "@types/aws-lambda": "8.10.161", "@types/jest": "30.0.0", - "@types/node": "25.5.2", + "@types/node": "25.6.0", "@typescript-eslint/eslint-plugin": "8.58.1", "@typescript-eslint/parser": "8.58.1", "eslint": "10.2.0", @@ -50,7 +50,7 @@ "globals": "17.4.0", "husky": "9.1.7", "jest": "30.3.0", - "prettier": "3.8.1", + "prettier": "3.8.2", "rimraf": "6.1.3", "ts-jest": "29.4.9", "ts-node": "10.9.2", @@ -58,10 +58,10 @@ "typescript-eslint": "8.58.1" }, "dependencies": { - "@aws-sdk/client-dynamodb": "3.1026.0", - "@aws-sdk/client-lambda": "3.1026.0", - "@aws-sdk/client-sns": "3.1026.0", - "@aws-sdk/lib-dynamodb": "3.1026.0", + "@aws-sdk/client-dynamodb": "3.1028.0", + "@aws-sdk/client-lambda": "3.1028.0", + "@aws-sdk/client-sns": "3.1028.0", + "@aws-sdk/lib-dynamodb": "3.1028.0", "@leanstacks/lambda-utils": "0.9.0", "zod": "4.3.6" }