Explore Developer Center's New Chatbot! MongoDB AI Chatbot can be accessed at the top of your navigation to answer all your MongoDB questions.

Introducing MongoDB 8.0, the fastest MongoDB ever!
MongoDB Developer
MongoDB
plus
Sign in to follow topics
MongoDB Developer Centerchevron-right
Developer Topicschevron-right
Productschevron-right
MongoDBchevron-right

How to Secure MongoDB Data Access with Views

Maxime Beugnet4 min read • Published Apr 07, 2023 • Updated Apr 07, 2023
MongoDBSecurity
Facebook Icontwitter iconlinkedin icon
Rate this article
star-empty
star-empty
star-empty
star-empty
star-empty

Introduction

Sometimes, MongoDB collections contain sensitive information that require access control. Using the Role-Based Access Control (RBAC) provided by MongoDB, it's easy to restrict access to this collection. But what if you want to share your collection to a wider audience without exposing sensitive data?
For example, it could be interesting to share your collections with the marketing team for analytics purposes without sharing personal identifiable information (PII) or data you prefer to keep private, like employee salaries.
It's possible to achieve this result with MongoDB views combined with the MongoDB RBAC, and this is what we are going to explore in this blog post.

Prerequisites

You'll need either:
  • A MongoDB cluster with authentication activated (which is somewhat recommended in production!).
  • A MongoDB Atlas cluster.
I'll assume you already have an admin user on your cluster with full authorizations or at least a user that can create views, custom roles. and users. If you are in Atlas, you can create this user in the Database Access tab or use the MongoDB Shell, like this:
1mongosh "mongodb://localhost/admin" --quiet --eval "db.createUser({'user': 'root', 'pwd': 'root', 'roles': ['root']});"
Then you can connect with the command line provided in Atlas or like this, if you are not in Atlas:
1mongosh "mongodb://localhost" --quiet -u root -p root

Creating a MongoDB collection with sensitive data

In this example, I'll pretend to have an employees collection with sensitive data:
1db.employees.insertMany(
2 [
3 {
4 _id: 1,
5 firstname: 'Scott',
6 lastname: 'Snyder',
7 age: 21,
8 ssn: '351-40-7153',
9 salary: 100000
10 },
11 {
12 _id: 2,
13 firstname: 'Patricia',
14 lastname: 'Hanna',
15 age: 57,
16 ssn: '426-57-8180',
17 salary: 95000
18 },
19 {
20 _id: 3,
21 firstname: 'Michelle',
22 lastname: 'Blair',
23 age: 61,
24 ssn: '399-04-0314',
25 salary: 71000
26 },
27 {
28 _id: 4,
29 firstname: 'Benjamin',
30 lastname: 'Roberts',
31 age: 46,
32 ssn: '712-13-9307',
33 salary: 60000
34 },
35 {
36 _id: 5,
37 firstname: 'Nicholas',
38 lastname: 'Parker',
39 age: 69,
40 ssn: '320-25-5610',
41 salary: 81000
42 }
43 ]
44)

How to create a view in MongoDB to hide sensitive fields

Now I want to share this collection to a wider audience, but I don’t want to share the social security numbers and salaries.
To solve this issue, I can create a view with a $project stage that only allows a set of selected fields.
1db.createView('employees_view', 'employees', [{$project: {firstname: 1, lastname: 1, age: 1}}])
Note that I'm not doing {$project: {ssn: 0, salary: 0}} because every field except these two would appear in the view. It works today, but maybe tomorrow, I'll add a credit_card field in some documents. It would then appear instantly in the view.
Let's confirm that the view works:
1db.employees_view.find()
Results:
1[
2 { _id: 1, firstname: 'Scott', lastname: 'Snyder', age: 21 },
3 { _id: 2, firstname: 'Patricia', lastname: 'Hanna', age: 57 },
4 { _id: 3, firstname: 'Michelle', lastname: 'Blair', age: 61 },
5 { _id: 4, firstname: 'Benjamin', lastname: 'Roberts', age: 46 },
6 { _id: 5, firstname: 'Nicholas', lastname: 'Parker', age: 69 }
7]
Depending on your schema design and how you want to filter the fields, it could be easier to use $unset instead of $project. You can learn more in the Practical MongoDB Aggregations Book. But again, $unset will just remove the specified fields without filtering new fields that could be added in the future.

Managing data access with MongoDB roles and users

Now that we have our view, we can share this with restricted access rights. In MongoDB, we need to create a custom role to achieve this.
Here are the command lines if you are not in Atlas.
1use admin
2db.createRole(
3 {
4 role: "view_access",
5 privileges: [
6 {resource: {db: "test", collection: "employees_view"}, actions: ["find"]}
7 ],
8 roles: []
9 }
10)
Then we can create the user:
1use admin
2db.createUser({user: 'view_user', pwd: '123', roles: ["view_access"]})
If you are in Atlas, database access is managed directly in the Atlas website in the Database Access tab. You can also use the Atlas CLI if you feel like it.
Database access tab in Atlas
Then you need to create a custom role.
Custom Roles tab in Atlas
Create the custom role in Atlas
Note: In Step 2, I only selected the Collection Actions > Query and Write Actions > find option.
Now that your role is created, head back to the Database Users tab and create a user with this custom role.
Navigation to create a user in Atlas
Create a user in Atlas with a custom role

Testing data access control with restricted user account

Now that our user is created, we can confirm that this new restricted user doesn't have access to the underlying collection but has access to the view.
1$ mongosh "mongodb+srv://hidingfields.as3qc0s.mongodb.net/test" --apiVersion 1 --username view_user --quiet
2Enter password: ***
3Atlas atlas-odym8f-shard-0 [primary] test> db.employees.find()
4MongoServerError: user is not allowed to do action [find] on [test.employees]
5Atlas atlas-odym8f-shard-0 [primary] test> db.employees_view.find()
6[
7 { _id: 1, firstname: 'Scott', lastname: 'Snyder', age: 21 },
8 { _id: 2, firstname: 'Patricia', lastname: 'Hanna', age: 57 },
9 { _id: 3, firstname: 'Michelle', lastname: 'Blair', age: 61 },
10 { _id: 4, firstname: 'Benjamin', lastname: 'Roberts', age: 46 },
11 { _id: 5, firstname: 'Nicholas', lastname: 'Parker', age: 69 }
12]

Wrap-up

In this blog post, you learned how to share your MongoDB collections to a wider audience — even the most critical ones — without exposing sensitive data.
Note that views can use the indexes from the source collection so your restricted user can leverage those for more advanced queries.
You could also choose to add an extra $match stage before your $project stage to filter entire documents from ever appearing in the view. You can see an example in the Practical MongoDB Aggregations Book. And don't forget to support the $match with an index!
Questions? Comments? Let's continue the conversation over at the MongoDB Developer Community.

Facebook Icontwitter iconlinkedin icon
Rate this article
star-empty
star-empty
star-empty
star-empty
star-empty
Related
Article

The Six Principles for Building Robust Yet Flexible Shared Data Applications


Sep 23, 2022 | 3 min read
Tutorial

Getting Started With the MongoDB Kotlin Driver


Sep 09, 2024 | 9 min read
Tutorial

Build a Newsletter Platform With Flask and MongoDB


Sep 04, 2024 | 11 min read
Tutorial

How to Use the Union All Aggregation Pipeline Stage in MongoDB 4.4


Sep 09, 2024 | 16 min read
Table of Contents