diff --git a/docs/getting-started/AWS_REDIS_SETUP.md b/docs/getting-started/AWS_REDIS_SETUP.md new file mode 100644 index 0000000..efae8d3 --- /dev/null +++ b/docs/getting-started/AWS_REDIS_SETUP.md @@ -0,0 +1,333 @@ +# AWS ElastiCache for Redis Setup Guide + +This guide walks you through setting up Redis on AWS using ElastiCache, which is AWS's managed Redis service. + +## Prerequisites + +- AWS Account with appropriate permissions +- AWS CLI configured (optional, but helpful) +- Your application running on AWS (EC2, ECS, Lambda, etc.) +- VPC (Virtual Private Cloud) set up in AWS + +## Step-by-Step Setup + +### Step 1: Create a VPC and Subnet Group (if not already done) + +ElastiCache requires a VPC. If you don't have one: + +1. **Go to AWS Console → VPC Dashboard** +2. **Create VPC** (if needed): + - Click "Create VPC" + - Choose "VPC and more" + - Name: `your-app-vpc` + - IPv4 CIDR: `10.0.0.0/16` + - Create public and private subnets + - Enable DNS hostnames + +3. **Create Subnet Group for ElastiCache**: + - Go to **ElastiCache → Subnet Groups** + - Click "Create subnet group" + - Name: `redis-subnet-group` + - VPC: Select your VPC + - Availability Zones: Select at least 2 zones + - Subnets: Select private subnets (recommended for security) + +### Step 2: Create Security Group + +1. **Go to EC2 → Security Groups** +2. **Create Security Group**: + - Name: `redis-security-group` + - Description: `Security group for ElastiCache Redis` + - VPC: Select your VPC + - **Inbound Rules**: Add rule + - Type: `Custom TCP` + - Port: `6379` + - Source: Select your application's security group (or specific IP/CIDR) + - **Outbound Rules**: Default (All traffic) + +### Step 3: Create ElastiCache Redis Cluster + +1. **Go to AWS Console → ElastiCache** +2. **Click "Create" → Choose "Redis"** +3. **Configure Cluster Settings**: + + **Cluster Settings**: + - **Name**: `your-app-redis` (must be unique) + - **Description**: `Redis cache for rate limiting and OTP` + - **Engine version**: Latest Redis 7.x (recommended) + - **Port**: `6379` (default) + - **Parameter group**: `default.redis7` (or create custom) + + **Node Type**: + - **Node type**: Choose based on your needs: + - `cache.t3.micro` - Free tier eligible, 0.5 GB RAM + - `cache.t3.small` - 1.37 GB RAM (~$15/month) + - `cache.t3.medium` - 3.09 GB RAM (~$30/month) + - For production: `cache.t4g.medium` or larger + + **Network & Security**: + - **VPC**: Select your VPC + - **Subnet group**: Select the subnet group created in Step 1 + - **Availability Zone(s)**: + - Single AZ (cheaper, less resilient) + - Multi-AZ (recommended for production, automatic failover) + - **Security groups**: Select `redis-security-group` created in Step 2 + + **Backup & Maintenance**: + - **Automatic backups**: Enable (recommended) + - **Backup retention**: 1-7 days (your choice) + - **Backup window**: Choose low-traffic time + - **Maintenance window**: Choose low-traffic time + + **Encryption**: + - **Encryption in-transit**: Enable (recommended for production) + - **Encryption at-rest**: Enable (recommended for production) + - **Auth token**: + - **Enable**: Recommended for production + - **Auth token**: Generate a strong password (save this!) + +4. **Review and Create** + - Review all settings + - Click "Create" + +### Step 4: Wait for Cluster Creation + +- ElastiCache takes 5-15 minutes to create +- Status will change from "creating" to "available" +- Note the **Primary Endpoint** (e.g., `your-app-redis.xxxxx.cache.amazonaws.com:6379`) + +### Step 5: Configure Your Application + +Update your `.env` file with the ElastiCache endpoint: + +#### Option A: Without Auth Token (Not Recommended for Production) + +```env +REDIS_URL=redis://your-app-redis.xxxxx.cache.amazonaws.com:6379 +``` + +#### Option B: With Auth Token (Recommended) + +```env +REDIS_URL=redis://:your-auth-token@your-app-redis.xxxxx.cache.amazonaws.com:6379 +``` + +#### Option C: Using Separate Variables + +```env +REDIS_HOST=your-app-redis.xxxxx.cache.amazonaws.com +REDIS_PORT=6379 +REDIS_PASSWORD=your-auth-token +``` + +#### Option D: With SSL/TLS (If Encryption in-transit is enabled) + +```env +REDIS_URL=rediss://:your-auth-token@your-app-redis.xxxxx.cache.amazonaws.com:6379 +``` + +**Note**: `rediss://` (with double 's') indicates SSL/TLS connection. + +### Step 6: Update Security Group (If Needed) + +If your application can't connect: + +1. **Check Security Group Rules**: + - Ensure your application's security group can access port 6379 + - Or add your application's security group ID to Redis security group inbound rules + +2. **Test Connection** (from EC2 instance): + ```bash + # Install redis-cli + sudo yum install redis -y # Amazon Linux + # or + sudo apt-get install redis-tools -y # Ubuntu + + # Test connection + redis-cli -h your-app-redis.xxxxx.cache.amazonaws.com -p 6379 -a your-auth-token ping + # Should return: PONG + ``` + +### Step 7: Verify Connection + +1. **Restart your application** +2. **Check logs** for: + ``` + ✅ Redis Client: Ready + ``` +3. **If you see errors**, check: + - Security group rules + - VPC routing + - Auth token is correct + - Endpoint URL is correct + +## Cost Optimization + +### Free Tier +- AWS Free Tier includes 750 hours/month of `cache.t2.micro` or `cache.t3.micro` +- Perfect for development/testing + +### Cost-Saving Tips +1. **Use smaller instance types** for development +2. **Disable automatic backups** for non-production +3. **Use single-AZ** for development (multi-AZ costs more) +4. **Stop/Delete** clusters when not in use +5. **Reserved Instances** for production (save up to 55%) + +## High Availability Setup + +### Multi-AZ Configuration +1. **Enable Multi-AZ** during cluster creation +2. **Automatic failover** if primary node fails +3. **Read Replicas** for read scaling: + - Go to ElastiCache → Your cluster → Actions → Add replica + - Choose availability zones + - Replicas can be promoted to primary if needed + +### Cluster Mode (Redis Cluster) +For larger scale: +1. **Enable Cluster Mode** during creation +2. **Multiple shards** for horizontal scaling +3. **Automatic sharding** across nodes + +## Security Best Practices + +1. **✅ Enable Auth Token** (password authentication) +2. **✅ Enable Encryption in-transit** (SSL/TLS) +3. **✅ Enable Encryption at-rest** +4. **✅ Use Private Subnets** (not public subnets) +5. **✅ Restrict Security Groups** (only allow your application) +6. **✅ Use VPC Endpoints** (if accessing from Lambda) +7. **✅ Regular Security Updates** (AWS handles this) + +## Monitoring and Alerts + +### CloudWatch Metrics +1. **Go to ElastiCache → Your Cluster → Monitoring** +2. **Key Metrics to Monitor**: + - `CPUUtilization` - Should be < 80% + - `MemoryUtilization` - Should be < 80% + - `NetworkBytesIn/Out` - Network traffic + - `CacheHits/CacheMisses` - Cache performance + - `Evictions` - Memory pressure indicator + +### Set Up Alarms +1. **Go to CloudWatch → Alarms** +2. **Create alarms for**: + - High CPU (> 80%) + - High Memory (> 80%) + - Connection failures + - Failover events + +## Troubleshooting + +### Connection Timeout + +**Problem**: Application can't connect to Redis + +**Solutions**: +1. Check security group allows traffic from your application +2. Verify VPC routing tables +3. Ensure both are in same VPC +4. Check if endpoint URL is correct +5. Verify auth token is correct + +### Authentication Failed + +**Problem**: `NOAUTH Authentication required` or `WRONGPASS` + +**Solutions**: +1. Verify auth token in `.env` matches ElastiCache auth token +2. Check if auth token is enabled in ElastiCache +3. Use format: `redis://:password@host:port` + +### High Memory Usage + +**Problem**: Memory utilization > 90% + +**Solutions**: +1. Upgrade to larger node type +2. Enable eviction policy (already enabled by default) +3. Review what data is stored in Redis +4. Set TTL on keys (your code already does this) + +### Slow Performance + +**Problem**: High latency or slow responses + +**Solutions**: +1. Check CPU utilization +2. Enable read replicas for read-heavy workloads +3. Upgrade node type +4. Check network latency (use same region as application) +5. Monitor `CacheHits` vs `CacheMisses` ratio + +## Alternative: AWS MemoryDB for Redis + +For even higher durability (data persisted to disk): + +1. **Go to MemoryDB** (separate service) +2. **Similar setup** to ElastiCache +3. **Better durability** (multi-AZ with automatic failover) +4. **Higher cost** than ElastiCache +5. **Use when**: Data persistence is critical + +## Alternative: Self-Hosted on EC2 + +If you prefer more control: + +1. **Launch EC2 instance** (Amazon Linux or Ubuntu) +2. **Install Redis**: + ```bash + sudo yum install redis -y # Amazon Linux + sudo systemctl start redis + sudo systemctl enable redis + ``` +3. **Configure security group** (port 6379) +4. **Set up Redis password** in `/etc/redis.conf` +5. **Use EC2 private IP** in your `.env` + +**Note**: You'll need to manage backups, updates, and scaling yourself. + +## Quick Reference + +### Get Endpoint URL +```bash +aws elasticache describe-cache-clusters \ + --cache-cluster-id your-app-redis \ + --show-cache-node-info \ + --query 'CacheClusters[0].CacheNodes[0].Endpoint.Address' +``` + +### Get Auth Token +- Go to ElastiCache → Your Cluster → Configuration +- Auth token is shown (or set during creation) + +### Update Auth Token +1. Go to ElastiCache → Your Cluster +2. Actions → Modify +3. Change auth token +4. Apply immediately or schedule + +### Delete Cluster +1. Go to ElastiCache → Your Cluster +2. Actions → Delete +3. Confirm deletion +4. **Warning**: This deletes all data! + +## Next Steps + +1. ✅ Create ElastiCache Redis cluster +2. ✅ Update `.env` with endpoint and auth token +3. ✅ Update security groups +4. ✅ Restart application +5. ✅ Verify connection: `✅ Redis Client: Ready` +6. ✅ Set up CloudWatch alarms +7. ✅ Monitor performance + +## Support + +- **AWS Documentation**: https://docs.aws.amazon.com/elasticache/ +- **AWS Support**: AWS Console → Support Center +- **Pricing Calculator**: https://calculator.aws/ + diff --git a/docs/getting-started/REDIS_SETUP.md b/docs/getting-started/REDIS_SETUP.md index 4d4c147..2963b5b 100644 --- a/docs/getting-started/REDIS_SETUP.md +++ b/docs/getting-started/REDIS_SETUP.md @@ -53,10 +53,12 @@ REDIS_URL=redis://localhost:6379 ### Option 3: Use Cloud Redis (Production) For production, use a managed Redis service: -- **AWS ElastiCache**: `redis://your-elasticache-endpoint:6379` +- **AWS ElastiCache**: `redis://your-elasticache-endpoint:6379` - [📖 Complete AWS Setup Guide](./AWS_REDIS_SETUP.md) - **Redis Cloud**: `redis://user:password@redis-cloud-host:6379` - **Azure Cache for Redis**: `redis://your-cache.redis.cache.windows.net:6380?ssl=true` +**For AWS deployments, see the detailed guide**: [AWS Redis Setup Guide](./AWS_REDIS_SETUP.md) + Add to your `.env` file: ```env diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json index 20b69ab..6d92e68 100644 --- a/node_modules/.package-lock.json +++ b/node_modules/.package-lock.json @@ -2206,12 +2206,12 @@ } }, "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.3.tgz", + "integrity": "sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==", "license": "MIT", "dependencies": { - "jwa": "^1.4.1", + "jwa": "^1.4.2", "safe-buffer": "^5.0.1" } }, diff --git a/node_modules/jws/CHANGELOG.md b/node_modules/jws/CHANGELOG.md index af8fc28..58d77c8 100644 --- a/node_modules/jws/CHANGELOG.md +++ b/node_modules/jws/CHANGELOG.md @@ -1,8 +1,20 @@ # Change Log + All notable changes to this project will be documented in this file. -## [3.0.0] +## [3.2.3] + ### Changed + +- Fix advisory GHSA-869p-cjfg-cm3x: createSign and createVerify now require + that a non empty secret is provided (via opts.secret, opts.privateKey or opts.key) + when using HMAC algorithms. +- Upgrading JWA version to 1.4.2, adressing a compatibility issue for Node >= 25. + +## [3.0.0] + +### Changed + - **BREAKING**: `jwt.verify` now requires an `algorithm` parameter, and `jws.createVerify` requires an `algorithm` option. The `"alg"` field signature headers is ignored. This mitigates a critical security flaw @@ -12,7 +24,9 @@ All notable changes to this project will be documented in this file. for details. ## [2.0.0] - 2015-01-30 + ### Changed + - **BREAKING**: Default payload encoding changed from `binary` to `utf8`. `utf8` is a is a more sensible default than `binary` because many payloads, as far as I can tell, will contain user-facing @@ -21,14 +35,13 @@ All notable changes to this project will be documented in this file. - Code reorganization, thanks [@fearphage]! ([7880050]) ### Added + - Option in all relevant methods for `encoding`. For those few users that might be depending on a `binary` encoding of the messages, this is for them. ([6b6de48]) [unreleased]: https://github.com/brianloveswords/node-jws/compare/v2.0.0...HEAD [2.0.0]: https://github.com/brianloveswords/node-jws/compare/v1.0.1...v2.0.0 - [7880050]: https://github.com/brianloveswords/node-jws/commit/7880050 [6b6de48]: https://github.com/brianloveswords/node-jws/commit/6b6de48 - [@fearphage]: https://github.com/fearphage diff --git a/node_modules/jws/lib/sign-stream.js b/node_modules/jws/lib/sign-stream.js index 6a7ee42..4a7b288 100644 --- a/node_modules/jws/lib/sign-stream.js +++ b/node_modules/jws/lib/sign-stream.js @@ -34,7 +34,12 @@ function jwsSign(opts) { } function SignStream(opts) { - var secret = opts.secret||opts.privateKey||opts.key; + var secret = opts.secret; + secret = secret == null ? opts.privateKey : secret; + secret = secret == null ? opts.key : secret; + if (/^hs/i.test(opts.header.alg) === true && secret == null) { + throw new TypeError('secret must be a string or buffer or a KeyObject') + } var secretStream = new DataStream(secret); this.readable = true; this.header = opts.header; diff --git a/node_modules/jws/lib/verify-stream.js b/node_modules/jws/lib/verify-stream.js index 39f7c73..bb1cb00 100644 --- a/node_modules/jws/lib/verify-stream.js +++ b/node_modules/jws/lib/verify-stream.js @@ -79,7 +79,12 @@ function jwsDecode(jwsSig, opts) { function VerifyStream(opts) { opts = opts || {}; - var secretOrKey = opts.secret||opts.publicKey||opts.key; + var secretOrKey = opts.secret; + secretOrKey = secretOrKey == null ? opts.publicKey : secretOrKey; + secretOrKey = secretOrKey == null ? opts.key : secretOrKey; + if (/^hs/i.test(opts.algorithm) === true && secretOrKey == null) { + throw new TypeError('secret must be a string or buffer or a KeyObject') + } var secretStream = new DataStream(secretOrKey); this.readable = true; this.algorithm = opts.algorithm; diff --git a/node_modules/jws/package.json b/node_modules/jws/package.json index 3fb2837..033f96e 100644 --- a/node_modules/jws/package.json +++ b/node_modules/jws/package.json @@ -1,6 +1,6 @@ { "name": "jws", - "version": "3.2.2", + "version": "3.2.3", "description": "Implementation of JSON Web Signatures", "main": "index.js", "directories": { @@ -24,7 +24,7 @@ "readmeFilename": "readme.md", "gitHead": "c0f6b27bcea5a2ad2e304d91c2e842e4076a6b03", "dependencies": { - "jwa": "^1.4.1", + "jwa": "^1.4.2", "safe-buffer": "^5.0.1" }, "devDependencies": { diff --git a/package-lock.json b/package-lock.json index 259a653..c5e376e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2240,12 +2240,12 @@ } }, "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.3.tgz", + "integrity": "sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==", "license": "MIT", "dependencies": { - "jwa": "^1.4.1", + "jwa": "^1.4.2", "safe-buffer": "^5.0.1" } },