Your data in Couchbase just got more secure.
Couchbase Server 7.0 introduced Scopes and Collections to better map between relational and NoSQL data models. But the 7.0 release also includes some additional enhancements to strengthen the security of the data platform. More specifically, role-based access control (RBAC) security is now supported at the level of individual Scopes and Collections.
What’s all this mean for your Couchbase deployments? Let’s dive in.
Existing RBAC Security Roles in Couchbase
Couchbase Server has allowed fine-grained controls of user access to the platform with role-based access control (RBAC) security for administrators since version 4.5 and for all users since version 5.0. Couchbase Collections were introduced as a developer preview feature in Couchbase Server 6.5 and are now fully supported in Couchbase Server 7.0.
Couchbase RBAC security roles were previously divided into two categories:
- Administration and Global: These roles are associated with cluster-wide privileges. Some of these roles are for administrators who might manage cluster-configurations, read statistics or enforce security. Others are for users and user-defined applications that require access to specific, cluster-wide resources.
- Per Bucket: These roles are associated with one or more Buckets and support the reading and writing of Bucket settings, access to data, and the management of services, indexes, and replication procedures.
An RBAC Example Using Scopes and Collections
For example, you may have given read access to a Bucket named Travel
to a trusted hotel search engine called Acme Co. with a user named acme
using a command like this in the command-line interface of a Linux-based cluster. (You may need to adjust the paths if using another platform.)
1 2 3 |
/opt/couchbase/bin/couchbase-cli user-manage -c localhost:8091 -u Administrator -p password \ --set --rbac-username acme --rbac-password cbpass7beta --rbac-name "Acme Co. (Hotel)" \ --roles data_reader[Travel] --auth-domain local |
What this would do is allow your hotel search partner Acme Co. to access all of the data your company is storing in the Travel
Couchbase Bucket. This might include orders, inventory and other pieces of data for not only hotels but also airlines and other travel products. Following the principle of least privilege, what if we wanted to limit what data Acme Co. has access to, instead of allowing them access to all travel data in our company?
Collections allow JSON documents in a Couchbase Bucket to be organized, first into Scopes, where a Scope is similar to a schema in a relational database (RDBMS). Next, the Scope is subdivided into individual Collections, similar to how a table would be structured in a traditional relational database.
The namespace within each Scope is independent of others, hence you can have the same Collection names within different Scopes. Similarly, document keys need to be unique only within a Collection and hence documents with the same key can exist in different Collections.
Before the introduction of Scopes and Collections, it was common to organize Couchbase documents based on key prefixes, such as Orders::Europe::Customer1
. Collections provide much more flexibility in the document keys than was previously available.
Below is a visual diagram of the relationship between Buckets, Scopes and Collections for an example travel dataset.
For seamless upgrades – and for backwards compatibility – every Bucket now has a _default
Scope, and the _default
Scope has a _default
Collection. The _default
Collection provides backward compatibility and a direct reference to the Bucket automatically maps to the _default
Collection. Also, on upgrade, all existing data is automatically added to the _default
Collection.
While the _default
Collection is provided as a backward compatibility mechanism, new applications should be written using named Collections. As you can see, Collections allow for additional options to organize data in a Couchbase Server cluster.
Returning to the example above, what if we wanted to only allow Acme Co. to see the hotel data only, instead of all travel data across the company? With Collections, you can now limit the confines of Acme’s access to only the Scope of your choosing.
For example, say Acme Co. needed to check the inventory of available hotel rooms, we can narrow their RBAC role down to the Hotel
Collection inside the Inventory
Scope within the Travel
Bucket.
Role-Based Access Control (RBAC) Security Explained
How do Scopes and Collections work with role-based access control in the database?
A user who has access to a Bucket inherits access to the children Scopes and Collections of that Bucket. Likewise, a user who has access to a Scope inherits access to the children Collections but not the parent Bucket.
Here’s a breakdown of how the new role-based security works with Collections:
Role | Description |
data_reader[*] |
Can read data in every Bucket, including every Scope and Collection, cluster-wide. |
data_reader[foo] |
Can read data in every Scope and Collection within only the Bucket foo . |
data_reader[foo:bar] |
Can read data in every Collection within the Scope bar of the Bucket foo . |
data_reader[foo:bar:baz] |
Can read data only in the Collection baz which is located in the Scope bar of the Bucket foo . |
For Acme Co, the CLI command is similar to the earlier example, but instead of setting the RBAC to a Bucket, you need to adjust it to allow only a single Scope and/or Collection.
In our example from above, we want to allow the acme
user access to the Hotel
Collection inside of the Inventory
Scope, so in this case the role would be data_reader[Travel:Inventory:Hotel]
.
1 2 3 |
/opt/couchbase/bin/couchbase-cli user-manage -c localhost:8091 -u Administrator -p password \ --set --rbac-username acme --rbac-password cbpass7beta --rbac-name "Acme Co. (Hotel)" \ --roles data_reader[Travel:Inventory:Hotel] --auth-domain local |
You’re probably wondering, what user access roles that can have a Scope and Collection defined? Here’s the complete list:
A Hands-on RBAC Security Example with Couchbase Server 7.0
Now it’s time for some more hands-on examples you can try out for yourself on Couchbase Server 7.0. As before, I’m using a Linux-based cluster, so you may need to adjust the paths if using another platform. You’ll need to be running the Couchbase Data, Query and Index Services for this example.
First, load the travel-sample
Bucket into your cluster.
1 2 |
curl -X POST -u Administrator:password http://localhost:8091/sampleBuckets/install -d '["travel-sample"]' [] |
Then, create some additional Collections in the Bucket. We’ll use the _default
Scope. You’ll need to use a Bucket administrator user (or higher privileges) to create the new Collections.
1 2 |
$ /opt/couchbase/bin/couchbase-cli collection-manage --create-collection _default.hotel -c localhost \ -u Administrator -p password --bucket travel-sample |
1 |
SUCCESS: Collection created |
1 2 |
$ /opt/couchbase/bin/couchbase-cli collection-manage --create-collection _default.airport -c localhost \ -u Administrator -p password --bucket travel-sample |
1 |
SUCCESS: Collection created |
1 2 |
$ /opt/couchbase/bin/couchbase-cli collection-manage --create-collection _default.airline -c localhost \ -u Administrator -p password --bucket travel-sample |
1 |
SUCCESS: Collection created |
1 2 |
$ /opt/couchbase/bin/couchbase-cli collection-manage --create-collection _default.landmark -c localhost \ -u Administrator -p password --bucket travel-sample |
1 |
SUCCESS: Collection created |
You can also see these Collections in the Couchbase Server Web UI, as pictured below.
Next, we’ll load data into each of the Collections based on a field which already exists in the documents, called type
. The document type
field matches to the new Collections we’ve just created. The data is copied into the Collection using the N1QL query language from the command line. Note: We need to be careful to escape characters the shell would try to execute such as backticks.
If you run into any issues with the formatting or getting the command to run, here’s an example image of what the command should look like.
1 2 3 |
/opt/couchbase/bin/cbq -u=Administrator -p=password --script=\ "INSERT INTO \`travel-sample\`._default.hotel (KEY _key, VALUE _value)\ SELECT meta().id _key, _value FROM \`travel-sample\` _value WHERE type='hotel'" |
1 2 3 |
/opt/couchbase/bin/cbq -u=Administrator -p=password --script=\ "INSERT INTO \`travel-sample\`._default.airport (KEY _key, VALUE _value)\ SELECT meta().id _key, _value FROM \`travel-sample\` _value WHERE type='airport'" |
1 2 3 |
/opt/couchbase/bin/cbq -u=Administrator -p=password --script=\ "INSERT INTO \`travel-sample\`._default.airline (KEY _key, VALUE _value)\ SELECT meta().id _key, _value FROM \`travel-sample\` _value WHERE type='airline'" |
1 2 3 |
/opt/couchbase/bin/cbq -u=Administrator -p=password --script=\ "INSERT INTO \`travel-sample\`._default.landmark (KEY _key, VALUE _value)\ SELECT meta().id _key, _value FROM \`travel-sample\` _value WHERE type='landmark'" |
Let’s create a primary index on the hotel
Collection as an administrator:
1 2 |
/opt/couchbase/bin/cbq -u=Administrator -p=password --script=\ "CREATE PRIMARY INDEX `hotel-primary` ON \`travel-sample\`._default.hotel" |
Now, let’s get a list of all users and roles:
1 |
/opt/couchbase/bin/couchbase-cli user-manage -c localhost:8091 -u Administrator -p password --list |
1 |
[] |
As you can see above, we currently only have the built-in Administrator and no additional users. So the output from the command is empty, as expected.
Next, let’s create a user, John Doe. We’ll give John both a data reader role and a query select role on the hotel
Collection, which is located in the _default
Scope.
1 2 3 4 |
/opt/couchbase/bin/couchbase-cli user-manage -c localhost:8091 -u Administrator -p password \ --set --rbac-username jdoe --rbac-password cbpass7beta --rbac-name "John Doe" \ --roles data_reader[travel-sample:_default:hotel],query_select[travel-sample:_default:hotel] \ --auth-domain local |
1 |
SUCCESS: User jdoe set |
Again, you can do this from the Web UI as well.
Then, we verify that John Doe has the permissions specific to the hotel
Collection. When John attempts to read from the entire travel-sample Bucket, he gets a permission denied error.
1 |
/opt/couchbase/bin/couchbase-cli user-manage -c localhost:8091 -u Administrator -p password --list |
1 2 |
/opt/couchbase/bin/cbq -u=jdoe -p=cbpass7beta --script=\ "SELECT type, name, hotel.country FROM \`travel-sample\` LIMIT 5;" |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
SELECT type, name, hotel.country FROM `travel-sample` LIMIT 5; { .... "results": [ ], "errors": [ { "code": 13014, "msg": "User does not have credentials to run SELECT queries on default:travel-sample. Add role query_select on default:travel-sample to allow the query to run." } ], "status": "fatal", … |
This time, as John, let’s select five hotels from just the hotel
Collection of the travel-sample
Bucket, which John does have access to.
1 2 |
/opt/couchbase/bin/cbq -u=jdoe -p=cbpass7beta --script=\ "SELECT type, name, hotel.country FROM \`travel-sample\`._default.hotel LIMIT 5;" |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
SELECT type, name, hotel.country FROM `travel-sample`._default.hotel LIMIT 5; { "requestID": "3cdc2fa8-b0cf-411a-a325-a1534280087a", "signature": { "country": "json", "name": "json", "type": "json" }, "results": [ { "country": "United Kingdom", "name": "Medway Youth Hostel", "type": "hotel" }, { "country": "United Kingdom", "name": "The Balmoral Guesthouse", "type": "hotel" }, { "country": "France", "name": "The Robins", "type": "hotel" }, { "country": "France", "name": "Le Clos Fleuri", "type": "hotel" }, { "country": "United Kingdom", "name": "Glasgow Grand Central", "type": "hotel" } ], "status": "success", ... } |
As shown in the examples above, you can qualify a Data Reader and Query Select role with a Scope and Collection confinement.
Have fun and secure your Collections with our new role-based access control functionality!
More Resources on the Couchbase 7.0 Release
- What’s New in Couchbase Server 7.0
- Couchbase 7.0 Release Notes
- How Scopes & Collections Simplify Multi-Tenant App Deployments on Couchbase
- Enterprise Edition customer support is available via your regular support channels. Community support is available through the Couchbase Forums
Want to try out RBAC security in Couchbase for yourself?
Give Couchbase a Spin Today
- What’s New in Couchbase Server 7.0
- Couchbase 7.0 Release Notes
- How Scopes & Collections Simplify Multi-Tenant App Deployments on Couchbase
- Enterprise Edition customer support is available via your regular support channels. Community support is available through the Couchbase Forums
Give Couchbase a Spin Today
Hi~ Thank you for your post.
I think there’s a typo here, so I’m leaving a comment.
//
Let’s create a user, John Doe who has a data reader and query select role on the hotel collection, which is located in the _default collection.
//
I think _default Collection >>> _default Scope
It’s right?
Once again, thank you for your helpful post.
Hello ckdgur. Happy to hear that the blog post is useful. Good spotting, that is indeed a typo. I’ve corrected it now. Also thanks a lot for giving the Couchbase 7 Beta a spin !
Hi
Can you confirm that “Application Access” can have a Scope and Collection defined?
From the documentation Application Access translates to full_bucket_access and is deprecated and when I tried it only bucket name was supported.
Cannot assign roles to user because the following roles are unknown, malformed or role parameters are undefined: [bucket_full_access[travel-sample:inventory]]”