diff --git a/.gitignore b/.gitignore index 9ad2297..da2d8ab 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ coverage webhook /test/hookecho build + +/selinux/tmp +/selinux/webhook.pp diff --git a/selinux/README.md b/selinux/README.md new file mode 100644 index 0000000..a59d6b5 --- /dev/null +++ b/selinux/README.md @@ -0,0 +1,44 @@ +## SELinux policy for webhook + +### Build & Install + +Install the selinux-policy-devel package, then run: + + cd webhook/selinux + make -f /usr/share/selinux/devel/Makefile + +It should produce the `webhook.pp` file. + +Install the module: + + sudo semodule -i webhook.pp + sudo restorecon /usr/bin/webhook /etc/webhook.conf + +Label any webhook scripts as `webhook_unconfined_exec_t` with `chcon`: + + sudo chcon -t webhook_unconfined_exec_t /usr/local/bin/deploy.sh + +### Policy + +The policy defines the following domain types + +* `webhook_t` +* `webhook_exec_t` +* `webhook_unconfined_t` +* `webhook_unconfined_exec_t` + +When `init_t` launches the `webhook` program, it will automatically +transition to the `webhook_t` domain. + +`webhook_t` is able to run any executables or scripts labeled with +the `webhook_unconfined_exec_t` file type. Those will run in the +unconfined `webhook_unconfined_t` domain. Other executables will +run with the `webhook_t` domain with minimum permissions. + +The policy also defines a default `on` boolean, `webhook_unconfined_exec_any`, +which allow running programs labeled as `bin_t` (files in `/usr/bin` or `/usr/local/bin`) +in the `webhook_unconfined_t` domain. + +Set the boolean to `off` to enable maximum protection: + + sudo setsebool webhook_unconfined_exec_any off diff --git a/selinux/webhook.fc b/selinux/webhook.fc new file mode 100644 index 0000000..d2f6bb8 --- /dev/null +++ b/selinux/webhook.fc @@ -0,0 +1,2 @@ +/usr/bin/webhook -- gen_context(system_u:object_r:webhook_exec_t,s0) +/etc/webhook.conf gen_context(system_u:object_r:webhook_conf_t,s0) diff --git a/selinux/webhook.if b/selinux/webhook.if new file mode 100644 index 0000000..4686453 --- /dev/null +++ b/selinux/webhook.if @@ -0,0 +1,40 @@ + +## policy for webhook + +######################################## +## +## Execute webhook_exec_t in the webhook domain. +## +## +## +## Domain allowed to transition. +## +## +# +interface(`webhook_domtrans',` + gen_require(` + type webhook_t, webhook_exec_t; + ') + + corecmd_search_bin($1) + domtrans_pattern($1, webhook_exec_t, webhook_t) +') + +###################################### +## +## Execute webhook in the caller domain. +## +## +## +## Domain allowed access. +## +## +# +interface(`webhook_exec',` + gen_require(` + type webhook_exec_t; + ') + + corecmd_search_bin($1) + can_exec($1, webhook_exec_t) +') diff --git a/selinux/webhook.te b/selinux/webhook.te new file mode 100644 index 0000000..1108195 --- /dev/null +++ b/selinux/webhook.te @@ -0,0 +1,86 @@ +policy_module(webhook, 1.0.0) + +######################################## +# +# Declarations +# + +gen_require(` + type etc_t; +') + +type webhook_t; +type webhook_exec_t; +init_daemon_domain(webhook_t, webhook_exec_t) + +type webhook_conf_t; +files_config_file(webhook_conf_t) + +# Custom entrypoint type for commands that run unconfined +type webhook_unconfined_t; +type webhook_unconfined_exec_t; +domain_type(webhook_unconfined_t) +corecmd_executable_file(webhook_unconfined_exec_t) +domain_entry_file(webhook_unconfined_t, webhook_unconfined_exec_t) +unconfined_domain(webhook_unconfined_t) +role system_r types webhook_unconfined_t; + +# permissive webhook_t; + +######################################## +# +# Booleans +# + +## +##

+## Allow webhook_t to execute any file and transition to unconfined_t. +## When disabled, webhook_t can only execute files labeled +## webhook_unconfined_exec_t and transition to unconfined_t. +##

+##
+gen_tunable(webhook_unconfined_exec_any, true) + +######################################## +# +# webhook local policy +# + +domain_use_interactive_fds(webhook_t) + +read_files_pattern(webhook_t, etc_t, webhook_conf_t) + +allow webhook_t cgroup_t:file read; +fs_search_cgroup_dirs(webhook_t) + +allow webhook_t self:tcp_socket { create accept listen bind setopt getattr read write }; +kernel_read_net_sysctls(webhook_t) +kernel_search_network_sysctl(webhook_t) +corenet_sendrecv_http_server_packets(webhook_t) +corenet_tcp_bind_http_port(webhook_t) +corenet_tcp_sendrecv_http_port(webhook_t) +corenet_tcp_bind_generic_node(webhook_t) + +######################################## +# +# Command execution and domain transition to webhook_unconfined_t +# + +# Always: webhook_t can execute files labeled webhook_unconfined_exec_t +# and transition to webhook_unconfined_t + +allow webhook_t webhook_unconfined_t:process2 { nnp_transition nosuid_transition }; +allow webhook_t webhook_unconfined_t:process { noatsecure rlimitinh siginh }; + +domtrans_pattern(webhook_t, webhook_unconfined_exec_t, webhook_unconfined_t) +corecmd_exec_shell(webhook_t) +corecmd_exec_bin(webhook_t) + + +# Optional (boolean on, default true): webhook_t can execute ANY file +# and transition to webhook_unconfined_t + +corecmd_bin_entry_type(webhook_unconfined_t) +tunable_policy(`webhook_unconfined_exec_any',` + corecmd_bin_domtrans(webhook_t, webhook_unconfined_t) +')