Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ci: add tests #1

Merged
merged 18 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
421 changes: 390 additions & 31 deletions .github/workflows/main.yml

Large diffs are not rendered by default.

14 changes: 13 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@

# -- Deprecated
ACTION_SERVICE=action
TESTING_CMD=local/test.sh
# --

start:
@docker compose up -d
Expand All @@ -16,8 +19,9 @@ stop:
down:
@docker compose down

# -- Deprecated
check-running:
@docker-compose ps --services | grep $(ACTION_SERVICE) > /dev/null || $(MAKE) start
@docker compose ps --services | grep $(ACTION_SERVICE) > /dev/null || $(MAKE) start

exec: check-running
@docker compose exec -it $(ACTION_SERVICE) sh
Expand All @@ -26,3 +30,11 @@ test: check-running
@docker compose exec -it $(ACTION_SERVICE) $(TESTING_CMD)

dev: start-f exec
# --

tests-build:
@docker build -f ./tests/host/Dockerfile -t docker_throw_ssh .

tests-deploy: tests-build
@docker tag docker_throw_ssh ghcr.io/tristiisch/docker_throw_ssh:latest
@docker push ghcr.io/tristiisch/docker_throw_ssh:latest
1 change: 0 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ inputs:
required: true
ssh_public_key:
description: 'Public key of the SSH server'
required: true
ssh_private_key:
description: 'Private key of the SSH client'
required: true
Expand Down
6 changes: 1 addition & 5 deletions docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ if [ -z "$INPUT_REMOTE_DOCKER_USERNAME" ]; then
error "Input remote_docker_username is required."
fi

if [ -z "$INPUT_SSH_PUBLIC_KEY" ]; then
error "Input ssh_public_key is required."
fi

if [ -z "$INPUT_SSH_PRIVATE_KEY" ]; then
error "Input ssh_private_key is required."
fi
Expand Down Expand Up @@ -85,7 +81,7 @@ case $INPUT_DEPLOYMENT_MODE in

# Rotate secret if any
POST_SCRIPTS_FOLDER=""
if [ -n "${INPUT_SECRETS+set}" ]; then
if [ -n "${INPUT_SECRETS+set}" ] && [ -n "$INPUT_SECRETS" ]; then
POST_SCRIPTS_FOLDER="/opt/scripts/post"
export POST_SCRIPTS_FOLDER
"$WORKDIR/scripts/docker_secrets.sh" "$INPUT_STACK_FILE_PATH" "$INPUT_STACK_NAME" $INPUT_SECRETS
Expand Down
4 changes: 2 additions & 2 deletions scripts/docker_compose.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ if [ "$INPUT_COPY_STACK_FILE" = "true" ] ; then
info "Removing outdated backup files"
execute_ssh "ls -t $INPUT_DEPLOY_PATH/stacks/docker-stack-* 2>/dev/null | tail -n +$INPUT_KEEP_FILES | xargs rm -- 2>/dev/null || true"

if ! [ -z "$INPUT_PULL_IMAGES_FIRST" ] && [ "$INPUT_PULL_IMAGES_FIRST" = 'true' ] ; then
if [ -n "$INPUT_PULL_IMAGES_FIRST" ] && [ "$INPUT_PULL_IMAGES_FIRST" = 'true' ] ; then
info "Pulling the latest Docker image"
execute_ssh "$DEPLOYMENT_COMMAND" "pull"
fi

if ! [ -z "$INPUT_PRE_DEPLOYMENT_COMMAND_ARGS" ]; then
if [ -n "$INPUT_PRE_DEPLOYMENT_COMMAND_ARGS" ]; then
info "Executing pre-commands"
execute_ssh "$DEPLOYMENT_COMMAND $INPUT_PRE_DEPLOYMENT_COMMAND_ARGS" 2>&1
fi
Expand Down
3 changes: 1 addition & 2 deletions scripts/docker_secrets.sh
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,7 @@ fi

debug "docker_secret.sh $*"

# Check if service_name is provided
if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] || [ -z "$4" ]; then
if [ -z "${1+set}" ] || [ -z "${2+set}" ] || [ -z "${3+set}" ] || [ -z "${4+set}" ]; then
echo "Usage: $0 docker-compose.yml stack_name service_name secret_name key1 value1 key2 value2 ..." >&2
exit 1
fi
Expand Down
111 changes: 85 additions & 26 deletions scripts/functions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,79 +3,118 @@ set -eu

