A small and ultrasecure LessPass database server written in Rust.
Simply download latest release from releases page. You can use systemd unit from Arch Linux package to run it.
tar xf rockpass-X.X.X-ARCH.tar.xz
sudo install -m755 rockpass-X.X.X-ARCH/rockpass /usr/bin/rockpass
sudo install -m644 rockpass-X.X.X-ARCH/rockpass/rockpass.toml.example \
/etc/rockpass.toml
sudo vim /etc/rockpass.toml # Configure Rockpass as you like
sudo curl 'https://aur.archlinux.org/cgit/aur.git/plain/rockpass.service?h=rockpass' \
-o /etc/systemd/system/rockpass.service
sudo systemctl start rockpass
sudo systemctl enable rockpass
Warning: The only binaries provided are for linux-amd64
and linux-arm64
,
if you need to run Rockpass on another architecture (like a Raspberry Pi
32bit) you must compile it, see how to do it in the from source
section.
Note that the systemd unit uses a dynamic user that has a persistent
directory in /var/lib/rockpass/
so it is recommended that the SQLite DB be
stored in this directory (see production sample section in
rockpass.toml.example
).
If everything worked correctly you should have a new clean database in
/var/lib/rockpass/rockpass.sqlite
. Go to the usage section to
learn how to create your first user.
You can download a Rockpass Docker image from here, from Docker
Hub or from Quay (only linux-amd64-musl
).
To run it, simply exec.
docker run -t -d \
--name=rockpass \
-p 8000:8000 \
ogarcia/rockpass
This start Rockpass and publish the port to host.
Warning: this is a basic run, all data will be destroyed after container stop and rm.
Rockpass Docker image uses a volume /var/lib/rockpass
to store sqlite
database. You can exec the following to mount it in your host as persistent
storage.
docker run -t -d \
--name=rockpass \
-p 8000:8000 \
-v /my/rockpass:/var/lib/rockpass \
ogarcia/rockpass
Take note that you must create before the directory /my/rockpass
and set
ownership to UID/GID 100.
mkdir -p /my/rockpass
chown -R 100:100 /my/rockpass
Variable | Used for | Default value |
---|---|---|
ROCKPASS_DATABASES |
Database location | {rockpass={url="/var/lib/rockpass/rockpass.sqlite"}} |
ROCKPASS_ADDRESS |
Listen address | 0.0.0.0 |
ROCKPASS_PORT |
Listen port | 8000 |
ROCKPASS_REGISTRATION_ENABLED |
Enable or disable the ability to register new users | true |
ROCKPASS_ACCESS_TOKEN_LIFETIME |
Time, in seconds, that the access token is valid | 3600 (1 hour) |
ROCKPASS_REFRESH_TOKEN_LIFETIME |
Time, in seconds, that the refresh token is valid | 2592000 (30 days) |
ROCKPASS_LOG_LEVEL |
Log level | critical |
Rockpass build has been tested with current Rust stable release version. You
can install Rust from your distribution package or use rustup
.
rustup default stable
If you prefer, you can use the stable version only for install Rockpass (you must clone the repository first).
rustup override set stable
Apart from Rust, to build rockpass you will need sqlite3
(usually the
-dev
package) and the compiler tools. For example in Debian.
apt install build-essential libsqlite3-dev
Depending on the Linux distribution you use these packages may vary, consult the manual of yours for more information.
To build Rockpass binary simply execute the following commands.
git clone https://gitlab.com/ogarcia/rockpass.git
cd rockpass
cargo build --release
After build the binary is located in target/release/rockpass
.
How Rockpass uses Rocket certain configuration parameters are
compatible with each other. You can look at the Rocket configuration
documentation to see what the basic parameters are. In any case,
a fully commented rockpass.toml.example
is provided and the most important
parameters are detailed below.
Setting | Use | Default value |
---|---|---|
address |
Listen address | 127.0.0.1 |
port |
Listen port | 8000 |
registration_enabled |
Enable or disable the ability to register new users | true |
access_token_lifetime |
Time, in seconds, that the access token is valid | 3600 (1 hour) |
refresh_token_lifetime |
Time, in seconds, that the refresh token is valid | 2592000 (30 days) |
databases |
SQLite database location (see below) | {rockpass={url=":memory:"}} |
The database configuration can be detailed in three options.
Option One.
databases = { rockpass = { url = "/location/of/rockpass.sqlite" } }
Option Two.
[release.databases]
rockpass = { url = "/location/of/rockpass.sqlite" }
Option Three.
[release.databases.rockpass]
url = "/location/of/rockpass.sqlite"
If you don't want use a config file you can use environment variables. For example to disable registration and listen in 8080.
export ROCKPASS_PORT=8080
export ROCKPASS_REGISTRATION_ENABLED=false
export ROCKPASS_DATABASES='{ rockpass = { url = "/location/of/rockpass.sqlite" } }'
rockpass
You can run Rockpass without any configuration. By default it creates an in-memory DB that is deleted once the process stops, this is useful for testing purposes.
rockpass
The latter is exactly the same as running Rockpass by setting the url
key
to :memory:
.
ROCKPASS_DATABASES='{rockpass = { url = ":memory:" }}' rockpass
You can use Rockpass directly on a local network, but if you want to expose it to the Internet it is best to set up some kind of http server in front of it (remember to configure it to listen only to localhost).
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name rockpass.example.com;
access_log /var/log/nginx/rockpass.access.log;
error_log /var/log/nginx/rockpass.error.log;
ssl_certificate /etc/letsencrypt/live/rockpass.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/rockpass.example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/rockpass.example.com/chain.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
ssl_session_tickets off;
ssl_protocols TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_stapling on;
ssl_stapling_verify on;
root /srv/http/pass/htdocs;
# Only exposes Rockpass on the endpoints it can handle
location ~ (/auth/|/passwords/) {
proxy_set_header Host $http_host;
proxy_max_temp_file_size 0;
proxy_read_timeout 1800s;
proxy_send_timeout 1800s;
proxy_pass http://127.0.0.1:8000;
proxy_redirect http:// https://;
}
}
You must create an empty index.html
file in /srv/http/pass/htdocs
so
that when someone accesses rockpass.example.com
they simply get a blank
page.
If you want to increase security you can introduce some kind of random string in the exposed endpoints as detailed in the following example.
# Expose Rockpass under very difficult URL
location ~ (/somerandomstring/auth/|/somerandomstring/passwords/) {
rewrite ^/somerandomstring/(.*) /$1 break;
proxy_set_header Host $http_host;
proxy_max_temp_file_size 0;
proxy_read_timeout 1800s;
proxy_send_timeout 1800s;
proxy_pass http://127.0.0.1:8000;
proxy_redirect http:// https://;
}
Now in the clients you must configure the server address as
https://rockpass.example.com/somerandomstring/
. This way it will be very
difficult for an external attacker to locate where you have Rockpass
listening.
$HTTP["url"] =~ "^/rockpass" {
proxy.server = ( "" => ( ( "host" => "127.0.0.1", "port" => "8000" )))
proxy.header = ( "map-urlpath" => ( "/rockpass" => ""))
}
In this case Rockpass will be listening at
https://rockpass.example.com/rockpass/
. If you change rockpass
to some
kind of random string you will increase the security.
Rockpass is an API server for LessPass so it does not expose any interface. You can use any of the existing LessPass applications (plugins, mobile...) to connect against the server or my own lesspass-client command line client implementation.
Let's see an example of use with lesspass-client
. First we start
rockpass
without options or configuration to work directly in memory (it
is an example). When we feel comfortable we can start Rockpass with its
final configuration.
rockpass
The first thing we need to be able to connect is to create a user. For this user to be compatible with the official LessPass applications we must encrypt their password as LessPass does. We can do this with the lesspass-client itself as follows.
$ lesspass-client -m Login_Password password build lesspass.com login@mail.com
|O}'bU/sW*7Dfw->
What we have done is encrypt a password Login_Password
for the user
login@mail.com
, this has resulted in the encrypted password
|O}'bU/sW*7Dfw->
which is the one we must use to create the user.
We now create the user as follows.
$ lesspass-client \
-s http://127.0.0.1:8000 \
user create "login@mail.com" "|O}'bU/sW*7Dfw->"
New user created successfully
From here we can connect against the API either with the client applications
or with the lesspass-client itself. If we do it with any of the client
applications (for example the Firefox plugin), we will use as
username login@mail.com
and password Login_Password
since the client
application itself will be responsible for encrypting it. If, on the other
hand, we do it with lesspass-client, the username will be the same but we
must use the encrypted password as detailed below.
# Add a new password profile
$ lesspass-client \
-s http://127.0.0.1:8000 \
-u "login@mail.com" \
-p "|O}'bU/sW*7Dfw->" \
password add example.com login@mail.com
New password created successfully
# List profiles stored on the server
$ lesspass-client \
-s http://127.0.0.1:8000 \
-u "login@mail.com" \
-p "|O}'bU/sW*7Dfw->" \
password list
example.com
# Show a profile
$ lesspass-client \
-s http://127.0.0.1:8000 \
-u "login@mail.com" \
-p "|O}'bU/sW*7Dfw->" \
password show example.com
ID: 1
Site: example.com
Login: login@mail.com
Lowercase: true
Uppercase: true
Symbols: true
Numbers: true
Length: 16
Couter: 1
# Encrypt a new password using a master password and the created profile
# Option One (Master password as environment variable)
$ export LESSPASS_MASTERPASS="very difficult master password"
$ lesspass-client \
-s http://127.0.0.1:8000 \
-u "login@mail.com" \
-p "|O}'bU/sW*7Dfw->" \
password show -p example.com
X?%x0O=yn&n4cWGU
# Option Two (Master password as argument)
$ lesspass-client \
-s http://127.0.0.1:8000 \
-u "login@mail.com" \
-p "|O}'bU/sW*7Dfw->" \
-m "very difficult master password as argument" \
password show -p example.com
:~xd`ZtYvS1/8I2+
# The passwords are different in each example because we have changed the
# master password.
All of the above is just an example, lesspass-client is a complete client so it is possible to perform multiple operations on the LessPass API. See the command help for more information.
If you want to migrate an account from any LessPass server to Rockpass you
can use lesspass-client
. You will need to encrypt the passwords to be able
to export and import the data, see the example above to know how to do it.
First we export the profiles to profiles.json
.
$ lesspass-client -s https://api.lesspass.example.com \
-u LOGIN_EMAIL \
-p ENCRYPTED_LOGIN_PASSWORD \
password export profiles.json
Then we import them.
$ lesspass-client -s http://127.0.0.1:8000 \
-u LOGIN_EMAIL \
-p ENCRYPTED_LOGIN_PASSWORD \
password import profiles.json
You can do this operation in memory without using a file as follows.
$ lesspass-client -s https://api.lesspass.example.com \
-u LOGIN_EMAIL \
-p ENCRYPTED_LOGIN_PASSWORD \
password export - | \
lesspass-client -s http://127.0.0.1:8000 \
-u LOGIN_EMAIL \
-p ENCRYPTED_LOGIN_PASSWORD \
password import -
Note that when importing data it is not overwritten so if you import the same JSON twice you will have repeated entries.
With the premise in mind of keeping the code simple (remember that it is for personal use so KISS), Rockpass has not implemented any password reset API. However, if any user does not remember their password, you can reset it by following the procedure below.
LessPass encrypts the passwords in the client before sending them, so we
must perform the same procedure since for each user the encrypted password
is different. My advice is to use a temporary easy password (in my examples
I will use 123456
) and then the user will change it to something more
secure.
To encrypt the password we can use LessPass itself or my lesspass-client. The parameters to use are the following.
- Site:
lesspass.com
- Login: The email address you use to authenticate. I will use
rockpass@example.com
in this example. - Master password: The new password you want to use. In my case as I said
before
123456
. - Options: Default. This means all options checked, size 16 and counter 1.
If we want to encrypt the password with lesspass-client the command would be.
$ lesspass-client -m 123456 password build lesspass.com rockpass@example.com
-!?}5Nx9E\%svt07
Regardless of how we encrypt the password the result is that our encrypted
password is -!?}5Nx9E\%svt07
. Obviously this is only valid if the user
name is rockpass@example.com
, if you use another user name it will
generate a different encrypted password.
Even if the password is encrypted by the client, Rockpass encrypts it again with Bcrypt hash, this is because in the client options you can select that the password is not encrypted and to increase security.
To encrypt the password with Bcrypt the easiest way is to use a web application that does it, for example Bcrypt-Generator or Bcrypt-Online. When encrypting with Bcrypt you have to set a cost factor, Rockpass uses a factor of 10, but it is OK to use a different factor.
Note that each time you encrypt with Bcrypt a new string is generated, this
is normal since Bcrypt generates a different salt each time. In my case
the password generated from -!?}5Nx9E\%svt07
is
$2y$10$EYeEDnNN/dIQOkJtU9VQAe2fGXhncHbsdZnTdmrs6JMaceKqLg.X6
.
- Connect to database.
sqlite3 /location/of/rockpass.sqlite
- Update password to the value
123456
for the userrockpass@example.com
.UPDATE users SET password='$2y$10$EYeEDnNN/dIQOkJtU9VQAe2fGXhncHbsdZnTdmrs6JMaceKqLg.X6' WHERE email = 'rockpass@example.com';
Now it would be possible to authenticate with the user
rockpass@example.com
with the password 123456
and modify it with the
application. Don't forget to do it!
Users can delete their own accounts using any of the mobile or
lesspass-client applications (browser extensions do not
have this option). You can still delete any user with the sqlite
command.
For example to delete user user@example.com and all of his/her passwords
settings.
- Connect to database.
sqlite3 /location/of/rockpass.sqlite
- Delete user.
PRAGMA foreign_keys = ON; DELETE FROM users WHERE email = 'user@example.com';