mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-07-07 15:05:23 +02:00
fix(backup): redact S3 credentials from logs and error output (#4648)
* fix(backup): redact S3 credentials from logs and error output (#4621) S3 backup credentials (access key + secret) were logged in plaintext to Dokploy service stdout via logger.info in getBackupCommand() and console.error in keepLatestNBackups(). Any operator with access to service logs could recover S3 credentials. Added redactRcloneCredentials() pure function that masks --s3-access-key-id and --s3-secret-access-key values with [REDACTED]. Applied to both the structured logger call and the error handler. Closes #4621 * fix(backups): redact sensitive information in error logs during web server backup process Updated error handling in the web server backup function to redact Rclone credentials from error messages before logging and notification. This change enhances security by preventing sensitive data exposure in logs. --------- Co-authored-by: Mauricio Siu <siumauricio@icloud.com>
This commit is contained in:
committed by
GitHub
parent
38de9ef218
commit
f8a3561f1e
@@ -11,6 +11,7 @@ import { startLogCleanup } from "../access-log/handler";
|
||||
import { cleanupAll } from "../docker/utils";
|
||||
import { sendDockerCleanupNotifications } from "../notifications/docker-cleanup";
|
||||
import { execAsync, execAsyncRemote } from "../process/execAsync";
|
||||
import { redactRcloneCredentials } from "./redact";
|
||||
import { getS3Credentials, normalizeS3Path, scheduleBackup } from "./utils";
|
||||
|
||||
export const initCronJobs = async () => {
|
||||
@@ -153,6 +154,6 @@ export const keepLatestNBackups = async (
|
||||
await execAsync(rcloneCommand);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
console.error(redactRcloneCredentials(String(error)));
|
||||
}
|
||||
};
|
||||
|
||||
12
packages/server/src/utils/backups/redact.ts
Normal file
12
packages/server/src/utils/backups/redact.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Redacts S3 credentials from rclone command strings.
|
||||
*
|
||||
* Used to prevent credential leakage in structured logs and error output.
|
||||
* Matches the flag format produced by `getS3Credentials()`:
|
||||
* --s3-access-key-id="VALUE" and --s3-secret-access-key="VALUE"
|
||||
*/
|
||||
export const redactRcloneCredentials = (command: string): string => {
|
||||
return command
|
||||
.replace(/(--s3-access-key-id=)"[^"]*"/g, '$1"[REDACTED]"')
|
||||
.replace(/(--s3-secret-access-key=)"[^"]*"/g, '$1"[REDACTED]"');
|
||||
};
|
||||
@@ -9,6 +9,7 @@ import { runMariadbBackup } from "./mariadb";
|
||||
import { runMongoBackup } from "./mongo";
|
||||
import { runMySqlBackup } from "./mysql";
|
||||
import { runPostgresBackup } from "./postgres";
|
||||
import { redactRcloneCredentials } from "./redact";
|
||||
import { runWebServerBackup } from "./web-server";
|
||||
|
||||
export const scheduleBackup = (backup: BackupSchedule) => {
|
||||
@@ -262,7 +263,7 @@ export const getBackupCommand = (
|
||||
{
|
||||
containerSearch,
|
||||
backupCommand,
|
||||
rcloneCommand,
|
||||
rcloneCommand: redactRcloneCredentials(rcloneCommand),
|
||||
logPath,
|
||||
},
|
||||
`Executing backup command: ${backup.databaseType} ${backup.backupType}`,
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
import { findDestinationById } from "@dokploy/server/services/destination";
|
||||
import { sendDokployBackupNotifications } from "../notifications/dokploy-backup";
|
||||
import { execAsync } from "../process/execAsync";
|
||||
import { redactRcloneCredentials } from "./redact";
|
||||
import { getBackupTimestamp, getS3Credentials, normalizeS3Path } from "./utils";
|
||||
|
||||
function formatBytes(bytes?: number) {
|
||||
@@ -113,20 +114,23 @@ export const runWebServerBackup = async (backup: BackupSchedule) => {
|
||||
try {
|
||||
await rm(tempDir, { recursive: true, force: true });
|
||||
} catch (cleanupError) {
|
||||
console.error("Cleanup error:", cleanupError);
|
||||
console.error(
|
||||
"Cleanup error:",
|
||||
redactRcloneCredentials(String(cleanupError)),
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Backup error:", error);
|
||||
writeStream.write("Backup error❌\n");
|
||||
writeStream.write(
|
||||
error instanceof Error ? error.message : "Unknown error\n",
|
||||
const safeErrorMessage = redactRcloneCredentials(
|
||||
error instanceof Error ? error.message : String(error),
|
||||
);
|
||||
console.error("Backup error:", redactRcloneCredentials(String(error)));
|
||||
writeStream.write("Backup error❌\n");
|
||||
writeStream.write(`${safeErrorMessage}\n`);
|
||||
writeStream.end();
|
||||
await sendDokployBackupNotifications({
|
||||
type: "error",
|
||||
// @ts-ignore
|
||||
errorMessage: error?.message || "Error message not provided",
|
||||
errorMessage: safeErrorMessage || "Error message not provided",
|
||||
backupSize: formatBytes(computedBackupSize),
|
||||
});
|
||||
await updateDeploymentStatus(deployment.deploymentId, "error");
|
||||
|
||||
Reference in New Issue
Block a user