KEY_NAME="docker_key"
SSH_FOLDER="$HOME/.ssh"
SSH_CONFIG_PATH="/etc/ssh/ssh_config.d/docker_stack_deployement.conf"
KEY_PATH="$SSH_FOLDER/$KEY_NAME"
STRICT_HOST="yes"
KNOWN_HOST_PATH=$SSH_FOLDER/known_hosts
KNOWN_HOST_PATH=$SSH_FOLDER/known_hosts_$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
DOCKER_CONTEXT_NAME="docker-remote"

setup_ssh() {
if [ -e "$KEY_PATH" ]; then
debug "SSH key setup already completed"
return 0
debug "SSH key setup already completed; it will be overwritten."
fi
SSH_HOST=$INPUT_REMOTE_DOCKER_HOST
SSH_KEY_TYPE=$(echo "$INPUT_SSH_PUBLIC_KEY" | cut -d ' ' -f 1)
SSH_PORT=$INPUT_REMOTE_DOCKER_PORT

SSH_VERSION=$(ssh -V 2>&1)
debug "SSH client version : $SSH_VERSION"

info "Registering SSH key"
info "Create SSH folder"
mkdir -p "$SSH_FOLDER"
chmod 700 "$SSH_FOLDER"
if is_debug; then
debug "Verify permission on ssh folder"
ls -l "$SSH_FOLDER"
fi

info "Registering SSH key"
printf '%s\n' "$INPUT_SSH_PRIVATE_KEY" > "$KEY_PATH"
chmod 600 "$KEY_PATH"

if is_debug; then
SERVER_PUBLIC_KEY=$(ssh-keyscan -t "$SSH_KEY_TYPE" "$SSH_HOST" 2>&1)
debug "Public key of ssh server $SSH_KEY_TYPE : $SERVER_PUBLIC_KEY"
debug "Verify permission on private key"
ls -l "$KEY_PATH"
fi

info "Adding known hosts"
printf '%s %s\n' "$SSH_HOST" "$INPUT_SSH_PUBLIC_KEY" > "$KNOWN_HOST_PATH"

KNOWN_HOST=$(cat "$KNOWN_HOST_PATH")
debug "$KNOWN_HOST"

cat <<EOF >> "/etc/ssh/ssh_config.d/docker_stack_deployement.conf"
IdentityFile $SSH_FOLDER/$KEY_NAME
cat <<EOF > "$SSH_CONFIG_PATH"
IdentityFile $KEY_PATH
UserKnownHostsFile $KNOWN_HOST_PATH
StrictHostKeyChecking $STRICT_HOST
ControlMaster auto
ControlPath $SSH_FOLDER/control-%C
ControlPersist yes
EOF

STRICT_HOST="accept-new"
if [ -n "$INPUT_SSH_PUBLIC_KEY" ]; then
STRICT_HOST="yes"
if is_debug; then
SSH_KEY_TYPE=$(echo "$INPUT_SSH_PUBLIC_KEY" | cut -d ' ' -f 1)
debug "Getting public key $SSH_KEY_TYPE of ssh server $SSH_HOST:$SSH_PORT ..."
ssh-keyscan -v -t "$SSH_KEY_TYPE" -p "$SSH_PORT" "$SSH_HOST"
fi

info "Adding known hosts"
if [ "$SSH_PORT" = "22" ]; then
printf '%s %s\n' "$SSH_HOST" "$INPUT_SSH_PUBLIC_KEY" > "$KNOWN_HOST_PATH"
else
printf '[%s]:%s %s\n' "$SSH_HOST" "$SSH_PORT" "$INPUT_SSH_PUBLIC_KEY" > "$KNOWN_HOST_PATH"
fi
chmod 600 "$KNOWN_HOST_PATH"
if is_debug; then
debug "Verify permission on known hosts"
ls -l "$KNOWN_HOST_PATH"
fi

KNOWN_HOST=$(cat "$KNOWN_HOST_PATH")
debug "$KNOWN_HOST_PATH :" "$KNOWN_HOST"
fi
printf ' StrictHostKeyChecking %s\n' $STRICT_HOST >> "$SSH_CONFIG_PATH"
SSH_CONFIG=$(cat "$SSH_CONFIG_PATH")
debug "$SSH_CONFIG_PATH :" "$SSH_CONFIG"

info "Testing SSH connection ..."
if is_debug; then
ssh -v -p "$SSH_PORT" "$DOCKER_USER_HOST" exit
else
ssh -p "$SSH_PORT" "$DOCKER_USER_HOST" exit
fi
info "Done !"
}

