建置一個只能執行 ssh 指令的跳板伺服器

phutidus
phutidus
Aug 29, 2017 · 12 min read

因為某些原因,我溫暖的家的 IP 被當成連線到某台伺服器的跳板。

但為了避免我在假日被其他人透過電話當成阿凡達操控的情況發生,所以我決定在我家放一台機器,讓需要的人們可以自行先 SSH 到該機器,再藉由我家的 IP 連到目的地。

有了動機以後,大致列出我要達到的目標

  • 找一個可以放在家裡,存在感低,能設置 SSH 服務的便宜機器
  • 讓這台機器盡量與我家內網隔離
  • 使用者連進來以後只能執行 ssh 指令,而且只能連到特定的遠端

開始一步一步處理這些事項


找一個可以放在家裡,存在感低,能設置 SSH 服務的便宜機器

定義所謂存在感低

  • 不會發出聲響,所以排除有散熱風扇的電腦
  • 不要吃太多電,Fanless PC 也排除
  • 體積小

↑↑↑其實上面的條件都是多餘的↑↑↑

光是便宜這個條件大概可以去掉 87% 的選項,留下 Raspberry Pi 這種 ARM 開發板作為候選。不過家裡的樹莓派現在都很忙,所以我只好再上淘寶找便宜的 ARM 開發板 (絕對不是我要找理由買新玩具)

一番尋找之後,就決定是 NanoPi NEO 了!NanoPi NEO 由中國的友善之臂出品,是一塊長 x 寬只有 40mm x 40mm,且具有 RJ-45 插孔的 ARM 開發板。友善之臂官方針對 NanoPi NEO 訂製並維護了一套 Ubuntu Core 16.04,不喜歡的話還有 ArmbianDietPi 等民間發行版可以選用,重點是板子本身便宜。然而這板子據說容易過熱,所以再加購官方散熱片,因為決定讓它裸機所以連外殼也省了,Micro SD 卡、USB 線以及電源用現成的。

NanoPi NEO w/512MB RAM. 如果家裡有多的散熱片就別買官方的, 這訂價也太貴了吧?

OS 基礎設定

分享一下我用過的 distro 感想:

  • Armbian (民間高手維護): 「似乎」可以跑 Docker、3.x kernel 可以用 I²C; 4.x kernel 實測結果不能用 I²C,MAC address 重開機就會變一次,當我試著固定它的時候就連不進去了,促使我改為安裝 Ubuntu Core 16.04
  • Ubuntu Core 16.04 (友善之臂維護): 官方有在更新、I²C 可用、kernel 版本新、網卡 MAC address 預設固定不變;不能跑 lxc (所以也不能用 Docker)

本文之後的設置都是以 Ubuntu Core 16.04 作為示範。插入灌好 OS 的記憶卡至 NanoPi NEO,開機等它抓到 IP,用 SSH 進去,它會顯示系統的基本資訊。可以看到我用的記憶卡容量只有 4GB,RAM 有 512MB,而且還顯示了本機的 IP。

截圖是為了寫本文才截的,uptime 就別在意了

系統起來了,緊接著開始進行設定


若不是使用 root 登入,請改用 root 登入,預設的密碼為 fa

先刪掉不需要的內建帳號 (fa) 並改掉其他內建帳號 (root, pi) 的密碼

# deluser fa
# passwd
# passwd pi

更新系統,並安裝我常用的 package

# apt-get update && apt-get dist-upgrade -y && apt-get install git curl wget htop byobu zsh vim tmux screen iotop bwm-ng man cron ufw python-software-properties software-properties-common apt-transport-https -y

改掉 hostname

# hostnamectl set-hostname "new-hostname"
## 可能還需要手動修改 /etc/hosts

改掉 timezone

# timedatectl set-timezone Asia/Taipei

產生用來登入的 ssh key

(略)

修改 SSH server 的 listening port 為 2222、不允許 X11Forwarding、不允許 tunneling、每次登入僅能進行一次登入嘗試、僅能使用 public key authentication 登入

## change port from 22 to 65536
# sed -i 's/^Port 22/Port 65536/g' /etc/ssh/sshd_config
## limit auth try per session to 1
# printf "\n\n# Allow only one auth try per session to limit\nMaxAuthTries 1" >> /etc/ssh/sshd_config
## 如果打算同時使用密碼認證以及 pub key 認證的話,不要執行下面這一行
# sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/g' /etc/ssh/sshd_config
## 不讓 root 登入 SSH,我習慣用 sudo 帳號登入
## optional but strongly recommended
# sed -i 's/PermitRootLogin yes/PermitRootLogin no/g' /etc/ssh/sshd_config
## 重啟 ssh
# systemctl restart ssh.service
## 重新啟動之後,不要斷掉目前的連線,開一個新的視窗試試看能不能登入,登不進去的話表示 sshd 設定出問題了,快用活著的連線去排除,不然你以後就連不進來了

disable 我目前用不到的 IPv6 (optional)

# echo "net.ipv6.conf.all.disable_ipv6 = 1" >> /etc/sysctl.conf

啟用 RTC (optional),會需要做這項設定是因為我手邊有剩下的 DS3231 RTC module,所以順手插上去。前面特別提到 I²C 支援的原因也是因為它

# sed -i 's/^blacklist rtc_ds1307/#blacklist rtc_ds1307/g' /etc/modprobe.d/matrix-blacklist.conf## Use DS3231 instead of the built-in RTC in H3 chip
# echo HCTOSYS_DEVICE=rtc1 >> /etc/default/hwclock

為了避免連進來的人玩弄我家區網,所以設定簡單的防火牆規則。為了方便我使用 ufw 進行設定

