feat: rsync-docker as first-party code, configureable strict host keys checking

This commit is contained in:
Burnett01 2025-09-01 13:08:48 +00:00
parent 92961b5880
commit 9b1bf7278e
11 changed files with 128 additions and 14 deletions

5
.dockerignore Normal file
View file

@ -0,0 +1,5 @@
Dockerfile
LICENSE
*.md
.git*
.github*

15
.editorconfig Normal file
View file

@ -0,0 +1,15 @@
root = true
[*]
charset = utf-8
end_of_line = lf
tab_width = 4
indent_size = 4
indent_style = space
max_line_length = 9999
insert_final_newline = true
trim_trailing_whitespace = true
[*.{yml,yaml}]
tab_width = 2
indent_size = 2

View file

@ -1,11 +1,14 @@
# drinternet/rsync@v1.5.1 FROM alpine:3.22.1 as base
FROM drinternet/rsync@sha256:e61f4047577b566872764fa39299092adeab691efb3884248dbd6495dc926527
RUN apk update && apk add --no-cache --upgrade rsync openssh-client openssl
# always force-upgrade rsync to get the latest security fixes
RUN apk update && apk add --no-cache --upgrade rsync openssl
RUN rm -rf /var/cache/apk/* RUN rm -rf /var/cache/apk/*
# Copy entrypoint COPY docker-rsync/* /bin/
RUN chmod +x /bin/agent-* /bin/hosts-*
FROM base as build
COPY entrypoint.sh /entrypoint.sh COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh RUN chmod +x /entrypoint.sh

View file

@ -1,6 +1,7 @@
MIT License MIT License
Copyright (c) 2019-2022 Contention Copyright (c) 2019-2022 Contention
Copyright (c) 2019-2025 Joshua Piper (Dr Internet)
Copyright (c) 2019-2025 Burnett01 Copyright (c) 2019-2025 Burnett01
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy

View file

@ -13,6 +13,10 @@ inputs:
description: 'Enables support for legacy RSA host keys on OpenSSH 8.8+' description: 'Enables support for legacy RSA host keys on OpenSSH 8.8+'
required: false required: false
default: 'false' default: 'false'
strict_hostkeys_checking:
description: 'Controls strict host keys checking'
required: false
default: 'false'
path: path:
description: 'The local path' description: 'The local path'
required: false required: false

6
docker-rsync/agent-add Executable file
View file

@ -0,0 +1,6 @@
#!/bin/sh
set -euo pipefail
source agent-start "${1:-default}"
cat - | tr -d '\r' | DISPLAY=1 SSH_ASKPASS=agent-askpass ssh-add - >/dev/null

5
docker-rsync/agent-askpass Executable file
View file

@ -0,0 +1,5 @@
#!/bin/sh
set -euo pipefail
echo "$SSH_PASS"

21
docker-rsync/agent-start Executable file
View file

@ -0,0 +1,21 @@
#!/bin/sh
set -euo pipefail
FOLDER=${1:-default}
STORE_PATH="/tmp/ssh-agent/$FOLDER"
mkdir -p "$STORE_PATH"
if [ -z "$SSH_AGENT_PID" ]; then
if [ -f "$STORE_PATH/id" ]; then
SSH_AGENT_PID=$(cat "$STORE_PATH/id")
export SSH_AGENT_PID
SSH_AUTH_SOCK=$(cat "$STORE_PATH/sock")
export SSH_AUTH_SOCK
else
eval "$(ssh-agent)" > /dev/null
echo "$SSH_AGENT_PID" > "$STORE_PATH"/id
echo "$SSH_AUTH_SOCK" > "$STORE_PATH"/sock
fi
fi

37
docker-rsync/agent-stop Executable file
View file

@ -0,0 +1,37 @@
#!/bin/sh
set -euo pipefail
if [ ! -z "$SSH_AGENT_PID" ]; then
# Here, the environment is set already, just kill the script.
eval $(ssh-agent -k) >/dev/null
exit $?
else
# The env isn't set, construct the file path.
FOLDER=${1:-default}
STORE_PATH="/tmp/ssh-agent/$FOLDER"
if [ ! -d "$STORE_PATH" ]; then
echo "Store Path $STORE_PATH doesn't exist!" >&2
exit 1
fi
# And check our files exist.
if [ -f "$STORE_PATH/id" ]; then
# Grab our PID and socket.
SSH_AGENT_PID=$(cat "$STORE_PATH/id")
export SSH_AGENT_PID
rm "$STORE_PATH/id"
SSH_AUTH_SOCK=$(cat "$STORE_PATH/sock")
export SSH_AUTH_SOCK
rm "$STORE_PATH/sock"
rmdir "$STORE_PATH"
eval $(ssh-agent -k) >/dev/null
exit $?
else
echo "SSH_AGENT_PID not set, $STORE_PATH/id doesn't exist!" >&2
exit 1
fi
fi

5
docker-rsync/ssh-init Executable file
View file

@ -0,0 +1,5 @@
#!/bin/sh
set -euo pipefail
mkdir -m 700 ~/.ssh

View file

@ -1,25 +1,37 @@
#!/bin/sh #!/bin/sh
set -euo pipefail
if [ -z "$(echo "$INPUT_REMOTE_PATH" | awk '{$1=$1};1')" ]; then if [ -z "$(echo "$INPUT_REMOTE_PATH" | awk '{$1=$1};1')" ]; then
echo "The remote_path can not be empty. see: github.com/Burnett01/rsync-deployments/issues/44" echo "The remote_path can not be empty. see: github.com/Burnett01/rsync-deployments/issues/44"
exit 1 exit 1
fi fi
# Initialize SSH and known hosts.
source ssh-init
# Start the SSH agent and load key. # Start the SSH agent and load key.
source agent-start "$GITHUB_ACTION" source agent-start "$GITHUB_ACTION"
echo "$INPUT_REMOTE_KEY" | SSH_PASS="$INPUT_REMOTE_KEY_PASS" agent-add printf '%s' "$INPUT_REMOTE_KEY" | SSH_PASS="${INPUT_REMOTE_KEY_PASS}" agent-add >/dev/null 2>&1
# Add strict errors.
set -eu
# Variables. # Variables.
LEGACY_RSA_HOSTKEYS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa" LEGACY_RSA_HOSTKEYS=""
LEGACY_RSA_HOSTKEYS=$([ "$INPUT_LEGACY_ALLOW_RSA_HOSTKEYS" = "true" ] && echo "$LEGACY_RSA_HOSTKEYS" || echo "") if [ "${INPUT_LEGACY_ALLOW_RSA_HOSTKEYS:-false}" = "true" ]; then
LEGACY_RSA_HOSTKEYS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa"
fi
SWITCHES="$INPUT_SWITCHES" STRICT_HOSTKEYS_CHECKING="-o StrictHostKeyChecking=no"
RSH="ssh -o StrictHostKeyChecking=no $LEGACY_RSA_HOSTKEYS -p $INPUT_REMOTE_PORT $INPUT_RSH" if [ "${INPUT_STRICT_HOSTKEYS_CHECKING:-false}" = "true" ]; then
STRICT_HOSTKEYS_CHECKING="-o StrictHostKeyChecking=yes"
fi
RSH="ssh $STRICT_HOSTKEYS_CHECKING $LEGACY_RSA_HOSTKEYS -p $INPUT_REMOTE_PORT $INPUT_RSH"
LOCAL_PATH="$GITHUB_WORKSPACE/$INPUT_PATH" LOCAL_PATH="$GITHUB_WORKSPACE/$INPUT_PATH"
DSN="$INPUT_REMOTE_USER@$INPUT_REMOTE_HOST" DSN="$INPUT_REMOTE_USER@$INPUT_REMOTE_HOST"
# Deploy. # Deploy.
sh -c "rsync $SWITCHES -e '$RSH' $LOCAL_PATH $DSN:$INPUT_REMOTE_PATH" exec rsync "$INPUT_SWITCHES" -e "'$RSH'" "$LOCAL_PATH" "$DSN:$INPUT_REMOTE_PATH"
# Clean up.
source agent-stop "$GITHUB_ACTION"