Using meta skuid or meta skgid is not working with nftables.

Trenix25

Well-Known Member
Joined
Aug 15, 2017
Messages
673
Reaction score
366
Credits
6,139
I'm trying to block a specific port for local users with nftables. I need to block access to port 80 for all users not in the web (120) group. This is my command:

nft add rule ip filter4 input ip daddr $VEGAIP tcp dport 80 meta skgid ne 120 drop

filter4 is the IPv4 filter table and input is the name of the input chain. VEGAIP is my local IPv4 address. 120 is the web group gid. nftables isn't recognizing meta skuid or meta skgid and CoPilot couldn't suggest any way to get this to work with nftables alone. I do not want to use iptables along with nftables. It needs to be just nftables alone. Even a non-privileged user is able to see that port 80 is open using -sT with nmap. I guess I'll just have to block all local access to this port until I can resolve this issue.

All of the drop rules are listed before any of the accept rules.

Signed,

Matthew Campbell
 


nft add rule ip filter4 input ip daddr $VEGAIP tcp dport 80 meta skgid ne 120 drop
skuid and skid work only for output rules and are not applicable to input rules.

If you want to harden your web server to group or user consider socket cgroupv2 instead which works by restricting traffic to service instead of user or group.

Example:
Bash:
nft add rule ip filter4 input ip daddr $VEGAIP tcp dport 80 socket cgroupv2 $firefox_cgroup accept

How do I populate $firefox_cgroup sample from above sample?
This sample bash script (called MyScript.sh populates 2 cgroup variables, one for Firefox, another for qbittorrent and writes them to nft script called variables.nft.

Bash:
#!/bin/bash

cgroup () {
    local string1=$(systemctl show -t slice,service -p ControlGroup | grep -oP "(?<=ControlGroup=/).+@$2\.service")
    local string2=$(systemctl status -t slice | grep -oP "$1[\d\w]+\.scope" | head -1)
    echo "$string1/app.slice/$string2"
}

printf "\n#\n# cgroups\n#\n" >> ./variables.nft
printf "define qbit_cgroup = \"$(cgroup 'app-org\.qbittorrent\.qBittorrent-' $(id -u $USERNAME))\"\n" >> ./variables.nft
printf "define firefox_cgroup = \"$(cgroup 'app-firefox-')\"\n" >> ./variables.nft

I'm sure you'll figure out how to learn cgroup name by hand using this sample script.
 
Last edited:
And what happens if a user tried to use curl or wget instead of Firefox?

I need certain users to be able to access certain ports while locking out other local users.

Signed,

Matthew Campbell
 
And what happens if a user tried to use curl or wget instead of Firefox?
You need separate socket cgroupv2 rule for each program or service you want to allow.

Note that socket cgroupv2 rules are valid only for as long as program or service is running, e.g. until system reboot, because on reboot or service/program restart cgroup name path changes making old rules no longer match.

A way around this is to deploy firewall from script upon reboot and keep the service alive or otherwise if it's a server it shouldn't reboot daily.

I need certain users to be able to access certain ports while locking out other local users.
Problem is that input traffic is not from local users but remote users so skuid and skid (which applies on local users) won't work on input traffic.
But you can restrict output response traffic with this meta.

socket cgroupv2 name path is per user so you can have multiple for different users as long as there are multiple same services running by different local users.
 
Last edited:
Do you have a filter table and an input chain set up like this?:
Bash:
nft add table ip filter4
nft add chain ip filter4 input { type filter hook input priority 0; }

Once that is done you can create the rules that allow users in web group to access port 80 and block users that are not:

Bash:
nft add rule ip filter4 input tcp dport 80 meta skgid == 120 accept

Bash:
nft add rule ip filter4 input tcp dport 80 meta skgid != 120 drop

Note:
1. "!=" syntax is used instead of "ne", you can try this as it is more commonly used and might be better recognized.

2. The add rule is added before the drop rule. This order is necessary according to the docs:
https://docs.redhat.com/en/document...tting-started-with-nftables_securing-networks
"If the rule also contains matching expressions, nftables performs the actions only if all previous expressions apply"
"rules define actions to perform on packets that pass a chain,"


You can run
Bash:
nft -a list ruleset
to get a comprehensive view of your configuration and verify that rules are in the correct order.
 
Do you have a filter table and an input chain set up like this?:
Bash:
nft add table ip filter4
nft add chain ip filter4 input { type filter hook input priority 0; }

Once that is done you can create the rules that allow users in web group to access port 80 and block users that are not:

Bash:
nft add rule ip filter4 input tcp dport 80 meta skgid == 120 accept

Bash:
nft add rule ip filter4 input tcp dport 80 meta skgid != 120 drop

Note:
1. "!=" syntax is used instead of "ne", you can try this as it is more commonly used and might be better recognized.

2. The add rule is added before the drop rule. This order is necessary according to the docs:
https://docs.redhat.com/en/document...tting-started-with-nftables_securing-networks
"If the rule also contains matching expressions, nftables performs the actions only if all previous expressions apply"
"rules define actions to perform on packets that pass a chain,"


You can run
Bash:
nft -a list ruleset
to get a comprehensive view of your configuration and verify that rules are in the correct order.
The problem is that meta skgid wasn't working. I'm try to block requests that are not from users of an approved group. I have an input chain and a table and all of that.

I've decided to fortify the web server instead to render the exploit that is being used against me ineffective and therefore worthless.

Signed,

Matthew Campbell
 

Staff online


Top