Skip to content

Commit 74778e9

Browse files
authored
Merge pull request #72 from LeChatP/dev
v3.1.0 Performance, configurability, features update
2 parents 6bda629 + 8b7c702 commit 74778e9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+12014
-6378
lines changed

.cargo/config.toml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,25 @@
11
[alias]
22
xtask = "run --package xtask --release --bin xtask --"
3+
4+
[env]
5+
RAR_CFG_TYPE = "json"
6+
RAR_CFG_PATH = "/etc/security/rootasrole.json"
7+
RAR_CFG_DATA_PATH = "/etc/security/rootasrole.json"
8+
RAR_BIN_PATH = "/usr/bin"
9+
RAR_CFG_IMMUTABLE = "true"
10+
RAR_TIMEOUT_TYPE = "ppid"
11+
RAR_TIMEOUT_DURATION = "00:05:00"
12+
RAR_TIMEOUT_MAX_USAGE = ""
13+
RAR_PATH_DEFAULT = "delete"
14+
RAR_PATH_ADD_LIST = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"
15+
RAR_PATH_REMOVE_LIST = ""
16+
RAR_ENV_DEFAULT = "delete"
17+
RAR_ENV_KEEP_LIST = "HOME,USER,LOGNAME,COLORS,DISPLAY,HOSTNAME,KRB5CCNAME,LS_COLORS,PS1,PS2,XAUTHORY,XAUTHORIZATION,XDG_CURRENT_DESKTOP"
18+
RAR_ENV_CHECK_LIST = "COLORTERM,LANG,LANGUAGE,LC_.*,LINGUAS,TERM,TZ"
19+
RAR_ENV_DELETE_LIST = "PS4,SHELLOPTS,PERLLIB,PERL5LIB,PERL5OPT,PYTHONINSPECT"
20+
RAR_ENV_SET_LIST = ""
21+
RAR_ENV_OVERRIDE_BEHAVIOR = "false"
22+
RAR_AUTHENTICATION = "perform"
23+
RAR_USER_CONSIDERED = "user"
24+
RAR_BOUNDING = "strict"
25+
RAR_WILDCARD_DENIED = "&|"

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
runs-on: ubuntu-latest
1515
container:
1616
image: xd009642/tarpaulin:develop-nightly
17-
options: --security-opt seccomp=unconfined
17+
options: --security-opt seccomp=unconfined --privileged
1818
steps:
1919
- name: Checkout code
2020
uses: actions/checkout@v2

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,7 @@ Cargo.lock
7474

7575
# Vagrant
7676
*.env
77-
*.vagrant/
77+
*.vagrant/
78+
79+
# Cargo config
80+
.cargo/config.toml

.vscode/launch.json

Lines changed: 6 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -5,59 +5,14 @@
55
"version": "0.2.0",
66
"configurations": [
77
{
8-
"name": "(gdb) Test",
9-
"type": "cppdbg",
10-
"request": "launch",
11-
"preLaunchTask": "make build_unit_test",
12-
"program": "${workspaceFolder}/bin/unit_test",
13-
"args": [],
14-
"stopAtEntry": false,
15-
"cwd": "${fileDirname}",
16-
"environment": [],
17-
"externalConsole": false,
18-
"MIMode": "gdb",
19-
"setupCommands": [
20-
{
21-
"description": "Enable pretty-printing for gdb",
22-
"text": "-enable-pretty-printing",
23-
"ignoreFailures": true
24-
},
25-
{
26-
"description": "Set Disassembly Flavor to Intel",
27-
"text": "-gdb-set disassembly-flavor intel",
28-
"ignoreFailures": true
29-
},
30-
{ "description": "The new process is debugged after a fork. The parent process runs unimpeded.",
31-
"text": "-gdb-set follow-fork-mode child",
32-
"ignoreFailures": true
33-
}
34-
]
35-
},
36-
{
37-
"name": "(gdb) Launch",
38-
"type": "cppdbg",
8+
"type": "lldb",
399
"request": "launch",
40-
"preLaunchTask": "setcap",
41-
"program": "/usr/bin/sr",
10+
"name": "Launch",
11+
"program": "${workspaceFolder}/target/debug/sr",
4212
"args": ["ls"],
43-
"stopAtEntry": false,
44-
"cwd": "${fileDirname}",
45-
"environment": [],
46-
"externalConsole": false,
47-
"MIMode": "gdb",
48-
"miDebuggerPath": "${workspaceFolder}/.vscode/gdb_root.sh",
49-
"setupCommands": [
50-
{
51-
"description": "Enable pretty-printing for gdb",
52-
"text": "-enable-pretty-printing",
53-
"ignoreFailures": true
54-
},
55-
{
56-
"description": "Set Disassembly Flavor to Intel",
57-
"text": "-gdb-set disassembly-flavor intel",
58-
"ignoreFailures": true
59-
}
60-
],
13+
"cwd": "${workspaceFolder}"
6114
}
15+
16+
6217
]
6318
}

.vscode/tasks.json

Lines changed: 2 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -6,58 +6,14 @@
66
}
77
},
88
"tasks": [
9-
{
10-
"type": "cppbuild",
11-
"label": "C/C++: gcc build active file",
12-
"command": "/usr/bin/gcc",
13-
"args": [
14-
"-fdiagnostics-color=always",
15-
"-g",
16-
"${file}",
17-
"-o",
18-
"${fileDirname}/${fileBasenameNoExtension}"
19-
],
20-
"options": {
21-
"cwd": "${fileDirname}"
22-
},
23-
"problemMatcher": [
24-
"$gcc"
25-
],
26-
"group": {
27-
"kind": "build",
28-
"isDefault": true
29-
},
30-
"detail": "Task generated by Debugger."
31-
},
32-
{
33-
"type": "shell",
34-
"label": "make",
35-
"command": "sudo",
36-
"args": [
37-
"-E",
38-
"/usr/bin/make",
39-
"install"
40-
],
41-
"options": {
42-
"cwd": "${cwd}"
43-
},
44-
"problemMatcher": [
45-
"$gcc"
46-
],
47-
"group": {
48-
"kind": "build",
49-
"isDefault": true
50-
},
51-
"detail": "Task generated by Debugger."
52-
},
9+
5310
{
5411
"type": "shell",
5512
"label": "setcap",
56-
"dependsOn": "make",
5713
"command": "sudo",
5814
"args": [
5915
"/usr/bin/setcap",
60-
"=eip",
16+
"=p",
6117
"${cwd}/bin/sr"
6218
],
6319
"options": {
@@ -66,58 +22,6 @@
6622
"group": {
6723
"kind": "none"
6824
}
69-
},
70-
{
71-
"type": "shell",
72-
"label": "make build_unit_test",
73-
"command": "sudo",
74-
"args": [
75-
"/usr/bin/make",
76-
"build_unit_test"
77-
],
78-
"options": {
79-
"cwd": "${workspaceFolder}",
80-
"env": {
81-
"GDB_DEBUG": "1",
82-
"DEBUG": "1"
83-
}
84-
},
85-
"problemMatcher": [
86-
"$gcc"
87-
],
88-
"group": {
89-
"kind": "build",
90-
"isDefault": true
91-
},
92-
"detail": "Task generated by Debugger."
93-
},
94-
{
95-
"type": "shell",
96-
"label": "debug unit_test",
97-
"dependsOn": "make build_unit_test",
98-
"command": "${cwd}/bin/unit_test",
99-
"args": [
100-
"--debug=gdb"
101-
],
102-
"options": {
103-
"cwd": "${cwd}"
104-
},
105-
"isBackground": true,
106-
"problemMatcher": {
107-
"pattern": [
108-
{
109-
"regexp": ".",
110-
"file": 1,
111-
"location": 2,
112-
"message": 3
113-
}
114-
],
115-
"background": {
116-
"activeOnStart": true,
117-
"beginsPattern": ".",
118-
"endsPattern": "Listening on port"
119-
}
120-
}
12125
}
12226

12327
],

Cargo.toml

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ members = ["xtask", "rar-common"]
44
[package]
55
name = "rootasrole"
66
# The project version is managed on json file in resources/rootasrole.json
7-
version = "3.0.6"
7+
version = "3.1.0"
88
rust-version = "1.76.0"
99
authors = ["Eddie Billoir <[email protected]>"]
1010
edition = "2021"
@@ -25,9 +25,17 @@ maintainance ={ status = "actively-maintained", badge = "https://img.shields.io/
2525
[profile.release]
2626
strip = "symbols"
2727
lto = true
28-
opt-level = "s"
28+
opt-level = 3
2929
codegen-units = 1
3030

31+
[profile.profiling]
32+
strip = "none"
33+
lto = false
34+
opt-level = 1
35+
inherits = "release"
36+
debug = true
37+
38+
3139
#[features]
3240
#cursive_lib = [ "cursive" ]
3341
#srlibs = [ "pam-client", "bitflags" ]
@@ -45,6 +53,7 @@ path = "src/chsr/main.rs"
4553
[features]
4654
default = ["finder"]
4755
finder = ["dep:pcre2", "rar-common/pcre2", "rar-common/finder"]
56+
pcre2 = ["dep:pcre2", "rar-common/pcre2"]
4857

4958
[lints.rust]
5059
unexpected_cfgs = { level = "allow", check-cfg = ['cfg(tarpaulin_include)'] }
@@ -65,7 +74,7 @@ capctl = "0.2"
6574
pcre2 = { version = "0.2", optional = true }
6675
serde = { version = "1.0", features=["rc", "derive"] }
6776
serde_json = "1.0"
68-
ciborium = "0.2"
77+
cbor4ii = { version = "1.0.0", features = ["serde", "serde1", "use_std"] }
6978
glob = "0.3"
7079
pam-client2 = "0.5"
7180
bitflags = { version = "2.6" }
@@ -80,6 +89,9 @@ pest = "2.7"
8089
pest_derive = "2.7"
8190
const_format = "0.2"
8291
hex = "0.4"
92+
bon = "3.5.1"
93+
serde_json_borrow = "0.7.1"
94+
konst = "0.3.16"
8395

8496
[dev-dependencies]
8597
log = "0.4"

README.md

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
<!-- The project version is managed on json file in resources/rootasrole.json -->
1717
<!-- markdownlint-restore -->
1818

19-
# RootAsRole (V3.0.6) : A memory-safe and security-oriented alternative to sudo/su commands
19+
# RootAsRole (V3.1.0) : A memory-safe and security-oriented alternative to sudo/su commands
2020

2121
**RootAsRole** is a project to allow Linux/Unix administrators to delegate their administrative tasks access rights to users. Its main features are :
2222

@@ -29,13 +29,15 @@
2929
* File relocation ability.
3030
* Multi-layered and inheritable execution environment configuration.
3131
* Interoperable and evolvable by using [JSON](https://www.json.org/) as the main configuration file format.
32+
* Interchangeable file format with [JSON5](https://www.json.org/) and [CBOR](https://cbor.io/) for performance and human readability.
33+
* Setuid managed by set of users or (set-of-)groups (all-and-deny, or nothing-then-grant), Thanks to @[hocineait7](https://github.com/hocineait7).
3234
* Command matching based on commonly-used open-source libraries:
33-
* [glob](https://docs.rs/glob/latest/glob/) for binary path
35+
* [glob](https://docs.rs/glob/latest/glob/) for binary pathv
3436
* [PCRE2](https://www.pcre.org/) for command arguments
3537

3638
If you need help to configure a RootAsRole policy, you can use our **[capable tool](https://github.com/LeChatP/RootAsRole-capable)**. This tool identifies the rights required by specific commands, making it easier to define a precise policy.
3739

38-
For administrators who already use **Ansible playbooks** for their tasks and wish to implement **RootAsRole**, our tool [gensr](https://github.com/LeChatP/RootAsRole-utils) can generate an initial draft of a **RootAsRole policy**. The `gensr` tool works by running your Ansible playbook alongside the [capable tool](https://github.com/LeChatP/RootAsRole-capable), creating a draft policy based on the observed required rights. This process helps administrators to harden their Ansible tasks. It helps to verify eventual third-party supply-chain attacks.
40+
For administrators who already use **Ansible playbooks** for their tasks and wish to implement RootAsRole, our tool [gensr](https://github.com/LeChatP/RootAsRole-utils) can generate an initial draft of a RootAsRole policy. The `gensr` tool works by running your Ansible playbook alongside the [capable tool](https://github.com/LeChatP/RootAsRole-capable), creating a draft policy based on the observed required rights. This process helps administrators to harden their Ansible tasks. It helps to verify eventual **third-party supply-chain attacks**.
3941

4042
**Note:** The `gensr` tool is still in development and may not work with all playbooks. If you wish to contribute to this project, feel free to make issues and pull requests.
4143

@@ -105,6 +107,9 @@ Execute privileged commands with a role-based access control system
105107
<u><b>Options</b></u>:
106108
<b>-r, --role</b> &lt;ROLE&gt; Role to select
107109
<b>-t, --task</b> &lt;TASK&gt; Task to select (--role required)
110+
<b>-u, --user</b> &lt;USER&gt; User to execute the command as
111+
<b>-g, --group</b> &lt;GROUP<,GROUP...>&gt; Group(s) to execute the command as
112+
<b>-E, --preserve-env</b> Keep environment variables from the current process
108113
<b>-p, --prompt</b> &lt;PROMPT&gt; Prompt to display
109114
<b>-i, --info</b> Display rights of executor
110115
<b>-h, --help</b> Print help (see more with '--help')
@@ -116,7 +121,22 @@ If you're accustomed to utilizing the sudo tool and find it difficult to break t
116121
alias sudo="sr"
117122
```
118123
119-
However you won't find out exact same options as sudo, you can use the `--role` option to specify the role you want to use instead.
124+
## Performance outperforms `sudo` (and `sudo-rs`) command
125+
126+
[![Performance comparison](https://github.com/LeChatP/RaR-perf/raw/main/result_25-07-04_15.44.png)](https://github.com/LeChatP/RaR-perf)
127+
128+
Since RootAsRole 3.1.0, the project introduced CBOR file format, consequently the performance of the `sr` command has been significantly improved. The new version now outperforms the `sudo` command by a raw 77% (with 1 rule each side), and more you add rules, more the performance gap increases. The slope between the `sudo` and `sr` commands is 40% better, meaning that the more rules you add, the more the `sr` command will outperform the `sudo` command. You can reproduce this performance test by following the [RaR-perf](https://github.com/LeChatP/RaR-perf) repository guideline.
129+
130+
The performance of `sudo-rs` are actually even-or-worse than `sudo` command for the few tests I was able to do. However, the sudo-rs project is crashing when you try to add more than 100 rules. [I created an issue on their repository, but it's tagged as won't fix](https://github.com/trifectatechfoundation/sudo-rs/issues/1192).
131+
132+
But that is not all, as we wish to introduce RDBMS (Relational Database Management System) support in the future (with Limbo SQLite and regular DBMS solutions), the performance will be even better.
133+
134+
135+
### Why Performance Matters
136+
137+
When it comes to managing infrastructure with tools like Ansible, executing privileged commands will become a common task, so you multiply the number of commands executed by the number of rules. With the `sudo` command, it didn't matters as long you had only one rule everywhere, but now with RootAsRole, you can have a lot of rules as long you configure it with `gensr` --- generating a first version of a very-specific policy --- thus increasing the number of rules inside the policy, so the performance of the `sr` command now matters.
138+
139+
With RootAsRole, you add more access control rules, enforcing a better POLP, without sacrificing performance.
120140

121141

122142
## Why do you need this tool ?

book/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
# Reference Guide
2424

2525
- [Configure RootAsRole](chsr/file-config.md)
26+
- [File Config Conversion](chsr/convert.md)
2627
- [Continuous Integration](continuous-integration.md)
2728
- [How to contribute](dev/CONTRIBUTE.md)
2829
- [FAQ](faq.md)

book/src/chsr/README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,11 @@ chsr options timeout [operation]
104104
del [items,...] Remove items from the list.
105105
set [items,...] Set items in the list.
106106
purge Remove all items from the list.
107-
</pre>
107+
108+
<u><b>Convert policy format :</b></u>
109+
chsr convert (-r) (--from [from_type] [from_file]) [to_type] [to_file]
110+
Supported types: json, cbor
111+
<b>-r, --reconfigure</b> Reconfigure /etc/security/rootasrole.json file to specify the new location.
112+
<b>--from</b> [from_type] [from_file] Specify the type and file to convert from.
113+
<b>Warning</b>: the new location should be under a protected directory.
114+
</pre>

book/src/chsr/convert.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# File Config Conversion
2+
3+
## Converting JSON to CBOR and vice versa
4+
5+
Converting the `/etc/security/rootasrole.json` file to CBOR format (and configure the policy to the new location with `-r` option) :
6+
7+
`chsr convert -r cbor /etc/security/rootasrole.bin`
8+
9+
This command will read the JSON file, convert it to CBOR format, and save it to `/etc/security/rootasrole.bin`. The `-r` option changes the file `/etc/security/rootasrole.json` to specify the new location in `path` field of the configuration file.
10+
11+
To convert the CBOR file back to JSON format, you can use the following command:
12+
13+
`chsr convert -r json /etc/security/rootasrole.json`
14+
15+
This command will read the CBOR file, convert it back to JSON format, and save it to `/etc/security/rootasrole.json`. The `-r` option changes the file `/etc/security/rootasrole.json` to specify the new location in `path` field of the configuration file.

0 commit comments

Comments
 (0)