Profile ownership and daemon access

Updated

The NetBird daemon runs as root, or as LocalSystem on Windows. Each local user can connect to its socket. Without a check, one user can read or change the profile of another user, or stop that user's connection.

To prevent this, the daemon identifies each caller and gives each profile an owner. A user can use only the profiles that they own. A connection belongs to the user who started it.

How the daemon identifies a caller

The daemon gets the identity of the caller from the operating system, not from the request. If the daemon cannot identify the caller, it refuses the request.

A TCP socket does not carry an identity, so the daemon refuses every request on it. TCP sockets are deprecated. For more information, see TCP sockets (deprecated).

Access levels

The daemon gives each request one of four access levels. Each level can do all the operations of the levels above it in this table.

LevelWhoOperations
IdentifiedAny user that the daemon can identifyRead basic status. List your profiles. Add a profile.
Profile ownerThe owner of the profileRead and change the profile configuration. Rename, remove, or deregister the profile.
Session holderThe owner of the active profile and the connection is upDisconnect. Log in. Switch profiles. Select networks. Read detailed status. Create a debug bundle.
PrivilegedRoot, an elevated administrator, or the user that the daemon runs asAll operations on all profiles. Claim a profile.

The daemon lets the user that it runs as act as a privileged user only when the daemon itself is not privileged. An example is a rootless container.

Profile ownership

Each profile records one owner. On Linux and macOS, the owner is a user ID, for example uid:1000. On Windows, the owner is a security identifier (SID), for example sid:S-1-5-21-....

When you add a profile, you become its owner. Root and administrators can see and use all profiles.

Commands and required access

CommandRequired level
netbird statusIdentified. Detailed status requires session holder.
netbird profile list, netbird profile addIdentified
netbird profile rename, netbird profile remove, netbird deregisterProfile owner
netbird down, netbird login, netbird profile selectSession holder
netbird debug bundleSession holder
netbird profile claimPrivileged

netbird profile list shows only the profiles that you own. To show the owner of each profile, add --show-owner:

sudo netbird profile list --show-owner
NAME     ACTIVE  OWNER
default  *       alice
work             bob
lab              unowned

Connections of other users

When a user connects, the active profile and its connection belong to that user. Other users cannot connect, disconnect, or switch profiles until the connection stops. To stop the connection of another user, run:

sudo netbird down

Claim a profile

To give a profile an owner, run netbird profile claim as root or as an administrator:

sudo netbird profile claim <profile> --owner <owner>

The <owner> value is an account name, a uid:<id> value, or a sid:<SID> value. The daemon does not check that a uid or sid value belongs to an existing account.

On Linux and macOS, if you do not set --owner, the owner is the user who ran sudo. If you run the command in a root shell without sudo, --owner is required. On Windows, --owner is required.

Restrict daemon access to a group

By default, all local users can connect to the daemon socket. To let only one group connect, set --allow-group when you install the service:

sudo netbird service install --allow-group netbird-users

The operating system then refuses connections from users outside the group. This restriction also applies to the HTTP/JSON daemon socket.

  • On Linux and macOS, you can set only one group. The value is a group name or a group ID.
  • On Windows, you can set a comma-separated list of groups or accounts. LocalSystem, elevated administrators, and the account that the daemon runs as always keep access.
  • The installer resolves group names to IDs, including LDAP, SSSD, and Active Directory groups. If a name does not resolve, the installation stops.
  • netbird service reconfigure resolves the names again.
  • To remove the restriction, run sudo netbird service reconfigure --allow-group "".

Socket location

This section applies to Linux, macOS, and FreeBSD. It does not apply to Windows.

When the daemon starts with --allow-group, it changes the group of the socket and sets the socket mode to 0660. Before this change, the daemon examines the directory that contains the socket. The daemon does not start if one of these conditions is true:

  • Other accounts can write to the directory, and the directory does not have the sticky bit.
  • The owner of the directory is not root and not the account that the daemon runs as.

The daemon does not examine the directories higher in the path. If you set a custom socket path with --daemon-addr or --json-socket, make sure that root or the daemon account owns each directory in the path, and that other users cannot write to these directories. If other users can write to a directory in the path, they can replace a directory while the daemon applies the restriction.

The default socket paths, /var/run/netbird.sock and /var/run/netbird-http.sock, meet these requirements. For example:

