How does configuration work?
The configuration is stored in a JSON file. The default path is /etc/security/rootasrole.json
. It is possible to change the path where the configuration is stored by changing the path
setting in the configuration file manually.
Note: The configuration file must be immutable after edition.
"storage": {
"method": "json",
"settings": {
"path": "/etc/security/rootasrole.json",
"immutable": true
}
}
Next, the configuration is divided into roles, tasks, commands, credentials, and options. Each role can have multiple tasks, each task can have multiple commands and credentials. The options are global and can be set for the whole configuration or for a specific role or task.
How configuration work with examples
A complete Config example
The following example shows a RootAsRole config without plugins when almost every field is modified with comments.
{
"version": "3.0.0-alpha.4", // Version of the configuration file
"storage": { // Storage settings, where the Roles and Execution options are stored
"method": "json", // Storage method
"settings": { // Storage settings
"immutable": false, // Program return error if the file is not immutable, default is true
"path": "target/rootasrole.json" // Path to the storage file
}
},
"options": {
"path": { // Path options
"default": "delete", // Default policy for path, delete-all, keep-safe, keep-unsafe, inherit
"add": [ // Paths to add to the whitelist
"path1",
"path2"
],
"sub": [ // Paths to remove from the whitelist
"path3",
"path4"
]
},
"env": { // Environment options
"default": "delete", // Default policy for environment, delete-all, keep-all, inherit
"keep": [ // Environment variables to keep
"env1",
"env2"
],
"check": [ // Environment variables to check for unsafe characters
"env3",
"env4"
],
"delete": [ // Environment variables to delete
"env5",
"env6"
]
},
"root": "privileged", // Default policy for root, privileged, user, inherit
"bounding": "ignore", // Default policy for bounding, strict, ignore, inherit
"wildcard-denied": "*", // Characters denied in any binary path
"timeout": {
"type": "ppid", // Type of timeout, tty, ppid, uid
"duration": "15:30:30", // Duration of the timeout
"max_usage": 1 // Maximum usage before timeout expires
}
},
"roles": [ // Role list
{
"name": "complete", // Role name
"actors": [ // Actors granted
{
"id": 0, // ID of the actor, could be a name
"type": "user" // Type of actor, user, group
},
{
"groups": 0, // ID of the group, could be a name
"type": "group"
},
{
"type": "group",
"groups": [ // List of groups, this is an AND condition between groups
"groupA",
"groupB"
]
}
],
"tasks": [ // List of role's tasks
{
"name": "t_complete", // Task name, must be unique in the role
"purpose": "complete", // Task purpose, just a description
"cred": {
"setuid": "user1", // User to setuid before executing the command
"setgid": [ // Groups to setgid before executing the command, The first one is the primary group
"group1",
"group2"
],
"capabilities": { // Capabilities to grants
"default": "all", // Default policy for capabilities, all, none
"add": [ // Capabilities to add
"CAP_LINUX_IMMUTABLE",
"CAP_NET_BIND_SERVICE"
],
"sub": [ // Capabilities to remove, overrides add
"CAP_SYS_ADMIN",
"CAP_SYS_BOOT"
]
}
},
"commands": {
"default": "all", // Default policy for commands, allow-all, deny-all
"add": [ // Commands to add to the whitelist
"ls",
"echo"
],
"sub": [ // Commands to add to the blacklist
"cat",
"grep"
]
},
"options": { // Task-level options
"path": {
"default": "delete", // When default is not inherit, all upper level options are ignored
"add": [
"path1",
"path2"
],
"sub": [
"path3",
"path4"
]
},
"env": {
"default": "delete",
"keep": [
"env1",
"env2"
],
"check": [
"env3",
"env4"
],
"delete": [
"env5",
"env6"
]
},
"root": "privileged",
"bounding": "ignore",
"wildcard-denied": "*",
"timeout": {
"type": "ppid",
"duration": "15:30:30",
"max_usage": 1
}
}
}
],
"options": { // Role-level options
"path": {
"default": "delete",
"add": [
"path1",
"path2"
],
"sub": [
"path3",
"path4"
]
},
"env": {
"default": "delete",
"keep": [
"env1",
"env2"
],
"check": [
"env3",
"env4"
],
"delete": [
"env5",
"env6"
]
},
"root": "privileged",
"bounding": "ignore",
"wildcard-denied": "*",
"timeout": {
"type": "ppid",
"duration": "15:30:30",
"max_usage": 1
}
}
}
]
}
Config example Role hierarchy plugin
The following example shows a RootAsRole config using role hierarchy plugin.
{
"version": "3.0.0-alpha.4",
"roles": [
{
"parents": ["user"],
"name": "admin",
"actors": [
{
"id": 0,
"type": "user"
}
],
"tasks": [
],
},
{
"name": "user",
"actors": [
{
"id": 1,
"type": "user"
}
],
"tasks": [
{
"name": "t_user",
"purpose": "user",
"commands": {
"default": "all",
"sub": [
"cat",
"grep"
]
}
}
]
}
]
}
In this example, the admin
role inherits from the user
role. The user
role has a task t_user
that denies cat
and grep
commands. The admin
role will inherit the t_user
task and deny cat
and grep
commands.
Config example Static separation of duties plugin
The following example shows a RootAsRole config using separation of duties plugin.
{
"version": "3.0.0-alpha.4",
"roles": [
{
"ssd": ["user"],
"name": "admin",
"actors": [
{
"id": 0,
"type": "user"
}
],
"tasks": [
],
},
{
"name": "user",
"actors": [
{
"id": 0,
"type": "user"
}
],
"tasks": [
{
"name": "t_user",
"purpose": "user",
"commands": {
"default": "all",
"sub": [
"cat",
"grep"
]
}
}
]
}
]
}
In this example, the admin
role is separated from the user
role. The user 0 cannot be in the user
role and the admin
role at the same time. But currently this user is still on these two roles. In resulting, the user 0 will not be able to execute any admin
or user
role's tasks.
Config example with hashchecker plugin
Hashchecker plugin verifies the integrity of the binary before executing it. The following example shows a RootAsRole config using hashchecker plugin.
{
"version": "3.0.0-alpha.4",
"roles": [
{
"name": "admin",
"actors": [
{
"id": 0,
"type": "user"
}
],
"tasks": [
{
"name": "t_admin",
"purpose": "admin",
"commands": {
"default": "none",
"add": [
{
"command": "/usr/bin/cat superfile",
"hash_type": "sha256",
"hash": "3b77deacba25588129debfb3b9603d7e7187c29d7f6c14bdb667426b7be91761"
}
]
}
}
]
}
]
}
This example shows a t_admin
task that allows the cat superfile
command only if the hash of the binary is 3b77deacba25588129debfb3b9603d7e7187c29d7f6c14bdb667426b7be91761
. If the hash of the binary is different, the command isn't even considered in configuration setup. Supported hashes : SHA224, SHA256, SHA384, SHA512.
How options work with examples
Path options example 1
Here is an example global configuration:
{
"options": {
"path": {
"default": "delete-all",
"add": [
"/usr/bin"
]
}
}
}
This configuration will delete all paths and add /usr/bin
to the whitelist.
{
"options": {
"path": {
"default": "delete-all",
"add": [
"/usr/bin"
]
}
},
"roles": {
"admin": {
"options": {
"path": {
"default": "inherit",
"add": [
"/usr/sbin"
]
}
}
}
}
}
This configuration will delete all paths and add /usr/bin
to the whitelist for all roles. The admin
role will inherit the global configuration and add /usr/sbin
to the whitelist. So the final configuration for the admin
role will be /usr/bin:/usr/sbin
.
Path options example 2
Here is an example global configuration:
{
"options": {
"path": {
"default": "keep-safe",
"add": [
"/usr/bin"
]
}
}
}
This configuration will keep all paths that are absolute and add /usr/bin
to the path.
{
"options": {
"path": {
"default": "keep-safe",
"add": [
"/usr/bin"
]
}
},
"roles": {
"admin": {
"options": {
"path": {
"default": "inherit",
"add": [
"/usr/sbin"
]
}
}
}
}
}
This configuration will keep all paths that are absolute and add /usr/bin
to the whitelist for all roles. The admin
role will inherit the global configuration and add /usr/sbin
to the whitelist. So the final configuration for the admin
role will be /usr/bin:/usr/sbin:$PATH
, where $PATH
is the current executor path value.
Path options example 3
Here is an example global configuration:
{
"options": {
"path": {
"default": "keep-unsafe",
"sub": [
"/usr/bin"
]
}
}
}
This configuration will keep all paths, even them that are relative, and remove /usr/bin
from the path.
{
"options": {
"path": {
"default": "keep-unsafe",
"add": [
"/usr/bin"
]
}
},
"roles": {
"admin": {
"options": {
"path": {
"default": "inherit",
"add": [
"/usr/sbin"
]
}
}
}
}
}
This configuration will keep all paths, even them that are relative, and add /usr/bin
to the whitelist for all roles. The admin
role will inherit the global configuration and add /usr/sbin
to the whitelist. So the final configuration for the admin
role will be /usr/bin:/usr/sbin:$PATH
, where $PATH
is the current executor path value.
Note: path are always prepended to the current path value.
Path options example 4
Here is an example global configuration:
{
"options": {
"path": {
"default": "inherit",
"add": [
"/usr/bin"
]
}
}
}
If the policy is inherit in global configuration, the policy will be delete-all
.
{
"options": {
"path": {
"default": "delete-all",
"add": [
"/usr/bin"
]
}
},
"roles": {
"admin": {
"options": {
"path": {
"default": "keep-safe",
"sub": [
"/usr/sbin"
]
}
},
"tasks": {
"task1": {
"options": {
"path": {
"default": "inherit",
"add": [
"/usr/sbin"
]
}
}
}
}
}
}
}
This complex configuration will delete-all paths in the global configuration for all roles except for admin
role. The admin
role will keep all paths that are absolute and remove /usr/sbin
from the path. The task1
task will inherit the admin
role configuration and tries to add /usr/sbin
to the path but it will be ignored because the task inherits the admin
role configuration, and it removes /usr/sbin
from the path. So the final path is the current executor path value less /usr/sbin
.
In conclusion, two logical properties can be deducted :
- The path removed from the path variable cannot be added, even by inheritance.
- When a more precise configuration defines a policy (delete-all,keep-safe,keep-unsafe), it will override less precise configuration.
- Global is less precise than Role, Role is less precise than Task
Environment options example 1
Here is an example global configuration:
{
"options": {
"env": {
"default": "delete",
"keep": [
"VAR1"
]
}
}
}
Environment variables are managed in the same way as paths. The policy can be delete
, keep
, or inherit
. The delete
policy will remove all environment variables except the ones in the keep
list. The keep
list is a list of environment variables that will be kept in the environment.
{
"options": {
"env": {
"default": "delete",
"keep": [
"VAR1"
]
}
},
"roles": {
"admin": {
"options": {
"env": {
"default": "inherit",
"keep": [
"VAR2"
]
}
}
}
}
}
This configuration will delete all environment variables except VAR1
for all roles. The admin
role will inherit the global configuration and keep VAR2
in the environment. So only VAR1
and VAR2
values will be kept in the environment for the admin
role.
Environment options example 2
Here is an example global configuration:
{
"options": {
"env": {
"default": "keep",
"delete": [
"VAR1"
]
}
}
}
The delete
list is a list of environment variables that will be removed from the environment.
{
"options": {
"env": {
"policy": "keep",
"delete": [
"VAR1"
]
}
},
"roles": {
"admin": {
"options": {
"env": {
"policy": "inherit",
"delete": [
"VAR2"
]
}
}
}
}
}
This configuration will keep all environment variables except VAR1
for all roles. The admin
role will inherit the global configuration and remove VAR2
from the environment. So only VAR1
and VAR2
values are removed from the environment for the admin
role.
Environment options example 3
Here is an example global configuration:
{
"options": {
"env": {
"default": "keep",
"check": [
"VAR1"
]
}
}
}
The check
list is a list of environment variables that will be checked for unsafe characters. If an environment variable contains unsafe characters, it will be removed from the environment.