Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion packages/web/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ async function initializeRedisClient(): Promise<RedisClientType> {
console.log(`AWS Region: ${awsRegion}`);
console.log('TLS encryption: ENABLED (required for IAM auth)');

// Verify AWS credentials/identity being used
console.log('Verifying AWS identity...');
try {
const { fromNodeProviderChain } = await import('@aws-sdk/credential-providers');
const credentialProvider = fromNodeProviderChain();
const credentials = await credentialProvider();
console.log(`Using AWS AccessKeyId: ${credentials.accessKeyId.substring(0, 10)}...`);
} catch (error) {
console.error('Failed to get AWS credentials:', error);
}

// Generate initial IAM auth token
console.log('Generating IAM authentication token...');
const token = await generateIAMAuthToken(host, port, username, awsRegion, isServerless);
Expand Down Expand Up @@ -343,7 +354,23 @@ async function start() {

} catch (error) {
console.error('Failed to start server:', error);
process.exit(1);

// In development/sandbox, allow app to start without Redis for debugging
if (process.env.ALLOW_STARTUP_WITHOUT_REDIS === 'true') {
console.warn('⚠️ ALLOW_STARTUP_WITHOUT_REDIS=true: Starting server despite connection failure');
console.warn('⚠️ Shopping cart functionality will NOT work');

// Start server without Redis
const server = app.listen(PORT, () => {
console.log(`Web server running on port ${PORT} (WITHOUT REDIS)`);
console.log(`API URL: ${process.env.API_URL || 'http://localhost:3000'}`);
});

process.on('SIGTERM', () => server.close());
process.on('SIGINT', () => server.close());
} else {
process.exit(1);
}
}
}

Expand Down
30 changes: 29 additions & 1 deletion packages/web/src/utils/elasticache-iam-auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ export async function generateIAMAuthToken(
const credentialProvider = fromNodeProviderChain();
const credentials = await credentialProvider();

// Log credential details for debugging (not the actual secrets)
console.log(`[IAM Token Debug] Using AWS credentials - AccessKeyId: ${credentials.accessKeyId.substring(0, 10)}...`);
if (credentials.sessionToken) {
console.log(`[IAM Token Debug] Session token present: ${credentials.sessionToken.substring(0, 20)}...`);
}

// Auto-detect if this is a serverless cache based on endpoint
const detectServerless = isServerless !== undefined
? isServerless
Expand Down Expand Up @@ -86,5 +92,27 @@ export async function generateIAMAuthToken(

// Strip the http:// prefix and return
// ElastiCache expects just the signed string, not the full URL
return signedUrl.toString().replace('http://', '');
const token = signedUrl.toString().replace('http://', '');

// Log token details for debugging
console.log(`[IAM Token Debug] Endpoint: ${endpoint}`);
console.log(`[IAM Token Debug] Serverless: ${detectServerless}`);
console.log(`[IAM Token Debug] Username: ${username}`);
console.log(`[IAM Token Debug] Token length: ${token.length}`);
console.log(`[IAM Token Debug] Full token: ${token}`);

// Parse and log query parameters for verification
try {
const tokenUrl = new URL('http://' + token);
console.log(`[IAM Token Debug] Query params:`);
tokenUrl.searchParams.forEach((value, key) => {
if (key === 'User' || key === 'Action' || key === 'ResourceType') {
console.log(` ${key}=${value}`);
}
});
} catch (e) {
console.error(`[IAM Token Debug] Failed to parse token as URL:`, e);
}

return token;
}