mirror of
https://github.com/juanfont/headscale.git
synced 2026-01-23 02:24:10 +00:00
integration: support auth keys without user
Add AuthKeyOptions to create auth keys owned by tags only.
This commit is contained in:
parent
3b4b9a4436
commit
740d2b5a2c
3 changed files with 70 additions and 53 deletions
|
|
@ -8,6 +8,7 @@ import (
|
||||||
policyv2 "github.com/juanfont/headscale/hscontrol/policy/v2"
|
policyv2 "github.com/juanfont/headscale/hscontrol/policy/v2"
|
||||||
"github.com/juanfont/headscale/hscontrol/routes"
|
"github.com/juanfont/headscale/hscontrol/routes"
|
||||||
"github.com/juanfont/headscale/hscontrol/types"
|
"github.com/juanfont/headscale/hscontrol/types"
|
||||||
|
"github.com/juanfont/headscale/integration/hsic"
|
||||||
"github.com/ory/dockertest/v3"
|
"github.com/ory/dockertest/v3"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
)
|
)
|
||||||
|
|
@ -25,6 +26,7 @@ type ControlServer interface {
|
||||||
CreateUser(user string) (*v1.User, error)
|
CreateUser(user string) (*v1.User, error)
|
||||||
CreateAuthKey(user uint64, reusable bool, ephemeral bool) (*v1.PreAuthKey, error)
|
CreateAuthKey(user uint64, reusable bool, ephemeral bool) (*v1.PreAuthKey, error)
|
||||||
CreateAuthKeyWithTags(user uint64, reusable bool, ephemeral bool, tags []string) (*v1.PreAuthKey, error)
|
CreateAuthKeyWithTags(user uint64, reusable bool, ephemeral bool, tags []string) (*v1.PreAuthKey, error)
|
||||||
|
CreateAuthKeyWithOptions(opts hsic.AuthKeyOptions) (*v1.PreAuthKey, error)
|
||||||
DeleteAuthKey(user uint64, key string) error
|
DeleteAuthKey(user uint64, key string) error
|
||||||
ListNodes(users ...string) ([]*v1.Node, error)
|
ListNodes(users ...string) ([]*v1.Node, error)
|
||||||
DeleteNode(nodeID uint64) error
|
DeleteNode(nodeID uint64) error
|
||||||
|
|
|
||||||
|
|
@ -1067,33 +1067,52 @@ func (t *HeadscaleInContainer) CreateUser(
|
||||||
return &u, nil
|
return &u, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateAuthKey creates a new "authorisation key" for a User that can be used
|
// AuthKeyOptions defines options for creating an auth key.
|
||||||
// to authorise a TailscaleClient with the Headscale instance.
|
type AuthKeyOptions struct {
|
||||||
func (t *HeadscaleInContainer) CreateAuthKey(
|
// User is the user ID that owns the auth key. If nil and Tags are specified,
|
||||||
user uint64,
|
// the auth key is owned by the tags only (tags-as-identity model).
|
||||||
reusable bool,
|
User *uint64
|
||||||
ephemeral bool,
|
// Reusable indicates if the key can be used multiple times
|
||||||
) (*v1.PreAuthKey, error) {
|
Reusable bool
|
||||||
|
// Ephemeral indicates if nodes registered with this key should be ephemeral
|
||||||
|
Ephemeral bool
|
||||||
|
// Tags are the tags to assign to the auth key
|
||||||
|
Tags []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateAuthKeyWithOptions creates a new "authorisation key" with the specified options.
|
||||||
|
// This supports both user-owned and tags-only auth keys.
|
||||||
|
func (t *HeadscaleInContainer) CreateAuthKeyWithOptions(opts AuthKeyOptions) (*v1.PreAuthKey, error) {
|
||||||
command := []string{
|
command := []string{
|
||||||
"headscale",
|
"headscale",
|
||||||
"--user",
|
}
|
||||||
strconv.FormatUint(user, 10),
|
|
||||||
|
// Only add --user flag if User is specified
|
||||||
|
if opts.User != nil {
|
||||||
|
command = append(command, "--user", strconv.FormatUint(*opts.User, 10))
|
||||||
|
}
|
||||||
|
|
||||||
|
command = append(command,
|
||||||
"preauthkeys",
|
"preauthkeys",
|
||||||
"create",
|
"create",
|
||||||
"--expiration",
|
"--expiration",
|
||||||
"24h",
|
"24h",
|
||||||
"--output",
|
"--output",
|
||||||
"json",
|
"json",
|
||||||
}
|
)
|
||||||
|
|
||||||
if reusable {
|
if opts.Reusable {
|
||||||
command = append(command, "--reusable")
|
command = append(command, "--reusable")
|
||||||
}
|
}
|
||||||
|
|
||||||
if ephemeral {
|
if opts.Ephemeral {
|
||||||
command = append(command, "--ephemeral")
|
command = append(command, "--ephemeral")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(opts.Tags) > 0 {
|
||||||
|
command = append(command, "--tags", strings.Join(opts.Tags, ","))
|
||||||
|
}
|
||||||
|
|
||||||
result, _, err := dockertestutil.ExecuteCommand(
|
result, _, err := dockertestutil.ExecuteCommand(
|
||||||
t.container,
|
t.container,
|
||||||
command,
|
command,
|
||||||
|
|
@ -1104,6 +1123,7 @@ func (t *HeadscaleInContainer) CreateAuthKey(
|
||||||
}
|
}
|
||||||
|
|
||||||
var preAuthKey v1.PreAuthKey
|
var preAuthKey v1.PreAuthKey
|
||||||
|
|
||||||
err = json.Unmarshal([]byte(result), &preAuthKey)
|
err = json.Unmarshal([]byte(result), &preAuthKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to unmarshal auth key: %w", err)
|
return nil, fmt.Errorf("failed to unmarshal auth key: %w", err)
|
||||||
|
|
@ -1112,6 +1132,20 @@ func (t *HeadscaleInContainer) CreateAuthKey(
|
||||||
return &preAuthKey, nil
|
return &preAuthKey, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateAuthKey creates a new "authorisation key" for a User that can be used
|
||||||
|
// to authorise a TailscaleClient with the Headscale instance.
|
||||||
|
func (t *HeadscaleInContainer) CreateAuthKey(
|
||||||
|
user uint64,
|
||||||
|
reusable bool,
|
||||||
|
ephemeral bool,
|
||||||
|
) (*v1.PreAuthKey, error) {
|
||||||
|
return t.CreateAuthKeyWithOptions(AuthKeyOptions{
|
||||||
|
User: &user,
|
||||||
|
Reusable: reusable,
|
||||||
|
Ephemeral: ephemeral,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// CreateAuthKeyWithTags creates a new "authorisation key" for a User with the specified tags.
|
// CreateAuthKeyWithTags creates a new "authorisation key" for a User with the specified tags.
|
||||||
// This is used to create tagged PreAuthKeys for testing the tags-as-identity model.
|
// This is used to create tagged PreAuthKeys for testing the tags-as-identity model.
|
||||||
func (t *HeadscaleInContainer) CreateAuthKeyWithTags(
|
func (t *HeadscaleInContainer) CreateAuthKeyWithTags(
|
||||||
|
|
@ -1120,47 +1154,12 @@ func (t *HeadscaleInContainer) CreateAuthKeyWithTags(
|
||||||
ephemeral bool,
|
ephemeral bool,
|
||||||
tags []string,
|
tags []string,
|
||||||
) (*v1.PreAuthKey, error) {
|
) (*v1.PreAuthKey, error) {
|
||||||
command := []string{
|
return t.CreateAuthKeyWithOptions(AuthKeyOptions{
|
||||||
"headscale",
|
User: &user,
|
||||||
"--user",
|
Reusable: reusable,
|
||||||
strconv.FormatUint(user, 10),
|
Ephemeral: ephemeral,
|
||||||
"preauthkeys",
|
Tags: tags,
|
||||||
"create",
|
})
|
||||||
"--expiration",
|
|
||||||
"24h",
|
|
||||||
"--output",
|
|
||||||
"json",
|
|
||||||
}
|
|
||||||
|
|
||||||
if reusable {
|
|
||||||
command = append(command, "--reusable")
|
|
||||||
}
|
|
||||||
|
|
||||||
if ephemeral {
|
|
||||||
command = append(command, "--ephemeral")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(tags) > 0 {
|
|
||||||
command = append(command, "--tags", strings.Join(tags, ","))
|
|
||||||
}
|
|
||||||
|
|
||||||
result, _, err := dockertestutil.ExecuteCommand(
|
|
||||||
t.container,
|
|
||||||
command,
|
|
||||||
[]string{},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to execute create auth key with tags command: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var preAuthKey v1.PreAuthKey
|
|
||||||
|
|
||||||
err = json.Unmarshal([]byte(result), &preAuthKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to unmarshal auth key: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &preAuthKey, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteAuthKey deletes an "authorisation key" for a User.
|
// DeleteAuthKey deletes an "authorisation key" for a User.
|
||||||
|
|
|
||||||
|
|
@ -478,6 +478,22 @@ func (s *Scenario) CreatePreAuthKey(
|
||||||
return nil, fmt.Errorf("failed to create user: %w", errNoHeadscaleAvailable)
|
return nil, fmt.Errorf("failed to create user: %w", errNoHeadscaleAvailable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreatePreAuthKeyWithOptions creates a "pre authorised key" with the specified options
|
||||||
|
// to be created in the Headscale instance on behalf of the Scenario.
|
||||||
|
func (s *Scenario) CreatePreAuthKeyWithOptions(opts hsic.AuthKeyOptions) (*v1.PreAuthKey, error) {
|
||||||
|
headscale, err := s.Headscale()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create preauth key with options: %w", errNoHeadscaleAvailable)
|
||||||
|
}
|
||||||
|
|
||||||
|
key, err := headscale.CreateAuthKeyWithOptions(opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create preauth key with options: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return key, nil
|
||||||
|
}
|
||||||
|
|
||||||
// CreatePreAuthKeyWithTags creates a "pre authorised key" with the specified tags
|
// CreatePreAuthKeyWithTags creates a "pre authorised key" with the specified tags
|
||||||
// to be created in the Headscale instance on behalf of the Scenario.
|
// to be created in the Headscale instance on behalf of the Scenario.
|
||||||
func (s *Scenario) CreatePreAuthKeyWithTags(
|
func (s *Scenario) CreatePreAuthKeyWithTags(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue