通过在脚本中修改/ etc / ssh / sshd_conf来禁用ssh root登录?

时间:2016-03-17 20:00:12

标签: bash shell ssh

再次是我。

非常感谢,所有极好的提示和提示都非常有用!也许你可能有心情把我的屁股踢到另一个障碍......

在设置我的Raspberries的过程中,我想通过ssh阻止root登录。与往常一样,它是一个“小脚本”(由跑步者召集)。

我的研究告诉我,即使在systemd时,/ etc / ssh / sshd_config也是要修改的文件。到现在为止还挺好。在我的谦虚理解中,需要做的是:逐行读取配置文件,匹配“PermitRootLogin yes”(空白匹配);如果不匹配,则将该行写入另一个文件,如果是,则将其替换为“PermitRootLogin no”,并写入另一个文件,最后用新文件替换原始配置文件,并通过systemd stuff重新启动sshd。 / p>

在Perl中,我读取整个文件,替换()行,并将东西写回另一个文件。但正如年轻的佛教徒所说:“没有Perl!”

仅限Bash(2)。

并且,一如既往地提前感谢!

的Carsten

7 个答案:

答案 0 :(得分:3)

以编程方式配置SSH

我对此进行了一些调查,我认为JNevevill的回答是最可靠的。 我有一些示例脚本说明了SEDAWK这两种方式。

准备

在示例中仅显示测试数据一次以提高可读性。每种方法都已使用相同的方式对其进行了初始化。它将在测试文件中定义一些规则,并提供新规则的字典,这些规则应替换文件中的规则或写入文件。

echo 'LoginGraceTime 120' > ./data.txt
echo '#PermitRootLogin yes' >> ./data.txt
echo 'PermitRootLogin no' >> ./data.txt
echo 'PasswordAuthentication yes' >> ./data.txt

declare -A rules=( 
    ["LoginGraceTime"]="1m"
    ["PermitRootLogin"]="no"
    ["PasswordAuthentication"]="no"
    ["AllowUsers"]="blue"
)

SED

SED将替换找到的规则。如果一行被注释,它将删除# 并替换该值。这种方法不太可靠,因为它可能导致重复的规则。即存在注释和未注释的规则。另外,如果不存在该规则,则根本不会编写该规则。

for rule in "${!rules[@]}"; do
  regex="s/#\?\(${rule}\s*\).*$/\1 ${rules[${rule}]}/"
  sed "${regex}" ./data.txt > temp.txt;
  mv -f temp.txt ./data.txt
done

结果:

LoginGraceTime  1m
PermitRootLogin  no
PermitRootLogin  no
PasswordAuthentication  no

AWK

AWK在这种情况下会更可靠。它产生更好的控制。 它将逐行读取并替换该值(如果存在)而不更改注释规则。如果在文件末尾没有找到规则,它将把该规则附加到文件中。这比SED方法更可靠。我们可以确定不会有重复的规则,并且所有规则都已定义。

for rule in "${!rules[@]}"; do
awk -v key="${rule}" -v val="${rules[${rule}]}" \
  '$1==key {foundLine=1; print key " " val} $1!=key{print $0} END{if(foundLine!=1) print key " " val}' \
  ./data.txt > sshd_config.tmp && mv sshd_config.tmp ./data.txt
done

结果:

LoginGraceTime 1m
#PermitRootLogin yes
PermitRootLogin no
PasswordAuthentication no
AllowUsers blue

结论

AWK显然是更好的选择。这样更安全,可以处理文件中未包含的规则。

答案 1 :(得分:2)

脚本:

$ sed -i 's/PermitRootLogin yes/PermitRootLogin no/g' /etc/ssh/sshd_config

然后:

$ service ssh reload

答案 2 :(得分:1)

如果你有GNU sed 4.2.2,你可以使用以下技巧:

sed -z 's/PermitRootLogin yes\|$/PermitRootLogin no/' file

-z将读取由NUL(\0)分隔的行,因此基本上在sed中启用slurp模式

-i将对您的文件进行现场编辑,因此请记住在使用它之前进行备份

替换很简单:

PermitRootLogin yes替换为PermitRootLogin no,如果找不到,请将PermitRootLogin no追加到最后。

您可以在搜索周围添加字词边界:\<PermitRootLogin yes\>

请注意,如果PermitRootLogin yes未匹配,则省略了跟踪换行符,因为PermitRootLogin no将在最后一个换行符后插入。

答案 3 :(得分:1)

你可以做那样的事情

#!/bin/bash
if [[ "${UID}" -ne 0 ]]; then
    echo " You need to run this script as root"
    exit 1
fi

#To directly modify sshd_config.

