最近有一个客户想在AWS EC2上安装SFTP服务,其实之前已经给他设置了AWS Transfer Family服务,可以直接为S3开通SFTP服务。不过这个客户觉得太贵,所以还是想在已经存在的EC2服务器上安装SFTP服务,并且连接到S3。本来以为很简单的事情,没想到花了一天时间,还差点把服务器弄坏了。
在EC2上安装S3FS
EC2也就是linux云服务器,为其安装SFTP其实很简单。创建一个专门的用户,生成ssh key,配置SSH,分配权限就可以了。
创建SFTP用户
创建SFTP的用户和用户组,并分配用户到组。最后修改用户目录权限。
$ groupadd sftp |
接着编辑/etc/ssh/sshd_config
注释掉Subsystem sftp /usr/lib/openssh/sftp-server
,换成Subsystem sftp internal-sftp
再添加下面的部分到最后
Match user mysftpuser |
然后用命令sshd -t service sshd restart
重启ssh服务就完成了。
但因为最后这一段是我从网上找到复制的,刚好有问题。重启ssh之后,实际上ssh已经挂了。直到过了一会我退出再重新登录的时候,AWS的默认用户都无法通过ssh登录到服务器了。这就导致了一个致命的问题,我没法登录服务器,也无法修复sshd_config文件了。修复的方法很麻烦,不算搜索过程,花了1小时多才算搞定。修复方法后面再说。
安装S3FS
S3FS全称是s3fs-fuse
。该工具基于FUSE,可以把AWS的S3(对象存储)目录映射到Linux,MacOS或FreeBCD上。这里我的EC2是用的Amazon Linux,所以按这个环境进行安装,其他环境略有不同,可以查看Github上S3FS项目的官方文档,这里不做赘述。
按文档上的命令安装
sudo amazon-linux-extras install epel |
然后失败了,因为这个EC2有点老,是Amazon Linux1,无法使用epel。不得已只好手动安装。
sudo git clone https://github.com/s3fs-fuse/s3fs-fuse.git |
验证一下是否安装成功
s3fs --version |
安装FUSE
然后还需要安装fuse
,也同样手动安装。
sudo wget https://github.com/libfuse/libfuse/releases/download/fuse-2.9.7/fuse-2.9.7.tar.gz |
验证一下是否安装成功
pkg-config --modversion fuse |
挂载S3 Bucket
创建SFTP的AWS配置文件
S3FS需要创建一个${HOME}/.passwd-s3fs
文件,作为保存AWS秘钥的文件。
echo [ACCESS_KEY_ID]:[SECRET_ACCESS_KEY] > ${HOME}/.passwd-s3fs |
把ID和KEY替换成你AWS S3的ID和KEY,写入该文件就行。还有设置正确的权限。
另外由于我使用默认用户ec2-user
登录和安装,和SFTP不是同一个用户,所以需要配置fuse,允许其他用户访问。在/etc
下创建fuse.conf
文件,然后写入:
# /etc/fuse.conf - Configuration file for Filesystem in Userspace (FUSE) |
主要是user_allow_other
选项就可以开启。
挂载S3
最后在挂载命令中用参数指明AWS的秘钥文件路径就可以了。
s3fs my-bucket /home/mysftpuser/myfolder -o passwd_file=${HOME}/.passwd-s3fs -o --allow-root -o dbglevel=info -f -o curldbg |
要注意的是不要直接挂载到用户根目录,所以我特别加了一层myfolder
,因为可能还需要添加.ssh
之类的文件到根目录,避免在SFTP中共享出来。
进入myfoler中查看一下是否出现S3对应bucket的文件,或者创建一个,看是否同步即可验证挂载是否成功。
撤销挂载
如果要撤销挂载,S3FS并不提供特别的命令,直接使用umount
命令即可。
umount /home/mysftpuser/myfolder |
修复EC2的SSH
现在来说说如何修复SSH受损的EC2。
在sshd_conf
文件受损后,我再次登录时会收到connection refused
的错误。由于这是一个普通的EC2,我也没有启用过串行控制台,所以只能选择“救援实例”的方式。
简单来说,就是创建另外一个EC2实例服务器作为救援实例,然后把受损的EC2的主硬盘卷拿出来当做数据盘挂载到这个救援实例上,再通过救援实例SSH登录上去修改数据盘中的sshd_conf文件。这个方法的唯一缺点是需要停止实例一小段时间,如果有实例存储之类的会在停止后丢失的东西,那就不太适合。
创建救援实例
- 选择与受损EC2实例相同的AMI创建救援实例,或者直接从受损实例创建一个snapshot,再用snapshot创建实例,保证其基本环境一致,而不会对挂载卷产生其他影响。
- 停止受损的EC2实例
- 在Volumn中分离受损卷(/dev/xvda 或 /dev/sda1)。
- SSH登录到救援实例上
- lsblk查看一下当前的卷
- 创建一个文件夹用于挂载受损卷
sudo mkdir /mnt/rescue |
- 挂载受损根卷,xvdf1是刚才查询到的卷名
sudo mount -t xfs -o nouuid /dev/xvdf1 /mnt/rescue/ |
- 再次lsblk查询一下
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT |
- 编辑修复sshd_conf文档
sudo vi /mnt/rescue/etc/ssh/sshd_config |
- 卸载修复的卷
sudo umount /mnt/rescue/ |
- 在AWS控制台上将修复的卷从救援实例上分离,再以根卷形式挂载到原受损实例上。
- 重新启动原实例,SSH登录测试是否成功。
- 停止救援实例。
这样就修复好了,以后还是应该谨慎一些,其实每次修改sshd_conf的时候,在退出前另外开一个终端登录一下就可以避免这种情况。DevOps还是需要一颗过度谨慎的心。