mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
fix: Security Audit SSH Errors #1377
- Fixed SSH key authentication detection in server-audit.ts - Added proper handling for prohibit-password and other secure root login options - Fixed typos in security audit UI labels - Improved error handling with optional chaining
This commit is contained in:
@@ -26,6 +26,16 @@ export const SecurityAudit = ({ serverId }: Props) => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
const _utils = api.useUtils();
|
const _utils = api.useUtils();
|
||||||
|
|
||||||
|
// Helper function to check if root login is securely configured
|
||||||
|
const isRootLoginSecure = () => {
|
||||||
|
if (!data?.ssh?.permitRootLogin) return false;
|
||||||
|
|
||||||
|
// These are secure options for PermitRootLogin
|
||||||
|
const secureOptions = ['no', 'prohibit-password', 'without-password', 'forced-commands-only'];
|
||||||
|
return secureOptions.includes(data.ssh.permitRootLogin);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CardContent className="p-0">
|
<CardContent className="p-0">
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
@@ -36,10 +46,10 @@ export const SecurityAudit = ({ serverId }: Props) => {
|
|||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<LockKeyhole className="size-5" />
|
<LockKeyhole className="size-5" />
|
||||||
<CardTitle className="text-xl">
|
<CardTitle className="text-xl">
|
||||||
Setup Security Sugestions
|
Setup Security Suggestions
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</div>
|
</div>
|
||||||
<CardDescription>Check the security sugestions</CardDescription>
|
<CardDescription>Check the security suggestions</CardDescription>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
isLoading={isRefreshing}
|
isLoading={isRefreshing}
|
||||||
@@ -120,36 +130,45 @@ export const SecurityAudit = ({ serverId }: Props) => {
|
|||||||
<div className="grid gap-2.5">
|
<div className="grid gap-2.5">
|
||||||
<StatusRow
|
<StatusRow
|
||||||
label="Enabled"
|
label="Enabled"
|
||||||
isEnabled={data?.ssh.enabled}
|
isEnabled={data?.ssh?.enabled}
|
||||||
description={
|
description={
|
||||||
data?.ssh.enabled
|
data?.ssh?.enabled
|
||||||
? "Enabled"
|
? "Enabled"
|
||||||
: "Not Enabled (SSH should be enabled)"
|
: "Not Enabled (SSH should be enabled)"
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<StatusRow
|
<StatusRow
|
||||||
label="Key Auth"
|
label="Key Auth"
|
||||||
isEnabled={data?.ssh.keyAuth}
|
isEnabled={data?.ssh?.keyAuth}
|
||||||
description={
|
description={
|
||||||
data?.ssh.keyAuth
|
data?.ssh?.keyAuth
|
||||||
? "Enabled (Recommended)"
|
? "Enabled (Recommended)"
|
||||||
: "Not Enabled (Key Authentication should be enabled)"
|
: "Not Enabled (Key Authentication should be enabled)"
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<StatusRow
|
<StatusRow
|
||||||
label="Password Auth"
|
label="Password Auth"
|
||||||
isEnabled={data?.ssh.passwordAuth === "no"}
|
isEnabled={data?.ssh?.passwordAuth === "no"}
|
||||||
description={
|
description={
|
||||||
data?.ssh.passwordAuth === "no"
|
data?.ssh?.passwordAuth === "no"
|
||||||
? "Disabled (Recommended)"
|
? "Disabled (Recommended)"
|
||||||
: "Enabled (Password Authentication should be disabled)"
|
: "Enabled (Password Authentication should be disabled)"
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<StatusRow
|
<StatusRow
|
||||||
label="Use PAM"
|
label="Root Login"
|
||||||
isEnabled={data?.ssh.usePam === "no"}
|
isEnabled={isRootLoginSecure()}
|
||||||
description={
|
description={
|
||||||
data?.ssh.usePam === "no"
|
isRootLoginSecure()
|
||||||
|
? `${data?.ssh?.permitRootLogin} (Secure)`
|
||||||
|
: `${data?.ssh?.permitRootLogin || "yes"} (Should be set to 'prohibit-password' or 'no')`
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<StatusRow
|
||||||
|
label="Use PAM"
|
||||||
|
isEnabled={data?.ssh?.usePam === "no"}
|
||||||
|
description={
|
||||||
|
data?.ssh?.usePam === "no"
|
||||||
? "Disabled (Recommended for key-based auth)"
|
? "Disabled (Recommended for key-based auth)"
|
||||||
: "Enabled (Should be disabled when using key-based auth)"
|
: "Enabled (Should be disabled when using key-based auth)"
|
||||||
}
|
}
|
||||||
@@ -166,9 +185,9 @@ export const SecurityAudit = ({ serverId }: Props) => {
|
|||||||
<div className="grid gap-2.5">
|
<div className="grid gap-2.5">
|
||||||
<StatusRow
|
<StatusRow
|
||||||
label="Installed"
|
label="Installed"
|
||||||
isEnabled={data?.fail2ban.installed}
|
isEnabled={data?.fail2ban?.installed}
|
||||||
description={
|
description={
|
||||||
data?.fail2ban.installed
|
data?.fail2ban?.installed
|
||||||
? "Installed (Recommended)"
|
? "Installed (Recommended)"
|
||||||
: "Not Installed (Fail2Ban should be installed for protection against brute force attacks)"
|
: "Not Installed (Fail2Ban should be installed for protection against brute force attacks)"
|
||||||
}
|
}
|
||||||
@@ -176,18 +195,18 @@ export const SecurityAudit = ({ serverId }: Props) => {
|
|||||||
|
|
||||||
<StatusRow
|
<StatusRow
|
||||||
label="Enabled"
|
label="Enabled"
|
||||||
isEnabled={data?.fail2ban.enabled}
|
isEnabled={data?.fail2ban?.enabled}
|
||||||
description={
|
description={
|
||||||
data?.fail2ban.enabled
|
data?.fail2ban?.enabled
|
||||||
? "Enabled (Recommended)"
|
? "Enabled (Recommended)"
|
||||||
: "Not Enabled (Fail2Ban service should be enabled)"
|
: "Not Enabled (Fail2Ban service should be enabled)"
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<StatusRow
|
<StatusRow
|
||||||
label="Active"
|
label="Active"
|
||||||
isEnabled={data?.fail2ban.active}
|
isEnabled={data?.fail2ban?.active}
|
||||||
description={
|
description={
|
||||||
data?.fail2ban.active
|
data?.fail2ban?.active
|
||||||
? "Active (Recommended)"
|
? "Active (Recommended)"
|
||||||
: "Not Active (Fail2Ban service should be running)"
|
: "Not Active (Fail2Ban service should be running)"
|
||||||
}
|
}
|
||||||
@@ -195,9 +214,9 @@ export const SecurityAudit = ({ serverId }: Props) => {
|
|||||||
|
|
||||||
<StatusRow
|
<StatusRow
|
||||||
label="SSH Protection"
|
label="SSH Protection"
|
||||||
isEnabled={data?.fail2ban.sshEnabled === "true"}
|
isEnabled={data?.fail2ban?.sshEnabled === "true"}
|
||||||
description={
|
description={
|
||||||
data?.fail2ban.sshEnabled === "true"
|
data?.fail2ban?.sshEnabled === "true"
|
||||||
? "Enabled (Recommended)"
|
? "Enabled (Recommended)"
|
||||||
: "Not Enabled (SSH protection should be enabled to prevent brute force attacks)"
|
: "Not Enabled (SSH protection should be enabled to prevent brute force attacks)"
|
||||||
}
|
}
|
||||||
@@ -205,11 +224,11 @@ export const SecurityAudit = ({ serverId }: Props) => {
|
|||||||
|
|
||||||
<StatusRow
|
<StatusRow
|
||||||
label="SSH Mode"
|
label="SSH Mode"
|
||||||
isEnabled={data?.fail2ban.sshMode === "aggressive"}
|
isEnabled={data?.fail2ban?.sshMode === "aggressive"}
|
||||||
description={
|
description={
|
||||||
data?.fail2ban.sshMode === "aggressive"
|
data?.fail2ban?.sshMode === "aggressive"
|
||||||
? "Aggressive Mode (Recommended)"
|
? "Aggressive Mode (Recommended)"
|
||||||
: `Mode: ${data?.fail2ban.sshMode || "Not Set"} (Aggressive mode recommended for better protection)`
|
: `Mode: ${data?.fail2ban?.sshMode || "Not Set"} (Aggressive mode recommended for better protection)`
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -14,13 +14,50 @@ const validateUfw = () => `
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const validateSsh = () => `
|
const validateSsh = () => `
|
||||||
if systemctl is-active --quiet sshd; then
|
if systemctl is-active --quiet sshd || systemctl is-active --quiet ssh; then
|
||||||
isEnabled=true
|
isEnabled=true
|
||||||
hasKeyAuth=$(find "$HOME/.ssh" -type f -name "authorized_keys" 2>/dev/null | grep -q . && echo true || echo false)
|
|
||||||
permitRootLogin=$(sudo sshd -T | grep -i "^PermitRootLogin" | awk '{print $2}')
|
# Get the sshd config file path
|
||||||
passwordAuth=$(sudo sshd -T | grep -i "^PasswordAuthentication" | awk '{print $2}')
|
sshd_config=$(sudo sshd -T 2>/dev/null | grep -i "^configfile" | awk '{print $2}')
|
||||||
usePam=$(sudo sshd -T | grep -i "^UsePAM" | awk '{print $2}')
|
|
||||||
echo "{\\"enabled\\": $isEnabled, \\"keyAuth\\": $hasKeyAuth, \\"permitRootLogin\\": \\"$permitRootLogin\\", \\"passwordAuth\\": \\"$passwordAuth\\", \\"usePam\\": \\"$usePam\\"}"
|
# If we couldn't get the path, use the default
|
||||||
|
if [ -z "$sshd_config" ]; then
|
||||||
|
sshd_config="/etc/ssh/sshd_config"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for key authentication
|
||||||
|
# SSH key auth is enabled by default unless explicitly disabled
|
||||||
|
pubkey_line=$(sudo grep -i "^PubkeyAuthentication" "$sshd_config" 2>/dev/null | grep -v "#")
|
||||||
|
if [ -z "$pubkey_line" ] || echo "$pubkey_line" | grep -q -i "yes"; then
|
||||||
|
keyAuth=true
|
||||||
|
else
|
||||||
|
keyAuth=false
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get the exact PermitRootLogin value from config
|
||||||
|
# This preserves values like "prohibit-password" without normalization
|
||||||
|
permitRootLogin=$(sudo grep -i "^PermitRootLogin" "$sshd_config" 2>/dev/null | grep -v "#" | awk '{print $2}')
|
||||||
|
if [ -z "$permitRootLogin" ]; then
|
||||||
|
# Default is prohibit-password in newer versions
|
||||||
|
permitRootLogin="prohibit-password"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get the exact PasswordAuthentication value from config
|
||||||
|
passwordAuth=$(sudo grep -i "^PasswordAuthentication" "$sshd_config" 2>/dev/null | grep -v "#" | awk '{print $2}')
|
||||||
|
if [ -z "$passwordAuth" ]; then
|
||||||
|
# Default is yes
|
||||||
|
passwordAuth="yes"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get the exact UsePAM value from config
|
||||||
|
usePam=$(sudo grep -i "^UsePAM" "$sshd_config" 2>/dev/null | grep -v "#" | awk '{print $2}')
|
||||||
|
if [ -z "$usePam" ]; then
|
||||||
|
# Default is yes in most distros
|
||||||
|
usePam="yes"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Return the results with exact values from config file
|
||||||
|
echo "{\\"enabled\\": $isEnabled, \\"keyAuth\\": $keyAuth, \\"permitRootLogin\\": \\"$permitRootLogin\\", \\"passwordAuth\\": \\"$passwordAuth\\", \\"usePam\\": \\"$usePam\\"}"
|
||||||
else
|
else
|
||||||
echo "{\\"enabled\\": false, \\"keyAuth\\": false, \\"permitRootLogin\\": \\"unknown\\", \\"passwordAuth\\": \\"unknown\\", \\"usePam\\": \\"unknown\\"}"
|
echo "{\\"enabled\\": false, \\"keyAuth\\": false, \\"permitRootLogin\\": \\"unknown\\", \\"passwordAuth\\": \\"unknown\\", \\"usePam\\": \\"unknown\\"}"
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user