mirror of
https://github.com/slackhq/nebula.git
synced 2025-12-08 06:09:49 +00:00
V2 certificate format (#1216)
Co-authored-by: Nate Brown <nbrown.us@gmail.com> Co-authored-by: Jack Doan <jackdoan@rivian.com> Co-authored-by: brad-defined <77982333+brad-defined@users.noreply.github.com> Co-authored-by: Jack Doan <me@jackdoan.com>
This commit is contained in:
parent
2b427a7e89
commit
d97ed57a19
105 changed files with 8276 additions and 4528 deletions
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/slackhq/nebula/firewall"
|
||||
"github.com/slackhq/nebula/test"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNewFirewall(t *testing.T) {
|
||||
|
|
@ -128,8 +129,8 @@ func TestFirewall_Drop(t *testing.T) {
|
|||
l.SetOutput(ob)
|
||||
|
||||
p := firewall.Packet{
|
||||
LocalIP: netip.MustParseAddr("1.2.3.4"),
|
||||
RemoteIP: netip.MustParseAddr("1.2.3.4"),
|
||||
LocalAddr: netip.MustParseAddr("1.2.3.4"),
|
||||
RemoteAddr: netip.MustParseAddr("1.2.3.4"),
|
||||
LocalPort: 10,
|
||||
RemotePort: 90,
|
||||
Protocol: firewall.ProtoUDP,
|
||||
|
|
@ -149,9 +150,9 @@ func TestFirewall_Drop(t *testing.T) {
|
|||
InvertedGroups: map[string]struct{}{"default-group": {}},
|
||||
},
|
||||
},
|
||||
vpnIp: netip.MustParseAddr("1.2.3.4"),
|
||||
vpnAddrs: []netip.Addr{netip.MustParseAddr("1.2.3.4")},
|
||||
}
|
||||
h.CreateRemoteCIDR(&c)
|
||||
h.buildNetworks(c.networks, c.unsafeNetworks)
|
||||
|
||||
fw := NewFirewall(l, time.Second, time.Minute, time.Hour, &c)
|
||||
assert.Nil(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"any"}, "", netip.Prefix{}, netip.Prefix{}, "", ""))
|
||||
|
|
@ -166,10 +167,10 @@ func TestFirewall_Drop(t *testing.T) {
|
|||
assert.NoError(t, fw.Drop(p, false, &h, cp, nil))
|
||||
|
||||
// test remote mismatch
|
||||
oldRemote := p.RemoteIP
|
||||
p.RemoteIP = netip.MustParseAddr("1.2.3.10")
|
||||
oldRemote := p.RemoteAddr
|
||||
p.RemoteAddr = netip.MustParseAddr("1.2.3.10")
|
||||
assert.Equal(t, fw.Drop(p, false, &h, cp, nil), ErrInvalidRemoteIP)
|
||||
p.RemoteIP = oldRemote
|
||||
p.RemoteAddr = oldRemote
|
||||
|
||||
// ensure signer doesn't get in the way of group checks
|
||||
fw = NewFirewall(l, time.Second, time.Minute, time.Hour, &c)
|
||||
|
|
@ -235,7 +236,7 @@ func BenchmarkFirewallTable_match(b *testing.B) {
|
|||
}
|
||||
ip := netip.MustParsePrefix("9.254.254.254/32")
|
||||
for n := 0; n < b.N; n++ {
|
||||
assert.False(b, ft.match(firewall.Packet{Protocol: firewall.ProtoTCP, LocalPort: 100, LocalIP: ip.Addr()}, true, c, cp))
|
||||
assert.False(b, ft.match(firewall.Packet{Protocol: firewall.ProtoTCP, LocalPort: 100, LocalAddr: ip.Addr()}, true, c, cp))
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -261,7 +262,7 @@ func BenchmarkFirewallTable_match(b *testing.B) {
|
|||
InvertedGroups: map[string]struct{}{"nope": {}},
|
||||
}
|
||||
for n := 0; n < b.N; n++ {
|
||||
assert.False(b, ft.match(firewall.Packet{Protocol: firewall.ProtoTCP, LocalPort: 100, LocalIP: pfix.Addr()}, true, c, cp))
|
||||
assert.False(b, ft.match(firewall.Packet{Protocol: firewall.ProtoTCP, LocalPort: 100, LocalAddr: pfix.Addr()}, true, c, cp))
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -285,7 +286,7 @@ func BenchmarkFirewallTable_match(b *testing.B) {
|
|||
InvertedGroups: map[string]struct{}{"good-group": {}},
|
||||
}
|
||||
for n := 0; n < b.N; n++ {
|
||||
assert.True(b, ft.match(firewall.Packet{Protocol: firewall.ProtoTCP, LocalPort: 100, LocalIP: pfix.Addr()}, true, c, cp))
|
||||
assert.True(b, ft.match(firewall.Packet{Protocol: firewall.ProtoTCP, LocalPort: 100, LocalAddr: pfix.Addr()}, true, c, cp))
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -308,8 +309,8 @@ func TestFirewall_Drop2(t *testing.T) {
|
|||
l.SetOutput(ob)
|
||||
|
||||
p := firewall.Packet{
|
||||
LocalIP: netip.MustParseAddr("1.2.3.4"),
|
||||
RemoteIP: netip.MustParseAddr("1.2.3.4"),
|
||||
LocalAddr: netip.MustParseAddr("1.2.3.4"),
|
||||
RemoteAddr: netip.MustParseAddr("1.2.3.4"),
|
||||
LocalPort: 10,
|
||||
RemotePort: 90,
|
||||
Protocol: firewall.ProtoUDP,
|
||||
|
|
@ -329,9 +330,9 @@ func TestFirewall_Drop2(t *testing.T) {
|
|||
ConnectionState: &ConnectionState{
|
||||
peerCert: &c,
|
||||
},
|
||||
vpnIp: network.Addr(),
|
||||
vpnAddrs: []netip.Addr{network.Addr()},
|
||||
}
|
||||
h.CreateRemoteCIDR(c.Certificate)
|
||||
h.buildNetworks(c.Certificate.Networks(), c.Certificate.UnsafeNetworks())
|
||||
|
||||
c1 := cert.CachedCertificate{
|
||||
Certificate: &dummyCert{
|
||||
|
|
@ -341,11 +342,12 @@ func TestFirewall_Drop2(t *testing.T) {
|
|||
InvertedGroups: map[string]struct{}{"default-group": {}, "test-group-not": {}},
|
||||
}
|
||||
h1 := HostInfo{
|
||||
vpnAddrs: []netip.Addr{network.Addr()},
|
||||
ConnectionState: &ConnectionState{
|
||||
peerCert: &c1,
|
||||
},
|
||||
}
|
||||
h1.CreateRemoteCIDR(c1.Certificate)
|
||||
h1.buildNetworks(c1.Certificate.Networks(), c1.Certificate.UnsafeNetworks())
|
||||
|
||||
fw := NewFirewall(l, time.Second, time.Minute, time.Hour, c.Certificate)
|
||||
assert.Nil(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"default-group", "test-group"}, "", netip.Prefix{}, netip.Prefix{}, "", ""))
|
||||
|
|
@ -364,8 +366,8 @@ func TestFirewall_Drop3(t *testing.T) {
|
|||
l.SetOutput(ob)
|
||||
|
||||
p := firewall.Packet{
|
||||
LocalIP: netip.MustParseAddr("1.2.3.4"),
|
||||
RemoteIP: netip.MustParseAddr("1.2.3.4"),
|
||||
LocalAddr: netip.MustParseAddr("1.2.3.4"),
|
||||
RemoteAddr: netip.MustParseAddr("1.2.3.4"),
|
||||
LocalPort: 1,
|
||||
RemotePort: 1,
|
||||
Protocol: firewall.ProtoUDP,
|
||||
|
|
@ -391,9 +393,9 @@ func TestFirewall_Drop3(t *testing.T) {
|
|||
ConnectionState: &ConnectionState{
|
||||
peerCert: &c1,
|
||||
},
|
||||
vpnIp: network.Addr(),
|
||||
vpnAddrs: []netip.Addr{network.Addr()},
|
||||
}
|
||||
h1.CreateRemoteCIDR(c1.Certificate)
|
||||
h1.buildNetworks(c1.Certificate.Networks(), c1.Certificate.UnsafeNetworks())
|
||||
|
||||
c2 := cert.CachedCertificate{
|
||||
Certificate: &dummyCert{
|
||||
|
|
@ -406,9 +408,9 @@ func TestFirewall_Drop3(t *testing.T) {
|
|||
ConnectionState: &ConnectionState{
|
||||
peerCert: &c2,
|
||||
},
|
||||
vpnIp: network.Addr(),
|
||||
vpnAddrs: []netip.Addr{network.Addr()},
|
||||
}
|
||||
h2.CreateRemoteCIDR(c2.Certificate)
|
||||
h2.buildNetworks(c2.Certificate.Networks(), c2.Certificate.UnsafeNetworks())
|
||||
|
||||
c3 := cert.CachedCertificate{
|
||||
Certificate: &dummyCert{
|
||||
|
|
@ -421,9 +423,9 @@ func TestFirewall_Drop3(t *testing.T) {
|
|||
ConnectionState: &ConnectionState{
|
||||
peerCert: &c3,
|
||||
},
|
||||
vpnIp: network.Addr(),
|
||||
vpnAddrs: []netip.Addr{network.Addr()},
|
||||
}
|
||||
h3.CreateRemoteCIDR(c3.Certificate)
|
||||
h3.buildNetworks(c3.Certificate.Networks(), c3.Certificate.UnsafeNetworks())
|
||||
|
||||
fw := NewFirewall(l, time.Second, time.Minute, time.Hour, c.Certificate)
|
||||
assert.Nil(t, fw.AddRule(true, firewall.ProtoAny, 1, 1, []string{}, "host1", netip.Prefix{}, netip.Prefix{}, "", ""))
|
||||
|
|
@ -446,8 +448,8 @@ func TestFirewall_DropConntrackReload(t *testing.T) {
|
|||
l.SetOutput(ob)
|
||||
|
||||
p := firewall.Packet{
|
||||
LocalIP: netip.MustParseAddr("1.2.3.4"),
|
||||
RemoteIP: netip.MustParseAddr("1.2.3.4"),
|
||||
LocalAddr: netip.MustParseAddr("1.2.3.4"),
|
||||
RemoteAddr: netip.MustParseAddr("1.2.3.4"),
|
||||
LocalPort: 10,
|
||||
RemotePort: 90,
|
||||
Protocol: firewall.ProtoUDP,
|
||||
|
|
@ -468,9 +470,9 @@ func TestFirewall_DropConntrackReload(t *testing.T) {
|
|||
ConnectionState: &ConnectionState{
|
||||
peerCert: &c,
|
||||
},
|
||||
vpnIp: network.Addr(),
|
||||
vpnAddrs: []netip.Addr{network.Addr()},
|
||||
}
|
||||
h.CreateRemoteCIDR(c.Certificate)
|
||||
h.buildNetworks(c.Certificate.Networks(), c.Certificate.UnsafeNetworks())
|
||||
|
||||
fw := NewFirewall(l, time.Second, time.Minute, time.Hour, c.Certificate)
|
||||
assert.Nil(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"any"}, "", netip.Prefix{}, netip.Prefix{}, "", ""))
|
||||
|
|
@ -574,8 +576,6 @@ func BenchmarkLookup(b *testing.B) {
|
|||
ml(m, a)
|
||||
}
|
||||
})
|
||||
|
||||
//TODO: only way array lookup in array will help is if both are sorted, then maybe it's faster
|
||||
}
|
||||
|
||||
func Test_parsePort(t *testing.T) {
|
||||
|
|
@ -622,55 +622,58 @@ func TestNewFirewallFromConfig(t *testing.T) {
|
|||
l := test.NewLogger()
|
||||
// Test a bad rule definition
|
||||
c := &dummyCert{}
|
||||
cs, err := newCertState(cert.Version2, nil, c, false, cert.Curve_CURVE25519, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
conf := config.NewC(l)
|
||||
conf.Settings["firewall"] = map[interface{}]interface{}{"outbound": "asdf"}
|
||||
_, err := NewFirewallFromConfig(l, c, conf)
|
||||
_, err = NewFirewallFromConfig(l, cs, conf)
|
||||
assert.EqualError(t, err, "firewall.outbound failed to parse, should be an array of rules")
|
||||
|
||||
// Test both port and code
|
||||
conf = config.NewC(l)
|
||||
conf.Settings["firewall"] = map[interface{}]interface{}{"outbound": []interface{}{map[interface{}]interface{}{"port": "1", "code": "2"}}}
|
||||
_, err = NewFirewallFromConfig(l, c, conf)
|
||||
_, err = NewFirewallFromConfig(l, cs, conf)
|
||||
assert.EqualError(t, err, "firewall.outbound rule #0; only one of port or code should be provided")
|
||||
|
||||
// Test missing host, group, cidr, ca_name and ca_sha
|
||||
conf = config.NewC(l)
|
||||
conf.Settings["firewall"] = map[interface{}]interface{}{"outbound": []interface{}{map[interface{}]interface{}{}}}
|
||||
_, err = NewFirewallFromConfig(l, c, conf)
|
||||
_, err = NewFirewallFromConfig(l, cs, conf)
|
||||
assert.EqualError(t, err, "firewall.outbound rule #0; at least one of host, group, cidr, local_cidr, ca_name, or ca_sha must be provided")
|
||||
|
||||
// Test code/port error
|
||||
conf = config.NewC(l)
|
||||
conf.Settings["firewall"] = map[interface{}]interface{}{"outbound": []interface{}{map[interface{}]interface{}{"code": "a", "host": "testh"}}}
|
||||
_, err = NewFirewallFromConfig(l, c, conf)
|
||||
_, err = NewFirewallFromConfig(l, cs, conf)
|
||||
assert.EqualError(t, err, "firewall.outbound rule #0; code was not a number; `a`")
|
||||
|
||||
conf.Settings["firewall"] = map[interface{}]interface{}{"outbound": []interface{}{map[interface{}]interface{}{"port": "a", "host": "testh"}}}
|
||||
_, err = NewFirewallFromConfig(l, c, conf)
|
||||
_, err = NewFirewallFromConfig(l, cs, conf)
|
||||
assert.EqualError(t, err, "firewall.outbound rule #0; port was not a number; `a`")
|
||||
|
||||
// Test proto error
|
||||
conf = config.NewC(l)
|
||||
conf.Settings["firewall"] = map[interface{}]interface{}{"outbound": []interface{}{map[interface{}]interface{}{"code": "1", "host": "testh"}}}
|
||||
_, err = NewFirewallFromConfig(l, c, conf)
|
||||
_, err = NewFirewallFromConfig(l, cs, conf)
|
||||
assert.EqualError(t, err, "firewall.outbound rule #0; proto was not understood; ``")
|
||||
|
||||
// Test cidr parse error
|
||||
conf = config.NewC(l)
|
||||
conf.Settings["firewall"] = map[interface{}]interface{}{"outbound": []interface{}{map[interface{}]interface{}{"code": "1", "cidr": "testh", "proto": "any"}}}
|
||||
_, err = NewFirewallFromConfig(l, c, conf)
|
||||
_, err = NewFirewallFromConfig(l, cs, conf)
|
||||
assert.EqualError(t, err, "firewall.outbound rule #0; cidr did not parse; netip.ParsePrefix(\"testh\"): no '/'")
|
||||
|
||||
// Test local_cidr parse error
|
||||
conf = config.NewC(l)
|
||||
conf.Settings["firewall"] = map[interface{}]interface{}{"outbound": []interface{}{map[interface{}]interface{}{"code": "1", "local_cidr": "testh", "proto": "any"}}}
|
||||
_, err = NewFirewallFromConfig(l, c, conf)
|
||||
_, err = NewFirewallFromConfig(l, cs, conf)
|
||||
assert.EqualError(t, err, "firewall.outbound rule #0; local_cidr did not parse; netip.ParsePrefix(\"testh\"): no '/'")
|
||||
|
||||
// Test both group and groups
|
||||
conf = config.NewC(l)
|
||||
conf.Settings["firewall"] = map[interface{}]interface{}{"inbound": []interface{}{map[interface{}]interface{}{"port": "1", "proto": "any", "group": "a", "groups": []string{"b", "c"}}}}
|
||||
_, err = NewFirewallFromConfig(l, c, conf)
|
||||
_, err = NewFirewallFromConfig(l, cs, conf)
|
||||
assert.EqualError(t, err, "firewall.inbound rule #0; only one of group or groups should be defined, both provided")
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue