30 December 2011

Today I needed to share files between linux server instances. Setting up a traditional NFS share is not an option since NFS V3 requires opening too many ports on the firewall. NFS v4 needs less ports but without Kerberos, there is no security. Since I already have ssh access opened, I decided to use Fuse which allow mounting filesystem in userspace + SSHFS which provides the Fuse driver to mount the remote filesystem thru an SSH tunnel. Here is how I set it up on my Amazon Linux instance.

Installing the tools

First, install Fuse if it’s not already installed.

$ sudo yum -y install fuse fuse-devel glib2-devel
Loaded plugins: fastestmirror, priorities, security, update-motd
Loading mirror speeds from cached hostfile
 * amzn-main: packages.eu-west-1.amazonaws.com
 * amzn-updates: packages.eu-west-1.amazonaws.com
Setting up Install Process
Resolving Dependencies
--> Running transaction check
---> Package fuse.x86_64 0:2.8.6-1.10.amzn1 will be installed
---> Package fuse-devel.x86_64 0:2.8.6-1.10.amzn1 will be installed
--> Processing Dependency: fuse-libs = 2.8.6-1.10.amzn1 for package: fuse-devel-2.8.6-1.10.amzn1.x86_64
--> Processing Dependency: libfuse.so.2()(64bit) for package: fuse-devel-2.8.6-1.10.amzn1.x86_64
--> Processing Dependency: libulockmgr.so.1()(64bit) for package: fuse-devel-2.8.6-1.10.amzn1.x86_64
---> Package glib2-devel.x86_64 0:2.22.5-6.9.amzn1 will be installed
--> Running transaction check
---> Package fuse-libs.x86_64 0:2.8.6-1.10.amzn1 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

 Package           Arch         Version                Repository          Size
 fuse              x86_64       2.8.6-1.10.amzn1       amzn-updates        76 k
 fuse-devel        x86_64       2.8.6-1.10.amzn1       amzn-updates        33 k
 glib2-devel       x86_64       2.22.5-6.9.amzn1       amzn-main          1.5 M
Installing for dependencies:
 fuse-libs         x86_64       2.8.6-1.10.amzn1       amzn-updates        84 k

Transaction Summary
Install       4 Package(s)

Total download size: 1.7 M
Installed size: 13 M
Downloading Packages:
(1/4): fuse-2.8.6-1.10.amzn1.x86_64.rpm                  |  76 kB     00:00
(2/4): fuse-devel-2.8.6-1.10.amzn1.x86_64.rpm            |  33 kB     00:00
(3/4): fuse-libs-2.8.6-1.10.amzn1.x86_64.rpm             |  84 kB     00:00
(4/4): glib2-devel-2.22.5-6.9.amzn1.x86_64.rpm           | 1.5 MB     00:00
Total                                           6.0 MB/s | 1.7 MB     00:00
Running rpm_check_debug
Running Transaction Test
Transaction Test Succeeded
Running Transaction
  Installing : fuse-libs-2.8.6-1.10.amzn1.x86_64                            1/4
  Installing : fuse-devel-2.8.6-1.10.amzn1.x86_64                           2/4
  Installing : fuse-2.8.6-1.10.amzn1.x86_64                                 3/4
  Installing : glib2-devel-2.22.5-6.9.amzn1.x86_64                          4/4

  fuse.x86_64 0:2.8.6-1.10.amzn1          fuse-devel.x86_64 0:2.8.6-1.10.amzn1
  glib2-devel.x86_64 0:2.22.5-6.9.amzn1

Dependency Installed:
  fuse-libs.x86_64 0:2.8.6-1.10.amzn1


Then download, compile and install SSHFS.

$ wget http://downloads.sourceforge.net/project/fuse/sshfs-fuse/2.3/sshfs-fuse-2.3.tar.gz
--2011-12-30 10:16:06--  http://downloads.sourceforge.net/project/fuse/sshfs-fuse/2.3/sshfs-fuse-2.3.tar.gz
Resolving downloads.sourceforge.net...
Connecting to downloads.sourceforge.net||:80... connected.
HTTP request sent, awaiting response... 302 Found
Location: http://heanet.dl.sourceforge.net/project/fuse/sshfs-fuse/2.3/sshfs-fuse-2.3.tar.gz [following]
--2011-12-30 10:16:06--  http://heanet.dl.sourceforge.net/project/fuse/sshfs-fuse/2.3/sshfs-fuse-2.3.tar.gz
Resolving heanet.dl.sourceforge.net..., 2001:770:18:aa40::c101:c142
Connecting to heanet.dl.sourceforge.net||:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 129222 (126K) [application/x-gzip]
Saving to: `sshfs-fuse-2.3.tar.gz'

100%[======================================>] 129,222     --.-K/s   in 0.05s

2011-12-30 10:16:06 (2.51 MB/s) - `sshfs-fuse-2.3.tar.gz' saved [129222/129222]
$ tar zxf sshfs-fuse-2.3.tar.gz
$ cd sshfs-fuse-2.3
$ ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking for style of include used by make... GNU
checking dependency style of gcc... gcc3
checking whether gcc and cc understand -c and -o together... yes
checking for library containing dlsym... -ldl
checking OpenSSH version... 5.3 >= 4.4, disabling NODELAY workaround
checking for pkg-config... /usr/bin/pkg-config
checking pkg-config is at least version 0.9.0... yes
checking for SSHFS... yes
checking for fuse_opt_parse... yes
configure: creating ./config.status
config.status: creating Makefile
config.status: creating config.h
config.status: config.h is unchanged
config.status: executing depfiles commands
$ make
make  all-am
make[1]: Entering directory `/tmp/sshfs-fuse-2.3'
gcc -DHAVE_CONFIG_H -I.  -D_REENTRANT -DFUSE_USE_VERSION=26 -DLIBDIR=\"/usr/local/lib\"  -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/fuse -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include   -g -O2 -Wall -W -MT sshfs-sshfs.o -MD -MP -MF .deps/sshfs-sshfs.Tpo -c -o sshfs-sshfs.o `test -f 'sshfs.c' || echo './'`sshfs.c
mv -f .deps/sshfs-sshfs.Tpo .deps/sshfs-sshfs.Po
gcc -DHAVE_CONFIG_H -I.  -D_REENTRANT -DFUSE_USE_VERSION=26 -DLIBDIR=\"/usr/local/lib\"  -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/fuse -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include   -g -O2 -Wall -W -MT sshfs-cache.o -MD -MP -MF .deps/sshfs-cache.Tpo -c -o sshfs-cache.o `test -f 'cache.c' || echo './'`cache.c
mv -f .deps/sshfs-cache.Tpo .deps/sshfs-cache.Po
gcc -D_FILE_OFFSET_BITS=64 -pthread -I/usr/include/fuse -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include   -g -O2 -Wall -W   -o sshfs sshfs-sshfs.o sshfs-cache.o  -pthread -L/lib64 -lfuse -ldl -lgthread-2.0 -lrt -lglib-2.0
make[1]: Leaving directory `/tmp/sshfs-fuse-2.3'
$ sudo make install
make[1]: Entering directory `/tmp/sshfs-fuse-2.3'
test -z "/usr/local/bin" || /bin/mkdir -p "/usr/local/bin"
  /usr/bin/install -c sshfs '/usr/local/bin'
test -z "/usr/local/share/man/man1" || /bin/mkdir -p "/usr/local/share/man/man1"
 /usr/bin/install -c -m 644 sshfs.1 '/usr/local/share/man/man1'
make[1]: Leaving directory `/tmp/sshfs-fuse-2.3'

Using sshfs

Before attempting to mount the filesystem we will setup ssh public key authentication to avoid typing password every time.

SSH public key authentication

Some ssh basic for the new comers…

Generate an ssh public key if you don’t already have one.

$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/srv/cloud/one/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /srv/cloud/one/.ssh/id_rsa.
Your public key has been saved in /srv/cloud/one/.ssh/id_rsa.pub.
The key fingerprint is:
d4:fc:84:51:a3:ca:8d:18:e0:5e:bf:b6:bf:79:d7:c6 oneadmin@ip-10-58-75-89
The key's randomart image is:
+--[ RSA 2048]----+
|    .     ..o    |
|   . .   o + .   |
|    . o . = .    |
|   . . * + o     |
|    . . S . .    |
|         .       |
|        o      o |
|       . . .. . E|
|        ..+o . . |

Now open the content of the ~/.ssh/id_rsa.pub file in the ~/.one/authorized_keys file on the remote host and test the connection.

$ ssh ec2-46-137-64-48.eu-west-1.compute.amazonaws.com hostname
The authenticity of host 'ec2-46-137-64-48.eu-west-1.compute.amazonaws.com (' can't be established.
RSA key fingerprint is b6:3e:8c:57:40:45:aa:de:98:f7:1b:37:0f:31:e1:b3.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'ec2-46-137-64-48.eu-west-1.compute.amazonaws.com,' (RSA) to the list of known hosts.

The first time you connect to a host with ssh, you need to accept the remote host key as the key to identify the remote host as a known host. Should this key change, ssh will report a warning as it may be a man in the middle attack attempt.

Mounting the remote filesystem

The command syntax to mount the remote filesystem thru an SSH tunnel will be in the form sshfs <public_instance_name>:<remote_directory> <local_mount_directory> but remember to create a mount point for the remote filesystem first.

$ mkdir /tmp/remote_fs
$ /usr/local/bin/sshfs ec2-46-137-64-48.eu-west-1.compute.amazonaws.com:/ /tmp/remote_fs
$ df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/xvda1            7.9G  1.3G  6.6G  16% /
tmpfs                 299M     0  299M   0% /dev/shm
                      7.9G  4.9G  2.9G  63% /tmp/remote_fs
$ ls /tmp/remote_fs/
AMI  boot  etc   lib    local       media  opt   root  sbin     srv  tmp  var
bin  dev   home  lib64  lost+found  mnt    proc  s3fs  selinux  sys  usr

It works. You can know access the remote filesystem using this mountpoint!

Unmounting the filesystem

Unmounting the filesystem is really easy. Just run the fusermount command with the -u argument.

$ fusermount -u /tmp/oneremote
$ df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/xvda1            7.9G  1.3G  6.6G  16% /
tmpfs                 299M     0  299M   0% /dev/shm

blog comments powered by Disqus