This is part of a series of posts on the design and technical steps of creating Himblick, a digital signage box based on the Raspberry Pi 4.
Time to setup ssh. We want to have admin access to the pi user, and we'd like
to have a broader access to a different, locked down user, to use to manage
media on the boxes via sftp.
The first step is to mount the exFAT media partition into /srv/media:
---
- name: "Install exfat drivers"
apt:
name: exfat-fuse,exfat-utils
state: present
update_cache: no
- name: "Create /srv directory"
file:
path: "/srv"
state: directory
owner: root
group: root
mode: 0755
- name: "Create /media mount point"
file:
path: "/srv/media"
state: directory
owner: pi
group: pi
mode: 0755
- name: "Configure mounting media directory"
copy:
src: srv-media.mount
dest: /etc/systemd/system/srv-media.mount
owner: root
group: root
mode: 0644
Mounting exFAT before Linux kernel 5.4 requires FUSE. Using a mount unit allows us to bring up the mount after FUSE is up, and get it mounted at boot reliably.
We add a round of filesystem checking, too: if people plug the SD into a computer to load media into it, we can't be sure that they unmount it cleanly.
This is srv-media.mount; note that .mount unit names need to match the
path of the mount point:
[Unit]
Description=Media Directory (/srv/media)
Before=local-fs.target
After=sys-fs-fuse-connections.mount
[Mount]
What=/dev/disk/by-label/media
Where=/srv/media
Type=exfat
Options=uid=0,gid=1001,fmask=117,dmask=007,rw,noatime,nosuid,nodev
ExecStartPre=-/sbin/fsck.exfat -a /dev/disk/by-label/media
[Install]
WantedBy=local-fs.target
gid 1001 is the media group id, shared by the pi user that runs the media
player, and by the media user that does sftp. We make everything the media
mount group-writable by the media user so both users can access it.
Next, we prepare a chroot jail for the media user. The root of the jail
needs to be writable only by root,
so we bind mount the media directory inside it:
- name: "Create the chroot jail for media: /srv"
file:
path: "/srv"
state: directory
owner: root
group: root
mode: 0755
- name: "Create the chroot jail for media: /srv/jail"
file:
path: "/srv/jail"
state: directory
owner: root
group: root
mode: 0755
- name: "Create the chroot jail for media: /srv/jail/media"
file:
path: "/srv/jail/media"
state: directory
owner: root
group: media
mode: 0755
- name: "Bind mount /srv/media under /srv/jail/media"
copy:
src: srv-jail-media.mount
dest: /etc/systemd/system/srv-jail-media.mount
owner: root
group: root
mode: 0644
This is the srv-jail-media.mount mount unit, neatly ordered to start after
/srv/media is mounted:
[Unit]
Description=Media Directory in sftp jail (/srv/jail/media)
Before=local-fs.target
After=srv-media.target
[Mount]
What=/srv/media
Where=/srv/jail/media
Type=none
Options=bind
[Install]
WantedBy=local-fs.target
Finally, the ssh configuration:
---
- name: "Disable ssh password authentication"
lineinfile:
path: /etc/ssh/sshd_config
regexp: '\bPasswordAuthentication\b'
line: 'PasswordAuthentication no'
- name: "Install ssh admin access key"
authorized_key:
user: pi
state: present
key: "{{SSH_AUTHORIZED_KEY}}"
when: SSH_AUTHORIZED_KEY is defined
- name: "Install ssh media access key"
authorized_key:
user: media
state: present
key: "{{SSH_MEDIA_PUBLIC_KEY}}"
when: SSH_MEDIA_PUBLIC_KEY is defined
- name: "Install media access key for the pi user"
copy:
dest: "/home/pi/.ssh/id_media"
content: "{{SSH_MEDIA_PRIVATE_KEY}}"
owner: pi
group: pi
mode: 0600
when: SSH_MEDIA_PRIVATE_KEY is defined
- name: "Configure internal sftp, so ssh does not need binaries inside the jail"
lineinfile:
path: /etc/ssh/sshd_config
regexp: ".*Subsystem\\s+sftp"
line: "Subsystem sftp internal-sftp"
- name: "Configure sftp chroot jail for user media"
blockinfile:
path: /etc/ssh/sshd_config
block: |
Match User media
ChrootDirectory /srv/jail
AllowTcpForwarding no
X11Forwarding no
ForceCommand internal-sftp
Don't forget to enable the media units:
# Enable the /srv/media mount point, which ansible, as we run it
# now, is unable to do
chroot.systemctl_enable("srv-media.mount")
chroot.systemctl_enable("srv-jail-media.mount")