setup_remote_docker() {
SSH_PORT=$INPUT_REMOTE_DOCKER_PORT
if ! docker context inspect "$DOCKER_CONTEXT_NAME" >/dev/null 2>&1; then
docker context create "$DOCKER_CONTEXT_NAME" --docker "host=ssh://$DOCKER_USER_HOST:$INPUT_REMOTE_DOCKER_PORT"
info "Create docker context"
debug "Adding context host=ssh://$DOCKER_USER_HOST:$SSH_PORT"
docker context create "$DOCKER_CONTEXT_NAME" --docker "host=ssh://$DOCKER_USER_HOST:$SSH_PORT"
fi

current_context=$(docker context show)
info "Current context used is $current_context"
if [ "$current_context" != "$DOCKER_CONTEXT_NAME" ]; then
docker context use $DOCKER_CONTEXT_NAME
info "Use docker context"
docker context use "$DOCKER_CONTEXT_NAME"
fi
}

execute_ssh(){
SSH_PORT=$INPUT_REMOTE_DOCKER_PORT
verbose_arg=""
if is_debug; then
verbose_arg="-v"
fi
debug "Execute Over SSH : $ $*"
ssh $verbose_arg -p "$INPUT_REMOTE_DOCKER_PORT" "$DOCKER_USER_HOST" "$@" 2>&1
ssh $verbose_arg -p "$SSH_PORT" "$DOCKER_USER_HOST" "$@" 2>&1
}

copy_ssh(){
SSH_PORT=$INPUT_REMOTE_DOCKER_PORT
verbose_arg=""
if is_debug; then
verbose_arg="-v"
fi
local_file="$1"
remote_file="$2"
debug "Copy Over SSH : $local_file -> $remote_file"
scp $verbose_arg -P "$INPUT_REMOTE_DOCKER_PORT" "$local_file" "$DOCKER_USER_HOST:$remote_file" 2>&1
scp $verbose_arg -P "$SSH_PORT" "$local_file" "$DOCKER_USER_HOST:$remote_file" 2>&1
}

