# MongoDB Security<br />ch2 Authorization and Encryption
###### tags: `MongoDB University M310`
## Authorization Model
MongoDB authorization model is **role based control access control.**
The model is for any given **user** we're going to go ahead and assign a **role** to that user. And that role is going to be assigned over a given namespace.
The namespace is just a **database** in mongodb.
For example we create a user named **kirby** and a role called **readWrite** role for the **products database**.
```javascript=
db.createUser({
user: 'kirby',
pwd: 'secret',
roles: [
{
role: 'readWrite',
db: 'products'
}
]
})
```
:::info
**Roles** are groups of **privileges**, **actions** over **resources**, that are granted to **users** over a given **namespace(database)**.
:::
| Actions | Resources |
| ---------- | ---------- |
| insert | collection |
| create | database |
| createUser | cluster |
| addShard | |
Role based access control gives a high level of responsibility isolation for operational tasks. This means we can grant what privileges the user need against their role in work.
## Built-in Roles
There are a lot of built-in roles in mongodb.
[Official Document Built-In Roles](https://docs.mongodb.com/manual/reference/built-in-roles/)
## User defined roles
Though the built-in roles should cover majority of the difference type of people who need to use database, we can build our own roles.
## Action, Resources and Privileges
There are 2 parts of privileges, **action** and **resources**.
**Action** describes the ***operations*** that given user may perform on a resources in the database.
e.g. find, insert, remove, update, createUser...
**Resources** are subject of actions, there are 4 resources in mongodb:
1. collection, databases
```javascript=
// a specific database
{ db: "products", collection: ""}
// a specific collection
{ db: "", collection: "inventory"}
// a specific collection on a specific databse
{ db: "products", collection: "inventory" }
// All none system collection on all databses
{ db: "", collection: "" }
```
2. cluster
```javascript=
{ cluster: true }
```
3. anyResource
```javascript=
// This resource is for internal usage only!
{ anyResource: true }
```
Privileges are defined by using a privileged document.
```javascript=
{
resource: {
db: <database>,
collection: <collection>
},
actions: [
<actions>
]
}
```
Run the command can get the privileged document of the role.
Read role for example.
```javascript=
db.getRole('read')
// to get privilege details
db.getRole('read', { showPrivileges: true })
```
## Create user with built in role
Let's get started with a real world example. There are 4 members in our team and we need to grant the specific privilege to each one of them.
* Alice - `security officer`
Needs to:
* Create/drop user in any database
* Grant/revoke roles
* Create/update/delete roles
Does not need to:
* See any collection data
* Create/drop any database or collection
* Perform backup/restore operations
```javascript=
db.createUser(
{
user: 'alice',
pwd: 'sharppencil',
roles: [
{
role: 'userAdminAnyDatabase', db: 'admin'
}
]
}
)
```
* Ben - `sysAdmin`
Needs to:
* Do maintainance operations
* Add/Remove member of a replica set
* Add/Remove shards in sharded cluster
Does not need to:
* See any collection data
* Create/Drop any database or collection
* List any database or collection
```javascript=
db.createUser(
{
user: 'ben',
pwd: 'secret',
roles: [
{
role: 'clusterManager', db: 'admin'
}
]
}
)
```
* Carol - `DBA`
Needs to:
* Check database status
* Kill long running operations
* Create collections, indexes, etc
Does not need to:
* Write to any collection
* Manage a cluster
* Create new users
```javascript=
// Wrong example
db.createUser(
{
user: 'carol',
pwd: 'secret',
roles: [
{ roles: 'dbAdmin', db: 'admin'}
]
}
)
// We found that Carol needs more privilege,
// so we should change Carol's role from dbAdmin to dbAdminAnyDatabase
db.updateUser('carol', roles: [
{
role: 'dbAdminAnyDabase',
db: 'admin'
}
])
```
* Dan - `intern`
Needs to:
* Query the nasa database
Does not need to:
* Do anythin else
```javascript=
db.createUser(
{
user: 'dan',
pwd: 'secret',
roles: [
{role: 'read', db: 'nasa'}
]
}
)
```
:::info
**Hint**
Since dan is created in nasa database,
The account need to authenticate against nasa database
:::
Sometimes we need to add --authenticationDatabase parameter to our command if the account is not created on the db we are performing to like:
```javascript=
// We have a user created in admin, and was granted the readWrite role on nasa
mongoimport -u botloader -p secret -d nasa -c meteorites nasa_meteorites.json --authenticationDatabase admin
```
## Create user defined role
Roles are comprised of three components: a name, a list of inherited roles and a list of privileged documents.
```javascript=
db.createRole({
role: <role name>,
privileges: [{
resource: {
db: <database>,
collection: <collection>
},
actions: [
<action>
]
}],
roles: [{
role: <role>,
db: <database>
}]
})
```
In this case, we want to change Dan's role to a user defined role.
The role allows to update the collection meteorites on the nasa database and we still want the role to be able to inherit the ability to read the nasa dababase.
```javascript=
db.createRole( {
role: 'customRole',
privileges: [{
resource: { db: 'nasa', collection: 'meteorites' }, actions: ["update"]
}],
roles: [
{ role: 'read', db: 'nasa' }
]
} )
db.updateUser( 'dan', { roles: [{ role: 'customRole', db: 'admin' }]})
```
## Grant new privileges to role
In mongodb, roles are updatable except the built-in roles. There are 3 ways to update a given role.
1. Update roles by pushing actions onto action array of the privilege
```javascript=
const role = db.getRole('customRole', {showPrivileges: ture})
const updatePrivileges = role.privileges
updatePrivileges[0].actions.push('insert')
db.updateRole('customRole', {privileges: updatePrivileges})
```
2. Use grantPrivilegesToRole function
```javascript=
db.grantPrivilegesToRole('customRole', [{resource: { db: 'nasa', collection: 'meteorites' }}], actions: ['insert'])
```
3. use grantRolesToRole
```javascript=
db.grantRolesToRole('customRole', ['readWriteAnyDatabase'])
```
## Revoke privilege from role
```javascript=
db.revokePrivilegesFromRole('customRole', [
{
resource: {
db: '',
collection: 'internlog'
},
action: ['update']
}
])
```
## Encryption Intro
* Transport Encryption
* Encryption at Rest
## Transport encryption (TLS)
MongoDB use TLS/SSL to encrypt information between client and server.
TLS is by the public/private key encryption algrithm through the utilization of SSL certificates.
This allow clients and server verify each other and provides the ability to encript messages.
MongoDB uses openssl libraries for TLS encryption. From MongoDB 4.0 onwards, the server uses native TLS/SSL library implementations.
## TLS connection modes
4 mode for SSL connection in MongoDB
* disabled
* allowSSL
* preferSSL
* requireSSL
```javascript=
mongod --sslMode requireSSL --sslPEMKeyFile server.pem
```
## Enable TLS between client and mongod
```javascript=
mongod --sslMode requireSSL --sslPEMKeyFile server.pem
mongod --sslMode requireSSL --sslPEMKeyFile server.pem --sslCAFile ca.pem
```
The difference between two command is the second command would verify the identify of client and make sure they are connecting with the certificate signed by the same ca.
If we don't provide the SSL CA file, that means that would be susceptible to a man-in-middle attack.
## Enable TLS within replica set
## Encrypted Storage Engine
### Application Level Encryption
Application level encryption is not an actual feature of MongoDB, we encryp and decrypt the information **within application layer**.
**MongoDB always keeps the encrypted ciphertext**.
### Storage Level Encryption
Only available on
* MongoDB enterprise 3.2
* WiredTiger storage engine
Basically our data lives in RAM as unencrypted text.
When mongodb decide to write informations to disk, it will ***encrypt the information in RAM and then store the encrypted information to disk.***
4 steps for storage engine encryption:
1. Generate a **master key**
2. Generate a key for each database and encrypt the database with the key
3. After each databse is encrypted, each key is encrypted with the master key
4. Each databse key is stored **within** MongoDB, the master key is stored **outside** the MongoDB
2 key management options for master key
* Key Management Interoperability Protocol(KMIP)
* Local Key Management(key file)
```javascript=
// Domo for local key management(not recommended)
// First, generate a key file
openssl rand -base64 32 > mongodb-keyfile
chmod 600 mongodb-keyfile
// Second, starting a mongod instance with storage engine
mongod --enableEncryption --encryptionKeyFile mongodb-keyfile
```
## KMIP Integration
MongoDB enterprise supports secure transfer of key files with a compatible key management appliance.
**KMIP Key Management**
* HIPAA
* PCI-DSS
* FERPA
Start mongod to connect kimp server
```javascript=
mongod --enableEncryption --kmipServerName <hostname> --kmipServerCAFile ca.pem --kmipClientCertificateFile client.pem
```