Socket pathResult
/srv/sockets/netbird.sock, where /srv/sockets has mode 0777The daemon does not start.
/run/netbird/netbird.sock, where root owns /run/netbird with mode 0755Supported.
/home/alice/sockets/netbird/netbird.sockNot supported, because a user can write to a directory in the path.

Set allowed groups with MDM

On managed Windows and macOS devices, use the allowGroups MDM policy key. On Windows, the Group Policy name is Restrict the daemon sockets.

  • The MDM value replaces the --allow-group value. An empty value removes a restriction that the installer set.
  • On macOS, set exactly one group ID, for example gid:1001.
  • On Windows, set a comma-separated list of SIDs, for example sid:S-1-5-21-....
  • Use IDs, not names. The daemon reads this value when it starts. It waits a maximum of 5 seconds to resolve names.

Environment variables

Set these variables on the daemon. For instructions, see Client environment variables.

VariableDescription
NB_DISABLE_PROFILE_OWNERSHIPSet to true to turn off profile ownership. All identified users can use all profiles and control all connections. Android and iOS always work this way.
NB_DISABLE_DEFAULT_PROFILE_CLAIMSet to true to stop the automatic claim of the default profile. The default profile then has no owner until an administrator claims it.

Upgrade from an earlier version

Earlier versions kept profiles in one directory for each user, for example /var/lib/netbird/<username>/, and recorded no owner. When the new daemon starts for the first time, it migrates these profiles. Your profiles stay in their directories.

The migration does these steps:

  1. Gives a new unique ID to profiles that have the same ID in different user directories.
  2. Records the owner of the profiles of the last active user and of the default profile.
  3. Writes the .migrated file in the profiles.v1 directory, for example /var/lib/netbird/profiles.v1/.migrated. This file shows that the migration is complete. It contains the version of the profile layout, for example {"version":1}.

If the migration fails, the daemon writes the error to the log and tries again at the next start. The daemon saves new profiles in the profiles.v1 directory.

Automatic claims

After the migration, some profiles can still have no owner. The daemon gives them an owner when a user sends a request:

  • Profiles in a user directory. The daemon records the user whose name matches the directory as the owner.
  • Default profile. The daemon records the first user who is logged in at the console of the device as the owner. For what counts as the console, see Set up a headless machine.

Root and administrators never become owners through an automatic claim.

On a device with no console, for example a server, the default profile keeps no owner. To give it an owner, run:

sudo netbird profile claim default --owner <owner>

Set up a headless machine

A headless machine, for example a server or a Raspberry Pi, has no user at the console. No user can claim the default profile automatically. A user without root privileges cannot connect the default profile.

A user is at the console when they are logged in locally on the machine:

OSConsole
LinuxThe active local session of a seat in systemd-logind. This includes a graphical login and a text login on a local terminal.
macOSThe user logged in to the graphical session.
WindowsThe user logged in to the physical console session.
FreeBSDA user logged in on a local virtual terminal.

These sessions are not at the console:

  • SSH sessions and other remote sessions.
  • Remote Desktop (RDP) sessions on Windows.
  • All sessions on a Linux machine without a logind service (systemd-logind or elogind), for example a container.

A machine with a screen and keyboard is also headless if no user logs in locally.

This protects machines that many users access over SSH, for example a shared server. If the first SSH user claimed the default profile, that user could control the connection of the machine and read its configuration. The daemon cannot know which SSH user is the correct owner, so it lets an administrator decide.

Use one of these two methods.

Connect as root

Use this method for servers that only administrators manage.

curl -fsSL https://pkgs.netbird.io/install.sh | sh
sudo netbird up --setup-key <SETUP_KEY>

The default profile keeps no owner. Use sudo for each command that changes the connection, for example sudo netbird down.

Give the default profile to a user

Use this method if a user without root privileges must control the connection.

curl -fsSL https://pkgs.netbird.io/install.sh | sh
sudo netbird profile claim default --owner <user>
netbird up --setup-key <SETUP_KEY>

Run netbird up as the user that you set with --owner. If you omit --owner, the owner is the user who ran sudo.

How a connection works on a shared machine

Profile ownership controls who can operate the daemon. It does not control who can send traffic through the connection.

The NetBird connection belongs to the whole machine. When a user connects, the daemon creates a network interface, routes, and DNS settings for all users of the machine. The daemon also connects at startup with the last active profile, before any user logs in.

On a shared machine, this has these results:

  • All local users use the connection. If Alice connects, Bob can log in and reach the same peers and resources as Alice. NetBird access policies apply to the peer, not to the local user.
  • Only the session holder controls the daemon. Bob cannot disconnect, switch profiles, or read detailed status. Bob gets a message that says another user has the machine connected.
  • The connection stays after the owner logs out. It stays until the owner or an administrator runs netbird down.

Share a profile between users

On a shared computer, for example in a lab or at a reception desk, many users can use the same profile. A profile has only one owner, so profile ownership stops the other users.

To let a known set of users share all profiles, do these three steps:

  1. Restrict the daemon to a group. Only users in this group can connect to the daemon.
  2. Turn off profile ownership. All users in the group can then use all profiles and control the connection.
  3. Turn off the automatic claim of the default profile. Without this step, the first user at the console becomes the owner. If you turn on profile ownership again later, the other users then lose access to the default profile.

Users outside the group cannot connect to the daemon at all.

Linux

  1. Create a group and add the users:

    sudo groupadd netbird-users
    sudo usermod -aG netbird-users alice
    sudo usermod -aG netbird-users bob
    
  2. Install the service with the group and the environment variables:

    sudo netbird service install \
      --allow-group netbird-users \
      --service-env NB_DISABLE_PROFILE_OWNERSHIP=true,NB_DISABLE_DEFAULT_PROFILE_CLAIM=true
    

    If the service is already installed, use netbird service reconfigure with the same flags.

A new group membership applies at the next login of the user.

Windows

In an elevated terminal, set the groups or accounts as a comma-separated list:

netbird service install --allow-group "NetBird Users" --service-env NB_DISABLE_PROFILE_OWNERSHIP=true,NB_DISABLE_DEFAULT_PROFILE_CLAIM=true

Administrators and LocalSystem always keep access.

Harden daemon access

Use the recommendations for your environment.

All environments

  • Use the default Unix socket on Linux and macOS, and the default named pipe on Windows. Do not use a TCP socket. A TCP socket carries no caller identity and is deprecated.
  • Keep the HTTP/JSON socket off, unless an integration needs it. It is off by default.
  • Set --allow-group to a group that contains the users that use NetBird on the machine. Users outside the group cannot connect to the daemon.
  • Do not set NB_DISABLE_PROFILE_OWNERSHIP without --allow-group.

Servers

  • Connect as root, and give the default profile to a user only when that user must control the connection.
  • Set NB_DISABLE_DEFAULT_PROFILE_CLAIM=true. A user who logs in on the local terminal then cannot claim the default profile.
  • Set --allow-group to the administrators group, or to an empty group. Root keeps access.

Managed devices

  • Set the allowGroups MDM key with group IDs, not names. The daemon then does not wait for a directory server when it starts.
  • Set disableProfiles or disableUpdateSettings if users must not change the configuration.

Containers and rootless daemons

  • If the daemon does not run as root, the user that it runs as is a privileged user. Do not run other workloads as this user.

Troubleshooting

Another user has this machine connected

Symptom: A command fails with a message that says another user has the machine connected.

Cause: Another user started the current connection.

Fix: Ask that user to disconnect, or run sudo netbird down.

The profile belongs to another user

Symptom: A command fails with a message that says the profile belongs to another user.

Cause: You do not own the profile.

Fix: Use a profile that you own. Or, ask an administrator to run sudo netbird profile claim <profile> --owner <your-user>.

The profile has no owner on record

Symptom: A command fails with a message that says the profile has no owner on record.

Cause: The profile was not claimed. This is usual on a device with no console, or when you connect over SSH.

Fix: Run the netbird profile claim command that the error message shows.

A profile is missing from the profile list

Cause: netbird profile list shows only the profiles that you own.

Fix: To see all profiles and their owners, run sudo netbird profile list --show-owner.

Detailed status is unavailable

Symptom: netbird status shows Detailed status is unavailable: the connection belongs to another user.

Cause: Another user holds the connection. You can see only the daemon status.

The daemon does not start after you set allowed groups

Possible causes:

  • A group name does not resolve.
  • You set more than one group on Linux or macOS.
  • The daemon or the JSON socket uses a TCP socket.
  • The daemon cannot read the MDM policy.

Fix: Read the daemon log. The log shows which of these causes stopped the daemon.

Service commands fail because a group name does not resolve

Symptom: On Windows, netbird service install and netbird service reconfigure fail with an error like this:

Error: resolve allowed group "netbird": look up account: The trust relationship between this workstation and the primary domain failed.

Cause: The service saves the --allow-group names in %ProgramData%\Netbird\service.json. Each install and reconfigure resolves these names again. If the device cannot connect to the domain controller, the name does not resolve and the command stops.

Fix: Do one of these steps in an elevated terminal:

  • To keep the restriction, set the group SID. The installer does not look up a SID. The allow_group_ids field in service.json shows the SID from the last installation.

    # Service is installed
    netbird service reconfigure --allow-group sid:<SID>
    # Service is not installed
    netbird service install --allow-group sid:<SID>
    
  • To remove the restriction, set an empty value:

    # Service is installed
    netbird service reconfigure --allow-group=""
    # Service is not installed
    netbird service install --allow-group=""
    

reconfigure works only on an installed service. To check, run netbird service status.

Confirm: Run netbird service status. Then connect to the daemon as a user in the group, for example with netbird status.

Remote desktop users cannot use the default profile

Symptom: A user in a remote desktop session gets a message that says the profile has no owner on record.

Cause: Only a user at the console can claim the default profile automatically. On Windows, a user in a Remote Desktop (RDP) session is not at the console. On Linux, a user in a remote session is not at the console.

Fix: Ask an administrator to claim the default profile for the user:

netbird profile claim default --owner <user>

Users lost access to the default profile after the upgrade

Symptom: After the upgrade, users who used the default profile before get a message that says the profile belongs to another user.

Cause: The migration gives the default profile to the user who was active last. A profile has only one owner.

Fix: Each of the other users adds a profile with netbird profile add. To give the default profile to a different user, run sudo netbird profile claim default --owner <user>.

The client uses the default profile after the upgrade

Symptom: After the upgrade, the daemon starts with the default profile, not the profile that was active before. The daemon log shows starting on the default profile, the active one could not be resolved.

Cause: Profiles of different users had the same ID. The migration cannot find which of these profiles was active. The daemon uses the default profile, so it does not connect with the profile of another user. The migration tries again at the next start.

Fix:

  1. Restart the service. The migration then gives each profile a unique ID.

    sudo netbird service restart
    
  2. Find the ID of your profile, and select it:

    netbird profile list --show-id
    netbird profile select <id-prefix>
    

Confirm: The daemon log shows profile migration complete.

Profiles from an earlier version have no owner

Symptom: A user gets a message that says the profile has no owner on record for a profile that they created in an earlier version. The daemon log shows cannot resolve ... to an account name, its legacy profiles stay unowned.

Cause: The daemon gives an old profile to the user whose account name matches the profile directory. The daemon could not get the account name. For example, the account was renamed or deleted, or the LDAP or Active Directory server was not available.

Fix: If the directory server was not available, run the command again when the server is available. The daemon tries again at each request. If the account was renamed or deleted, ask an administrator to run sudo netbird profile claim <profile> --owner <user>.

An integration lost access to the daemon

Symptom: A monitoring tool, a script, or a scheduled job gets less status information than before, or the daemon refuses its requests.

Cause: The integration runs as a user that does not own the active profile. That user gets only basic status. The daemon refuses requests to connect, disconnect, or change the profile.

Fix: Run the integration as the owner of the profile, or as root. If the integration uses a TCP socket, change it to a Unix socket or a named pipe. See TCP sockets (deprecated).

Turn off profile ownership temporarily

If the upgrade stops a critical workflow, you can turn off profile ownership until you fix the cause:

sudo netbird service reconfigure --service-env NB_DISABLE_PROFILE_OWNERSHIP=true

To turn profile ownership on again, run:

sudo netbird service reconfigure --service-env NB_DISABLE_PROFILE_OWNERSHIP=false

Collect information for support

A debug bundle includes profiles.txt and active_profile.json. These files show each profile, its owner, and the active profile. For instructions, see Troubleshooting client issues.