create DB struct

This is step one in detaching the Database layer from Headscale (h). The
ultimate goal is to have all function that does database operations in
its own package, and keep the business logic and writing separate.

Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
This commit is contained in:
Kristoffer Dalby 2023-05-11 09:09:18 +02:00 committed by Kristoffer Dalby
parent b01f1f1867
commit 14e29a7bee
48 changed files with 1731 additions and 1572 deletions

View file

@ -30,8 +30,8 @@ func (s *Suite) TestBrokenHuJson(c *check.C) {
func (s *Suite) TestInvalidPolicyHuson(c *check.C) {
acl := []byte(`
{
"valid_json": true,
"but_a_policy_though": false
"valid_json": true,
"but_a_policy_though": false
}
`)
err := app.LoadACLPolicyFromBytes(acl, "hujson")
@ -60,129 +60,129 @@ func (s *Suite) TestParseInvalidCIDR(c *check.C) {
func (s *Suite) TestRuleInvalidGeneration(c *check.C) {
acl := []byte(`
{
// Declare static groups of users beyond those in the identity service.
"groups": {
"group:example": [
"user1@example.com",
"user2@example.com",
],
},
// Declare hostname aliases to use in place of IP addresses or subnets.
"hosts": {
"example-host-1": "100.100.100.100",
"example-host-2": "100.100.101.100/24",
},
// Define who is allowed to use which tags.
"tagOwners": {
// Everyone in the montreal-admins or global-admins group are
// allowed to tag servers as montreal-webserver.
"tag:montreal-webserver": [
"group:montreal-admins",
"group:global-admins",
],
// Only a few admins are allowed to create API servers.
"tag:api-server": [
"group:global-admins",
"example-host-1",
],
},
// Access control lists.
"acls": [
// Engineering users, plus the president, can access port 22 (ssh)
// and port 3389 (remote desktop protocol) on all servers, and all
// ports on git-server or ci-server.
{
"action": "accept",
"src": [
"group:engineering",
"president@example.com"
],
"dst": [
"*:22,3389",
"git-server:*",
"ci-server:*"
],
},
// Allow engineer users to access any port on a device tagged with
// tag:production.
{
"action": "accept",
"src": [
"group:engineers"
],
"dst": [
"tag:production:*"
],
},
// Allow servers in the my-subnet host and 192.168.1.0/24 to access hosts
// on both networks.
{
"action": "accept",
"src": [
"my-subnet",
"192.168.1.0/24"
],
"dst": [
"my-subnet:*",
"192.168.1.0/24:*"
],
},
// Allow every user of your network to access anything on the network.
// Comment out this section if you want to define specific ACL
// restrictions above.
{
"action": "accept",
"src": [
"*"
],
"dst": [
"*:*"
],
},
// All users in Montreal are allowed to access the Montreal web
// servers.
{
"action": "accept",
"src": [
"group:montreal-users"
],
"dst": [
"tag:montreal-webserver:80,443"
],
},
// Montreal web servers are allowed to make outgoing connections to
// the API servers, but only on https port 443.
// In contrast, this doesn't grant API servers the right to initiate
// any connections.
{
"action": "accept",
"src": [
"tag:montreal-webserver"
],
"dst": [
"tag:api-server:443"
],
},
],
// Declare tests to check functionality of ACL rules
"tests": [
{
"src": "user1@example.com",
"accept": [
"example-host-1:22",
"example-host-2:80"
],
"deny": [
"exapmle-host-2:100"
],
},
{
"src": "user2@example.com",
"accept": [
"100.60.3.4:22"
],
},
],
// Declare static groups of users beyond those in the identity service.
"groups": {
"group:example": [
"user1@example.com",
"user2@example.com",
],
},
// Declare hostname aliases to use in place of IP addresses or subnets.
"hosts": {
"example-host-1": "100.100.100.100",
"example-host-2": "100.100.101.100/24",
},
// Define who is allowed to use which tags.
"tagOwners": {
// Everyone in the montreal-admins or global-admins group are
// allowed to tag servers as montreal-webserver.
"tag:montreal-webserver": [
"group:montreal-admins",
"group:global-admins",
],
// Only a few admins are allowed to create API servers.
"tag:api-server": [
"group:global-admins",
"example-host-1",
],
},
// Access control lists.
"acls": [
// Engineering users, plus the president, can access port 22 (ssh)
// and port 3389 (remote desktop protocol) on all servers, and all
// ports on git-server or ci-server.
{
"action": "accept",
"src": [
"group:engineering",
"president@example.com"
],
"dst": [
"*:22,3389",
"git-server:*",
"ci-server:*"
],
},
// Allow engineer users to access any port on a device tagged with
// tag:production.
{
"action": "accept",
"src": [
"group:engineers"
],
"dst": [
"tag:production:*"
],
},
// Allow servers in the my-subnet host and 192.168.1.0/24 to access hosts
// on both networks.
{
"action": "accept",
"src": [
"my-subnet",
"192.168.1.0/24"
],
"dst": [
"my-subnet:*",
"192.168.1.0/24:*"
],
},
// Allow every user of your network to access anything on the network.
// Comment out this section if you want to define specific ACL
// restrictions above.
{
"action": "accept",
"src": [
"*"
],
"dst": [
"*:*"
],
},
// All users in Montreal are allowed to access the Montreal web
// servers.
{
"action": "accept",
"src": [
"group:montreal-users"
],
"dst": [
"tag:montreal-webserver:80,443"
],
},
// Montreal web servers are allowed to make outgoing connections to
// the API servers, but only on https port 443.
// In contrast, this doesn't grant API servers the right to initiate
// any connections.
{
"action": "accept",
"src": [
"tag:montreal-webserver"
],
"dst": [
"tag:api-server:443"
],
},
],
// Declare tests to check functionality of ACL rules
"tests": [
{
"src": "user1@example.com",
"accept": [
"example-host-1:22",
"example-host-2:80"
],
"deny": [
"exapmle-host-2:100"
],
},
{
"src": "user2@example.com",
"accept": [
"100.60.3.4:22"
],
},
],
}
`)
err := app.LoadACLPolicyFromBytes(acl, "hujson")
@ -192,24 +192,24 @@ func (s *Suite) TestRuleInvalidGeneration(c *check.C) {
func (s *Suite) TestBasicRule(c *check.C) {
acl := []byte(`
{
"hosts": {
"host-1": "100.100.100.100",
"subnet-1": "100.100.101.100/24",
},
"hosts": {
"host-1": "100.100.100.100",
"subnet-1": "100.100.101.100/24",
},
"acls": [
{
"action": "accept",
"src": [
"subnet-1",
"192.168.1.0/24"
],
"dst": [
"*:22,3389",
"host-1:*",
],
},
],
"acls": [
{
"action": "accept",
"src": [
"subnet-1",
"192.168.1.0/24"
],
"dst": [
"*:22,3389",
"host-1:*",
],
},
],
}
`)
err := app.LoadACLPolicyFromBytes(acl, "hujson")
@ -238,13 +238,13 @@ func (s *Suite) TestInvalidAction(c *check.C) {
func (s *Suite) TestSshRules(c *check.C) {
envknob.Setenv("HEADSCALE_EXPERIMENTAL_FEATURE_SSH", "1")
user, err := app.CreateUser("user1")
user, err := app.db.CreateUser("user1")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
pak, err := app.db.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("user1", "testmachine")
_, err = app.db.GetMachine("user1", "testmachine")
c.Assert(err, check.NotNil)
hostInfo := tailcfg.Hostinfo{
OS: "centos",
@ -264,7 +264,7 @@ func (s *Suite) TestSshRules(c *check.C) {
AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo),
}
app.db.Save(&machine)
app.db.db.Save(&machine)
app.aclPolicy = &ACLPolicy{
Groups: Groups{
@ -348,13 +348,13 @@ func (s *Suite) TestInvalidTagOwners(c *check.C) {
// match properly the IP's of the related hosts. The owner is valid and the tag is also valid.
// the tag is matched in the Sources section.
func (s *Suite) TestValidExpandTagOwnersInSources(c *check.C) {
user, err := app.CreateUser("user1")
user, err := app.db.CreateUser("user1")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
pak, err := app.db.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("user1", "testmachine")
_, err = app.db.GetMachine("user1", "testmachine")
c.Assert(err, check.NotNil)
hostInfo := tailcfg.Hostinfo{
OS: "centos",
@ -374,7 +374,7 @@ func (s *Suite) TestValidExpandTagOwnersInSources(c *check.C) {
AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo),
}
app.db.Save(&machine)
app.db.db.Save(&machine)
app.aclPolicy = &ACLPolicy{
Groups: Groups{"group:test": []string{"user1", "user2"}},
@ -398,13 +398,13 @@ func (s *Suite) TestValidExpandTagOwnersInSources(c *check.C) {
// match properly the IP's of the related hosts. The owner is valid and the tag is also valid.
// the tag is matched in the Destinations section.
func (s *Suite) TestValidExpandTagOwnersInDestinations(c *check.C) {
user, err := app.CreateUser("user1")
user, err := app.db.CreateUser("user1")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
pak, err := app.db.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("user1", "testmachine")
_, err = app.db.GetMachine("user1", "testmachine")
c.Assert(err, check.NotNil)
hostInfo := tailcfg.Hostinfo{
OS: "centos",
@ -424,7 +424,7 @@ func (s *Suite) TestValidExpandTagOwnersInDestinations(c *check.C) {
AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo),
}
app.db.Save(&machine)
app.db.db.Save(&machine)
app.aclPolicy = &ACLPolicy{
Groups: Groups{"group:test": []string{"user1", "user2"}},
@ -448,13 +448,13 @@ func (s *Suite) TestValidExpandTagOwnersInDestinations(c *check.C) {
// tag on a host that isn't owned by a tag owners. So the user
// of the host should be valid.
func (s *Suite) TestInvalidTagValidUser(c *check.C) {
user, err := app.CreateUser("user1")
user, err := app.db.CreateUser("user1")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
pak, err := app.db.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("user1", "testmachine")
_, err = app.db.GetMachine("user1", "testmachine")
c.Assert(err, check.NotNil)
hostInfo := tailcfg.Hostinfo{
OS: "centos",
@ -474,7 +474,7 @@ func (s *Suite) TestInvalidTagValidUser(c *check.C) {
AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo),
}
app.db.Save(&machine)
app.db.db.Save(&machine)
app.aclPolicy = &ACLPolicy{
TagOwners: TagOwners{"tag:test": []string{"user1"}},
@ -497,13 +497,13 @@ func (s *Suite) TestInvalidTagValidUser(c *check.C) {
// an ACL rule is matching the tag to a user. It should not be valid since the
// host should be tied to the tag now.
func (s *Suite) TestValidTagInvalidUser(c *check.C) {
user, err := app.CreateUser("user1")
user, err := app.db.CreateUser("user1")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
pak, err := app.db.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("user1", "webserver")
_, err = app.db.GetMachine("user1", "webserver")
c.Assert(err, check.NotNil)
hostInfo := tailcfg.Hostinfo{
OS: "centos",
@ -523,8 +523,8 @@ func (s *Suite) TestValidTagInvalidUser(c *check.C) {
AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo),
}
app.db.Save(&machine)
_, err = app.GetMachine("user1", "user")
app.db.db.Save(&machine)
_, err = app.db.GetMachine("user1", "user")
hostInfo2 := tailcfg.Hostinfo{
OS: "debian",
Hostname: "Hostname",
@ -542,7 +542,7 @@ func (s *Suite) TestValidTagInvalidUser(c *check.C) {
AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo2),
}
app.db.Save(&machine)
app.db.db.Save(&machine)
app.aclPolicy = &ACLPolicy{
TagOwners: TagOwners{"tag:webapp": []string{"user1"}},
@ -571,22 +571,22 @@ func (s *Suite) TestValidTagInvalidUser(c *check.C) {
func (s *Suite) TestPortRange(c *check.C) {
acl := []byte(`
{
"hosts": {
"host-1": "100.100.100.100",
"subnet-1": "100.100.101.100/24",
},
"hosts": {
"host-1": "100.100.100.100",
"subnet-1": "100.100.101.100/24",
},
"acls": [
{
"action": "accept",
"src": [
"subnet-1",
],
"dst": [
"host-1:5400-5500",
],
},
],
"acls": [
{
"action": "accept",
"src": [
"subnet-1",
],
"dst": [
"host-1:5400-5500",
],
},
],
}
`)
err := app.LoadACLPolicyFromBytes(acl, "hujson")
@ -605,43 +605,43 @@ func (s *Suite) TestPortRange(c *check.C) {
func (s *Suite) TestProtocolParsing(c *check.C) {
acl := []byte(`
{
"hosts": {
"host-1": "100.100.100.100",
"subnet-1": "100.100.101.100/24",
},
"hosts": {
"host-1": "100.100.100.100",
"subnet-1": "100.100.101.100/24",
},
"acls": [
{
"Action": "accept",
"src": [
"*",
],
"proto": "tcp",
"dst": [
"host-1:*",
],
},
{
"Action": "accept",
"src": [
"*",
],
"proto": "udp",
"dst": [
"host-1:53",
],
},
{
"Action": "accept",
"src": [
"*",
],
"proto": "icmp",
"dst": [
"host-1:*",
],
},
],
"acls": [
{
"Action": "accept",
"src": [
"*",
],
"proto": "tcp",
"dst": [
"host-1:*",
],
},
{
"Action": "accept",
"src": [
"*",
],
"proto": "udp",
"dst": [
"host-1:53",
],
},
{
"Action": "accept",
"src": [
"*",
],
"proto": "icmp",
"dst": [
"host-1:*",
],
},
],
}
`)
err := app.LoadACLPolicyFromBytes(acl, "hujson")
@ -660,22 +660,22 @@ func (s *Suite) TestProtocolParsing(c *check.C) {
func (s *Suite) TestPortWildcard(c *check.C) {
acl := []byte(`
{
"hosts": {
"host-1": "100.100.100.100",
"subnet-1": "100.100.101.100/24",
},
"hosts": {
"host-1": "100.100.100.100",
"subnet-1": "100.100.101.100/24",
},
"acls": [
{
"Action": "accept",
"src": [
"*",
],
"dst": [
"host-1:*",
],
},
],
"acls": [
{
"Action": "accept",
"src": [
"*",
],
"dst": [
"host-1:*",
],
},
],
}
`)
err := app.LoadACLPolicyFromBytes(acl, "hujson")
@ -694,8 +694,7 @@ func (s *Suite) TestPortWildcard(c *check.C) {
}
func (s *Suite) TestPortWildcardYAML(c *check.C) {
acl := []byte(`
---
acl := []byte(`---
hosts:
host-1: 100.100.100.100/32
subnet-1: 100.100.101.100/24
@ -704,8 +703,7 @@ acls:
src:
- "*"
dst:
- host-1:*
`)
- host-1:*`)
err := app.LoadACLPolicyFromBytes(acl, "yaml")
c.Assert(err, check.IsNil)
@ -722,15 +720,15 @@ acls:
}
func (s *Suite) TestPortUser(c *check.C) {
user, err := app.CreateUser("testuser")
user, err := app.db.CreateUser("testuser")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
pak, err := app.db.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("testuser", "testmachine")
_, err = app.db.GetMachine("testuser", "testmachine")
c.Assert(err, check.NotNil)
ips, _ := app.getAvailableIPs()
ips, _ := app.db.getAvailableIPs()
machine := Machine{
ID: 0,
MachineKey: "12345",
@ -742,32 +740,32 @@ func (s *Suite) TestPortUser(c *check.C) {
IPAddresses: ips,
AuthKeyID: uint(pak.ID),
}
app.db.Save(&machine)
app.db.db.Save(&machine)
acl := []byte(`
{
"hosts": {
"host-1": "100.100.100.100",
"subnet-1": "100.100.101.100/24",
},
"hosts": {
"host-1": "100.100.100.100",
"subnet-1": "100.100.101.100/24",
},
"acls": [
{
"action": "accept",
"src": [
"testuser",
],
"dst": [
"host-1:*",
],
},
],
"acls": [
{
"action": "accept",
"src": [
"testuser",
],
"dst": [
"host-1:*",
],
},
],
}
`)
err = app.LoadACLPolicyFromBytes(acl, "hujson")
c.Assert(err, check.IsNil)
machines, err := app.ListMachines()
machines, err := app.db.ListMachines()
c.Assert(err, check.IsNil)
rules, err := app.aclPolicy.generateFilterRules(machines, false)
@ -785,15 +783,15 @@ func (s *Suite) TestPortUser(c *check.C) {
}
func (s *Suite) TestPortGroup(c *check.C) {
user, err := app.CreateUser("testuser")
user, err := app.db.CreateUser("testuser")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
pak, err := app.db.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("testuser", "testmachine")
_, err = app.db.GetMachine("testuser", "testmachine")
c.Assert(err, check.NotNil)
ips, _ := app.getAvailableIPs()
ips, _ := app.db.getAvailableIPs()
machine := Machine{
ID: 0,
MachineKey: "foo",
@ -805,38 +803,38 @@ func (s *Suite) TestPortGroup(c *check.C) {
IPAddresses: ips,
AuthKeyID: uint(pak.ID),
}
app.db.Save(&machine)
app.db.db.Save(&machine)
acl := []byte(`
{
"groups": {
"group:example": [
"testuser",
],
},
"groups": {
"group:example": [
"testuser",
],
},
"hosts": {
"host-1": "100.100.100.100",
"subnet-1": "100.100.101.100/24",
},
"hosts": {
"host-1": "100.100.100.100",
"subnet-1": "100.100.101.100/24",
},
"acls": [
{
"action": "accept",
"src": [
"group:example",
],
"dst": [
"host-1:*",
],
},
],
"acls": [
{
"action": "accept",
"src": [
"group:example",
],
"dst": [
"host-1:*",
],
},
],
}
`)
err = app.LoadACLPolicyFromBytes(acl, "hujson")
c.Assert(err, check.IsNil)
machines, err := app.ListMachines()
machines, err := app.db.ListMachines()
c.Assert(err, check.IsNil)
rules, err := app.aclPolicy.generateFilterRules(machines, false)