sed -i 's/#\?\(Port\s*\).*$/\1 2231/' /etc/ssh/sshd_config
sed -i 's/#\?\(PerminRootLogin\s*\).*$/\1 no/' /etc/ssh/sshd_config
sed -i 's/#\?\(PubkeyAuthentication\s*\).*$/\1 yes/' /etc/ssh/sshd_config
sed -i 's/#\?\(PermitEmptyPasswords\s*\).*$/\1 no/' /etc/ssh/sshd_config
sed -i 's/#\?\(PasswordAuthentication\s*\).*$/\1 no/' /etc/ssh/sshd_config

#Check the exit status of the last command

if [[ "${?}" -ne 0 ]]; then
   echo "The sshd_config file was not modified successfully"
   exit 1
fi
/etc/init.d/ssh restart

exit 0

答案 4 :(得分:0)

您可以使用awk

awk '$1=="PermitRootLogin"{foundLine=1; print "PermitRootLogin no"} $1!="PermitRootLogin"{print $0} END{if(foundLine!=1) print "permitRootLogin no"}' sshd_config > sshd_config.tmp && mv sshd_config.tmp sshd_config

如果第一个元素(由awk的默认delim分隔)是“PermitRootLogin”然​​后将其更改为“no”并捕获您找到它,则遍历文件中的每一行。如果该行不包含“PermitRootLogin”,则按原样将其写出。如果在处理完所有行(END)后没有找到“PermitRootLogin”,则写入该行。

答案 5 :(得分:0)

@cyrus:

我当前的脚本如下所示:

#!/bin/bash

touch /tmp/sshd_config
while read -r line || [[ -n "$line" ]]; do
    if [ "$line" = "PermitRootLogin yes" ]; then
        match=1
        echo "PermitRootLogin no" >> /tmp/sshd_config
    else
        echo "$line" >> /tmp/sshd_config
    fi
done < /etc/ssh/sshd_config

if [ "$match" != "1" ]; then
    echo "PermitRootLogin no" >> /tmp/sshd_config
fi

它有效,但看起来很糟糕。我更喜欢更多的\ s +'ish样式来捕获“PermitRootLogin(manySpaces)yes”和“PermitRootLogin(tabTabTab)yes”行。使用'grep'的方法肯定会更好。

到目前为止已经回答并提到sed和awk的任何人:你的提案中有三​​个警告。 1:我,因为我不是发行版的维护者,不能保证将安装一个或两个。 2:我不知道是否有人想要修改我的脚本是sed和/或awk破解。 3:我可以保证,除了sed和awk是华丽的,令人敬畏的,优雅的工具来处理这些东西之外,我对sed和awk完全不了解。是的,这是一个令人羞辱的差距。

====== 后脚本......

在玩了一下并在原始剧本中找到一个丑陋的警告之后,这是我当前的版本:

#!/bin/bash

INFILE=/etc/ssh/sshd_config
TMPFILE=/var/tmp/sshd_config

touch $TMPFILE

while read -r line || [[ -n "$line" ]]; do
    if [ `echo "$line" | grep -c -P "^\s*PermitRootLogin\s+"` = "1" ]; then
        match=1
        echo "PermitRootLogin no" >> $TMPFILE
    else
        echo "$line" >> $TMPFILE
    fi
done < $INFILE

if [ "$match" != "1" ]; then
    echo "" >> $TMPFILE
    echo "# Do not permit root to log in directly" >> $TMPFILE
    echo "PermitRootLogin no" >> $TMPFILE
fi

cp -f $TMPFILE $INFILE
sync

与旧版本的不同之处在于,从简单比较到grep的变化,但是pcre确实是必要的。如果未来的发行版附带“PermitRootLogin no”,则前一版本将为配置添加至少不必要的条目。另一个漂亮的事情是,另一行的配置文件在注释中包含“PermitRootLogin yes”。一个简单的grep -c -P“PermitRootLogin \ s + yes”就会匹配(再次)。

新版本仍然看起来笨拙和丑陋,但它有效:)

答案 6 :(得分:0)

这可以进一步简化为一些线性脚本,您可以在其中传递要更改的变量,并且可以随时为您更改。检查各种语法,并确保最终结果都完美完成。

也可以转换为交换机

致用户脚本

replace_string.sh sshd_config.old PasswordAuthentication PermitRootLogin

我的脚本看起来像这样


#! /bin/bash 
sshd_config_file=$1

search_replace() 
{
grep -i "^${search_string} yes$" ${sshd_config_file} | grep -v "^#"|grep -v "${search_string} no" || sed -i "" "s|^#*${search_string}.*$|${search_string} yes|" ${sshd_config_file} 
}

#for search_string in $@; do 
for search_string in $(eval echo ${*:2}); do 
  search_replace
done