is_debug() {
Expand All @@ -97,21 +136,41 @@ WHITE='\e[0;37m'
RESET='\e[0m'

error() {
printf "${RED}ERROR\t%s${RESET}\n" "$*"
printf "${RED}ERROR\t%s${RESET}\n" "$1"
shift
while [ "$#" -gt 0 ]; do
printf "%s\n" "$1"
shift
done
exit 1
}

warning() {
printf "${YELLOW}WARNING\t%s${RESET}\n" "$*"
printf "${YELLOW}WARNING\t%s${RESET}\n" "$1"
shift
while [ "$#" -gt 0 ]; do
printf "%s\n" "$1"
shift
done
}

info() {
printf "${CYAN}INFO\t%s${RESET}\n" "$*"
printf "${CYAN}INFO\t%s${RESET}\n" "$1"
shift
while [ "$#" -gt 0 ]; do
printf "%s\n" "$1"
shift
done
}

debug() {
if ! is_debug; then
return
fi
printf "${MAGENTA}DEBUG\t%s${RESET}\n" "$*"
printf "${MAGENTA}DEBUG\t%s${RESET}\n" "$1"
shift
while [ "$#" -gt 0 ]; do
printf "%s\n" "$1"
shift
done
}
5 changes: 5 additions & 0 deletions tests/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
services:
web:
image: nginx:alpine
ports:
- "80"
69 changes: 69 additions & 0 deletions tests/host/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
FROM debian:12
ARG SHELL=/bin/bash

LABEL org.opencontainers.image.source=https://github.com/tristiisch/docker-stack-deployment

ENV container=docker
ENV DEBIAN_FRONTEND=noninteractive

# Install systemd
RUN apt update && \
apt install -y \
systemd \
systemd-sysv\
dbus && \
# Clean up
rm -rf /var/lib/apt/lists/*

RUN rm -rf /lib/systemd/system/multi-user.target.wants/* && \
rm -rf /etc/systemd/system/*.wants/* && \
rm -rf /lib/systemd/system/local-fs.target.wants/* && \
rm -rf /lib/systemd/system/sockets.target.wants/*udev* && \
rm -rf /lib/systemd/system/sockets.target.wants/*initctl* && \
rm -rf /lib/systemd/system/sysinit.target.wants/systemd-tmpfiles-setup* && \
rm -rf /lib/systemd/system/systemd-update-utmp*

RUN \
# SSH server and tools to install Docker's APT repository
apt update && \
apt install -y --no-install-recommends \
ca-certificates \
curl \
gnupg \
lsb-release \
software-properties-common \
openssh-server && \
# Clean up
rm -rf /var/lib/apt/lists/*

# Setup Docker's APT repository and install Docker
RUN install -m 0755 -d /etc/apt/keyrings && \
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc && \
chmod a+r /etc/apt/keyrings/docker.asc && \
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
tee /etc/apt/sources.list.d/docker.list && \
apt update && \
apt install -y --no-install-recommends \
docker-ce \
docker-ce-cli \
containerd.io \
docker-buildx-plugin \
docker-compose-plugin && \
# Clean up
rm -rf /var/lib/apt/lists/*

# SSH Server Configuration
RUN mkdir -p /run/sshd && \
echo 'PermitRootLogin no' >> /etc/ssh/sshd_config.d/custom && \
echo 'PasswordAuthentication yes' >> /etc/ssh/sshd_config.d/custom && \
useradd -m -s $SHELL president && \
usermod -aG docker president && \
chmod 700 -R /home/president && \
echo 'president:P@ssword!' | chpasswd
# && rm /etc/ssh/ssh_host_*
# ssh-keygen -A

VOLUME ["/sys/fs/cgroup"]
EXPOSE 22
STOPSIGNAL SIGRTMIN+3
CMD ["/lib/systemd/systemd"]
17 changes: 17 additions & 0 deletions tests/host/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
services:
docker_throw_ssh:
build:
context: .
dockerfile: ./Dockerfile
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup
ports:
- 2222:22
tty: true
cap_add:
- NET_ADMIN
- NET_RAW
tmpfs:
- /run
- /run/lock
- /tmp
26 changes: 26 additions & 0 deletions tests/host/with_key/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

ARG BASE_TAG=latest

FROM ghcr.io/tristiisch/docker_throw_ssh:${BASE_TAG}
ARG SSH_PUBLIC_KEY

Check warning on line 5 in tests/host/with_key/Dockerfile

View workflow job for this annotation

GitHub Actions / Build test service

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ARG "SSH_PUBLIC_KEY") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ARG SSH_PRIVATE_ACCOUNT=deploy

RUN test -n "$SSH_PUBLIC_KEY" || (echo "Error: SSH_PUBLIC_KEY is not set" && exit 1)

# Authentification only with key
RUN echo 'PasswordAuthentication no' >> /etc/ssh/sshd_config.d/aa-custom

# SSH Account
RUN useradd -m $SSH_PRIVATE_ACCOUNT \
&& usermod -aG docker $SSH_PRIVATE_ACCOUNT \
&& chmod 700 -R /home/$SSH_PRIVATE_ACCOUNT \
&& mkdir -p /home/$SSH_PRIVATE_ACCOUNT/.ssh \
&& chmod 700 /home/$SSH_PRIVATE_ACCOUNT/.ssh \
&& chown $SSH_PRIVATE_ACCOUNT:$SSH_PRIVATE_ACCOUNT /home/$SSH_PRIVATE_ACCOUNT/.ssh \
&& echo "$SSH_PUBLIC_KEY" > /home/$SSH_PRIVATE_ACCOUNT/.ssh/authorized_keys \
&& chmod 600 /home/$SSH_PRIVATE_ACCOUNT/.ssh/authorized_keys \
&& chown $SSH_PRIVATE_ACCOUNT:$SSH_PRIVATE_ACCOUNT /home/$SSH_PRIVATE_ACCOUNT/.ssh/authorized_keys

# Create one shot usage service to init swarm on first container boot
COPY ./docker-swarm-init.service /etc/systemd/system/docker-swarm-init.service
RUN ln -s /etc/systemd/system/docker-swarm-init.service /etc/systemd/system/multi-user.target.wants/docker-swarm-init.service
Loading