Browse Source

new: [rsync-backup-target] a key identifier is now required and enforced

The key identifier will be used to fence each key in its own folder.

Signed-off-by: Valentin Lab <valentin.lab@kalysto.org>
lokavaluto/dev/master
Valentin Lab 5 years ago
parent
commit
a4ceebbddd
  1. 22
      rsync-backup-target/build/Dockerfile
  2. 12
      rsync-backup-target/build/entrypoint.sh
  3. 118
      rsync-backup-target/build/src/etc/ssh/sshd_config
  4. 23
      rsync-backup-target/build/src/etc/sudoers.d/rsync
  5. 51
      rsync-backup-target/build/src/usr/local/sbin/ssh-cmd-validate
  6. 25
      rsync-backup-target/hooks/init

22
rsync-backup-target/build/Dockerfile

@ -1,24 +1,24 @@
FROM debian:jessie
FROM alpine:3.9
MAINTAINER Valentin Lab <valentin.lab@kalysto.org>
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install --force-yes -y --no-install-recommends openssh-server sudo rsync && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
COPY ./src/usr/local/sbin/* /usr/local/sbin/
RUN apk add rsync sudo bash openssh-server
RUN ssh-keygen -A
## New user/group rsync/rsync with home dir in /var/lib/rsync
RUN mkdir -p /var/lib/rsync && \
groupadd -r rsync && \
useradd -r rsync -d /var/lib/rsync -g rsync && \
addgroup -S rsync && \
adduser -S rsync -h /var/lib/rsync -G rsync && \
chown rsync:rsync /var/lib/rsync
## Without this, account is concidered locked by SSH
RUN sed -ri 's/^rsync:!:/rsync:*NP*:/g' /etc/shadow
## Withouth this, force-command will not run
RUN sed -ri 's%^(rsync.*:)[^:]+$%\1/bin/bash%g' /etc/passwd
## Allow rsync to access /var/mirror
COPY /src/etc/sudoers.d/rsync /etc/sudoers.d/rsync
COPY /src /
RUN chmod 440 /etc/sudoers.d/*

12
rsync-backup-target/build/entrypoint.sh

@ -7,15 +7,21 @@
chmod 440 /etc/sudoers.d/* -R
KEYS=/etc/rsync/keys/
KEYS=/etc/rsync/keys
RSYNC_HOME=/var/lib/rsync
mkdir -p "$RSYNC_HOME/.ssh"
for f in "$KEYS"/*; do
for f in "$KEYS"/*.pub; do
[ -e "$f" ] || continue
content=$(cat "$f")
echo "command=\"/usr/local/sbin/ssh-cmd-validate\" $content"
ident="${f##*/}"
ident="${ident%.pub}"
if ! [[ "$ident" =~ ^[a-zA-Z0-9._-]+$ ]]; then
echo "bad: '$ident'"
continue
fi
echo "command=\"/usr/local/sbin/ssh-cmd-validate \\\"$ident\\\"\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty $content"
done > "$RSYNC_HOME"/.ssh/authorized_keys
chown rsync:rsync -R "$RSYNC_HOME"/.ssh -R

118
rsync-backup-target/build/src/etc/ssh/sshd_config

