feat(icos): First phase of the firewall setup feature (DRE-258)
Per https://dfinity.atlassian.net/browse/DRE-258 .
We have successfully loaded rules of well-formed /boot/config/firewall.json in HostOS and GuestOS.
Details: We would like to allow the node operator / provider to modify the firewall rules in order to allow incoming traffic to their nodes. This can be used to get the ability to fetch logs and metrics from the nodes in the same DC.
To achieve this, the node provider should add a new config file named firewall.json in the SetupOS config. This file is then propagated to the other parts of the IC-OS stack.
Note that the firewall rules can only be configured during node (re)deployment, in this phase. In phase 2, it will become possible to reconfigure already running nodes. Phase 2 will be more effort than phase 1.
This PR rides atop this other one: https://github.com/dfinity/ic/pull/2077
We don't yet do anything with the firewall.json file, but all this work, already, is enormous just to pass a silly config file down the pipe. Horrible. I am so looking forward to your work @andrewbattat enabling the use of the configuration structures making this job enormously easier and deleting so much code from our codebase.
Vulnerable dependency information The dependency-check job for the MR has new findings. Please update or remove these dependencies or obtain a commit exception from product security.
The findings are: [Finding(repository='ic', scanner='BAZEL_RUST', vulnerable_dependency=Dependency(id='https://crates.io/crates/mio', name='mio', version='0.8.10', fix_version_for_vulnerability={'https://rustsec.org/advisories/RUSTSEC-2024-0019': ['>=0.8.11', '<0.7.2']}), vulnerabilities=[Vulnerability(id='https://rustsec.org/advisories/RUSTSEC-2024-0019', name='RUSTSEC-2024-0019', description='Tokens for named pipes may be delivered after deregistration', score=-1, risk_note=' ')], first_level_dependencies=[], projects=[], risk_assessor=[], risk=None, owning_teams=[], patch_responsible=[], due_date=None, score=-1, more_info=None), Finding(repository='ic', scanner='BAZEL_RUST', vulnerable_dependency=Dependency(id='https://crates.io/crates/rsa', name='rsa', version='0.9.2', fix_version_for_vulnerability={}), vulnerabilities=[Vulnerability(id='https://rustsec.org/advisories/RUSTSEC-2023-0071', name='RUSTSEC-2023-0071', description='Marvin Attack: potential key recovery through timing sidechannels', score=5, risk_note=' ')], first_level_dependencies=[], projects=[], risk_assessor=[], risk=None, owning_teams=[], patch_responsible=[], due_date=None, score=5, more_info=None)]
Vulnerable dependency information
This was due to a mixup in testing. Should be resolved now.
@andrewbattat for some reason Github refuses to show me the thread where you and I were chatting about the empty firewall.json file. I still need your stamp in order to merge though. What do we do?
@andrewbattat for some reason Github refuses to show me the thread where you and I were chatting about the empty
firewall.jsonfile. I still need your stamp in order to merge though. What do we do?
Here it is: https://github.com/dfinity/ic/pull/1451#discussion_r1781696405
I unresolved a few threads, and I'll do another review later today.
Firewall rules loaded successfully in installed HostOS.
From this config:
[
{
"from": "2001:db8:abcd:0013::0/64",
"to": "HostOS",
"protocol": "tcp",
"action": "accept"
}
]
we get this result (see chain provider_INPUT):
root@host-696e76697274:~# nft list table ip6 filter
table ip6 filter {
set rate_limit {
type ipv6_addr
size 65535
flags dynamic
}
set connection_limit {
type ipv6_addr
size 65535
flags dynamic
}
set dfinity_dcs {
type ipv6_addr
flags interval
auto-merge
elements = { 2001:438:fffd:11c::/64,
2001:470:1:c76::/64,
2001:920:401a:1706::/64,
2001:920:401a:1708::/64,
2001:920:401a:1710::/64,
2001:1900:2100:2827::/64,
2001:4d78:400:10a::/64,
2001:4d78:40d::/48,
2401:3f00:1000:22::-2401:3f00:1000:24:ffff:ffff:ffff:ffff,
2600:c00:2:100::/64,
2600:c02:b002:15::/64,
2600:c0d:3002:4::/64,
2600:2c01:21::/64,
2600:3000:1300:1300::/64,
2600:3000:6100:200::/64,
2600:3004:1200:1200::/56,
2600:3006:1400:1500::/64,
2602:fb2b:100::/48,
2602:fb2b:110::/48,
2602:fb2b:120::/48,
2602:ffe4:801:16::-2602:ffe4:801:18:ffff:ffff:ffff:ffff,
2604:1380:4091:3000::/56,
2604:1380:40e1:4700::/56,
2604:1380:45e1:a600::/56,
2604:1380:4601:6200::/56,
2604:1380:4641:6100::/56,
2604:3fc0:2001::/48,
2604:3fc0:3002::/48,
2604:6800:258:1::/64,
2604:7e00:30:3::/64,
2604:7e00:50::/64,
2604:b900:4001:76::/64,
2607:f1d0:10:1::/64,
2607:f6f0:3004::/48,
2607:f758:1220::/64,
2607:f758:c300::/64,
2607:ff70:3:2::/64,
2610:190:6000:1::/64,
2610:190:df01:5::/64,
2a00:fa0:3::/48,
2a00:fc0:5000:300::/64,
2a00:fb01:400::/55,
2a01:138:900a::/48,
2a01:2a8:a13c::-2a01:2a8:a13e:ffff:ffff:ffff:ffff:ffff,
2a02:418:3002::/48,
2a02:41b:300e::/48,
2a02:800:2:2003::/64,
2a04:9dc0:0:108::/64,
2a0b:21c0:4003:2::/64,
2a0b:21c0:4006:100::/56,
2a0b:21c0:b002:2::/64,
2a0f:cd00:2::/56,
fd00:2:1:1::/64 }
}
set telemetry_clients {
type ipv6_addr
flags interval
elements = { 2001:4d78:40d::/48,
2602:fb2b:100::/48,
2602:fb2b:110::/48,
2602:fb2b:120::/48,
2607:f6f0:3004::/48 }
}
set node_providers {
type ipv6_addr
flags interval
}
chain metrics_proxy {
ct state new add @rate_limit { ip6 saddr limit rate over 100/minute burst 5 packets } drop comment "Maximum 100 connections per minute"
ct state new add @connection_limit { ip6 saddr ct count over 6 } drop comment "No more than 6 connections per source at a time"
accept
}
chain provider_INPUT {
ip6 saddr 2001:db8:abcd:13::/64 ct state new tcp flags syn accept
}
chain INPUT {
type filter hook input priority filter; policy drop;
iif "lo" accept
ct state invalid drop
ct state { established, related } accept
icmpv6 type destination-unreachable accept
icmpv6 type packet-too-big accept
icmpv6 type time-exceeded accept
icmpv6 type parameter-problem accept
icmpv6 type echo-request accept
icmpv6 type echo-reply accept
icmpv6 type nd-router-advert accept
icmpv6 type nd-neighbor-solicit accept
icmpv6 type nd-neighbor-advert accept
ip6 saddr @dfinity_dcs ct state new tcp dport { 22, 9100, 19100, 19531 } accept
ip6 saddr @telemetry_clients ct state new tcp dport { 9100, 19100, 19531 } accept
ip6 saddr @node_providers ct state new tcp dport { 22, 9100, 19531 } accept
jump provider_INPUT
tcp dport 42372 goto metrics_proxy
}
chain FORWARD {
type filter hook forward priority filter; policy drop;
}
chain OUTPUT {
type filter hook output priority filter; policy drop;
oif "lo" accept
ct state invalid drop
ct state { established, related } accept
icmpv6 type destination-unreachable accept
icmpv6 type packet-too-big accept
icmpv6 type time-exceeded accept
icmpv6 type parameter-problem accept
icmpv6 type echo-request accept
icmpv6 type echo-reply accept
icmpv6 type nd-router-solicit accept
icmpv6 type nd-neighbor-solicit accept
icmpv6 type nd-neighbor-advert accept
ip6 daddr ::/0 ct state new tcp dport 53 accept
ip6 daddr ::/0 ct state new udp dport 53 accept
ip6 daddr ::/0 ct state new udp dport 123 accept
ip6 daddr ::/0 ct state new tcp dport { 80, 443, 8080 } accept
ip6 daddr ::/0 ct state new tcp dport 42372 accept comment "Permit outbound connections to metrics-proxy instances so local metrics-proxy can fetch data from GuestOS
metrics-proxy."
}
}