Skip to content

Authenticated port knocking in Rust

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT
Notifications You must be signed in to change notification settings

mbuesch/letmein

Repository files navigation

letmein - Authenticated port knocking

Letmein is a simple port knocker with a simple and secure authentication mechanism.

It can be used to hide services on a server behind a knock authentication to reduce the attack surface of a service. The service will not be accessible unless a knock authentication is successful. In case of a successful knock, the letmeind server will only open the knocked port for the client IP address that performed the knocking. Machines with different IP addresses still won't have access to the protected service.

Machines that can't successfully authenticate the knock sequence won't be able to access the protected service.

Letmein requires an nftables based firewall. It will not work with iptables.

Homepage

Git repository

Github repository

Usage example: Put OpenSSH (sshd) access behind a knock authentication barrier

On the server install the letmein server software (see sections below).

On the client install the letmein client software (see sections below).

Please read the nftables.conf example configuration file provided with this project. Adding a letmein specific input chain to your existing nftables configuration is required. Modify your nftables.conf accordingly.

Generate shared secret key and a user identifier to be installed on the server and client with the following client command:

letmein gen-key -u 00000000

The gen-key command will print the generated key string to the console. By default this will generate a secure random key for the user identifier 00000000. You can manually edit the user identifier, if you want, or you can just leave it as-is.

Add the generated string (user identifier and the shared secret) to the server configuration in /opt/letmein/etc/letmeind.conf. Put the generated key string together with the user identifier into the [KEYS] section of the configuration file.

Add the same generated string (user identifier and shared secret) to the client configuration in /opt/letmein/etc/letmein.conf. Put the generated key string together with the user identifier into the [KEYS] section of the configuration file.

Create a resource in the server that describes the sshd port that can be opened. In the [RESOURCES] section of the server configuration file /opt/letmein/etc/letmeind.conf all ports that may be opened must be specified. A resource consists of a resource identifier followed by a port identifier like that:

[RESOURCES]
00000022 = port: 22

The resource identifier is an 8 digit hexdecimal number. In this example it is 22(hex), but it can be any number. It just has to be the same number on the server and the client. After port: the port number (in decimal) that can be knocked-open is specified.

Add the same resource with the same resource identifier and the same port number to the client configuration in /opt/letmein/etc/letmein.conf.

Restart the letmein server:

systemctl restart letmeind.service

Now remove your static sshd port (22) accept from your nftables.conf firewall configuration. Letmein will install such a rule dynamically into the letmein input chain after successful knock authentication. Then restart nftables:

systemctl restart nftables.service

Done! You should now be able to knock-open the sshd port on your server:

# This must fail! No successful knock authentication, yet.
# If this does not fail, check if you have removed the sshd accept rule from nftables.conf.
ssh your-server.com

# Knock-open port 22 (sshd) on the server using user-id/key 00000000:
# (You do not have to specify -u 00000000 if that is your default user (see config).)
letmein knock -u 00000000 your-server.com 22

# Now you should be able to ssh into your server successfully:
ssh your-server.com

Prerequisites

The Rust compiler must be installed to build letmein. It is recommended to use the latest version of the stable Rust compiler:

Rust installer

The Rust installer will install the compiler and the build tool cargo.

The build requires the additional cargo-audit and cargo-auditable tools to be installed. Run this command to install both tools:

cargo install cargo-audit cargo-auditable

At runtime the nftables nft binary is required to be installed reachable in the $PATH. On Debian please install the nftables package:

apt install nftables

Building letmein

Run the build.sh script to build letmein.

After installing all build prerequisites, run the build script:

./build.sh

Installing letmein

Install server

After building, run the install-server.sh to install the letmeind server to /opt/letmein/:

./install-server.sh

Installing the server will also install the service and socket into systemd and start the letmeind server.

The server is used to receive knock packets from the client. Upon successful knock authentication, the server will open the knocked port in its nftables firewall.

Install client

Then run the install-client.sh to install the letmein client to /opt/letmein/:

./install-client.sh

The client is used to send a knock packet to the server.

Security attention: User identifiers and resource identifiers

Please be aware that the user identifiers and resource identifiers from the configuration files are transmitted over the network without encryption in clear text.

Make sure the user identifiers and resource identifiers do not include any private information.

These identifiers are merely meant to be an abstract identification for managing different letmein keys, installations and setups.

Platform support

Server

The server application letmeind is Linux-only, because it only supports nftables as firewall backend.

Client

The client application letmein is portable and should run on all major platforms. Tested platforms are:

  • Linux
  • Android, under Termux
  • Windows

Internals and design goals

The main design goals of letmein are:

  • It is implemented in a memory-safe programming language that makes certain classes of severe bugs impossible.
  • The algorithms and implementation are as simple as reasonably possible.
  • It does not implement complicated cryptographic algorithms such as asymmetric public/private key crypto. It uses a shared secret together with HMAC/SHA3 for authentication instead.
  • It has a replay protection. Replaying a knock packet sequence does not result in a successful authentication.
  • A MiM attack has no security impact.
  • It only opens the port for the IP address that made the knock request. By default for both IPv4 and IPv6, if available. This behavior can be adjusted with the -4 and -6 client command line options.
  • letmein does not link to libraries (.so) written in unsafe languages, except for the ones required by the operating system or by the Rust compiler. The only dynamically linked libraries are:
    • libc.so
    • libm.so
    • libgcc_s.so
    • linux-vdso.so

Security analysis

The program has carefully been design to be secure, to the best of my knowledge.

However, nobody is infallible.

  • Please read the code and comment on it.
  • Feel free to open an issue, if you have questions, suggestions or requests.
  • Please discuss the pros and cons of the design decisions.

I am interested to hear your opinion.

If you find a security vulnerability, you deserve all the credit and feel free to have a good ROFLMAO over my broken design. I deserve all the blame and I have all the responsibility for fixing the problem. Therefore, I'd like to ask you to fully disclose the details of your valuable findings either in public in a Github issue or privately via mail to me.

TODO

Ideas for future changes and improvements in letmein:

  • Currently all users that are configured on the server can access (knock-open) all resources that are configured on the server. It might be useful to restrict certain users to certain resources only.

License

Copyright (c) 2024 Michael Büsch [email protected]

Licensed under the Apache License version 2.0 or the MIT license, at your option.

About

Authenticated port knocking in Rust

Topics

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published