@ -0,0 +1,118 @@
# $OpenBSD: sshd_config,v 1.103 2018/04/09 20:41:22 tj Exp $
# This is the sshd server system-wide configuration file. See
# sshd_config(5) for more information.
# This sshd was compiled with PATH=/bin:/usr/bin:/sbin:/usr/sbin
# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented. Uncommented options override the
# default value.
#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key
# Ciphers and keying
#RekeyLimit default none
# Logging
#SyslogFacility AUTH
#LogLevel INFO
# Authentication:
#LoginGraceTime 2m
#PermitRootLogin prohibit-password
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
#PubkeyAuthentication yes
# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
# but this is overridden so installations will only check .ssh/authorized_keys
AuthorizedKeysFile .ssh/authorized_keys
#AuthorizedPrincipalsFile none
#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes
# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication no
PermitEmptyPasswords no
# Change to no to disable s/key passwords
ChallengeResponseAuthentication no
# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication. Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
#UsePAM yes
#AllowAgentForwarding yes
# Feel free to re-enable these if your use case requires them.
AllowTcpForwarding no
GatewayPorts no
X11Forwarding no
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
#PrintMotd yes
#PrintLastLog yes
#TCPKeepAlive yes
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#UseDNS no
#PidFile /run/sshd.pid
#MaxStartups 10:30:100
PermitTunnel no
#ChrootDirectory none
#VersionAddendum none
# no default banner path
#Banner none
# override default of no subsystems
#Subsystem sftp /usr/lib/ssh/sftp-server
# Example of overriding settings on a per-user basis
#Match User anoncvs
# X11Forwarding no
# AllowTcpForwarding no
# PermitTTY no
# ForceCommand cvs server

23
rsync-backup-target/build/src/etc/sudoers.d/rsync

