From 27b5fb9fdbd65b4b946ee70893005f28201095c8 Mon Sep 17 00:00:00 2001 From: saksham-45 Date: Mon, 19 Jan 2026 17:52:35 -0500 Subject: [PATCH] Security Hardening: Forced TLS, Environment Variable Support, and Injection Protection - Added XRDP_USERS env var support for secure credential handling - Forced TLS security layer in xrdp.ini - Implemented automatic TLS certificate generation in entrypoints - Hardened shell scripts with quoting and -- separators to prevent argument injection - Updated README with secure usage guidelines - Synchronized hardened config across Ubuntu, Fedora, and CentOS variants --- README.md | 18 +++++-- build/run.sh | 107 +++++++++++++++++++++++++------------ build/ubuntu-run.sh | 114 ++++++++++++++++++++++++++-------------- build/xrdp.ini | 6 +-- centos8-xfce/Dockerfile | 2 +- fedora-xfce/Dockerfile | 2 +- ubuntu-xfce/Dockerfile | 2 + 7 files changed, 167 insertions(+), 84 deletions(-) diff --git a/README.md b/README.md index 613644f..6856e43 100644 --- a/README.md +++ b/README.md @@ -20,18 +20,26 @@ Example: docker pull danchitnis/xrdp:ubuntu-xfce ``` -You have to give username, password, and sudo ability as input arguments to the docker run command. Hence, each user has three parameters. The process will exit if the input arguments are incorrect. Please run as interactive mode at first instance. +### Secure Usage (Recommended) -Example when username is _foo_, password is _bar_ and sudo ability is _no_: +Pass user credentials via environment variables to prevent them from appearing in the process list of the host system. ```bash -docker run -it -p 33890:3389 danchitnis/xrdp:ubuntu-xfce foo bar no +docker run -d -p 33890:3389 -e XRDP_USERS="foo:bar:yes" danchitnis/xrdp:ubuntu-xfce ``` -Similarly for detached mode +For multiple users, use a comma-separated list: ```bash -docker run -d -p 33890:3389 danchitnis/xrdp:ubuntu-xfce foo bar no +docker run -d -p 33890:3389 -e XRDP_USERS="alice:secret:yes,bob:password:no" danchitnis/xrdp:ubuntu-xfce +``` + +### Legacy Usage (Argument-based) + +Passing credentials via command-line arguments is still supported but **discouraged** due to security risks (visible via `ps` or `docker ps`). + +```bash +docker run -it -p 33890:3389 danchitnis/xrdp:ubuntu-xfce foo bar no ``` Once running, open Remote Desktop Connection. Enter "localhost:33890" as the address. diff --git a/build/run.sh b/build/run.sh index 81100e9..55c7acc 100644 --- a/build/run.sh +++ b/build/run.sh @@ -1,4 +1,15 @@ #!/bin/bash +set -e + +# Generate self-signed certificate if it doesn't exist +generate_certificates() { + if [ ! -f /etc/xrdp/cert.pem ] || [ ! -f /etc/xrdp/key.pem ]; then + echo "Generating self-signed certificates..." + openssl req -x509 -newkey rsa:2048 -nodes -keyout /etc/xrdp/key.pem -out /etc/xrdp/cert.pem -days 365 -subj "/C=US/ST=State/L=City/O=Organization/OU=Unit/CN=localhost" + chmod 600 /etc/xrdp/key.pem + chown xrdp:xrdp /etc/xrdp/key.pem /etc/xrdp/cert.pem || true + fi +} start_xrdp_services() { # Preventing xrdp startup failure @@ -18,49 +29,77 @@ stop_xrdp_services() { exit 0 } -echo Entryponit script is Running... -echo +add_user() { + local username="$1" + local password="$2" + local sudo="$3" + + if id -- "$username" &>/dev/null; then + echo "User '$username' already exists, skipping creation." + return + fi + + echo "Adding user '$username'..." + # Use -- to prevent argument injection + useradd -m -s /bin/bash -- "$username" + echo "$username:$password" | chpasswd + + if [[ "$sudo" == "yes" ]]; then + usermod -aG wheel -- "$username" + fi + echo "User '$username' is added" +} -users=$(($#/3)) -mod=$(($# % 3)) +echo "Entrypoint script is Running..." +echo -echo "users is $users" -echo "mod is $mod" +USER_CREATED=false -if [[ $# -eq 0 ]]; then - echo "No input parameters. exiting..." - echo "there should be 3 input parameters per user" - exit +# 1. Process users from environment variables (Recommended/Secure) +# Format: XRDP_USERS="user1:pass1:yes,user2:pass2:no" +if [ -n "$XRDP_USERS" ]; then + IFS=',' read -ra ADDR <<< "$XRDP_USERS" + for user_record in "${ADDR[@]}"; do + IFS=':' read -ra USER_DATA <<< "$user_record" + if [ ${#USER_DATA[@]} -eq 3 ]; then + add_user "${USER_DATA[0]}" "${USER_DATA[1]}" "${USER_DATA[2]}" + USER_CREATED=true + else + echo "Invalid user record in XRDP_USERS: $user_record. Expected user:pass:sudo" + fi + done fi -if [[ $mod -ne 0 ]]; then - echo "incorrect input. exiting..." - echo "there should be 3 input parameters per user" - exit -fi -echo "You entered $users users" - -while [ $# -ne 0 ]; do - - #echo "username is $1" - useradd $1 - wait - #getent passwd | grep foo - echo $1:$2 | chpasswd - wait - #echo "sudo is $3" - if [[ $3 == "yes" ]]; then - usermod -aG wheel $1 +# 2. Process users from CLI arguments (Legacy/Less Secure) +if [ $# -ne 0 ]; then + echo "Processing users from CLI arguments..." + echo "WARNING: Passing passwords via CLI is insecure as they are visible in process lists." + + users=$(($#/3)) + mod=$(($# % 3)) + + if [[ $mod -ne 0 ]]; then + echo "Incorrect input. There should be 3 input parameters per user." + exit 1 fi - wait - echo "user '$1' is added" + + echo "You entered $users users via CLI" - # Shift all the parameters down by three - shift 3 -done + while [ $# -ne 0 ]; do + add_user "$1" "$2" "$3" + USER_CREATED=true + shift 3 + done +fi -echo -e "This script is ended\n" +# If no users were created and we aren't already running as a non-root user that can login +if [ "$USER_CREATED" = false ] && [ "$(id -u)" -eq 0 ]; then + echo "No users defined via environment variables or CLI arguments, and running as root." + echo "Please provide at least one user to allow RDP login." + exit 1 +fi +generate_certificates echo -e "starting xrdp services...\n" trap "stop_xrdp_services" SIGKILL SIGTERM SIGHUP SIGINT EXIT diff --git a/build/ubuntu-run.sh b/build/ubuntu-run.sh index a20723d..b8d69de 100644 --- a/build/ubuntu-run.sh +++ b/build/ubuntu-run.sh @@ -1,5 +1,15 @@ #!/bin/bash - +set -e + +# Generate self-signed certificate if it doesn't exist +generate_certificates() { + if [ ! -f /etc/xrdp/cert.pem ] || [ ! -f /etc/xrdp/key.pem ]; then + echo "Generating self-signed certificates..." + openssl req -x509 -newkey rsa:2048 -nodes -keyout /etc/xrdp/key.pem -out /etc/xrdp/cert.pem -days 365 -subj "/C=US/ST=State/L=City/O=Organization/OU=Unit/CN=localhost" + chmod 600 /etc/xrdp/key.pem + chown xrdp:xrdp /etc/xrdp/key.pem /etc/xrdp/cert.pem || true + fi +} start_xrdp_services() { # Preventing xrdp startup failure @@ -18,54 +28,78 @@ stop_xrdp_services() { exit 0 } +add_user() { + local username="$1" + local password="$2" + local sudo="$3" -echo Entryponit script is Running... -echo - -users=$(($#/3)) -mod=$(($# % 3)) + if id -- "$username" &>/dev/null; then + echo "User '$username' already exists, skipping creation." + return + fi -#echo "users is $users" -#echo "mod is $mod" + echo "Adding user '$username'..." + # Use -- to prevent argument injection + groupadd -- "$username" + useradd -m -s /bin/bash -g "$username" -- "$username" + echo "$username:$password" | chpasswd + + if [[ "$sudo" == "yes" ]]; then + usermod -aG sudo -- "$username" + fi + echo "User '$username' is added" +} -if [[ $# -eq 0 ]]; then - echo "No input parameters. exiting..." - echo "there should be 3 input parameters per user" - exit -fi +echo "Entrypoint script is Running..." +echo -if [[ $mod -ne 0 ]]; then - echo "incorrect input. exiting..." - echo "there should be 3 input parameters per user" - exit +USER_CREATED=false + +# 1. Process users from environment variables (Recommended/Secure) +# Format: XRDP_USERS="user1:pass1:yes,user2:pass2:no" +if [ -n "$XRDP_USERS" ]; then + IFS=',' read -ra ADDR <<< "$XRDP_USERS" + for user_record in "${ADDR[@]}"; do + IFS=':' read -ra USER_DATA <<< "$user_record" + if [ ${#USER_DATA[@]} -eq 3 ]; then + add_user "${USER_DATA[0]}" "${USER_DATA[1]}" "${USER_DATA[2]}" + USER_CREATED=true + else + echo "Invalid user record in XRDP_USERS: $user_record. Expected user:pass:sudo" + fi + done fi -echo "You entered $users users" - -while [ $# -ne 0 ]; do - - addgroup $1 - #echo "username is $1" - useradd -m -s /bin/bash -g $1 $1 - wait - #getent passwd | grep foo - echo $1:$2 | chpasswd - wait - #echo "sudo is $3" - if [[ $3 == "yes" ]]; then - usermod -aG sudo $1 +# 2. Process users from CLI arguments (Legacy/Less Secure) +if [ $# -ne 0 ]; then + echo "Processing users from CLI arguments..." + echo "WARNING: Passing passwords via CLI is insecure as they are visible in process lists." + + users=$(($#/3)) + mod=$(($# % 3)) + + if [[ $mod -ne 0 ]]; then + echo "Incorrect input. There should be 3 input parameters per user." + exit 1 fi - wait - echo "user '$1' is added" - - # Shift all the parameters down by three - shift 3 -done - - + + echo "You entered $users users via CLI" + + while [ $# -ne 0 ]; do + add_user "$1" "$2" "$3" + USER_CREATED=true + shift 3 + done +fi -echo -e "This script is ended\n" +# If no users were created and we aren't already running as a non-root user that can login +if [ "$USER_CREATED" = false ] && [ "$(id -u)" -eq 0 ]; then + echo "No users defined via environment variables or CLI arguments, and running as root." + echo "Please provide at least one user to allow RDP login." + exit 1 +fi +generate_certificates echo -e "starting xrdp services...\n" trap "stop_xrdp_services" SIGKILL SIGTERM SIGHUP SIGINT EXIT diff --git a/build/xrdp.ini b/build/xrdp.ini index bfd74bb..3493a1a 100644 --- a/build/xrdp.ini +++ b/build/xrdp.ini @@ -40,7 +40,7 @@ tcp_keepalive=true ; security layer can be 'tls', 'rdp' or 'negotiate' ; for client compatible layer -security_layer=negotiate +security_layer=tls ; minimum security level allowed for client for classic RDP encryption ; use tls_ciphers to configure TLS encryption @@ -49,8 +49,8 @@ crypt_level=high ; X.509 certificate and private key ; openssl req -x509 -newkey rsa:2048 -nodes -keyout key.pem -out cert.pem -days 365 -certificate= -key_file= +certificate=/etc/xrdp/cert.pem +key_file=/etc/xrdp/key.pem ; set SSL protocols ; can be comma separated list of 'SSLv3', 'TLSv1', 'TLSv1.1', 'TLSv1.2', 'TLSv1.3' diff --git a/centos8-xfce/Dockerfile b/centos8-xfce/Dockerfile index b03317f..579848c 100644 --- a/centos8-xfce/Dockerfile +++ b/centos8-xfce/Dockerfile @@ -12,7 +12,7 @@ RUN bash -c 'echo PREFERRED=/usr/bin/xfce4-session > /etc/sysconfig/desktop' RUN yum install -y xrdp xorgxrdp -RUN yum -y install sudo nload passwd nano gedit +RUN yum -y install sudo nload passwd nano gedit openssl COPY ./build/xrdp.ini /etc/xrdp/ diff --git a/fedora-xfce/Dockerfile b/fedora-xfce/Dockerfile index e8fccd8..1cf7bd4 100644 --- a/fedora-xfce/Dockerfile +++ b/fedora-xfce/Dockerfile @@ -10,7 +10,7 @@ RUN bash -c 'echo PREFERRED=/usr/bin/xfce4-session > /etc/sysconfig/desktop' RUN dnf install -y xrdp xorgxrdp -RUN dnf -y install sudo nload passwd nano gedit +RUN dnf -y install sudo nload passwd nano gedit openssl RUN dnf clean all diff --git a/ubuntu-xfce/Dockerfile b/ubuntu-xfce/Dockerfile index b26aa4a..5956b8e 100644 --- a/ubuntu-xfce/Dockerfile +++ b/ubuntu-xfce/Dockerfile @@ -21,6 +21,7 @@ RUN apt-get install -y \ dbus-x11 RUN apt-get install -y \ + openssl \ sudo \ wget \ xorgxrdp \ @@ -29,6 +30,7 @@ RUN apt-get install -y \ apt autoremove -y && \ rm -rf /var/cache/apt /var/lib/apt/lists +COPY ./build/xrdp.ini /etc/xrdp/ COPY ./build/ubuntu-run.sh /usr/bin/ RUN mv /usr/bin/ubuntu-run.sh /usr/bin/run.sh RUN chmod +x /usr/bin/run.sh