├── .gitignore ├── .gitlab-ci.yml ├── Dockerfile ├── LICENSE ├── README.md ├── conf.d └── etc │ └── profile.d │ └── ubuntu-bashrc.sh └── entrypoint.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .idea -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | stages: 2 | - build 3 | - deploy 4 | 5 | services: 6 | - docker:dind 7 | 8 | image: docker:20 9 | 10 | before_script: 11 | - apk add --no-cache shellcheck w3m curl jq gawk grep bash 12 | - find . -name "*.sh" -maxdepth 1 -print0 | xargs -0 -r -n1 bash -n 13 | - find . -name "*.sh" -maxdepth 1 -print0 | xargs -0 -r -n1 shellcheck 14 | - export CURRENT_ALPINE_VERSION="$(w3m -dump https://alpinelinux.org/releases/ | grep "edge" -A1 | tail -1 | awk '{print $1}' | cut -d "v" -f 2)" 15 | - export OPENSSH_VERSION="$(w3m -dump "https://pkgs.alpinelinux.org/packages?name=openssh&branch=v${CURRENT_ALPINE_VERSION}" | grep -m 1 "x86" | awk '{print $2}')" 16 | - echo "Building Open-SSH in version '${OPENSSH_VERSION}' on Alpine '${CURRENT_ALPINE_VERSION}'" 17 | 18 | build:docker: 19 | stage: build 20 | script: 21 | - > 22 | docker build 23 | --no-cache 24 | --pull 25 | --build-arg ALPINE_VERSION="${CURRENT_ALPINE_VERSION}" 26 | --build-arg OPENSSH_VERSION="${OPENSSH_VERSION}" 27 | --tag "${IMAGE_NAME}:${OPENSSH_VERSION}-alpine${ALPINE_VERSION}" 28 | --tag "${IMAGE_NAME}:${OPENSSH_VERSION}-alpine" 29 | --tag "${IMAGE_NAME}:${OPENSSH_VERSION}" 30 | --tag "${IMAGE_NAME}:latest" 31 | --file "${CI_PROJECT_DIR}/Dockerfile" 32 | "${CI_PROJECT_DIR}" 33 | except: 34 | - master 35 | parallel: 36 | matrix: 37 | - IMAGE_NAME: [ "hermsi/alpine-sshd" ] 38 | 39 | deploy:docker: 40 | stage: deploy 41 | script: 42 | - > 43 | docker build 44 | --no-cache 45 | --pull 46 | --build-arg ALPINE_VERSION="${CURRENT_ALPINE_VERSION}" 47 | --build-arg OPENSSH_VERSION="${OPENSSH_VERSION}" 48 | --tag "${IMAGE_NAME}:${OPENSSH_VERSION}-alpine${CURRENT_ALPINE_VERSION}" 49 | --tag "${IMAGE_NAME}:${OPENSSH_VERSION}-alpine" 50 | --tag "${IMAGE_NAME}:${OPENSSH_VERSION}" 51 | --tag "${IMAGE_NAME}:latest" 52 | --file "${CI_PROJECT_DIR}/Dockerfile" 53 | "${CI_PROJECT_DIR}" 54 | - > 55 | mkdir -p "${HOME}/.docker" && 56 | mv "${DOCKER_CONFIG_JSON}" "${HOME}/.docker/config.json" && 57 | chmod 0600 "${HOME}/.docker/config.json" 58 | - docker push "${IMAGE_NAME}:${OPENSSH_VERSION}-alpine${CURRENT_ALPINE_VERSION}" 59 | - docker push "${IMAGE_NAME}:${OPENSSH_VERSION}-alpine" 60 | - docker push "${IMAGE_NAME}:${OPENSSH_VERSION}" 61 | - docker push "${IMAGE_NAME}:latest" 62 | only: 63 | - master 64 | parallel: 65 | matrix: 66 | - IMAGE_NAME: [ "hermsi/alpine-sshd", "quay.io/hermsi1337/alpine-sshd" ] 67 | - IMAGE_NAME: [ "hermsi/alpine-sshd", "quay.io/hermsi1337/alpine-sshd" ] -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG ALPINE_VERSION="${ALPINE_VERSION:-3.15}" 2 | FROM alpine:${ALPINE_VERSION} 3 | 4 | LABEL maintainer="https://github.com/hermsi1337" 5 | 6 | ARG OPENSSH_VERSION="${OPENSSH_VERSION:-8.8_p1-r1}" 7 | ENV CONF_VOLUME="/conf.d" 8 | ENV OPENSSH_VERSION="${OPENSSH_VERSION}" \ 9 | CACHED_SSH_DIRECTORY="${CONF_VOLUME}/ssh" \ 10 | AUTHORIZED_KEYS_VOLUME="${CONF_VOLUME}/authorized_keys" \ 11 | ROOT_KEYPAIR_LOGIN_ENABLED="false" \ 12 | ROOT_LOGIN_UNLOCKED="false" \ 13 | USER_LOGIN_SHELL="/bin/bash" \ 14 | USER_LOGIN_SHELL_FALLBACK="/bin/ash" 15 | 16 | RUN apk add --upgrade --no-cache \ 17 | bash \ 18 | bash-completion \ 19 | rsync \ 20 | openssh=${OPENSSH_VERSION} \ 21 | && \ 22 | mkdir -p /root/.ssh "${CONF_VOLUME}" "${AUTHORIZED_KEYS_VOLUME}" \ 23 | && \ 24 | cp -a /etc/ssh "${CACHED_SSH_DIRECTORY}" \ 25 | && \ 26 | rm -rf /var/cache/apk/* 27 | 28 | COPY entrypoint.sh / 29 | COPY conf.d/etc/ /etc/ 30 | EXPOSE 22 31 | VOLUME ["/etc/ssh"] 32 | ENTRYPOINT ["/entrypoint.sh"] 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Dennis Hermsmeier 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Travis](https://shields.beevelop.com/travis/Hermsi1337/docker-sshd.svg?style=flat-square)](https://travis-ci.com/Hermsi1337/docker-sshd) 2 | [![Pulls](https://shields.beevelop.com/docker/pulls/hermsi/alpine-sshd.svg?style=flat-square)](https://hub.docker.com/r/hermsi/alpine-sshd/) 3 | [![Stars](https://shields.beevelop.com/docker/stars/hermsi/alpine-sshd.svg?style=flat-square)](https://hub.docker.com/r/hermsi/alpine-sshd/) 4 | [![Layers](https://shields.beevelop.com/docker/image/layers/hermsi/alpine-sshd/latest.svg?style=flat-square)](https://hub.docker.com/r/hermsi/alpine-sshd/) 5 | [![Size](https://shields.beevelop.com/docker/image/image-size/hermsi/alpine-sshd/latest.svg?style=flat-square)](https://hub.docker.com/r/hermsi/alpine-sshd/) 6 | [![Donate](https://img.shields.io/badge/Donate-PayPal-yellow.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=T85UYT37P3YNJ&source=url) 7 | 8 | ## Make your OpenSSH fly on Alpine 9 | 10 | ### Overview 11 | 12 | Use this Dockerfile / -image to start a slim and highly customizable sshd-server with `bash` and `rsync` installed. 13 | 14 | ### Regular builds, automagically 15 | 16 | Thanks to [Travis-CI](https://travis-ci.com/) this image is pushed weekly and creates new [tags](https://hub.docker.com/r/hermsi/alpine-sshd/tags/) if there are new versions available. 17 | 18 | ### Tags 19 | 20 | For recent tags check [Dockerhub](https://hub.docker.com/r/hermsi/alpine-sshd/tags/). 21 | 22 | ### Features 23 | 24 | * `bash`-shell and `rsync` installed 25 | * Default `.bashrc` from `ubuntu` 26 | * Desired shell is configurable by --env 27 | * En- or disable `root`-user by --env 28 | * Choose between keypar and password auth for `root` 29 | * Password for `root` is configurable by --env 30 | * Additional ssh-users can be created by --env 31 | * Authentication for additional users is done by keypair 32 | * Beautifully colored log output 33 | 34 | ### Usage examples 35 | 36 | #### Authentication as root by password 37 | 38 | ```bash 39 | $ docker run --rm \ 40 | --publish=1337:22 \ 41 | --env ROOT_PASSWORD=MyRootPW123 \ 42 | hermsi/alpine-sshd 43 | ``` 44 | 45 | After the container is up you are able to ssh in it as root with the in --env provided password for "root"-user. 46 | 47 | ```bash 48 | $ ssh root@mydomain.tld -p 1337 49 | ``` 50 | 51 | #### Authentication as root by ssh-keypair 52 | 53 | ```bash 54 | $ docker run --rm \ 55 | --publish=1337:22 \ 56 | --env ROOT_KEYPAIR_LOGIN_ENABLED=true \ 57 | --volume /path/to/authorized_keys:/root/.ssh/authorized_keys \ 58 | hermsi/alpine-sshd 59 | ``` 60 | 61 | 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. 62 | 63 | ```bash 64 | $ ssh root@mydomain.tld -p 1337 -i /path/to/private_key 65 | ``` 66 | 67 | #### Authenticate as additional user by ssh-keypair 68 | 69 | ```bash 70 | $ docker run --rm \ 71 | --publish=1337:22 \ 72 | --env SSH_USERS="hermsi:1000:1000" \ 73 | --volume /path/to/hermsi_public_key:/conf.d/authorized_keys/hermsi \ 74 | hermsi/alpine-sshd 75 | ``` 76 | 77 | 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. 78 | 79 | ```bash 80 | $ ssh mydomain.tld -l hermsi -p 1337 -i /path/to/hermsi_private_key 81 | ``` 82 | 83 | #### Create multiple, additional users with keypair 84 | 85 | ```bash 86 | $ docker run --rm \ 87 | --publish=1337:22 \ 88 | --env SSH_USERS="hermsi:1000:1000,dennis:1001:1001" \ 89 | --volume /path/to/hermsi_public_key:/conf.d/authorized_keys/hermsi \ 90 | --volume /path/to/dennis_public_key:/conf.d/authorized_keys/dennis \ 91 | hermsi/alpine-sshd 92 | ``` 93 | 94 | 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. 95 | 96 | ```bash 97 | $ ssh root@mydomain.tld -p 1337 -i /path/to/private_key 98 | ``` 99 | 100 | ### Configuration 101 | 102 | While beeing very slim and vanilla this image is still highly customizable. 103 | 104 | #### Environment variables 105 | 106 | | Variable | Possible Values | Default value | Explanation | 107 | |:-----------------:|:-----------------:|:----------------------------------------------:|:------------------------------------------------------------------------------------------------------------------------------------:| 108 | | ROOT_LOGIN_UNLOCKED | 'true' or 'false' | 'false' | Whether to enable or disable login as 'root' user | 109 | | 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` | 110 | | ROOT_PASSWORD | any desired string | `undefined` | Set password for login as `root` (implies `ROOT_LOGIN_UNLOCKED`) | 111 | | 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 | 112 | 113 | ### Extending this image 114 | 115 | This image is designed to be as slim and vanilla as possible. 116 | If you need additional Tools like `git` , I definetly recommend to build your own image on top of `alpine-sshd`: 117 | 118 | ```Dockerfile 119 | FROM hermsi/alpine-sshd:latest 120 | 121 | RUN apk add --no-cache \ 122 | git 123 | ``` 124 | 125 | ### Use with docker-compose 126 | 127 | I built this image in order to use it along with a nginx and fpm-php container for transferring files via sftp. 128 | 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) 129 | -------------------------------------------------------------------------------- /conf.d/etc/profile.d/ubuntu-bashrc.sh: -------------------------------------------------------------------------------- 1 | # ~/.bashrc: executed by bash(1) for non-login shells. 2 | # see /usr/share/doc/bash/examples/startup-files (in the package bash-doc) 3 | # for examples 4 | 5 | # If not running interactively, don't do anything 6 | [ -z "$PS1" ] && return 7 | 8 | # don't put duplicate lines in the history. See bash(1) for more options 9 | # ... or force ignoredups and ignorespace 10 | HISTCONTROL=ignoredups:ignorespace 11 | 12 | # append to the history file, don't overwrite it 13 | shopt -s histappend 14 | 15 | # for setting history length see HISTSIZE and HISTFILESIZE in bash(1) 16 | HISTSIZE=1000 17 | HISTFILESIZE=2000 18 | 19 | # check the window size after each command and, if necessary, 20 | # update the values of LINES and COLUMNS. 21 | shopt -s checkwinsize 22 | 23 | # make less more friendly for non-text input files, see lesspipe(1) 24 | [ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)" 25 | 26 | # set variable identifying the chroot you work in (used in the prompt below) 27 | if [ -z "$debian_chroot" ] && [ -r /etc/debian_chroot ]; then 28 | debian_chroot=$(cat /etc/debian_chroot) 29 | fi 30 | 31 | # set a fancy prompt (non-color, unless we know we "want" color) 32 | case "$TERM" in 33 | xterm-color) color_prompt=yes;; 34 | esac 35 | 36 | # uncomment for a colored prompt, if the terminal has the capability; turned 37 | # off by default to not distract the user: the focus in a terminal window 38 | # should be on the output of commands, not on the prompt 39 | #force_color_prompt=yes 40 | 41 | if [ -n "$force_color_prompt" ]; then 42 | if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then 43 | # We have color support; assume it's compliant with Ecma-48 44 | # (ISO/IEC-6429). (Lack of such support is extremely rare, and such 45 | # a case would tend to support setf rather than setaf.) 46 | color_prompt=yes 47 | else 48 | color_prompt= 49 | fi 50 | fi 51 | 52 | if [ "$color_prompt" = yes ]; then 53 | PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' 54 | else 55 | PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' 56 | fi 57 | unset color_prompt force_color_prompt 58 | 59 | # If this is an xterm set the title to user@host:dir 60 | case "$TERM" in 61 | xterm*|rxvt*) 62 | PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1" 63 | ;; 64 | *) 65 | ;; 66 | esac 67 | 68 | # enable color support of ls and also add handy aliases 69 | if [ -x /usr/bin/dircolors ]; then 70 | test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" 71 | alias ls='ls --color=auto' 72 | #alias dir='dir --color=auto' 73 | #alias vdir='vdir --color=auto' 74 | 75 | alias grep='grep --color=auto' 76 | alias fgrep='fgrep --color=auto' 77 | alias egrep='egrep --color=auto' 78 | fi 79 | 80 | # some more ls aliases 81 | alias ll='ls -alF' 82 | alias la='ls -A' 83 | alias l='ls -CF' 84 | 85 | # Add an "alert" alias for long running commands. Use like so: 86 | # sleep 10; alert 87 | 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$//'\'')"' 88 | 89 | # Alias definitions. 90 | # You may want to put all your additions into a separate file like 91 | # ~/.bash_aliases, instead of adding them here directly. 92 | # See /usr/share/doc/bash-doc/examples in the bash-doc package. 93 | 94 | if [ -f ~/.bash_aliases ]; then 95 | . ~/.bash_aliases 96 | fi 97 | 98 | # enable programmable completion features (you don't need to enable 99 | # this, if it's already enabled in /etc/bash.bashrc and /etc/profile 100 | # sources /etc/bash.bashrc). 101 | if [ -f /etc/bash_completion ] && ! shopt -oq posix; then 102 | . /etc/bash_completion 103 | fi -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | # enable debug mode if desired 6 | if [[ "${DEBUG}" == "true" ]]; then 7 | set -x 8 | fi 9 | 10 | log() { 11 | LEVEL="${1}" 12 | TO_LOG="${2}" 13 | 14 | WHITE='\033[1;37m' 15 | YELLOW='\033[1;33m' 16 | RED='\033[1;31m' 17 | NO_COLOR='\033[0m' 18 | 19 | if [[ "${LEVEL}" == "warning" ]]; then 20 | LOG_LEVEL="${YELLOW}WARN${NO_COLOR}" 21 | elif [[ "${LEVEL}" == "error" ]]; then 22 | LOG_LEVEL="${RED}ERROR${NO_COLOR}" 23 | else 24 | LOG_LEVEL="${WHITE}INFO${NO_COLOR}" 25 | if [[ -z "${TO_LOG}" ]]; then 26 | TO_LOG="${1}" 27 | fi 28 | fi 29 | 30 | echo -e "[${LOG_LEVEL}] ${TO_LOG}" 31 | } 32 | 33 | ensure_mod() { 34 | FILE="${1}" 35 | MOD="${2}" 36 | U_ID="${3}" 37 | G_ID="${4}" 38 | 39 | chmod "${MOD}" "${FILE}" 40 | chown "${U_ID}":"${G_ID}" "${FILE}" 41 | } 42 | 43 | generate_passwd() { 44 | hexdump -e '"%02x"' -n 16 /dev/urandom 45 | } 46 | 47 | # ensure backward comaptibility for earlier versions of this image 48 | if [[ -n "${KEYPAIR_LOGIN}" ]] && [[ "${KEYPAIR_LOGIN}" == "true" ]]; then 49 | ROOT_KEYPAIR_LOGIN_ENABLED="${KEYPAIR_LOGIN}" 50 | fi 51 | if [[ -n "${ROOT_PASSWORD}" ]]; then 52 | ROOT_LOGIN_UNLOCKED="true" 53 | fi 54 | 55 | # enable root login if keypair login is enabled 56 | if [[ "${ROOT_KEYPAIR_LOGIN_ENABLED}" == "true" ]]; then 57 | ROOT_LOGIN_UNLOCKED="true" 58 | fi 59 | 60 | # initiate default sshd-config if there is none available 61 | if [[ ! "$(ls -A /etc/ssh)" ]]; then 62 | cp -a "${CACHED_SSH_DIRECTORY}"/* /etc/ssh/. 63 | fi 64 | rm -rf "${CACHED_SSH_DIRECTORY}" 65 | 66 | # generate host keys if not present 67 | ssh-keygen -A 1>/dev/null 68 | 69 | log "Applying configuration for 'root' user ..." 70 | 71 | if [[ "${ROOT_LOGIN_UNLOCKED}" == "true" ]] ; then 72 | 73 | # generate random root password 74 | if [[ -z "${ROOT_PASSWORD}" ]]; then 75 | log " generating random password for user 'root'" 76 | ROOT_PASSWORD="$(generate_passwd)" 77 | fi 78 | 79 | echo "root:${ROOT_PASSWORD}" | chpasswd &>/dev/null 80 | log " password for user 'root' set" 81 | log "warning" " user 'root' is now UNLOCKED" 82 | 83 | # set root login mode by password or keypair 84 | if [[ "${ROOT_KEYPAIR_LOGIN_ENABLED}" == "true" ]] && [[ -f "${HOME}/.ssh/authorized_keys" ]]; then 85 | sed -i "s/#PermitRootLogin.*/PermitRootLogin without-password/" /etc/ssh/sshd_config 86 | sed -i "s/#PasswordAuthentication.*/PasswordAuthentication no/" /etc/ssh/sshd_config 87 | ensure_mod "${HOME}/.ssh/authorized_keys" "0600" "root" "root" 88 | log " enabled login by keypair and disabled password-login for user 'root'" 89 | else 90 | sed -i "s/#PermitRootLogin.*/PermitRootLogin\ yes/" /etc/ssh/sshd_config 91 | log " enabled login by password for user 'root'" 92 | fi 93 | 94 | else 95 | 96 | sed -i "s/#PermitRootLogin.*/PermitRootLogin no/" /etc/ssh/sshd_config 97 | log " disabled login for user 'root'" 98 | log " user 'root' is now LOCKED" 99 | 100 | fi 101 | 102 | printf "\n" 103 | 104 | log "Applying configuration for additional users ..." 105 | 106 | if [[ ! -x "${USER_LOGIN_SHELL}" ]]; then 107 | log "error" " can not allocate desired shell '${USER_LOGIN_SHELL}', falling back to '${USER_LOGIN_SHELL_FALLBACK}' ..." 108 | USER_LOGIN_SHELL="${USER_LOGIN_SHELL_FALLBACK}" 109 | fi 110 | 111 | log " desired shell is ${USER_LOGIN_SHELL}" 112 | 113 | 114 | if [[ -n "${SSH_USERS}" ]]; then 115 | 116 | IFS="," 117 | for USER in ${SSH_USERS}; do 118 | 119 | log " '${USER}'" 120 | 121 | USER_NAME="$(echo "${USER}" | cut -d ':' -f 1)" 122 | USER_UID="$(echo "${USER}" | cut -d ':' -f 2)" 123 | USER_GID="$(echo "${USER}" | cut -d ':' -f 3)" 124 | 125 | if [[ -z "${USER_NAME}" ]] || [[ -z "${USER_UID}" ]] || [[ -z "${USER_GID}" ]]; then 126 | log "error" " skipping invalid data '${USER_NAME}' - UID: '${USER_UID}' GID: '${USER_GID}'" 127 | continue 128 | fi 129 | 130 | USER_GROUP="${USER_NAME}" 131 | if getent group "${USER_GID}" &>/dev/null ; then 132 | USER_GROUP="$(getent group "${USER_GID}" | cut -d ':' -f 1)" 133 | log "warning" " desired GID is already present in system. Using the present group-name - GID: '${USER_GID}' GNAME: '${USER_GROUP}'" 134 | else 135 | addgroup -g "${USER_GID}" "${USER_GROUP}" 136 | fi 137 | 138 | if getent passwd "${USER_NAME}" &>/dev/null ; then 139 | log "warning" " desired USER_NAME is already present in system. Skipping creation - USER_NAME: '${USER_NAME}'" 140 | else 141 | adduser -s "${USER_LOGIN_SHELL}" -D -u "${USER_UID}" -G "${USER_GROUP}" "${USER_NAME}" 142 | log " user '${USER_NAME}' created - UID: '${USER_UID}' GID: '${USER_GID}' GNAME: '${USER_GROUP}'" 143 | fi 144 | 145 | passwd -u "${USER_NAME}" &>/dev/null || true 146 | mkdir -p "/home/${USER_NAME}/.ssh" 147 | 148 | MOUNTED_AUTHORIZED_KEYS="${AUTHORIZED_KEYS_VOLUME}/${USER_NAME}" 149 | LOCAL_AUTHORIZED_KEYS="/home/${USER_NAME}/.ssh/authorized_keys" 150 | 151 | if [[ ! -e "${MOUNTED_AUTHORIZED_KEYS}" ]]; then 152 | log "warning" " no SSH authorized_keys found for user '${USER_NAME}'" 153 | else 154 | cp "${MOUNTED_AUTHORIZED_KEYS}" "${LOCAL_AUTHORIZED_KEYS}" 155 | log " copied ${MOUNTED_AUTHORIZED_KEYS} to ${LOCAL_AUTHORIZED_KEYS}" 156 | ensure_mod "${LOCAL_AUTHORIZED_KEYS}" "0600" "${USER_NAME}" "${USER_GID}" 157 | log " set mod 0600 on ${LOCAL_AUTHORIZED_KEYS}" 158 | fi 159 | 160 | printf "\n" 161 | 162 | done 163 | unset IFS 164 | 165 | else 166 | 167 | log " no additional SSH-users set" 168 | 169 | fi 170 | 171 | echo "" 172 | 173 | # do not detach (-D), log to stderr (-e), passthrough other arguments 174 | exec /usr/sbin/sshd -D -e "$@" 175 | --------------------------------------------------------------------------------