@ -1,21 +1,4 @@
## allow rsync to access /var/mirror
rsync ALL=(root) NOPASSWD: /usr/bin/rsync --server -vlogDtprRz --delete . /var/mirror/*
rsync ALL=(root) NOPASSWD: /usr/bin/rsync --server -vlogDtprRze.iLs --delete . /var/mirror/*
rsync ALL=(root) NOPASSWD: /usr/bin/rsync --server -vlogDtprRze.iLsf --delete . /var/mirror/*
rsync ALL=(root) NOPASSWD: /usr/bin/rsync --server -vlogDtprRze.iLsf --bwlimit=200 --delete . /var/mirror/*
rsync ALL=(root) NOPASSWD: /usr/bin/rsync --server -vlogDtpArRze.iLsf --delete . /var/mirror/*
rsync ALL=(root) NOPASSWD: /usr/bin/rsync --server -vlogDtpArRze.iLs --delete --partial-dir .rsync-partial --numeric-ids . /var/mirror/*
rsync ALL=(root) NOPASSWD: /usr/bin/rsync --server -vlogDtprRze.iLs --delete --partial-dir .rsync-partial --numeric-ids . /var/mirror/*
rsync ALL=(root) NOPASSWD: /usr/bin/rsync --server -vlHogDtpArRze.iLs --delete --partial-dir .rsync-partial --numeric-ids . /var/mirror/*
rsync ALL=(root) NOPASSWD: /usr/bin/rsync --server -vlogDtpArRze.iLsf --delete --partial-dir .rsync-partial --numeric-ids . /var/mirror/*
rsync ALL=(root) NOPASSWD: /usr/bin/rsync --server -vlogDtpArRze.iLsf --bwlimit=200 --delete . /var/mirror/*
rsync ALL=(root) NOPASSWD: /usr/bin/rsync --server -vlogDtpArRze.iLsfx --delete --partial-dir .rsync-partial --numeric-ids . /var/mirror/*
rsync ALL=(root) NOPASSWD: /usr/bin/rsync --server -vlogDtpArze.iLsfx --delete --partial-dir .rsync-partial --numeric-ids . /var/mirror/*
rsync ALL=(root) NOPASSWD: /usr/bin/rsync --server -vlHogDtpArRze.iLsfx --delete --partial-dir .rsync-partial --numeric-ids . /var/mirror/*
## allow rsync to access /var/mirror, this is really not sufficient, but
## the real check is done on the ``ssh-cmd-validate`` side.
rsync ALL=(root) NOPASSWD: /usr/bin/rsync --server * . /var/mirror/*

51
rsync-backup-target/build/src/usr/local/sbin/ssh-cmd-validate

@ -1,22 +1,43 @@
#!/bin/sh
#!/bin/bash
## Note that the shebang is not used, but it's the login shell that
## will execute this command.
exname=$(basename "$0")
if [ -z "$1" ] || ! [[ "$1" =~ ^[a-zA-Z0-9._-]+$ ]]; then
logger -t "$exname" "INVALID SETUP, ARG IS: '$1'"
echo "Your command has been rejected. Contact administrator."
exit 1
fi
reject() {
logger -t "$exname" "REJECTED: $SSH_ORIGINAL_COMMAND"
echo "Your command has been rejected and reported to sys admin."
# echo "ORIG: $SSH_ORIGINAL_COMMAND" >&2
echo "Your command has been rejected and reported to sys admin." >&2
exit 1
}
case "$SSH_ORIGINAL_COMMAND" in
*\&* | *\(* | *\{* | *\;* | *\<* | *\`*)
reject
;;
md5sum\ /var/mirror/*|find\ /var/mirror/*|rsync\ --server*)
echo "ACCEPTED: $SSH_ORIGINAL_COMMAND" >/tmp/accepted
logger -t "$exname" "ACCEPTED: $SSH_ORIGINAL_COMMAND"
sudo $SSH_ORIGINAL_COMMAND
;;
*)
reject
;;
esac
if [[ "$SSH_ORIGINAL_COMMAND" =~ [\&\(\{\;\<\>\`\$\}] ]]; then
# echo "Bad chars: $SSH_ORIGINAL_COMMAND" >&2
reject
fi
if [[ "$SSH_ORIGINAL_COMMAND" =~ ^"rsync --server -"[vloHgDtpArRzCeiLsfx\.]+(" --"[a-z-]+|" --partial-dir .rsync-partial")*" . /var/mirror/$1"$ ]]; then
logger -t "$exname" "ACCEPTED: $SSH_ORIGINAL_COMMAND"
# echo "Would accept: $SSH_ORIGINAL_COMMAND" >&2
exec sudo $SSH_ORIGINAL_COMMAND
else
reject
fi
## For other commands, like `find` or `md5`, that could be used to
## challenge the backups and check that archive is actually
## functional, I would suggest to write a simple command that takes no
## arguments, so as to prevent allowing wildcards or suspicious
## contents. Letting `find` go through is dangerous for instance
## because of the `-exec`. And path traversal can be done also when
## allowing /my/path/* by using '..'. This is why a fixed purpose
## embedded executable will be much simpler to handle, and to be honest
## we don't need much more.

25
rsync-backup-target/hooks/init

@ -15,20 +15,31 @@ set -e
service_def=$(get_compose_service_def "$SERVICE_NAME")
keys=$(echo "$service_def" | shyaml get-value options.keys 2>/dev/null) || true
keys=$(echo "$service_def" | shyaml -y get-value options.keys 2>/dev/null) || {
err "You must specify a ${WHITE}keys${NORMAL} struct to use this service"
exit 1
}
[ "$keys" ] || exit 0
[ "$(echo "$keys" | shyaml -y get-type 2>/dev/null)" == "struct" ] || {
err "Invalid value type for ${WHITE}keys${NORMAL}, please provide a struct"
exit 1
}
local_path_key=/etc/rsync/keys
host_path_key="$SERVICE_CONFIGSTORE${local_path_key}"
key_nb=0
volume_keys=()
while read-0 key; do
debug "Creating access key ${key_nb}" || true
echo "$key" | file_put "$host_path_key/key_${key_nb}.pub"
((key_nb++)) || true
done < <(echo "$keys" | shyaml get-values-0)
all_keys=" "
while read-0 ident key; do
if ! [[ "$ident" =~ ^[a-zA-Z0-9._-]+$ ]]; then
err "Invalid identifier '$ident'," \
"please use only alphanumerical char, dots, dash or underscores."
exit 1
fi
debug "Creating access key for ${ident}" || true
echo "$key" | file_put "$host_path_key/${ident}.pub"
done < <(echo "$keys" | shyaml key-values-0)
volume_keys+=("$host_path_key:$local_path_key:ro")

Loading…
Cancel
Save