## 允許 SSH 連入
# ufw limit 65536/tcp comment 'SSH'
## 阻擋連出至 router 特定服務、允許連到 router,阻擋連出到內網設備
# ufw deny out from any to x.x.x.1 port 65536 comment 'Router web'
# ufw allow out from any to x.x.x.1 comment 'Router'
# ufw deny out from any to x.x.x.0/24
## 允許連線到 VIP
# ufw allow out from any to x.x.x.x port 65536 proto tcp comment 'VIP SSH'
## 如果規則沒設好,可能在下列的指令打完之後就連不進來了...
# ufw default deny outgoing
# ufw enable

其他規則、router 的防火牆以及 NAT 設定在此省略。

做到這裡,建議先重開機,確認改了這些東西後 NanoPi NEO 還能動。

# reboot

如果你在設定 SSH server 的時候有設定 PermitRootLogin no,記得改用擁有 sudo 權限的帳號 (如預設的 pi) 登入,並使用下列指令切換成 root 後再接著操作後面的部分

$ sudo su -

讓使用者連入 Nano Pi NEO 後只能 SSH 到某伺服器

OS 基礎大概處理好之後,再來是:怎麼讓使用者專心工作,不亂玩這片小板子。

防火牆的部分前面已經設定完成,現在要讓他們只能在 shell 執行 ssh 指令,關於這項,我考慮過幾種方案:

  • rssh: 只能連進來執行 scp/sftp 的 shell,跟我的要求不一樣
  • rbash: 有功能限制的 bash,有著不能 cd …… 等限制,但不能限制使用者可以執行的指令,只能達到部分要求
  • chroot: 將登入使用者的根目錄換成某個資料夾,達成某種程度的隔離效果,但是檔案是跟沒有 chroot 的使用者放在一起的,我覺得隔離不夠乾淨
  • container (Docker 或是只使用 lxc): 使用 cgroups 等技術,建立一個與 host 隔離的容器,可以設定各種資源的使用限制,而且如果覺得不乾淨把整個 container 刪掉就解決,再加上 chroot 還有 rbash 根本完美

我原本想用 Docker+chroot+rbash 進行設定,但是因為前面的設定都用好了之後我才發現 Ubuntu Core 的 kernel 不支援 lxc,最後只能捨棄 Docker,僅用 chroot+rbash


以下開始設定 chroot 環境 (部分參考 Restrict an SSH user session to a specific directory by setting chrooted jail)

建立 chroot資料夾結構、複製必要的檔案

我們需要一個簡化版的 linux 根目錄結構,讓使用者的帳號在登入後被 chroot 到該資料夾下

# JAIL=/home/jails
# mkdir -p $JAIL
# mkdir -p $JAIL/dev/
# mknod -m 666 $JAIL/dev/null c 1 3
# mknod -m 666 $JAIL/dev/tty c 5 0
# mknod -m 666 $JAIL/dev/zero c 1 5
# mknod -m 666 $JAIL/dev/random c 1 8cd $JAIL
# chmod 0755 $JAIL
# cd $JAIL
# mkdir homes

複製 rbash, ssh 及其依賴的 library

就是只給使用者連線到伺服器所需要的工具,其他的一概不提供,這樣他們就會專心工作了吧 (?)

網路上有人分享了一個 script (Export a linux binary with its lib dependencies to a chroot or initramfs, …) 除了幫忙複製 binary 本身,也一併將相依的 library 複製到 chroot 資料夾內

## 複製上述文章內的 script 並存檔為 exportbin.sh# chmod +x exportbin.sh
# ./exportbin.sh /bin/rbash $JAIL
# ./exportbin.sh /usr/bin/ssh $JAIL

建立帳號、密碼、chroot 時的家目錄

這次我新增 aaa, bbb 兩個 user

## 建立帳號
# adduser aaa
# adduser bbb
## 設定密碼
# passwd aaa
# passwd bbb
## 設定家目錄
# mkdir $JAIL/home/aaa
# mkdir $JAIL/home/bbb
## enable color prompt
# COLOR_PROMPT="PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '"
# echo $COLOR_PROMPT > $JAIL/home/aaa/.profile
# echo $COLOR_PROMPT > $JAIL/home/bbb/.profile
## disable motd on user login
# touch $JAIL/home/aaa/.hushlogin
# touch $JAIL/home/bbb/.hushlogin
## 每次新增了要被 chroot 的帳號後,都需同步 passwd & groups
## 也可以選擇不複製這些檔案,但這將導致使用者登入後
## shell 原本應該顯示 username 的地方顯示 "I have no name!"
# cp /etc/passwd $JAIL/etc/passwd
# cp /etc/groups $JAIL/etc/groups

到這裡大概就可以了,趕快從公司網路試試看能不能連,然後玩一下:

除了 ssh 什麼都不能做,這樣他們會高興嘛?

好,可以連線了,把 NanoPi NEO 電源拔掉。

為什麼?

畢竟只有在假日需要上 server 處理問題的時候才會用到這塊跳板,所以平常都是維持斷電狀態的,只在被召喚的時候才會把它插上電源。


其他要設定 TOTP 還是 YubiPAM 或者其他認證方式這裡沒提到了,各位可以自行實作想要的措施。

有點麻煩的點在於,若使用者要改密碼的話,我就必須先登入沒有被 chroot 的 sudo 帳號,然後把鍵盤借給他們輸入新的密碼…很麻煩


本文若有幫到你的話,請考慮贊助我一杯咖啡!

Bitcoin: 1Lrboa558FTmuecz8TwCB6eaidzjd1wGTT
Monero: 49WrA7vjaAahGh3jE7ss6eNFDuwJ2oMvPjLEmhCSFeTEHuYrrnvjmjbeoLkiFH4nwYMfxuBoRz2DKggNMTAPLJRt2X51h8W

)
Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade