-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Feature lighthouse host query filtering #1358
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Feature lighthouse host query filtering #1358
Conversation
864bc8e
to
f7f3ff3
Compare
This is a really interesting concept, thanks for putting this together! If I understand this correctly, it looks like you're deciding whether or not to filter a host query based on if that host's firewall would permit a handshake, which definitely makes sense. I was curious if you had considered an implementation where hosts send their entire firewall to the lighthouse? The lighthouse wouldn't be able to evaluate protocol+port rules, obviously, but in theory, you could allow the lighthouse to filter out queries that it "knows" would be unable to communicate with the queried-for host. One potential issue that comes to mind with both approaches is the potential size of the |
Yes, your description somewhat summarizes the functionality implemented by this PR. The foundational PR #1357 establishes filtering at the node level, filtering connections between nodes that either know the nebula port or can infer it. This PR then extends the filtering capabilities to the lighthouse, implementing the approach you outlined. Initially, my intention was to transmit the inbound firewall rule structure to the lighthouse. However, upon reviewing the code, I recognized that, given the information available to the lighthouse for filtering, I can omit some data. The
Good input! While I considered strategies to minimize network and CPU load on both nodes and lighthouses - such as transmitting data only in the initial message or when local firewall rules are modified - I had not accounted for the issue of packet fragmentation. A solution could be to create a dedicated message type. Since the user controls the MTU, I could manage packet sizes accordingly and split the data into multiple packets as necessary. Group names may be likely to be repeated across firewall rules, compression could be efficient in further reducing the size of the transmitted data. What do you think? |
@jampe can you describe the situation that led you to a client authoritative approach for this? |
I have given this considerable thought and descided based on the following arguments: Arguments for Client Authority
Arguments for Lighthouse Authority
Neutral Considerations
In my view, the arguments in favor of client authority outweigh those supporting Lighthouse authority. I have aimed to minimize the amount of code touched and to keep the implementation as simple as possible. Additionally, the extra network load is kept to a minimum by sending the rules to the Lighthouse only during the initial announcement or when the local firewall rules have changed. |
- send HostQueryWhitelist when NebulaMeta_HostUpdateNotificationAck is handled - support multiple HostQueryWhitelist messages based on node mtu - handle lost udp packet using NebulaMeta_HostQueryWhitelistAck message - improved testing
} | ||
} | ||
|
||
if initial || c.HasChanged("tun.routes") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dont really like parsing tun.routes here too but I didn't find a better way to have access to the mtu data. do you know a better way?
@jampe I was looking for more information regarding your mesh network and what properties it had that led you to choose the client authoritative model. For example, a lighthouse authoritative model would fit more cleanly with networks that have someone with administrative permissions over the entire network, think a company wide ops team or running your own home lab. |
Well we looked at nebula during a red team assignment of a customer where we discovered that we could leak internal ip's after we gained access to an infected, external client. We had some spare time so the customer allowed us to submit a PR attempting to fix the problem. They use an ansible role to manage / create all the configs. So basically it would be possible for them to manage the rules on the lighthouse as well. I just looked at the code and thought a client authoritative model is more "nebula style" as the lighthouse has zero information about its clients when starting up and learns all the data when they announce themselves (e.g. the ips or the relay servers to use with a client). |
I thought about how this would change if we were to implement it on the lighthouse side. The implementation would be relatively straightforward, touching way less code. To maintain the same level of control as the current implementation, I would propose adding a new section to the lighthouse configuration, as follows: lighthouse:
# This option governs which nodes are permitted to query specific hosts (or groups of hosts)
# within the network. You can specify either a single host, a range of hosts or a subnet as the key, along with
# the corresponding rules that determine which nodes are authorized to perform host queries as value.
# Nodes that do not conform to the defined rules but still attempt to make a query will receive
# no response. If no rules are defined, all queries will be permitted.
hostquery_filtering:
10.0.10.10:
hosts:
- 10.0.10.100
group:
- europe
- webservers
10.0.10.20,10.0.10.25,10.0.10.29:
# this AND's the groups. A node has to be in each group for the query to be allowed
group:
- - webservers
- apache
- - webservers
- nginx
- reverseproxy
10.0.10.30-10.0.10.35:
cidrs:
- 10.0.10.0/24
10.0.10.40:
ca_names:
- myCA
ca_shas:
- xxxxxx
10.0.10.128/26,10.0.10.192/28:
group:
- europe
- datacenter-a
ca_shas:
- xxxxxx With something like this, the only remaining task would be to code the parsing logic, as the filtering logic could be utilized largely as it is. I still think the dynamic, client side approach is more flexible however 9 definitely see the argument of central management and strict rule enforcement via lighthouse rules as well. Additionally with adding / editing way less code we would prevent adding additional complexity. I'd be happy to help implementing what ever solution / approach you guys prefer. |
=> This PR builds upon PR "Incoming Handshake filtering based on firewall rules" #1357 and will remain in draft status until that PR is either merged or declined.
This pull request introduces the functionality to send the flattened firewall rules (hostname, groups, group combos and cidrs) to a node's lighthouses. After a node has transmitted this information to its lighthouse, the lighthouse will filter host queries for that node based on the provided whitelist. The node includes this flattened firewall rules in the initial HostUpdateNotification message and will resend it if there are any changes to the data.
Config changes:
A new configuration value has been added within the Lighthouse section to enable this feature:
Implementation details:
When sending a HostUpdateNotification message, the function
HandshakeFilter:ToHandshakeFilteringWhitelist
is called to convert the whitelist from its map format to the appropriate protobuf data structure. Then the functionHandshakeFilter:FromHandshakeFilteringWhitelist
performs the inverse operation on the lighthouse side. Afterwards the lighthouse stores the HandshakeFilter instance in the node's RemoteList structure by invokingRemoteList:unlockedSetHandshakeFilteringWhitelist()
.Upon receiving host queries, the lighthouse checks for any stored rules associated with the queried node. If rules are present, the whitelist is consulted to determine whether the query should be permitted.
To accommodate the flattened firewall rules sent to the lighthouse, the HostUpdateNotification message has been extended. The whitelist is sent to the lighthouses only on the initial request, when the whitelist changes locally, or when the tunnel to the lighthouse was rebuilt. This approach helps reduce unnecessary network load for users operating Nebula with many nodes.
To identify potentially malicious or infected nodes, a new metric, "lighthouse.hostqueries.filtered", has been introduced to track filtered host queries on a lighthouse.