Merge pull request #3 from Hermsi1337/maint/major-refactoring
do some major refactoring and add a lot more features
This commit is contained in:
commit
92c3ff8539
35
Dockerfile
35
Dockerfile
@ -1,19 +1,32 @@
|
||||
ARG ALPINE_VERSION=${ALPINE_VERSION:-3.9}
|
||||
FROM alpine:${ALPINE_VERSION}
|
||||
ARG ALPINE_VERSION="${ALPINE_VERSION:-3.9}"
|
||||
FROM alpine:"${ALPINE_VERSION}"
|
||||
|
||||
LABEL maintainer="https://github.com/hermsi1337"
|
||||
|
||||
ARG OPENSSH_VERSION=${OPENSSH_VERSION:-7.9_p1-r5}
|
||||
ENV OPENSSH_VERSION=${OPENSSH_VERSION} \
|
||||
ROOT_PASSWORD=root \
|
||||
KEYPAIR_LOGIN=false
|
||||
ARG OPENSSH_VERSION="${OPENSSH_VERSION:-7.9_p1-r5}"
|
||||
ENV CONF_VOLUME="/conf.d"
|
||||
ENV OPENSSH_VERSION="${OPENSSH_VERSION}" \
|
||||
CACHED_SSH_DIRECTORY="${CONF_VOLUME}/ssh" \
|
||||
AUTHORIZED_KEYS_VOLUME="${CONF_VOLUME}/authorized_keys" \
|
||||
ROOT_KEYPAIR_LOGIN_ENABLED="false" \
|
||||
ROOT_LOGIN_UNLOCKED="false" \
|
||||
USER_LOGIN_SHELL="/bin/bash" \
|
||||
USER_LOGIN_SHELL_FALLBACK="/bin/ash"
|
||||
|
||||
RUN apk add --upgrade --no-cache \
|
||||
bash \
|
||||
bash-completion \
|
||||
rsync \
|
||||
openssh=${OPENSSH_VERSION} \
|
||||
&& \
|
||||
mkdir -p /root/.ssh "${CONF_VOLUME}" "${AUTHORIZED_KEYS_VOLUME}" \
|
||||
&& \
|
||||
cp -a /etc/ssh "${CACHED_SSH_DIRECTORY}" \
|
||||
&& \
|
||||
rm -rf /var/cache/apk/*
|
||||
|
||||
COPY entrypoint.sh /
|
||||
RUN apk add --upgrade --no-cache openssh=${OPENSSH_VERSION} \
|
||||
&& chmod +x /entrypoint.sh \
|
||||
&& mkdir -p /root/.ssh \
|
||||
&& rm -rf /var/cache/apk/* /tmp/*
|
||||
|
||||
COPY conf.d/etc/ /etc/
|
||||
EXPOSE 22
|
||||
VOLUME ["/etc/ssh"]
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
90
README.md
90
README.md
@ -1,7 +1,7 @@
|
||||
## Make your OpenSSH fly on Alpine
|
||||
|
||||
### Overview
|
||||
Use this Dockerfile / -image to start a sshd-server upon a lightweight Alpine container.
|
||||
Use this Dockerfile / -image to start a slim and highly customizable sshd-server with `bash` and `rsync` installed.
|
||||
|
||||
### Regular builds, automagically
|
||||
[](https://travis-ci.com/Hermsi1337/docker-sshd)
|
||||
@ -11,23 +11,19 @@ Thanks to [Travis-CI](https://travis-ci.com/) this image is pushed weekly and cr
|
||||
For recent tags check [Dockerhub](https://hub.docker.com/r/hermsi/alpine-sshd/tags/).
|
||||
|
||||
### Features
|
||||
* Always installs the latest OpenSSH-Version available for Alpine
|
||||
* Password of "root"-user can be changed when starting the container using --env
|
||||
* You can choose between ssh-keypair- and password auth
|
||||
* `bash`-shell and `rsync` installed
|
||||
* Default `.bashrc` from `ubuntu`
|
||||
* Desired shell is configurable by --env
|
||||
* En- or disable `root`-user by --env
|
||||
* Choose between keypar and password auth for `root`
|
||||
* Password for `root` is configurable by --env
|
||||
* Additional ssh-users can be created by --env
|
||||
* Authentication for additional users is done by keypair
|
||||
* Beautifully colored log output
|
||||
|
||||
### Extending this image
|
||||
This image is designed to be as slim and vanilla as possible.
|
||||
If you need additional Tools like `git` or `bash`-shell, I definetly recommend to build your own image on top of `alpine-sshd`:
|
||||
```Dockerfile
|
||||
FROM hermsi/alpine-sshd:latest
|
||||
|
||||
RUN apk add --no-cache --upgrade \
|
||||
git \
|
||||
bash
|
||||
```
|
||||
### Basic Usage
|
||||
#### Authentication by password
|
||||
```
|
||||
### Usage examples
|
||||
#### Authentication as root by password
|
||||
```bash
|
||||
$ docker run --rm \
|
||||
--publish=1337:22 \
|
||||
--env ROOT_PASSWORD=MyRootPW123 \
|
||||
@ -35,21 +31,71 @@ hermsi/alpine-sshd
|
||||
```
|
||||
|
||||
After the container is up you are able to ssh in it as root with the in --env provided password for "root"-user.
|
||||
```
|
||||
```bash
|
||||
$ ssh root@mydomain.tld -p 1337
|
||||
```
|
||||
#### Authentication by ssh-keypair
|
||||
```
|
||||
|
||||
#### Authentication as root by ssh-keypair
|
||||
```bash
|
||||
$ docker run --rm \
|
||||
--publish=1337:22 \
|
||||
--env KEYPAIR_LOGIN=true \
|
||||
--env ROOT_KEYPAIR_LOGIN_ENABLED=true \
|
||||
--volume /path/to/authorized_keys:/root/.ssh/authorized_keys \
|
||||
hermsi/alpine-sshd
|
||||
```
|
||||
|
||||
After the container is up you are able to ssh in it as root with a private-key which matches the provided public-key in authorized_keys for "root"-user.
|
||||
```
|
||||
```bash
|
||||
$ ssh root@mydomain.tld -p 1337 -i /path/to/private_key
|
||||
```
|
||||
|
||||
#### Authenticate as additional user by ssh-keypair
|
||||
$ docker run --rm \
|
||||
--publish=1337:22 \
|
||||
--env SSH_USERS="hermsi:1000:1000" \
|
||||
--volume /path/to/hermsi_public_key:/conf.d/authorized_keys/hermsi \
|
||||
hermsi/alpine-sshd
|
||||
```
|
||||
|
||||
After the container is up you are able to ssh in it as the given user with a private-key that matches the provided public-key in authorized_keys for your created user.
|
||||
```bash
|
||||
$ ssh mydomain.tld -l hermsi -p 1337 -i /path/to/hermsi_private_key
|
||||
```
|
||||
|
||||
#### Create multiple, additional users with keypair
|
||||
$ docker run --rm \
|
||||
--publish=1337:22 \
|
||||
--env SSH_USERS="hermsi:1000:1000,dennis:1001:1001" \
|
||||
--volume /path/to/hermsi_public_key:/conf.d/authorized_keys/hermsi \
|
||||
--volume /path/to/dennis_public_key:/conf.d/authorized_keys/dennis \
|
||||
hermsi/alpine-sshd
|
||||
```
|
||||
|
||||
After the container is up you are able to ssh in it as one of the given users with a private-key that matches the provided public-key in authorized_keys for your desired user.
|
||||
```bash
|
||||
$ ssh root@mydomain.tld -p 1337 -i /path/to/private_key
|
||||
```
|
||||
|
||||
### Configuration
|
||||
While beeing very slim and vanilla this image is still highly customizable.
|
||||
|
||||
#### Environment variables
|
||||
| Variable | Possible Values | Default value | Explanation |
|
||||
|:-----------------:|:-----------------:|:----------------------------------------------:|:------------------------------------------------------------------------------------------------------------------------------------:|
|
||||
| ROOT_LOGIN_UNLOCKED | 'true' or 'false' | 'false' | Whether to enable or disable login as 'root' user |
|
||||
| ROOT_KEYPAIR_LOGIN_ENABLED | 'true' or 'false' | 'false' | Enable login as 'root' by keypair (implies `ROOT_LOGIN_UNLOCKED`). Must mount public-key into container: `/root/.ssh/authorized_keys` |
|
||||
| USER_LOGIN_SHELL | any existing shell | `/bin/bash` | Choose the desired default shell for all additional users. If the configured shell is not existent, a fallback to `/bin/ash` is applied. |
|
||||
|
||||
### Extending this image
|
||||
This image is designed to be as slim and vanilla as possible.
|
||||
If you need additional Tools like `git` , I definetly recommend to build your own image on top of `alpine-sshd`:
|
||||
```Dockerfile
|
||||
FROM hermsi/alpine-sshd:latest
|
||||
|
||||
RUN apk add --no-cache \
|
||||
git
|
||||
```
|
||||
|
||||
### Use with docker-compose
|
||||
I built this image in order to use it along with a nginx and fpm-php container for transferring files via sftp.
|
||||
If you are interested in a Dockerfile which fulfills this need: [this way](https://github.com/Hermsi1337/docker-compose/blob/master/full_php_dev_stack/docker-compose.yml)
|
||||
|
103
conf.d/etc/profile.d/ubuntu-bashrc.sh
Normal file
103
conf.d/etc/profile.d/ubuntu-bashrc.sh
Normal file
@ -0,0 +1,103 @@
|
||||
# ~/.bashrc: executed by bash(1) for non-login shells.
|
||||
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
|
||||
# for examples
|
||||
|
||||
# If not running interactively, don't do anything
|
||||
[ -z "$PS1" ] && return
|
||||
|
||||
# don't put duplicate lines in the history. See bash(1) for more options
|
||||
# ... or force ignoredups and ignorespace
|
||||
HISTCONTROL=ignoredups:ignorespace
|
||||
|
||||
# append to the history file, don't overwrite it
|
||||
shopt -s histappend
|
||||
|
||||
# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
|
||||
HISTSIZE=1000
|
||||
HISTFILESIZE=2000
|
||||
|
||||
# check the window size after each command and, if necessary,
|
||||
# update the values of LINES and COLUMNS.
|
||||
shopt -s checkwinsize
|
||||
|
||||
# make less more friendly for non-text input files, see lesspipe(1)
|
||||
[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"
|
||||
|
||||
# set variable identifying the chroot you work in (used in the prompt below)
|
||||
if [ -z "$debian_chroot" ] && [ -r /etc/debian_chroot ]; then
|
||||
debian_chroot=$(cat /etc/debian_chroot)
|
||||
fi
|
||||
|
||||
# set a fancy prompt (non-color, unless we know we "want" color)
|
||||
case "$TERM" in
|
||||
xterm-color) color_prompt=yes;;
|
||||
esac
|
||||
|
||||
# uncomment for a colored prompt, if the terminal has the capability; turned
|
||||
# off by default to not distract the user: the focus in a terminal window
|
||||
# should be on the output of commands, not on the prompt
|
||||
#force_color_prompt=yes
|
||||
|
||||
if [ -n "$force_color_prompt" ]; then
|
||||
if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
|
||||
# We have color support; assume it's compliant with Ecma-48
|
||||
# (ISO/IEC-6429). (Lack of such support is extremely rare, and such
|
||||
# a case would tend to support setf rather than setaf.)
|
||||
color_prompt=yes
|
||||
else
|
||||
color_prompt=
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$color_prompt" = yes ]; then
|
||||
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
|
||||
else
|
||||
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
|
||||
fi
|
||||
unset color_prompt force_color_prompt
|
||||
|
||||
# If this is an xterm set the title to user@host:dir
|
||||
case "$TERM" in
|
||||
xterm*|rxvt*)
|
||||
PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1"
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
|
||||
# enable color support of ls and also add handy aliases
|
||||
if [ -x /usr/bin/dircolors ]; then
|
||||
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
|
||||
alias ls='ls --color=auto'
|
||||
#alias dir='dir --color=auto'
|
||||
#alias vdir='vdir --color=auto'
|
||||
|
||||
alias grep='grep --color=auto'
|
||||
alias fgrep='fgrep --color=auto'
|
||||
alias egrep='egrep --color=auto'
|
||||
fi
|
||||
|
||||
# some more ls aliases
|
||||
alias ll='ls -alF'
|
||||
alias la='ls -A'
|
||||
alias l='ls -CF'
|
||||
|
||||
# Add an "alert" alias for long running commands. Use like so:
|
||||
# sleep 10; alert
|
||||
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'
|
||||
|
||||
# Alias definitions.
|
||||
# You may want to put all your additions into a separate file like
|
||||
# ~/.bash_aliases, instead of adding them here directly.
|
||||
# See /usr/share/doc/bash-doc/examples in the bash-doc package.
|
||||
|
||||
if [ -f ~/.bash_aliases ]; then
|
||||
. ~/.bash_aliases
|
||||
fi
|
||||
|
||||
# enable programmable completion features (you don't need to enable
|
||||
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
|
||||
# sources /etc/bash.bashrc).
|
||||
if [ -f /etc/bash_completion ] && ! shopt -oq posix; then
|
||||
. /etc/bash_completion
|
||||
fi
|
167
entrypoint.sh
167
entrypoint.sh
@ -1,26 +1,163 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env sh
|
||||
|
||||
if [ "${ROOT_PASSWORD}" == "root" ] || [ -z "${ROOT_PASSWORD}" ]; then
|
||||
export ROOT_PASSWORD="$(hexdump -e '"%02x"' -n 16 /dev/urandom)"
|
||||
echo "Successfully generated a random password for root"
|
||||
set -e
|
||||
|
||||
# enable debug mode if desired
|
||||
if [ "${DEBUG}" = "true" ]; then
|
||||
set -x
|
||||
fi
|
||||
|
||||
echo "root:${ROOT_PASSWORD}" | chpasswd
|
||||
log() {
|
||||
LEVEL="${1}"
|
||||
TO_LOG="${2}"
|
||||
|
||||
WHITE='\033[1;37m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[1;31m'
|
||||
NO_COLOR='\033[0m'
|
||||
|
||||
if [ "${LEVEL}" = "warning" ]; then
|
||||
LOG_LEVEL="${YELLOW}WARN${NO_COLOR}"
|
||||
elif [ "${LEVEL}" = "error" ]; then
|
||||
LOG_LEVEL="${RED}ERROR${NO_COLOR}"
|
||||
else
|
||||
LOG_LEVEL="${WHITE}INFO${NO_COLOR}"
|
||||
if [ -z "${TO_LOG}" ]; then
|
||||
TO_LOG="${1}"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -e "[${LOG_LEVEL}] ${TO_LOG}"
|
||||
}
|
||||
|
||||
ensure_mod() {
|
||||
FILE="${1}"
|
||||
MOD="${2}"
|
||||
U_ID="${3}"
|
||||
G_ID="${4}"
|
||||
|
||||
chmod "${MOD}" "${FILE}"
|
||||
chown "${U_ID}"."${G_ID}" "${FILE}"
|
||||
}
|
||||
|
||||
generate_passwd() {
|
||||
hexdump -e '"%02x"' -n 16 /dev/urandom
|
||||
}
|
||||
|
||||
# ensure backward comaptibility for earlier versions of this image
|
||||
if [ -n "${KEYPAIR_LOGIN}" ] && [ "${KEYPAIR_LOGIN}" = "true" ]; then
|
||||
ROOT_KEYPAIR_LOGIN_ENABLED="${KEYPAIR_LOGIN}"
|
||||
fi
|
||||
if [ -n "${ROOT_PASSWORD}" ]; then
|
||||
ROOT_LOGIN_UNLOCKED="true"
|
||||
fi
|
||||
|
||||
# enable root login if keypair login is enabled
|
||||
if [ "${ROOT_KEYPAIR_LOGIN_ENABLED}" = "true" ]; then
|
||||
ROOT_LOGIN_UNLOCKED="true"
|
||||
fi
|
||||
|
||||
# initiate default sshd-config if there is none available
|
||||
if ! find "/etc/ssh" -mindepth 1 -print -quit 2>/dev/null | grep -q .; then
|
||||
cp -a "${CACHED_SSH_DIRECTORY}"/* /etc/ssh/.
|
||||
fi
|
||||
rm -rf "${CACHED_SSH_DIRECTORY}"
|
||||
|
||||
# generate host keys if not present
|
||||
ssh-keygen -A
|
||||
ssh-keygen -A 1>/dev/null
|
||||
|
||||
log "Applying configuration for 'root' user ..."
|
||||
|
||||
if [ "${ROOT_LOGIN_UNLOCKED}" = "true" ] ; then
|
||||
|
||||
# generate random root password
|
||||
if [ -z "${ROOT_PASSWORD}" ]; then
|
||||
log " generating random password for user 'root'"
|
||||
ROOT_PASSWORD="$(generate_passwd)"
|
||||
fi
|
||||
|
||||
echo "root:${ROOT_PASSWORD}" | chpasswd >/dev/null 2>&1
|
||||
log " password for user 'root' set"
|
||||
log "warning" " user 'root' is now UNLOCKED"
|
||||
|
||||
# set root login mode by password or keypair
|
||||
if [ "${ROOT_KEYPAIR_LOGIN_ENABLED}" = "true" ] && [ -f "${HOME}/.ssh/authorized_keys" ] ; then
|
||||
sed -i "s/#PermitRootLogin.*/PermitRootLogin without-password/" /etc/ssh/sshd_config
|
||||
sed -i "s/#PasswordAuthentication.*/PasswordAuthentication no/" /etc/ssh/sshd_config
|
||||
ensure_mod "${HOME}/.ssh/authorized_keys" "0600" "root" "root"
|
||||
log " enabled login by keypair and disabled password-login for user 'root'"
|
||||
else
|
||||
sed -i "s/#PermitRootLogin.*/PermitRootLogin\ yes/" /etc/ssh/sshd_config
|
||||
log " enabled login by password for user 'root'"
|
||||
fi
|
||||
|
||||
# set root login mode by password or keypair
|
||||
if [ "${KEYPAIR_LOGIN}" = "true" ] && [ -f "${HOME}/.ssh/authorized_keys" ] ; then
|
||||
sed -i "s/#PermitRootLogin.*/PermitRootLogin without-password/" /etc/ssh/sshd_config
|
||||
sed -i "s/#PasswordAuthentication.*/PasswordAuthentication no/" /etc/ssh/sshd_config
|
||||
chmod 600 "${HOME}/.ssh/authorized_keys"
|
||||
chown root.root "${HOME}/.ssh/authorized_keys"
|
||||
echo "Enabled root-login by keypair and disabled password-login"
|
||||
else
|
||||
sed -i s/#PermitRootLogin.*/PermitRootLogin\ yes/ /etc/ssh/sshd_config
|
||||
echo "Enabled root-login by password"
|
||||
|
||||
sed -i "s/#PermitRootLogin.*/PermitRootLogin no/" /etc/ssh/sshd_config
|
||||
log " disabled login for user 'root'"
|
||||
log " user 'root' is now LOCKED"
|
||||
|
||||
fi
|
||||
|
||||
printf "\n" ""
|
||||
|
||||
log "Applying configuration for additional users ..."
|
||||
|
||||
if [ ! -x "${USER_LOGIN_SHELL}" ]; then
|
||||
log "error" " can not allocate desired shell '${USER_LOGIN_SHELL}', falling back to '${USER_LOGIN_SHELL_FALLBACK}' ..."
|
||||
USER_LOGIN_SHELL="${USER_LOGIN_SHELL_FALLBACK}"
|
||||
fi
|
||||
|
||||
log " desired shell is ${USER_LOGIN_SHELL}"
|
||||
|
||||
|
||||
if [ -n "${SSH_USERS}" ]; then
|
||||
|
||||
IFS=","
|
||||
for USER in ${SSH_USERS}; do
|
||||
|
||||
log " '${USER}'"
|
||||
|
||||
USER_NAME="$(echo "${USER}" | cut -d ':' -f 1)"
|
||||
USER_UID="$(echo "${USER}" | cut -d ':' -f 2)"
|
||||
USER_GID="$(echo "${USER}" | cut -d ':' -f 3)"
|
||||
|
||||
if [ -z "${USER_NAME}" ] || [ -z "${USER_UID}" ] || [ -z "${USER_GID}" ]; then
|
||||
log "error" " skipping invalid data '${USER_NAME}' - UID: '${USER_UID}' GID: '${USER_GID}'"
|
||||
continue
|
||||
fi
|
||||
|
||||
getent group "${USER_GID}" >/dev/null 2>&1 || addgroup -g "${USER_GID}" "${USER_NAME}"
|
||||
getent passwd "${USER_NAME}" >/dev/null 2>&1 || adduser -s "${USER_LOGIN_SHELL}" -D -u "${USER_UID}" -G "${USER_NAME}" "${USER_NAME}"
|
||||
passwd -u "${USER_NAME}" >/dev/null 2>&1
|
||||
mkdir -p "/home/${USER_NAME}/.ssh"
|
||||
|
||||
log " user '${USER_NAME}' created - UID: '${USER_UID}' GID: '${USER_GID}'"
|
||||
|
||||
MOUNTED_AUTHORIZED_KEYS="${AUTHORIZED_KEYS_VOLUME}/${USER_NAME}"
|
||||
LOCAL_AUTHORIZED_KEYS="/home/${USER_NAME}/.ssh/authorized_keys"
|
||||
|
||||
if [ ! -e "${MOUNTED_AUTHORIZED_KEYS}" ]; then
|
||||
log "warning" " no SSH authorized_keys found for user '${USER_NAME}'"
|
||||
else
|
||||
cp "${MOUNTED_AUTHORIZED_KEYS}" "${LOCAL_AUTHORIZED_KEYS}"
|
||||
log " copied ${MOUNTED_AUTHORIZED_KEYS} to ${LOCAL_AUTHORIZED_KEYS}"
|
||||
ensure_mod "${LOCAL_AUTHORIZED_KEYS}" "0600" "${USER_NAME}" "${USER_GID}"
|
||||
log " set mod 0600 on ${LOCAL_AUTHORIZED_KEYS}"
|
||||
fi
|
||||
|
||||
printf "\n" ""
|
||||
|
||||
done
|
||||
unset IFS
|
||||
|
||||
else
|
||||
|
||||
log " no additional SSH-users set"
|
||||
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# do not detach (-D), log to stderr (-e), passthrough other arguments
|
||||
exec /usr/sbin/sshd -D -e "$@"
|
Loading…
x
Reference in New Issue
Block a user