diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..ce9ca413e970d897a8db92d8d347c1a0c881ac65 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,29 @@ +FROM debian:buster-slim + +# https://manpages.debian.org/stretch/openssh-server/sshd.8.en.html +RUN apt-get -y update \ +&& apt-get -y install openssh-server + +RUN mkdir /var/run/sshd + +RUN chmod g+r /etc/ssh/ssh_host_ed25519_key + +# OpenShift pod will run as non-root user, who can't create pid file. +RUN touch /run/sshd.pid \ +&& chmod g+w /run/sshd.pid + +# Create sftpuser. Password authentication is disabled in sshd. +RUN useradd -g root sftpuser -p '*' \ +&& chmod g+w /home + +# Make /etc/passwd writable by root group. So sftpuser can take UID of running pod. +RUN chmod g+w /etc/passwd + +EXPOSE 2022 + +COPY sshd_config /etc/ssh/sshd_config +RUN chmod g+r /etc/ssh/sshd_config + +COPY startup.sh /usr/local/bin +RUN chmod +x /usr/local/bin/startup.sh +CMD ["startup.sh"] diff --git a/README.md b/README.md deleted file mode 100644 index 4d3adbcaf47f8160336d36c4e0c9089cf13d853a..0000000000000000000000000000000000000000 --- a/README.md +++ /dev/null @@ -1,95 +0,0 @@ -## umich-sftp -This runs an sftp/ssh server that runs as a non-root user required for multi-tenanted container hosting systems like OpenShift. The build process creates a user: `sftpuser` that is associated with the uid used by an OpenShift project to run all pods. The range for the uid is declared in a project's annotations. Essentially, the pod runs as the sftpuser. - -### Setup Directions - -#### Generate an ssh key for later use: -- `ssh-keygen -f /path/to/keys/ssh_user_ed25519_key -N '' -t ed25519` -- `chmod 400 /path/to/keys/ssh_user_ed25519_key` - - -#### Instructions for use as a local docker container -clone repo -- `git clone git@gitlab.umich.edu:its-web-platforms/umich-sftp.git` -- `cd umich-sftp` - -There are 2 docker images to build, the first has ubuntu and ssh config: -- `docker build -t ubuntu-ssh ./ubuntu-ssh/` - -The second image contains user-specific instructions. -- `docker build -t umich-sftp ./umich-sftp/` - -Pass in the public keys and startup the container -- `docker run -it -p 2022:2022 -u 1000000000 -v /path/to/keys/:/tmp/keys umich-sftp` - -And now sftp to the container. -- `sftp -oIdentityFile=./ssh_user_ed25519_key -P 2022 sftpuser@localhost` - - -#### Instructions for use in Openshift -The first build is made in the its-curation namespace. This will be updated whenever ubuntu or the code is updated. -##### NOTE: this only needs to be done once. Please check if the image already exists in its-curation and don't run these next two steps if it already exists. -``` -oc project its-curation -oc new-build https://gitlab.umich.edu/its-web-platforms/umich-sftp.git --context-dir=ubuntu-ssh --name=ubuntu-ssh -oc tag its-curation/ubuntu-ssh:latest openshift/ubuntu-ssh:latest -``` - -The next build leverages the tag in the openshift namespace and is made in a user's project. Determine the UID in use by your project, and create the umich-sftp image with this: -``` -uid=$(oc get project $(oc project -q) -o custom-columns="uid:.metadata.annotations.openshift\.io\/sa\.scc\.uid-range" | tail -n +2) -uid=$(echo $uid | sed -e "s|/10000||g") -sed -i s/REPLACE_ME/$uid/g openshift-artifacts/bc-umich-sftp.json -oc create -f openshift-artifacts/bc-umich-sftp.json -``` - -Alternative build process: -``` -uid=$(oc get project $(oc project -q) -o custom-columns="uid:.metadata.annotations.openshift\.io\/sa\.scc\.uid-range" | tail -n +2) -uid=$(echo $uid | sed -e "s|/10000||g") -oc new-build openshift/ubuntu-ssh~https://gitlab.umich.edu/its-web-platforms/umich-sftp.git --context-dir=umich-sftp --build-arg SFTP_UID=$uid --strategy=docker -``` - -Create a secret with the public key you previously generated: -- The makerator will create a blank secret of the same name. You will have to delete the existing secret first in a project generated by the makerator. -- `oc create secret generic public-ssh-keys --from-file=/path/to/keys/ssh_user_ed25519_key.pub` - -Create the dc and svc. The first command updates the dc to retrieve the image from the current project: -``` -sed -i s/NAMESPACE/$(oc project -q)/g openshift-artifacts/dc-umich-sftp.json -oc create -f openshift-artifacts/dc-umich-sftp.json -oc create -f openshift-artifacts/svc-umich-sftp.json -``` - -Create a route on the tcp-router: -- `oc expose svc umich-sftp -l router=tcp-router` - -Find out the port assigned to your pod: -- `oc get route umich-sftp -o custom-columns=port:.metadata.labels.exposed-port` - -Connect using to that instance on containersnp (need to be on VPN): -- `sftp -oIdentityFile=/path/to/keys/ssh_user_ed25519_key -P 30000 sftpuser@tcp.aws-np.web.umich.edu` -- NOTE: you will need to subsitute 30000 with the port from the previous command. And `tcp.aws-np.web.umich.edu` will need to be substituted with `tcp.aws.web.umich.edu` if working in the production environment. - -#### Persistent Volumes -The default deployment does not mount a persistent volume. The makerator or kiri will generally create persistent volume claims and modify the deployment configuration for umich-sftp to leverage them. If you wish to test writing to persistent volumes with using makerator or kiri, perform the following operations: -``` -oc set volume dc/umich-sftp --add --name=wps-cms-pvc -t pvc --claim-size=1G --mount-path=/home/sftpuser/wps --overwrite -``` - -#### Troubleshooting -1. You are asked for a password when accessing via sftp. This is because your ssh key is not being recognized. - - Have you added your key to the secret and restarted the pod? - - Are you passing your key with the sftp/ssh command? - -2. The umich-sftp pod assumes it is running as a non-root user. - - -#### Minishift -If you see messages within the pod logs indicating that the sftpuser has been locked out, look to see if your pod is running as root. On minishift, this can be caused by the system:authenticated group being added to the anyuid scc. Run this cmd as a cluster-admin to remove this privilege for all users: -` oc adm policy remove-scc-from-group anyuid system:authenticated` - -## Good background material: -https://serverfault.com/questions/660160/openssh-difference-between-internal-sftp-and-sftp-server - -https://www.ssh.com/ssh/sshd diff --git a/openshift-artifacts/bc-umich-sftp.json b/openshift-artifacts/bc-umich-sshd.json similarity index 70% rename from openshift-artifacts/bc-umich-sftp.json rename to openshift-artifacts/bc-umich-sshd.json index fb4fd06ebca6b697a329c85d7c22d9ea2874165a..806909c86c9a2f8b2b2887c04156019831358e67 100644 --- a/openshift-artifacts/bc-umich-sftp.json +++ b/openshift-artifacts/bc-umich-sshd.json @@ -4,9 +4,9 @@ "metadata": { "creationTimestamp": null, "labels": { - "app": "umich-sftp" + "app": "umich-sshd" }, - "name": "umich-sftp" + "name": "umich-sshd" }, "spec": { "failedBuildsHistoryLimit": 5, @@ -14,31 +14,25 @@ "output": { "to": { "kind": "ImageStreamTag", - "name": "umich-sftp:latest" + "name": "umich-sshd:latest" } }, "postCommit": {}, "resources": {}, "runPolicy": "Serial", "source": { - "contextDir": "umich-sftp", + "contextDir": "umich-sshd", "git": { - "uri": "https://gitlab.umich.edu/its-web-platforms/umich-sftp.git" + "uri": "https://gitlab.umich.edu/its-web-platforms/umich-sshd.git" }, "type": "Git" }, "strategy": { "dockerStrategy": { - "buildArgs": [ - { - "name": "SFTP_UID", - "value": "REPLACE_ME" - } - ], "from": { "kind": "ImageStreamTag", - "name": "ubuntu-ssh:latest", - "namespace": "openshift" + "name": "debian:buster-slim", + "namespace": "its-curation" } }, "type": "Docker" @@ -47,7 +41,7 @@ "triggers": [ { "imageChange": { - "lastTriggeredImageID": "docker-registry.default.svc:5000/openshift/ubuntu-ssh:latest" + "lastTriggeredImageID": "docker-registry.default.svc:5000/its-curation/umich-sshd:latest" }, "type": "ImageChange" }, diff --git a/openshift-artifacts/dc-umich-sftp.json b/openshift-artifacts/dc-umich-sshd.json similarity index 85% rename from openshift-artifacts/dc-umich-sftp.json rename to openshift-artifacts/dc-umich-sshd.json index 2f6e04951668afe791d8b3a75608ce2279966ffb..751b36dcc2acb9fd668be1e03b8d519226d3675f 100644 --- a/openshift-artifacts/dc-umich-sftp.json +++ b/openshift-artifacts/dc-umich-sshd.json @@ -5,16 +5,16 @@ "creationTimestamp": null, "generation": 1, "labels": { - "app": "umich-sftp" + "app": "umich-sshd" }, - "name": "umich-sftp" + "name": "umich-sshd" }, "spec": { "replicas": 1, "revisionHistoryLimit": 10, "selector": { - "app": "umich-sftp", - "deploymentconfig": "umich-sftp" + "app": "umich-sshd", + "deploymentconfig": "umich-sshd" }, "strategy": { "activeDeadlineSeconds": 21600, @@ -32,16 +32,16 @@ "metadata": { "creationTimestamp": null, "labels": { - "app": "umich-sftp", - "deploymentconfig": "umich-sftp" + "app": "umich-sshd", + "deploymentconfig": "umich-sshd" } }, "spec": { "containers": [ { - "image": "docker-registry.default.svc:5000/NAMESPACE/umich-sftp:latest", + "image": "docker-registry.default.svc:5000/openshift/umich-sshd:latest", "imagePullPolicy": "Always", - "name": "umich-sftp", + "name": "umich-sshd", "ports": [ { "containerPort": 2022, @@ -53,7 +53,7 @@ "terminationMessagePolicy": "File", "volumeMounts": [ { - "mountPath": "/tmp/keys", + "mountPath": "/mnt/keys", "name": "ssh-key-secret", "readOnly": true } @@ -82,12 +82,12 @@ "imageChangeParams": { "automatic": true, "containerNames": [ - "umich-sftp" + "umich-sshd" ], "from": { "kind": "ImageStreamTag", - "name": "umich-sftp:latest", - "namespace": "NAMESPACE" + "name": "umich-sshd:latest", + "namespace": "openshift" } }, "type": "ImageChange" diff --git a/openshift-artifacts/svc-umich-sftp.json b/openshift-artifacts/svc-umich-sshd.json similarity index 78% rename from openshift-artifacts/svc-umich-sftp.json rename to openshift-artifacts/svc-umich-sshd.json index 48e7cf1c865a29bcafef7caac69d4b82303df5f1..61b5f6325c1b683c8c91e3bca3964437f7f1518c 100644 --- a/openshift-artifacts/svc-umich-sftp.json +++ b/openshift-artifacts/svc-umich-sshd.json @@ -4,9 +4,9 @@ "metadata": { "creationTimestamp": null, "labels": { - "app": "umich-sftp" + "app": "umich-sshd" }, - "name": "umich-sftp" + "name": "umich-sshd" }, "spec": { "ports": [ @@ -18,8 +18,8 @@ } ], "selector": { - "app": "umich-sftp", - "deploymentconfig": "umich-sftp" + "app": "umich-sshd", + "deploymentconfig": "umich-sshd" }, "sessionAffinity": "None", "type": "ClusterIP" diff --git a/readme.md b/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..e4ec966922c02fbd965a5bafcf1f2f47d4ea1ad9 --- /dev/null +++ b/readme.md @@ -0,0 +1,83 @@ +## umich-sshd +This runs a containerized sshd server that runs as a non-root user required by multi-tenanted container hosting systems like OpenShift. The pod runs as the user: `sftpuser`. The startup script looks for a mounted volume at /mnt/pvc and symlinks this into the sftpuser's home directory. + +### Setup Directions + +#### Generate an ssh key for later use: +- `ssh-keygen -f /path/to/keys/ssh_user_ed25519_key -N '' -t ed25519` +- `chmod 400 /path/to/keys/ssh_user_ed25519_key` + + +#### Instructions for use as a local docker container +clone repo +- `git clone git@gitlab.umich.edu:its-web-platforms/umich-sshd.git` + +Build the image: +- `docker build -t umich-sshd .` + +Pass in the public keys and startup the container: +- `docker run -it -p 2022:2022 -v /path/to/keys/:/mnt/keys -u 100000 umich-sshd` + +Alternatively, pass in public keys and test for mounting host volumes: +- `docker run -it -p 2022:2022 -v /path/to/keys:/mnt/keys -v /path/to/volume:/mnt/pvc -u 100000 umich-sshd` + +And now sftp to the container. +- `sftp -oIdentityFile=./ssh_user_ed25519_key -P 2022 sftpuser@localhost` + + +#### Instructions for use in Openshift +The build is made in the its-curation namespace. This will be updated whenever debian:buster-slim or the code is updated. The build process makes the /etc/passwd file writable by the root group. The startup script modifies the UID for the `sftpuser` user, who runs the sshd server, to use that provided to the OpenShift project. +##### NOTE: this only needs to be done once. Please check if the image already exists in its-curation and don't run these next two steps if it already exists. +``` +oc project its-curation +oc new-build https://gitlab.umich.edu/its-web-platforms/umich-sshd.git +oc tag its-curation/umich-sshd:latest openshift/umich-sshd:latest +``` + +Create a secret with the public key you previously generated: +- The makerator will create a blank secret of the same name. You will have to delete the existing secret first in a project generated by the makerator. +- `oc create secret generic public-ssh-keys --from-file=/path/to/keys/ssh_user_ed25519_key.pub`, or for multiple keys: +- `oc create secret generic public-ssh-keys --from-file=/path/to/keys/*.pub` + +Create the dc and svc. The first command updates the dc to retrieve the image from the current project: +``` +oc create -f openshift-artifacts/dc-umich-sshd.json +oc create -f openshift-artifacts/svc-umich-sshd.json +``` + +Create a route on the tcp-router: +- `oc expose svc umich-sshd -l router=tcp-router` + +Find out the port assigned to your pod: +- `oc get route umich-sshd -o custom-columns=port:.metadata.labels.exposed-port` + +Connect using to that instance on containersnp (need to be on VPN): +- `sftp -oIdentityFile=/path/to/keys/ssh_user_ed25519_key -P 30000 sftpuser@tcp.aws-np.web.umich.edu` +- NOTE: you will need to subsitute 30000 with the port from the previous command. And `tcp.aws-np.web.umich.edu` will need to be substituted with `tcp.aws.web.umich.edu` if working in the production environment. + + +#### Persistent Volumes +The default deployment does not mount a persistent volume. The makerator or kiri will generally create persistent volume claims and modify the deployment configuration for umich-sshd to leverage them. + +If you wish to test writing to persistent volumes with using makerator or kiri, perform the following operations: +``` +oc set volume dc/umich-sshd --add --name=mwps-volume -t pvc --claim-size=1G --mount-path=/mnt/pvc --overwrite +``` + + +#### Troubleshooting +1. You are asked for a password when accessing via sftp. This is because your ssh key is not being recognized. + - Have you added your key to the secret and restarted the pod? + - Are you passing your key with the sftp/ssh command? + +2. The umich-sshd pod assumes it is running as a non-root user. + + +#### Minishift +If you see messages within the pod logs indicating that the sftpuser has been locked out, look to see if your pod is running as root. On minishift, this can be caused by the system:authenticated group being added to the anyuid scc. Run this cmd as a cluster-admin to remove this privilege for all users: +` oc adm policy remove-scc-from-group anyuid system:authenticated` + +## Good background material: +https://serverfault.com/questions/660160/openssh-difference-between-internal-sftp-and-sftp-server + +https://www.ssh.com/ssh/sshd diff --git a/ubuntu-ssh/sshd_config b/sshd_config similarity index 72% rename from ubuntu-ssh/sshd_config rename to sshd_config index 2858b4701f1bbc545e49eaccc10f2a8dd14d37f0..92cab587b627d61f5d7d2de798d0a0c38854060e 100644 --- a/ubuntu-ssh/sshd_config +++ b/sshd_config @@ -3,6 +3,9 @@ Port 2022 # Key for running sshd HostKey /etc/ssh/ssh_host_ed25519_key +#PidFile /home/sftpuser/sshd.pid +PasswordAuthentication no + # Limited access PermitRootLogin no @@ -13,8 +16,5 @@ AllowTcpForwarding no Subsystem sftp internal-sftp ForceCommand internal-sftp -# Regardless of explicit dir or var, os pod cannot chroot to chroot dir -#ChrootDirectory /home/sftpuser - # Logging LogLevel VERBOSE diff --git a/startup.sh b/startup.sh new file mode 100644 index 0000000000000000000000000000000000000000..087f3f897317fa0c635cf732a9df67e458737c3a --- /dev/null +++ b/startup.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# The following commands belong in this script, rather than in +# the dockerfile, in order to run as the sftpuser. +if [ "$(id -u)" -ge 1000 ] ; then + sed -e "/^sftpuser:/c sftpuser:x:$(id -u):$(id -g)::/home/sftpuser:/usr/sbin/nologin" /etc/passwd > /tmp/passwd + cat /tmp/passwd > /etc/passwd + rm /tmp/passwd +fi + +mkdir -p /home/sftpuser/.ssh +#chown sftpuser:root /home/sftpuser /home/sftpuser/.ssh + +# If there is a mounted pvc, symlink to it within the user's home dir. +if [ -d /mnt/pvc ]; +then + ln -s /mnt/pvc /home/sftpuser/mwps +fi + +# If the user has specified keys either from a docker volume or openshift secret, +# place those in the authorized_keys file at container start-up. +if [ -f /mnt/keys/*.pub ]; +then + cat /mnt/keys/*.pub > /home/sftpuser/.ssh/authorized_keys + chown sftpuser /home/sftpuser/.ssh/authorized_keys + chmod 400 /home/sftpuser/.ssh/authorized_keys +fi + +# https://www.ssh.com/ssh/sshd#command-line-options +# -e option is useful for logging to stderr. +# -D don't run as daemon, -d debugging mode +#exec /usr/sbin/sshd -D -d -e +exec /usr/sbin/sshd -D -e diff --git a/ubuntu-ssh/Dockerfile b/ubuntu-ssh/Dockerfile deleted file mode 100644 index 5000c0cb99309428a81589254e99402f6b071ea9..0000000000000000000000000000000000000000 --- a/ubuntu-ssh/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM ubuntu:18.04 - -RUN apt-get -y update \ -&& apt-get -y install openssh-server -# https://help.ubuntu.com/lts/serverguide/openssh-server.html - -RUN mkdir /var/run/sshd - -COPY sshd_config /etc/ssh/sshd_config -RUN chmod g+r /etc/ssh/sshd_config - -# Allow access to server keys for sftpuser -RUN chmod g+r /etc/ssh/ssh_host_ed25519_key - -EXPOSE 2022 - -ADD startup.sh /usr/local/bin -RUN chmod +x /usr/local/bin/startup.sh -CMD ["startup.sh"] diff --git a/ubuntu-ssh/startup.sh b/ubuntu-ssh/startup.sh deleted file mode 100644 index d30e705918e9730844cf953b3b25c727313ddbea..0000000000000000000000000000000000000000 --- a/ubuntu-ssh/startup.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -# The following commands belong in this script, rather than in -# the dockerfile, in order to run as the sftpuser. - -# If the user has specified keys either from a docker volume or openshift secret, -# place those in the authorized_keys file at container start-up. -if [ -f /tmp/keys/*.pub ]; -then - cat /tmp/keys/*.pub > /home/sftpuser/.ssh/authorized_keys -fi - -# Ensure public keys have correct permissions. -chmod 400 /home/sftpuser/.ssh/authorized_keys - -# https://www.ssh.com/ssh/sshd#command-line-options -# -e option is useful for logging to stderr. -# -D don't run as daemon, -d debugging mode -#exec /usr/sbin/sshd -D -d -e -exec /usr/sbin/sshd -D -e diff --git a/umich-sftp/Dockerfile b/umich-sftp/Dockerfile deleted file mode 100644 index 949cb0c669494f4e24ea9babf87ccd5f276f30ac..0000000000000000000000000000000000000000 --- a/umich-sftp/Dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM ubuntu-ssh:latest - -# This default is overwritten a variable passed into build process -# $ docker build --build-arg SFTP_UID=1000110000 -t umich-sftp . -ARG SFTP_UID=1000000000 - -# http://manpages.ubuntu.com/manpages/bionic/man8/useradd.8.html -# d: which home dir, g: group, l: don't add to lastlog and faillog, m: create home -# s: which shell, o: non-unique, u: uid, -RUN useradd -g root -m -d /home/sftpuser -s /bin/bash -l -o -u $SFTP_UID sftpuser - -RUN su - sftpuser -c "mkdir -p /home/sftpuser/.ssh" - -# Workaround issue where non-root user can't create pid file. -RUN touch /run/sshd.pid -RUN chown sftpuser:root /run/sshd.pid diff --git a/utility-scripts/update-umich-sftp.sh b/utility-scripts/update-umich-sftp.sh deleted file mode 100755 index 8e9c9a126f53a22bc96625605c6df38ffbdaacd1..0000000000000000000000000000000000000000 --- a/utility-scripts/update-umich-sftp.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -for project in wps000009 wps000010 wps000012 wps000016 wps000021 wps000023 wps000025 wps000026 wps000027 wps000029 wps000031 wps000032 wps000033 wps000034 -do - echo "project is $project" - oc delete bc,dc,is -l app=umich-sftp -n ${project} - oc delete bc,dc,is -l build=umich-sftp -n ${project} - uid=$(oc get project $project -o custom-columns="uid:.metadata.annotations.openshift\.io/sa\.scc\.uid-range" | tail -n +2) - #echo "uid is $uid" - uid=$(echo $uid | sed -e "s|/10000||g") - echo "uid is $uid" - #oc policy add-role-to-user system:image-puller system-serviceaccount:${project}:builder -n its-curation - #oc policy add-role-to-user system:image-puller system-serviceaccount:${project}:default -n its-curation - oc new-build openshift/ubuntu-ssh~https://gitlab.umich.edu/its-web-platforms/umich-sftp.git --context-dir=umich-sftp --build-arg SFTP_UID=${uid} --strategy=docker -n ${project} - oc create secret generic public-ssh-keys -n ${project} - oc create -f pvc.yaml -n ${project} - cp dc-umich-sftp.yaml dc.yaml - sed -i s/NAMESPACE/${project}/g dc.yaml - oc create -f dc.yaml -n ${project} - rm dc.yaml -done