Couchbase Server 7.0 Beta is now available with some additional enhancements to strengthen the security of the platform. Couchbase Server has allowed fine grain 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. A new important announcement is the introduction of collections support to RBAC Security.
Couchbase RBAC security roles were previously divided into 2 categories.
- Administration and Global: Associated with cluster-wide privileges. Some of these roles are for administrators; who might manage cluster-configurations; or read statistics; or enforce security. Others are for users and user-defined applications that require access to specific, cluster-wide resources.
- Per Bucket: Associated with one or more buckets. These roles support the reading and writing of bucket-settings; the management of services, indexes, and replication procedures; and access to data.
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 CLI 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 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 documents in a Couchbase Bucket to be organized, first into scopes, where a ‘Scope’ is similar to a ‘Schema’ in a relational database; and 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 in 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 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 available previously.
For seamless upgrade, and for backwards compatibility, every bucket has a ‘_default’ scope and the ‘_default’ scope has a ‘_default’ collection. The _default collection provides backward compatibility as a direct reference to the bucket will automatically map to the _default collection. Also, on upgrade all existing data will automatically go to the _default collection.
While the _default collection is provided as a backward compatibility mechanism, it is recommended that 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.
Going back to the previous example, 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, we can now limit the confines of Acme’s access to only the ‘scope’ of our 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.
RBAC Security Explained
How do scopes and collections work with RBAC security roles in the database? A user who has access to a bucket will inherit access to the children scopes and collections of that bucket. Likewise, a user who has access to a scope will inherit access to the children collections but not the parent bucket.
Here’s some examples of how the scope of the roles work 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 with-in only the bucket foo |
data_reader[foo:bar] | Can read data in every collection with-in 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 very similar to the earlier example, but instead of setting the RBAC to a bucket, we just need to adjust it to allow only a single scope and collection
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 |
What are the list of user access roles that can have a scope and collection defined ?
- Application Access
- Data Reader
- Data Writer
- Data DCP Reader
- Data Monitoring
- (FTS) Search Reader
- Query Select
- Query Update
- Query Insert
- Query Delete
- Query Manage Index
- Analytics Select
We’ve also added the ability to provide a Manage Collections in Scope role to allow a user to add and remove collections in a specific scope on a bucket.
Practical Hands-on RBAC Security Example with Couchbase Server 7.0 Beta
Now for some more hands-on examples you can try out in the Couchbase Server 7.0 Beta. Again, 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 Data, Query and Index services for this example.
Load the travel-sample bucket into your cluster.
1 2 |
curl -X POST -u Administrator:password https://localhost:8091/sampleBuckets/install -d '["travel-sample"]' [] |
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.
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 is matching to the new collections we have just created. The data is copied into the collection using N1QL from the command line. 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, 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 / roles
1 |
/opt/couchbase/bin/couchbase-cli user-manage -c localhost:8091 -u Administrator -p password --list |
1 |
[] |
We currently only have the built-in Administrator and no additional users. So the output from the command is empty, as expected.
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 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.
Now we can 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", ... |
Now this time let’s select 5 hotels as John 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 39 |
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, 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 RBAC security functionality !
Availability and Duration of Beta
Documentation
Additional Blogs
Scopes and Collections for Modern Multi-Tenant Applications: Couchbase 7.0
Couchbase Transactions with N1QL
Get the Beta of Community Edition and Enterprise Edition
Couchbase 7 Beta is available for both Enterprise and Community Editions. Everyone can download the software from https://www.couchbase.com/downloads
Customer support is available via your regular support channels, while Community support is available through the Couchbase forums at https://forums.couchbase.com/
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 !