一、前言
最近给linux配置只允许sftp传输文件的账号,想支持账密连接和秘钥连接两种方法。
账密连接方法之前的文章总结过了,没想到配置秘钥连接又踩一个大坑:
bash
Permission denied (publickey,gssapi-keyex,gssapi-with-mic)
在此总结下解决方法和完整流程。
二、步骤
1.目标
准备给linux服务器创建一个用户,名字叫sftpuser,这个账户只能用来sftp传输文件,不能登录系统,并且支持账号密码和秘钥两种连接方法。
2.创建用户目录
bash
#这个当做用户目录
sudo mkdir -p /home/sftp/sftpuser
3.创建用户,指定用户目录
bash
# 创建用户 sftpuser,指定 home
sudo useradd -m -d /home/sftp/sftpuser -s /usr/sbin/nologin sftpuser
PS:其中,nologin意思是这个用户不允许ssh登录。
如果允许用户登录,就这样写:sudo useradd -m -d /home/sftp/sftpuser -s /bin/bash sftpuser
4.设置用户密码
bash
sudo passwd sftpuser
这个是给sftpuser用户设置密码,输入后会提示你输入两次新密码。
5. 给用户目录配置权限(注意权限)
bash
#home目录应该都有,不用动
#sudo chown root:root /home
#sudo chmod 755 /home
#sftp目录属于root
sudo chown root:root /home/sftp
#sftp目录权限755
sudo chmod 755 /home/sftp
#sftpuser目录属于root
sudo chown root:root /home/sftp/sftpuser
#sftpuser目录权限755
sudo chmod 755 /home/sftp/sftpuser
这里设置父目录sftp与子目录sftpuser属于root用户,权限是755。
根目录下一般都有home文件夹,不用设置。(如果没有,也可以设置属于root用户,755)
6.创建这个用户的文件上传下载目录(注意权限)
bash
#这个当做可以上传下载文件的目录
sudo mkdir -p /home/sftp/sftpuser/data
sudo chown root:root /home/sftp/sftpuser/data
sudo chmod 755 /home/sftp/sftpuser/data
这里多创建了一个data目录,准备用来当登录sftp时的根目录。(也就是登录sftp后,看到的是根目录,但是其实文件在这个data里)
7.创建公钥文件夹与文件(注意权限)
(1)首先确认下,用户home地址对不对
bash
cat /etc/passwd | grep sftpuser
显示如下:
bash
sftpuser:x:1001:1001::/home/sftp/sftpuser:/usr/sbin/nologin
这样就说明,用户sftpuser的home地址是/home/sftp/sftpuser,没有问题。
(2)创建公钥文件夹与文件(注意权限)
bash
#创建文件夹
sudo mkdir -p /home/sftp/sftpuser/.ssh
#创建文件
sudo touch /home/sftp/sftpuser/.ssh/authorized_keys
#权限
sudo chown sftpuser:sftpuser /home/sftp/sftpuser/.ssh
sudo chmod 700 /home/sftp/sftpuser/.ssh
#权限
sudo chown sftpuser:sftpuser /home/sftp/sftpuser/.ssh/authorized_keys
sudo chmod 600 /home/sftp/sftpuser/.ssh/authorized_keys
这一步在sftpuser用户的home目录下创建了.ssh文件夹(没有自动生成就自己手动创建);
然后创建了authorized_keys文件,目前是空的,一会把公钥内容放进去。
(3)创建公钥私钥
在linux服务器上执行命令:
bash
ssh-keygen -t rsa -b 4096
然后会让你输入秘钥生成位置,可以写./,生成在当前目录,防止找不到;
还会提示是否要给秘钥设置密码,设置也可以,不设置就直接回车为空,没有密码;
然后就会默认生成两个文件:
bash
id_rsa ← 私钥
id_rsa.pub ← 公钥
私钥用来自己登录用,公钥需要配置到authorized_keys文件里。
(4)配置公钥
首先看下公钥内容:
bash
cat id_rsa.pub
然后可以复制内容,使用vi命令,写到authorized_keys文件里。
bash
sudo vi /home/sftp/sftpuser/.ssh/authorized_keys
进去后按a,开启编辑模式
然后右键鼠标黏贴(这个文件可以配置多行公钥)
然后按ESC
输入:wq
按回车,保存退出
配置完毕后,后续就可以用对应的私钥登录了。
8.配置账号信息
使用命令:
bash
sudo vi /etc/ssh/sshd_config
编辑sshd配置文件。
注意,要在最下方输入:
bash
Match User sftpuser
ChrootDirectory /home/sftp/%u/data
ForceCommand internal-sftp
PasswordAuthentication yes
RSAAuthentication yes
PubkeyAuthentication yes
AllowAgentForwarding no
X11Forwarding no
PermitTunnel no
AllowTcpForwarding no
输入完成后保存退出vi。
这个配置文件的信息是,匹配用户sftpuser,下方配置对这个用户生效;
ChrootDirectory 是设置用户sftp文件根目录,以data作为根目录;
PasswordAuthentication 是允许该用户用密码登录(如果不允许就写no)
RSAAuthentication 和PubkeyAuthentication 是允许该用户用RSA秘钥和秘钥登录(如果不允许就写no)
ForceCommand 是设置了仅允许sftp命令连接。(根据需要调整;不过注意,除了这个地方的限制、还有上方的nologin也配置了不允许ssh登录的)
9.重启配置文件并检查
bash
#重启配置文件
sudo systemctl restart sshd
#检查配置文件状态
sudo systemctl status sshd
如果没有错,就可以继续下一步了。
10.准备测试
根目录只有root用户能创建文件夹,sftpuser不能创建,所以先创建几个测试用。
bash
sudo mkdir -p /home/sftp/sftpuser/data/upload
sudo mkdir -p /home/sftp/sftpuser/data/download
sudo chmod -R 777 /home/sftp/sftpuser/data/*
这里创建了两个文件夹,upload和download,然后设置权限777(省事,所有用户都能用)。
11.FileZilla测试
(1)测试账户密码连接sftp
使用FileZilla测试,输入服务器ip,用户名是sftpuser,密码是自己设置的用户密码,注意端口输入22。(sftp端口22)


正常情况如图,是以服务器的data文件夹作为根目录的,上级目录不可见;里面有刚才创建的download与upload文件夹,用户可以在子文件夹里继续上传下载文件。
(注意,根目录data不行,必须属于root用户,sftpuser用户不能直接在根目录操作)
(2)测试秘钥连接sftp

如图,选择自己的私钥文件(就是刚才生成的id_rsa文件),输入服务器ip,连接,正常情况下就可以连接上了(秘钥方法默认端口22,可以不写)。
三、总结
1.Permission denied (publickey,gssapi-keyex,gssapi-with-mic)错误,是当时增加秘钥连接方法时,创建的.ssh和authorized_keys的权限错误设置给了root用户(应该设置给sftpuser用户才行,被chatgpt骗了),然后用秘钥连不上服务器,就报这个错。
2.还有一个坑是把.ssh文件夹错误放到了data文件夹下(应该放到/etc/passwd里配置的用户home路径下的,chatgpt一直让我放到/etc/ssh/sshd_config里配置的ChrootDirectory 路径下,也是个坑)
3.正常情况下,按照本文的操作,把各种权限搞对,应该是没有问题的。
如果还有问题,可以用这个命令自测:
bash
#格式
sftp -i <私钥路径> <登录用户名>@<目标服务器名>
#例:私钥文件是id_rsa
sftp -i /home/sftp/sftpuser/id_rsa sftpuser@127.0.0.1
看下是否能用秘钥连接成功。
4.sftpuser的用户目录和data目录必须属于root,.ssh目录和authorized_keys文件必须属于自己(sftpuser),最后data目录里上传下载的upload子目录和download子目录没有特别要求(可以设置777,可以属于root)。