Skip to content
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

Added way to block members using CIDR #196

Merged
merged 18 commits into from
Apr 8, 2020

Conversation

pierresouchay
Copy link
Contributor

Added 2 new fields in configuration of memberlists to allow/disallow
others machines joining memberlist.

This will allow protecting some machines from joining a cluster and will increase security as well.

Will be useful to implement hashicorp/consul#5916
as suggested my @mkeller

net.go Outdated Show resolved Hide resolved
@pierresouchay pierresouchay force-pushed the block_memberlist_using_cidr branch from ef409b4 to b4cd6df Compare June 25, 2019 06:21
@pierresouchay
Copy link
Contributor Author

@mkeeler Is it what you had in mind in hashicorp/consul#5916 (comment) ?

@pierresouchay
Copy link
Contributor Author

@mkeeler Could you have a look and tell me if it is Ok to achieve hashicorp/consul#5916 ?

Copy link
Member

@mkeeler mkeeler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall I think this would work. My one concern is all the string parsing and checks that would have to be done for every UDP packet or TCP connection. Would it still work if the CIDR checks were done in these two places instead (rough locations):

state = &nodeState{

// If DeadNodeReclaimTime is configured, check if enough time has elapsed since the node died.

In the first location we are handling an alive event for a new node. In the second location we are handling an alive event for an existing node but already know that either the IP or port has changed. What this doesn't do is CIDR validation when handling an alive event for a node whose IP or port has not been updated (which should be the normal and most prevalent case).

@pierresouchay
Copy link
Contributor Author

@mkeeler DONE as you suggested

Copy link
Member

@mkeeler mkeeler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

config.go Outdated Show resolved Hide resolved
config.go Outdated Show resolved Hide resolved
state.go Outdated Show resolved Hide resolved
Copy link
Member

@rboyer rboyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please take a look at my comments and see if I've misunderstood anything about your intent.

@pierresouchay pierresouchay force-pushed the block_memberlist_using_cidr branch 2 times, most recently from 1ff23f4 to 6bb8396 Compare August 28, 2019 08:47
@pierresouchay
Copy link
Contributor Author

Please take a look at my comments and see if I've misunderstood anything about your intent.

I fixed issues you mentioned. Are you Ok with the implementation I made to protect NotifyAliveor do you have another suggestion?

@pierresouchay
Copy link
Contributor Author

Ping @rboyer @mkeeler ?

Copy link
Member

@rboyer rboyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies for the delay. I was having a hard time figuring out how to describe my remaining reservations with the proposed implementation but I think I've got it now.

Overall the best solution here is to always ensure you are using gossip encryption in your consul clusters which should prevent accidental joins, since the stray agents would lack the necessary keys to formulate valid memberlist messages. But I can see situations where someone may be in a situation where enabling gossip encryption isn't feasible and so something shaped like the proposed solution is beneficial.

I think the pairing of an allow and a deny configuration is offering too much complexity for a likely rarely used subfeature. The allow_write_http_from consul configuration option has the semantics that if you don't configure it at all it is default-allow, and if you configure anything it switches to default-deny. It does require that you have the ability to enumerate all allowable addresses in CIDR form sanely.

For straightforward behind-the-firewall setups this might be as straightforward as dumping all of the class-C networks (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, and an ipv6 equivalent if being used) into the allow list. If you are incapable of doing this because your IP addresses don't neatly fit into CIDR blocks, my assumption is that you are probably drifting into the territory where you would be better served with the gossip encryption option.

I'd like it if you could reduce the complexity here and only expose a single tunable AllowedCIDRs setting that defaults to nil with the semantics that it is default-allow unless configured to a non-empty slice of data.

When the feature is in default-allow mode it would also be nice to avoid incurring any additional operations or allocations that can be avoided (namely we should avoid parsing net.Addr.Network() into an interim net.IP when we know the user has not activated this CIDR feature at all.

net.go Outdated Show resolved Hide resolved
config.go Show resolved Hide resolved
@pierresouchay
Copy link
Contributor Author

@rboyer Thank you for the review, I think I addressed all your points!

config.go Outdated Show resolved Hide resolved
Copy link
Member

@rboyer rboyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. The only thing missing for me now that you've made the big changes is some test showcasing the feature successfully keeping awareness of a blocked node from making it into the memberlist of a node configured to block it.

config_test.go Outdated Show resolved Hide resolved
@hanshasselberg hanshasselberg self-assigned this Dec 19, 2019
@hanshasselberg
Copy link
Member

@pierresouchay The only thing thats left, seem to be

[...] some test showcasing the feature successfully keeping awareness of a blocked node from making it into the memberlist of a node configured to block it.

@pierresouchay
Copy link
Contributor Author

@i0rek yes, I have started to implement test, but I have many things to change, including the shell script to create sub networks for Mac, I'll find some time soon to work on this

@pierresouchay
Copy link
Contributor Author

@i0rek DONE

@pierresouchay
Copy link
Contributor Author

@rboyer I added the tests as required

Added 2 new fields in configuration of memberlists to allow/disallow
others machines joining memberlist.

This will allow protecting some machines from joining a cluster.

Will be useful to implement hashicorp/consul#5916
as suggested my @mkeller
@rboyer
Copy link
Member

rboyer commented Apr 7, 2020

OK the last comments I left should be pretty quick to fix and after that we are golden.

config.go Outdated Show resolved Hide resolved
@pierresouchay
Copy link
Contributor Author

pierresouchay commented Apr 7, 2020

@rboyer Thank you for the review, I think I resolved all your issues

I actually kept eb90195 because the it might have some effect if a delegate has been setup

If you prefer to remove this 'double check', I'll revert it

@pierresouchay pierresouchay requested a review from rboyer April 7, 2020 20:59
config_test.go Outdated Show resolved Hide resolved
net.go Outdated Show resolved Hide resolved
@pierresouchay
Copy link
Contributor Author

hu... fun, unit tests do not work anymore :(

Also had to fix unit test blocking all connectivity when
AllowedCIDR was set to [] instead of nil
@pierresouchay
Copy link
Contributor Author

@rboyer Ok, I found the issue with the unit tests, now, Join() by default assert that Name / Addr is set by default, so my unit tests were not working anymore, but last commit fixes that.

On another topic, the change you asked to use:

func (c *Config) IPMustBeChecked() bool {
	return len(c.CIDRsAllowed) > 0
}

instead of cheking nil also broke another test (I fixed it), that was asserting that AllowedCIDRs = [] was blocking everything.

When I wrote it initially, I thought in terms of security that blocking everything is always a nice feature, but for the project itself, it might defeat its own purpose, so I don't think it is a big deal.

An finally, the unit tests are not run in the PR, not a big deal, but it might be a good addition

I think everything is ok now

Copy link
Member

@rboyer rboyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@rboyer rboyer merged commit f72d204 into hashicorp:master Apr 8, 2020
@rboyer
Copy link
Member

rboyer commented Apr 8, 2020

We can tag a new version of this after you start using this from serf or consul, in case you discover a need to do any last minute refactor of this feature while attempting to use it.

@pierresouchay
Copy link
Contributor Author

@rboyer Thanks, I'll try the integration in Consul soon, but it should be straigforward

@pierresouchay
Copy link
Contributor Author

@rboyer I made the PR in Consul some time ago, maybe you could have a look at hashicorp/consul#7628 ?

Thank you

pierresouchay added a commit to pierresouchay/consul that referenced this pull request May 19, 2020
Based on work done in hashicorp/memberlist#196
this allows to restrict the IP ranges that can join a given Serf cluster
and be a member of the cluster.

Restrictions on IPs can be done separatly using 2 new differents flags
and config options to restrict IPs for LAN and WAN Serf.
hanshasselberg pushed a commit to hashicorp/consul that referenced this pull request May 20, 2020
…7628)

Based on work done in hashicorp/memberlist#196
this allows to restrict the IP ranges that can join a given Serf cluster
and be a member of the cluster.

Restrictions on IPs can be done separatly using 2 new differents flags
and config options to restrict IPs for LAN and WAN Serf.
rboyer pushed a commit to hashicorp/consul that referenced this pull request Jun 1, 2020
…7628)

Based on work done in hashicorp/memberlist#196
this allows to restrict the IP ranges that can join a given Serf cluster
and be a member of the cluster.

Restrictions on IPs can be done separatly using 2 new differents flags
and config options to restrict IPs for LAN and WAN Serf.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants