While modern software often leans heavily on graphical interfaces and web applications, command-line-based applications are still very much alive and in use. In fact, SSH-based shell applications remain a lightweight, efficient way for users to interact with terminal-based programs. However, if not configured carefully, these applications can inadvertently provide users with unrestricted shell access — something that’s often not intended.
The good news? Securing SSH shell applications is straightforward and can be done quickly with a few well-placed configurations. This article walks through how to set up a terminal-based application accessed via SSH and secure it in a way that restricts users to just the application.
Table of Contents
- What is an SSH Shell Application?
- Setting Up the Application
- Configuring SSH for Application Access
- Console Access Considerations
- Summary
What is an SSH Shell Application?
SSH Shell Applications are terminal-based programs that users can run remotely by connecting over SSH. They are especially handy in environments where minimal resource usage is critical or where web interfaces are overkill.
Users can connect using SSH clients like PuTTY, Termius, or native Linux/macOS terminals. These apps are lightweight, fast, and easy to distribute. Because they don’t rely on the user’s home environment or graphical stack, they can also add an extra layer of separation and security.
However, without careful planning, a user might break out of the application into a standard shell — unintentionally or otherwise. That’s why additional steps must be taken to confine users strictly to the app’s environment.
Setting Up the Application
For our example, we'll use a simple, self-contained Python application placed in /opt/test_app/app_entrypoint.py
. A key part of securing this app is disabling critical control characters like Ctrl+C
and Ctrl+Z
, which would otherwise interrupt the application or suspend it to the background, potentially giving the user shell access.
Here’s how we disable those signals:
import signal
def disable_signals():
# Ignore Ctrl+C (SIGINT) and Ctrl+Z (SIGTSTP)
signal.signal(signal.SIGINT, signal.SIG_IGN)
signal.signal(signal.SIGTSTP, signal.SIG_IGN)
To handle attempts to exit via Ctrl+D
(EOF), the app should catch the EOFError
:
import time
while True:
try:
choice = input("Select an option [1-4]: ").strip()
except EOFError:
print("\n❌ Ctrl+D detected. Exiting securely.")
time.sleep(1)
break
This ensures that if a user tries to drop out of the app with Ctrl+D
, the application exits cleanly and ends the SSH session — preventing shell access.
👉 You can find the full code here.
If your application is not able to integrate these signal-handling and input restrictions directly (for example, if it's a third-party binary or legacy script), a wrapper script can be used instead. The wrapper acts as a secure launch layer, applying these restrictions before executing the app. You can find a sample wrapper script here.
Configuring SSH for Application Access
There are two main ways to launch an SSH shell app:
- From the user's
.bashrc
or similar login script. - Directly from the SSH daemon (
sshd
) configuration.
This article focuses on the second method, which is cleaner and more secure.
First, a dedicated Linux group (e.g., app_group
) is created to contain the application users. Then, we use SSHD's Match Group
directive to force members of that group to run only the application.
Here's a sample snippet added to /etc/ssh/sshd_config
:
Match Group app_group
ForceCommand /opt/test_app/app_entrypoint.py
PermitTTY yes
AllowTcpForwarding no
X11Forwarding no
This configuration ensures that:
- Users in
app_group
are automatically placed into the application. -
PermitTTY yes
allows for interactive input. -
AllowTcpForwarding
andX11Forwarding
are disabled to prevent the session from being misused as a jump host.
Regular system administrators or non-application users are unaffected and continue to log in normally.
Console Access Considerations
While SSH access is now locked down, don’t forget about direct console access or users logging in via su - app_user
. In these cases, users can still access the full shell unless additional safeguards are in place.
To block non-SSH logins (such as physical terminal or su
sessions), add the following to the app user’s .bashrc
:
if [ -z "$SSH_CONNECTION" ]; then
echo "🚫 Direct login is not allowed."
exit 1
fi
This script checks whether the session is initiated over SSH. If it’s not, the login is terminated immediately.
Summary
In this guide, we’ve walked through how to:
- Create a simple terminal-based application.
- Restrict user access to that app only via SSH.
- Prevent users from breaking out of the application into the shell.
- Secure against direct console or
su
access.
These steps don't indicate a lack of trust in users. Most end users don’t have the means or intent to break out of restricted environments — but we always prepare for the worst. If a threat actor ever gains access to one of these accounts, these protections act as a vital layer of defense.
Security is all about layers. Beyond giving users access to the tools or files they need, we must always ask: Do they need shell access too? If the answer is no, let’s make sure the system enforces it.
Need Linux expertise? I help businesses streamline servers, secure infrastructure, and automate workflows. Whether you're troubleshooting, optimizing, or building from scratch—I've got you covered.
📬 Drop a comment or email me to collaborate. For more tutorials, tools, and insights, visit sebostechnology.com.
☕ Did you find this article helpful?
Consider supporting more content like this by buying me a coffee:
Buy Me A Coffee
Your support helps me write more Linux tips, tutorials, and deep dives.
Top comments (0)