User Access
How to create and manage access for users on a new server
Once your raw metal server is ready to host a Solana validator, the system administrator must provision access for the validator operators. This guide walks you through the process of running the Ansible script to provision users on a newly provisioned metal server.
Pre-Requisites
This page assumes you have access to a provisioned bare metal with the ubuntu
user with sudo
access as explained in the Choosing Your Metal page.
Since the user provisioning is done via an Ansible script, you must also have a running Ansible Control.
Architecture
Our security strategy follows the principle of least privilege.
We define IAM users and roles in advance, which serve as the blueprint during setup. Each role maps directly to an Ubuntu group, ensuring every user operating on the host has only the minimal access required for their tasks.
🎭 Roles
These are the roles with their asserted purpose and description:
📂 sysadmin Purpose: Complete system administration
Sudo access. Break-glass access for critical system emergencies
📂 validator_operators Purpose: Validator admin, operations & process control
Complete validator management without OS access. Can do everything to the validator config either directly or via the Ansible Control, including install/uninstall, but nothing to the server or OS.
📂 validator_viewers Purpose: System observability & metrics
Observability without modification capability. This role is intended for users who need read-only access to the validator. Members can view service status, access logs, monitor, and inspect validator keys, but cannot perform any administrative or operational actions either directly or via the Ansible Control.
🚦 Permissions
These are the permissions that apply to each role along with some example commands that apply to each permission:
user_mgmt
Example commands:
sudo passwd forgetfuluser
sudo userdel baduser
sudo useradd gooduser
✅
❌
❌
pkg_mgmt
Example commands:
sudo apt update
sudo apt install htop
✅
✅
❌
pwd_selfsvc
Example commands:
sudo reset-my-password
✅
✅
❌
validator_mgmt
Example commands:
sudo systemctl restart sol
kill UID sol service
✅
✅
❌
validator_monitoring
Example commands:
systemctl status sol
journalctl -u sol.service -f
✅
✅
✅
👥 Users
Users belong to roles, except ubuntu
and sol
, which have special treatment as shown here:
⚙️ ubuntu
Provisioned by ASN with a server. Disabled after secure user setup.
To provision server users.
⚙️ sol
Primary validator service runner and owner of the validator files and data.
Runs the validator service. Restricted to everything else.
🧍Operator User: >>> alice, bob, etc.
Each human operator has his/her dedicated user.
Access the server via SSH, with no password. Can run some Ansible scripts from the Ansible Control depending on their role membership.
If a non-member user of a role, attempts to execute any of the commands within one of the permission, or attempts to run an Ansible Script with permissions they don't have, they will get an error that looks like this:
Sorry, user hugo is not allowed to execute '/usr/bin/apt udpate' as root on host-charlie.
Each role operates under the principle of least privilege with deny-by-default access control. Users are granted only the specific permissions explicitly defined using dedicated config files for each role. You can see the details later on this guide on under the User Access section.
User Setup
🎛️ Config File
The pb_setup_server_users.yml
expects a CSV with users and groups meta that will be used for the identity and access management provisioning.
You can use the template below as a starting point and modify as needed. Once you are happy with the setup, put in this folder ~/new-metal-box/iam_setup.csv
. You'll be using this path as a parameter when running the script.
❇️ Provisioning
Before running the user provisioning playbook, ensure that your inventory file (target_one_host.yml
) is updated with the IP address of the target server where you will install the users. Your inventory file should look like this:
all:
hosts:
new-metal-box:
ansible_host: 192.168.1.100
ansible_port: 22
Replace <target_ip_address>
with your actual values. Once the inventory is updated, you can run the playbook using:
ansible-playbook playbooks/pb_setup_server_users.yml \
-i target_one_host.yml \
-e "target_host=new-metal-box" \
-e "ansible_user=ubuntu" \
-e "csv_file=iam_setup.csv"
Note: The playbook is configured to run with the user ubuntu
which is the only user in the newly provisioned server.
Upon running the playbook, you will see a confirmation asking you to verify the IP of the host you are about to change:
TASK [Show server IP and location for confirmation] ******************************
[Show server IP and location for confirmation]
IMPORTANT: You are about to run this playbook on the server with IP: 192.168.1.100
Location Information:
- City: Unknown
- Country: Unknown
- Organization: Unknown
To continue, please type exactly this IP: 192.168.1.100
If you are not sure, press Ctrl+C to cancel.
Type IP here
This step is a safety measure to ensure you are provisioning the correct server. Type the IP address shown to continue. If you are not sure, press Ctrl+C to cancel the process.
❌ Ubuntu User
Before the playbook completes, a final security warning is issued to inform the operator that the default ubuntu
user will be disabled. This is a deliberate security measure, as many cloud providers (ASN) preconfigure servers with the ubuntu
user by default, which poses a risk if left active.
A notification is displayed with the following message:
TASK [iam_manager : Notify about upcoming ubuntu user disablement] ******************************
MSG:
IMPORTANT WARNING: The ubuntu user will now be disabled.
After this task completes, you will LOSE CONNECTION to this server.
Please ensure you can connect with one of the newly created users:
- alan
- alice
- bob
TASK [iam_manager : Pause for warning] **********************************************************
[iam_manager : Pause for warning]
Press Enter to continue and disable ubuntu user (you will lose connection!), or Ctrl+C to abort:
Once confirmed, the ubuntu
user is disabled, and the SSH session will be terminated.
🎟️ User Access
The playbook automatically configures the required sudo permissions for each role by deploying dedicated policy files under /etc/sudoers.d/
. The system uses a hierarchical approach where higher roles inherit permissions from lower roles.
Role Hierarchy and Permissions
sysadmin
10-sysadmin
None (top level)
validator_operators
20-validator-operators
Inherits from viewers
validator_viewers
40-validator-viewers
Base level
Password Self Service
Users who belong to the sysadmin
or validator_operators
groups are required to set their own password in order to perform privilege escalation via sudo
.
Initial Access
After the user logs in using their SSH private key, they will see a welcome message guiding them through the self-service password setup:
ssh -p 2522 [email protected]
===============================================================================
WELCOME TO THE SYSTEM
===============================================================================
Welcome, alan!
===============================================================================
===============================================================================
PASSWORD MANAGEMENT
===============================================================================
To change your password, use: sudo reset-my-password
This command allows you to reset your password without entering your current
sudo password. It's a self-service feature for your convenience.
===============================================================================
Run the following command once logged in:
sudo reset-my-password
Security Question Setup
After running the sudo reset-my-password
command for the first time, users will be prompted to configure a personal security question and answer. This is a mandatory step in the password self-service process.
First-time setup: create your personal security question.
Question (min 10 chars): secure question > 10 chars
Answer (min 6 chars, will not echo):
This security question and answer can be randomly generated using a password manager such as 1Password and securely stored in the same vault alongside your other credentials. It is important that the question is not something obvious or personal, as attackers may attempt to guess it using social engineering techniques. Treat your security question and answer with the same level of confidentiality as your password to ensure maximum protection.
The security question and answer are encrypted using AES-256 with a high number of iterations and a unique salt, ensuring robust protection against brute-force or dictionary attacks. This encrypted data is stored in the path /etc/password-security/alan
, with strict file permissions accessible only by root.
If a user wishes to reset their password using the self-service script (sudo reset-my-password
), they will be prompted to correctly answer their security question.
The user has a maximum of 3 attempts. After three failed answers, the script will deny further access for 24 hours, displaying the following message:
sudo reset-my-password
Security check: secure question > 10 chars...
Answer:
Incorrect answer. 2 attempts remaining.
Answer:
Incorrect answer. 1 attempts remaining.
Answer:
sdfsIncorrect answer. 0 attempts remaining.
Too many failed attempts. Account locked for 24 hours.
Contact administrator for immediate unlock.
To regain access before the lockout period ends, a user from the sysadmin
group must either:
Manually reset the password using
sudo passwd alan
, orRemove the lock file at
/etc/password-security/password-reset-blocked-alan
to re-enable the self-service flow.
Password Self-Service Logging
To ensure full traceability and auditability, all user interactions with the reset-my-password
script are logged in the file /var/log/password-reset.log
. This includes events such as security question setup, password resets, and encryption actions.
Each log entry includes a timestamp, session ID, username, event type, and source IP address. This enables administrators to monitor and audit all password self-service activity in a secure and structured format.
[2025-07-23 03:51:09] [INFO] [SESSION:95939d91] [USER:alan] [TYPE:SESSION_START] [IP:172.25.0.10] Password reset process initiated
[2025-07-23 03:51:09] [INFO] [SESSION:95939d91] [USER:alan] [TYPE:FIRST_TIME_SETUP] [IP:172.25.0.10] User creating initial security question
[2025-07-23 03:55:59] [INFO] [SESSION:6298dffe] [USER:alan] [TYPE:QUESTION_CREATED] [IP:172.25.0.10] Security question created successfully
[2025-07-23 04:04:31] [INFO] [SESSION:e56002e8] [USER:alan] [TYPE:ANSWER_CREATED] [IP:172.25.0.10] Security answer created successfully
[2025-07-23 04:04:32] [INFO] [SESSION:e85a52ef] [USER:alan] [TYPE:QUESTION_ENCRYPTED] [IP:172.25.0.10] Security question encrypted with AES-256
[2025-07-23 04:04:32] [INFO] [SESSION:e85a52ef] [USER:alan] [TYPE:SECURITY_QUESTION_SAVED] [IP:172.25.0.10] Security question and answer stored successfully
All log files are owned by root
and are protected from unauthorized access. This logging system ensures compliance with internal audit policies and helps detect misuse or suspicious activity in password operations.
Discovering Your Sudo Permissions
To help users understand what commands they are allowed to run, a message is displayed at login as part of the system's welcome screen:
===============================================================================
WELCOME TO THE SYSTEM
===============================================================================
Welcome, alan!
===============================================================================
===============================================================================
USEFUL COMMANDS
===============================================================================
To check your current permissions, run:
sudo -l -U alan
To view your permissions file:
cat ~/permissions.txt
===============================================================================
Each user is provided with a permissions.txt
file in their home directory. This file is:
Automatically generated by Ansible during provisioning
Updated based on the user’s assigned role and sudoers configuration
cat ~/permissions.txt
cat ~/permissions.txt
# REAL USER PERMISSIONS FOR alan
# ================================================
# This file shows the REAL permissions you have on this server
# based on your current sudoers configuration
#
# Automatically generated by Ansible
# Last updated: 2025-07-23T02:47:16Z
systemctl status sol.service
journalctl -u sol.service --no-pager
tail -f /home/sol/logs/agave-validator.log
tail -n 50 /home/sol/logs/agave-validator.log
pgrep -f sol.service
du -sh /mnt/ledger
du -sh /mnt/accounts
Last updated
Was this helpful?