Created
April 7, 2025 10:11
-
-
Save rishabhgargg/8b717c118b773f87e53a38be785c8829 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Use 'aws-sdk' and 'pg' as strings in require | |
const AWS = require('aws-sdk'); | |
const { Client } = require('pg'); | |
exports.handler = async (event) => { | |
// Use comma to separate arguments in console.log | |
console.log('Lambda event:', JSON.stringify(event)); | |
const secretName = process.env.SECRET_NAME; | |
const dbHost = process.env.DB_HOST; | |
const dbName = process.env.DB_NAME; | |
const iamUser = process.env.IAM_USER; // Example: 'my_iam_user' | |
// Basic validation/sanitization for iamUser to prevent SQL injection | |
// Adjust regex as needed for valid PostgreSQL identifier characters | |
if (!iamUser || !/^[a-zA-Z_][a-zA-Z0-9_$-]*$/.test(iamUser)) { | |
console.error('Invalid or potentially unsafe iamUser provided:', iamUser); | |
return { | |
statusCode: 400, // Bad Request | |
body: JSON.stringify({ | |
message: 'Invalid iamUser format provided.', | |
}), | |
}; | |
} | |
// Use double quotes for PostgreSQL identifiers to handle potential reserved words or special chars | |
const safeIamUserIdentifier = `"${iamUser.replace(/"/g, '""')}"`; // Escape double quotes within the identifier | |
// Log environment variables (be cautious not to log sensitive info) | |
console.log('Using environment variables:', { secretName, dbHost, dbName, iamUser }); | |
const sm = new AWS.SecretsManager(); | |
let secret; | |
try { | |
secret = await sm.getSecretValue({ SecretId: secretName }).promise(); | |
console.log('Successfully retrieved secret from SecretsManager.'); | |
} catch (error) { | |
console.error( | |
'Error retrieving secret from SecretsManager:', | |
error.message, | |
error.stack | |
); | |
return { | |
statusCode: 500, | |
body: JSON.stringify({ | |
message: 'Error retrieving secret: ' + error.message, | |
}), | |
}; | |
} | |
let creds; | |
try { | |
creds = JSON.parse(secret.SecretString); | |
console.log('Parsed credentials from secret.'); | |
} catch (error) { | |
console.error('Error parsing secret JSON:', error.message, error.stack); | |
return { | |
statusCode: 500, | |
body: JSON.stringify({ | |
message: 'Error parsing secret JSON: ' + error.message, | |
}), | |
}; | |
} | |
const masterUser = creds.username; | |
const masterPwd = creds.password; | |
const client = new Client({ | |
host: dbHost, | |
database: dbName, | |
user: masterUser, | |
password: masterPwd, | |
// Consider enabling SSL verification in production for security | |
// ssl: { rejectUnauthorized: true, ca: /* provide CA cert if needed */ }, | |
ssl: { rejectUnauthorized: false }, // Use with caution, less secure | |
}); | |
try { | |
console.log('Attempting to connect to the database at', dbHost); | |
await client.connect(); | |
console.log('Database connection successful.'); | |
} catch (error) { | |
console.error( | |
'Error connecting to the database:', | |
error.message, | |
error.stack | |
); | |
return { | |
statusCode: 500, | |
body: JSON.stringify({ | |
message: 'Database connection error: ' + error.message, | |
}), | |
}; | |
} | |
try { | |
console.log('Attempting to create user:', safeIamUserIdentifier); | |
// Use the sanitized and quoted identifier | |
await client.query(`CREATE USER ${safeIamUserIdentifier} WITH LOGIN`); | |
console.log('User created successfully.'); | |
} catch (error) { | |
// Check if the error is because the role already exists (PostgreSQL error code 42710) | |
if (error.code === '42710') { | |
console.warn(`User ${safeIamUserIdentifier} already exists.`); | |
} else { | |
console.error( | |
'User creation failed:', | |
error.message, | |
error.stack | |
); | |
// Optionally, you might want to stop execution here if user creation fails for other reasons | |
} | |
} | |
try { | |
console.log('Attempting to grant rds_iam to user:', safeIamUserIdentifier); | |
// Use the sanitized and quoted identifier | |
await client.query(`GRANT rds_iam TO ${safeIamUserIdentifier}`); | |
console.log('Role granted successfully.'); | |
} catch (error) { | |
console.error('Error granting role to user:', error.message, error.stack); | |
// Optionally, handle specific grant errors | |
} | |
try { | |
console.log('Check existing roles/user in db'); | |
// Add a valid SQL query here | |
const queryText = ` | |
SELECT r.rolname, r.rolsuper, r.rolinherit, | |
r.rolcreaterole, r.rolcreatedb, r.rolcanlogin, | |
r.rolconnlimit, r.rolvaliduntil, | |
ARRAY(SELECT b.rolname | |
FROM pg_catalog.pg_auth_members m | |
JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid) | |
WHERE m.member = r.oid) as memberof | |
FROM pg_catalog.pg_roles r | |
WHERE r.rolname = $1 OR r.rolname = 'rds_iam' -- Check specific user and rds_iam role | |
ORDER BY 1; | |
`; | |
// Parameterize where possible (like in WHERE clause) | |
const result = await client.query(queryText, [iamUser]); // Use original iamUser here for the WHERE clause value | |
console.log(`Check complete. Found ${result.rows.length} relevant roles/users:`); | |
console.table(result.rows); // Display the captured rows | |
} catch (error) { | |
console.error('Error during check roles/users:', error.message, error.stack); | |
} | |
try { | |
await client.end(); | |
console.log('Database connection closed.'); | |
} catch (error) { | |
console.error( | |
'Error closing database connection:', | |
error.message, | |
error.stack | |
); | |
} | |
// Return a safe success message. DO NOT include credentials. | |
return { | |
statusCode: 200, | |
body: JSON.stringify({ | |
message: `IAM user processing for ${iamUser} completed. Check logs for details.` | |
}), | |
}; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment