Mastering NetBox User Access with Permission Constraints

Mastering NetBox User Access with Permission Constraints

During one of our NetBox training sessions, one of our students asked:

Can I restrict a user within NetBox to only see devices for a given site?

The short answer is yes. However, getting there involves a good understanding of the NetBox permission feature set, so today, we will look into NetBox permissions and how to configure NetBox to only permit a user to access devices for a single site.

What is NetBox?

NetBox is an open-source IPAM/DCIM, built upon Python Django. NetBox allows you to model and document your infrastructure and acts as a Source of Truth for your infrastructure/network.
NetBox provides a range of network automation features, allowing you to leverage the data via APIs, Ansible and/or Nornir.

image2

NetBox Permissions 101

When granting access to what users (i.e NetBox admins) can access, NetBox provides various authentication settings. As expected, NetBox allows you to create users and groups. Against these users and groups, you can also define:

  • Actions - View, add, change, delete.
  • Objects - The various objects the actions can be applied to.

image4

Though we gain a huge amount of flexibility with Actions and Objects, we need to leverage Constraints to gain further control and assign more granularity to what users should or should not access.

NetBox Constraints

What are NetBox Constraints?

Let's say we select that we have configured NetBox so that a user can read the object DCIM > Device. This means the user will be able to read all devices within NetBox. Therefore, Constraints provide the ability to further filter these NetBox objects, and in turn further restrict what the user has access to.

For example, going back to our original use case: filter the Device object for a given site to limit the devices the user sees.

Constraint Input

So the next question is:

How do I define these NetBox constraints?

NetBox permission constraints are defined using JSON, where we define the field name and lookup value that we want to use to constrain the given object.

For example. To define a constraint where we, the user, will only see SiteA for the DCIM > Site object, we would perform:

{"name": "SiteA"}

Great. Let's now dive a little deeper.

Under the NetBox hood, what is happening is we are performing a QuerySet filter on the given object, and it is this JSON input that is used as the input to the QuerySet filter.

What's a QuerySet?

In Django, a QuerySet is used for querying the database using a high-level API instead of raw SQL. It's designed to be lazy, executing its SQL only when necessary. This optimises database interactions.

Therefore, knowing a little about QuerySets is essential as it makes it easier to define your Constraints.

Heres an example of performing a QuerySet filter directly within Python on a NetBox server to filter and return only the objects against the Device model with a name of spine1-nxos.

$ /opt/netbox/venv/bin/python manage.py nbshell
>>> from dcim.models import Device

# Perform a QuerySet on the Device model/object
>>> device = Device.objects.filter(name="spine1-nxos")

# See the result of the QuerySet
>>> device
<ConfigContextModelQuerySet [<Device: spine1-nxos>]>

# See the 1st entry within our QuerySet result
>>> device[0]
<Device: spine1-nxos>

# Explore the result. Using __dict__ to see the objects data attributes
>>> from pprint import pprint as pp
>>> pp(device[0].__dict__)
{'_name': 'spine00000001-nxos',
 '_state': <django.db.models.base.ModelState object at 0x7f2dee9c8190>,
 'asset_tag': None,
 'cluster_id': None,
 'comments': ",
 'created': datetime.date(2021, 12, 14),
 'custom_field_data': {},
 'device_role_id': 1,
 'device_type_id': 3,
 'face': ",
 'id': 1,
 'last_updated': datetime.datetime(2022, 10, 8, 22, 14, 44, 892220, tzinfo=<UTC>),
 'local_context_data': None,
 'location_id': 1,
 'name': 'spine1-nxos',
 'platform_id': 4,
 'position': None,
 'primary_ip4_id': 3,
 'primary_ip6_id': None,
 'rack_id': None,
 'serial': ",
 'site_id': 1,
 'status': 'active',
 'tenant_id': None,
 'vc_position': None,
 'vc_priority': None,
 'virtual_chassis_id': None}

Therefore, to perform this filter within the NetBox Constraints, we would of:

  1. Select the Object: DCIM > Device
  2. Provided a Constraint of {"name": "spine1-nxos"}

QuerySets Filter Expressions

So far, we have seen that we can provide our QuerySet filter with a field name and the value that the field should be evaluated against. But what else can we do with these QuerySet filters? Here are some examples.

This table provides examples of filtering the Device model using various query filter lookups based on the Device fields.

Query Filter NetBox Device Model Example Description
contains name__contains='spine1-nxos' Field contains the phrase "spine1-nxos".
icontains name__icontains='spine1-nxos' Field contains the phrase "spine1-nxos", case-insensitive.
endswith name__endswith='nxos' Field ends with the phrase "nxos".
iendswith name__iendswith='NXos' Field ends with the phrase "NXos", case-insensitive.

This table demonstrates how to filter the Device model based on fields from related models. For instance, the Device might be related to Site or DeviceType, and we can query the Device based on fields from these related models.

Query Filter NetBox Device Model Example with Related Field Description
related_field site__name='SiteA' Device is related to, a Site with the name "SiteA".
related_field__contains site__name__contains='Site' Device is related to, any Site with a name containing the phrase "Site".

Now that we understand this, it gives us tremendous flexibility regarding our NetBox permissions. Therefore, let's turn our attention back to our original use case and configure NetBox to allow users to see devices from a single site only.

Configuration Example

Create User

First, we create our user - user1.

Create Group

Next, we create a group - Group-SiteA. And assign our user.

Create Permission Constraints

Next we:

  1. Create our permissions and constraints via:
    Admin > Authentication > Permissions > +.

  2. We will create 3 x permission entries, containing the data in the screenshot below.

Note: Pre NetBox 3.6.1, you will need to configure directly within the admin panel (i.e. /admin)


As you can see, we've created 3 different permissions, and here is the caveat with Constraints. Other objects have different fields. Therefore, our filter expression must be adjusted based on the model type. If not, the QuerySet will return an error to say it cannot find the field within the object.

For the eagle-eyed, you will have noticed that based on these permissions, our user will be limited to seeing a single site and only the devices within the site, but he will be able to see the components for all the site devices. However, You can lock this down further if required based on what we have covered.

Closing Comments

I hope this post is helpful and helps you understand the NetBox permission feature set. As you can see, NetBox provides a huge amount of functionality and flexibility when it comes to permitting and restricting user access, and I hope this post will help you configure this within your environment.

Subscribe to our newsletter and stay updated.

Don't miss anything. Get all the latest posts delivered straight to your inbox.
Great! Check your inbox and click the link to confirm your subscription.
Error! Please enter a valid email address!