Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save rishabhgargg/8b717c118b773f87e53a38be785c8829 to your computer and use it in GitHub Desktop.
Save rishabhgargg/8b717c118b773f87e53a38be785c8829 to your computer and use it in GitHub Desktop.
// 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