You've already forked ionscale
mirror of
https://github.com/jsiebens/ionscale.git
synced 2026-04-06 13:02:58 +01:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 45572397ea | |||
| e5a3d3c589 | |||
| 2a5fe7f136 | |||
| 7ee4b27688 | |||
| 69f7c22307 | |||
| 4e5f89ab7e | |||
| c1ffe03e81 | |||
| 7ad91c4c20 | |||
| fb04248db4 | |||
| d84bad12d0 | |||
| cadf938e2a | |||
| 980ae6dd85 | |||
| 6e3e22bc72 | |||
| 0051eec355 | |||
| 617575803c | |||
| 8c6ea9041b |
@@ -4,6 +4,9 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -19,4 +22,5 @@ jobs:
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
go test ./...
|
||||
go build cmd/ionscale/main.go
|
||||
@@ -0,0 +1,48 @@
|
||||
name: "Security Analysis"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0'
|
||||
|
||||
jobs:
|
||||
codeql:
|
||||
name: CodeQL
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: go
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
|
||||
trivy:
|
||||
name: Trivy
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
security-events: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Run Trivy vulnerability scanner
|
||||
uses: aquasecurity/trivy-action@master
|
||||
with:
|
||||
image-ref: ghcr.io/jsiebens/ionscale:latest
|
||||
format: 'sarif'
|
||||
output: 'trivy-results.sarif'
|
||||
- name: Upload Trivy scan results
|
||||
uses: github/codeql-action/upload-sarif@v1
|
||||
with:
|
||||
sarif_file: 'trivy-results.sarif'
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/lib/pq"
|
||||
"github.com/pkg/errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -16,13 +15,9 @@ type pgPubsub struct {
|
||||
target Pubsub
|
||||
}
|
||||
|
||||
// NewPubsub creates a new Pubsub implementation using a PostgreSQL connection.
|
||||
func NewPubsub(ctx context.Context, database *sql.DB, connectURL string) (Pubsub, error) {
|
||||
// Creates a new listener using pq.
|
||||
errCh := make(chan error)
|
||||
listener := pq.NewListener(connectURL, time.Second, time.Minute, func(event pq.ListenerEventType, err error) {
|
||||
// This callback gets events whenever the connection state changes.
|
||||
// Don't send if the errChannel has already been closed.
|
||||
select {
|
||||
case <-errCh:
|
||||
return
|
||||
@@ -35,14 +30,14 @@ func NewPubsub(ctx context.Context, database *sql.DB, connectURL string) (Pubsub
|
||||
select {
|
||||
case err := <-errCh:
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("create pq listener: %w", err)
|
||||
return nil, fmt.Errorf("create pq listener: %w", err)
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
|
||||
if err := listener.Listen("ionscale_events"); err != nil {
|
||||
return nil, errors.Errorf("listen: %w", err)
|
||||
return nil, fmt.Errorf("listen: %w", err)
|
||||
}
|
||||
|
||||
pubsub := &pgPubsub{
|
||||
@@ -55,7 +50,6 @@ func NewPubsub(ctx context.Context, database *sql.DB, connectURL string) (Pubsub
|
||||
return pubsub, nil
|
||||
}
|
||||
|
||||
// Close closes the pubsub instance.
|
||||
func (p *pgPubsub) Close() error {
|
||||
return p.pgListener.Close()
|
||||
}
|
||||
@@ -75,18 +69,14 @@ func (p *pgPubsub) Publish(tailnet uint64, message *Signal) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// This is safe because we are calling pq.QuoteLiteral. pg_notify doesn't
|
||||
// support the first parameter being a prepared statement.
|
||||
//nolint:gosec
|
||||
_, err = p.db.ExecContext(context.Background(), `select pg_notify(`+pq.QuoteLiteral("ionscale_events")+`, $1)`, payload)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return errors.Errorf("exec pg_notify: %w", err)
|
||||
return fmt.Errorf("exec pg_notify: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// listen begins receiving messages on the pq listener.
|
||||
func (p *pgPubsub) listen(ctx context.Context) {
|
||||
var (
|
||||
notif *pq.Notification
|
||||
|
||||
+111
-53
@@ -29,6 +29,8 @@ func machineCommands() *coral.Command {
|
||||
command.AddCommand(enableMachineRoutesCommand())
|
||||
command.AddCommand(disableMachineRoutesCommand())
|
||||
command.AddCommand(enableMachineKeyExpiryCommand())
|
||||
command.AddCommand(enableExitNodeCommand())
|
||||
command.AddCommand(disableExitNodeCommand())
|
||||
command.AddCommand(disableMachineKeyExpiryCommand())
|
||||
|
||||
return command
|
||||
@@ -126,6 +128,16 @@ func getMachineCommand() *coral.Command {
|
||||
}
|
||||
}
|
||||
|
||||
if m.AdvertisedExitNode {
|
||||
if m.EnabledExitNode {
|
||||
fmt.Fprintf(w, "%s\t%s\n", "Exit node", "enabled")
|
||||
} else {
|
||||
fmt.Fprintf(w, "%s\t%s\n", "Exit node", "disabled")
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintf(w, "%s\t%s\n", "Exit node", "no")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -279,25 +291,7 @@ func getMachineRoutesCommand() *coral.Command {
|
||||
return err
|
||||
}
|
||||
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(os.Stdout, 8, 8, 0, '\t', 0)
|
||||
defer w.Flush()
|
||||
|
||||
for i, t := range resp.Msg.AdvertisedRoutes {
|
||||
if i == 0 {
|
||||
fmt.Fprintf(w, "%s\t%s\n", "Advertised routes", t)
|
||||
} else {
|
||||
fmt.Fprintf(w, "%s\t%s\n", "", t)
|
||||
}
|
||||
}
|
||||
|
||||
for i, t := range resp.Msg.EnabledRoutes {
|
||||
if i == 0 {
|
||||
fmt.Fprintf(w, "%s\t%s\n", "Enabled routes", t)
|
||||
} else {
|
||||
fmt.Fprintf(w, "%s\t%s\n", "", t)
|
||||
}
|
||||
}
|
||||
printMachinesRoutesResponse(resp.Msg)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -341,25 +335,7 @@ func enableMachineRoutesCommand() *coral.Command {
|
||||
return err
|
||||
}
|
||||
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(os.Stdout, 8, 8, 0, '\t', 0)
|
||||
defer w.Flush()
|
||||
|
||||
for i, t := range resp.Msg.AdvertisedRoutes {
|
||||
if i == 0 {
|
||||
fmt.Fprintf(w, "%s\t%s\n", "Advertised routes", t)
|
||||
} else {
|
||||
fmt.Fprintf(w, "%s\t%s\n", "", t)
|
||||
}
|
||||
}
|
||||
|
||||
for i, t := range resp.Msg.EnabledRoutes {
|
||||
if i == 0 {
|
||||
fmt.Fprintf(w, "%s\t%s\n", "Enabled routes", t)
|
||||
} else {
|
||||
fmt.Fprintf(w, "%s\t%s\n", "", t)
|
||||
}
|
||||
}
|
||||
printMachinesRoutesResponse(resp.Msg)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -401,26 +377,76 @@ func disableMachineRoutesCommand() *coral.Command {
|
||||
return err
|
||||
}
|
||||
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(os.Stdout, 8, 8, 0, '\t', 0)
|
||||
defer w.Flush()
|
||||
printMachinesRoutesResponse(resp.Msg)
|
||||
|
||||
for i, t := range resp.Msg.AdvertisedRoutes {
|
||||
if i == 0 {
|
||||
fmt.Fprintf(w, "%s\t%s\n", "Advertised routes", t)
|
||||
} else {
|
||||
fmt.Fprintf(w, "%s\t%s\n", "", t)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return command
|
||||
}
|
||||
|
||||
func enableExitNodeCommand() *coral.Command {
|
||||
command := &coral.Command{
|
||||
Use: "enable-exit-node",
|
||||
Short: "Enable given machine as an exit node",
|
||||
SilenceUsage: true,
|
||||
}
|
||||
|
||||
var machineID uint64
|
||||
var target = Target{}
|
||||
target.prepareCommand(command)
|
||||
command.Flags().Uint64Var(&machineID, "machine-id", 0, "Machine ID")
|
||||
|
||||
_ = command.MarkFlagRequired("machine-id")
|
||||
|
||||
command.RunE = func(command *coral.Command, args []string) error {
|
||||
client, err := target.createGRPCClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i, t := range resp.Msg.EnabledRoutes {
|
||||
if i == 0 {
|
||||
fmt.Fprintf(w, "%s\t%s\n", "Enabled routes", t)
|
||||
} else {
|
||||
fmt.Fprintf(w, "%s\t%s\n", "", t)
|
||||
}
|
||||
req := api.EnableExitNodeRequest{MachineId: machineID}
|
||||
resp, err := client.EnableExitNode(context.Background(), connect.NewRequest(&req))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printMachinesRoutesResponse(resp.Msg)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return command
|
||||
}
|
||||
|
||||
func disableExitNodeCommand() *coral.Command {
|
||||
command := &coral.Command{
|
||||
Use: "disable-exit-node",
|
||||
Short: "Disable given machine as an exit node",
|
||||
SilenceUsage: true,
|
||||
}
|
||||
|
||||
var machineID uint64
|
||||
var target = Target{}
|
||||
target.prepareCommand(command)
|
||||
command.Flags().Uint64Var(&machineID, "machine-id", 0, "Machine ID")
|
||||
|
||||
_ = command.MarkFlagRequired("machine-id")
|
||||
|
||||
command.RunE = func(command *coral.Command, args []string) error {
|
||||
client, err := target.createGRPCClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req := api.DisableExitNodeRequest{MachineId: machineID}
|
||||
resp, err := client.DisableExitNode(context.Background(), connect.NewRequest(&req))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printMachinesRoutesResponse(resp.Msg)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -472,3 +498,35 @@ func configureSetMachineKeyExpiryCommand(command *coral.Command, v bool) *coral.
|
||||
|
||||
return command
|
||||
}
|
||||
|
||||
func printMachinesRoutesResponse(msg *api.GetMachineRoutesResponse) {
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(os.Stdout, 8, 8, 0, '\t', 0)
|
||||
defer w.Flush()
|
||||
|
||||
for i, t := range msg.AdvertisedRoutes {
|
||||
if i == 0 {
|
||||
fmt.Fprintf(w, "%s\t%s\n", "Advertised routes", t)
|
||||
} else {
|
||||
fmt.Fprintf(w, "%s\t%s\n", "", t)
|
||||
}
|
||||
}
|
||||
|
||||
for i, t := range msg.EnabledRoutes {
|
||||
if i == 0 {
|
||||
fmt.Fprintf(w, "%s\t%s\n", "Enabled routes", t)
|
||||
} else {
|
||||
fmt.Fprintf(w, "%s\t%s\n", "", t)
|
||||
}
|
||||
}
|
||||
|
||||
if msg.AdvertisedExitNode {
|
||||
if msg.EnabledExitNode {
|
||||
fmt.Fprintf(w, "%s\t%s\n", "Exit node", "enabled")
|
||||
} else {
|
||||
fmt.Fprintf(w, "%s\t%s\n", "Exit node", "disabled")
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintf(w, "%s\t%s\n", "Exit node", "no")
|
||||
}
|
||||
}
|
||||
|
||||
+1
-45
@@ -4,7 +4,6 @@ import (
|
||||
"github.com/jsiebens/ionscale/internal/config"
|
||||
"github.com/jsiebens/ionscale/internal/server"
|
||||
"github.com/muesli/coral"
|
||||
"time"
|
||||
)
|
||||
|
||||
func serverCommand() *coral.Command {
|
||||
@@ -14,15 +13,13 @@ func serverCommand() *coral.Command {
|
||||
SilenceUsage: true,
|
||||
}
|
||||
|
||||
var cbf = configByFlags{}
|
||||
var configFile string
|
||||
|
||||
cbf.prepareCommand(command)
|
||||
command.Flags().StringVarP(&configFile, "config", "c", "", "Path to the configuration file.")
|
||||
|
||||
command.RunE = func(command *coral.Command, args []string) error {
|
||||
|
||||
c, err := config.LoadConfig(configFile, &cbf.c)
|
||||
c, err := config.LoadConfig(configFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -32,44 +29,3 @@ func serverCommand() *coral.Command {
|
||||
|
||||
return command
|
||||
}
|
||||
|
||||
type configByFlags struct {
|
||||
c config.Config
|
||||
}
|
||||
|
||||
func (c *configByFlags) prepareCommand(cmd *coral.Command) {
|
||||
cmd.Flags().StringVar(&c.c.HttpListenAddr, "http-listen-addr", "", "")
|
||||
cmd.Flags().StringVar(&c.c.HttpsListenAddr, "https-listen-addr", "", "")
|
||||
cmd.Flags().StringVar(&c.c.MetricsListenAddr, "metrics-listen-addr", "", "")
|
||||
cmd.Flags().StringVar(&c.c.ServerUrl, "server-url", "", "")
|
||||
|
||||
cmd.Flags().BoolVar(&c.c.Tls.Disable, "tls-disable", false, "")
|
||||
cmd.Flags().BoolVar(&c.c.Tls.ForceHttps, "tls-force-https", true, "")
|
||||
cmd.Flags().StringVar(&c.c.Tls.CertFile, "tls-cert-file", "", "")
|
||||
cmd.Flags().StringVar(&c.c.Tls.KeyFile, "tls-key-file", "", "")
|
||||
cmd.Flags().BoolVar(&c.c.Tls.AcmeEnabled, "tls-acme", false, "")
|
||||
cmd.Flags().StringVar(&c.c.Tls.AcmeEmail, "tls-acme-email", "", "")
|
||||
cmd.Flags().StringVar(&c.c.Tls.AcmeCA, "tls-acme-ca", "", "")
|
||||
cmd.Flags().StringVar(&c.c.Tls.AcmePath, "tls-acme-path", "", "")
|
||||
|
||||
cmd.Flags().DurationVar(&c.c.PollNet.KeepAliveInterval, "poll-net-keep-alive-interval", 1*time.Minute, "")
|
||||
|
||||
cmd.Flags().StringVar(&c.c.Keys.SystemAdminKey, "system-admin-key", "", "")
|
||||
cmd.Flags().StringVar(&c.c.Keys.ControlKey, "control-key", "", "")
|
||||
cmd.Flags().StringVar(&c.c.Keys.LegacyControlKey, "legacy-control-key", "", "")
|
||||
|
||||
cmd.Flags().StringVar(&c.c.Database.Type, "database-type", "", "")
|
||||
cmd.Flags().StringVar(&c.c.Database.Url, "database-url", "", "")
|
||||
|
||||
cmd.Flags().StringVar(&c.c.AuthProvider.Issuer, "auth-provider-issuer", "", "")
|
||||
cmd.Flags().StringVar(&c.c.AuthProvider.ClientID, "auth-provider-client-id", "", "")
|
||||
cmd.Flags().StringVar(&c.c.AuthProvider.ClientSecret, "auth-provider-client-secret", "", "")
|
||||
cmd.Flags().StringSliceVar(&c.c.AuthProvider.Scopes, "auth-provider-additional-scopes", []string{}, "")
|
||||
cmd.Flags().StringSliceVar(&c.c.AuthProvider.SystemAdminPolicy.Subs, "auth-provider-system-admins-subs", []string{}, "")
|
||||
cmd.Flags().StringSliceVar(&c.c.AuthProvider.SystemAdminPolicy.Emails, "auth-provider-system-admins-emails", []string{}, "")
|
||||
cmd.Flags().StringSliceVar(&c.c.AuthProvider.SystemAdminPolicy.Filters, "auth-provider-system-admins-filters", []string{}, "")
|
||||
|
||||
cmd.Flags().StringVar(&c.c.Logging.Level, "logging-level", "", "")
|
||||
cmd.Flags().StringVar(&c.c.Logging.Format, "logging-format", "", "")
|
||||
cmd.Flags().StringVar(&c.c.Logging.File, "logging-file", "", "")
|
||||
}
|
||||
|
||||
+46
-2
@@ -4,9 +4,11 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/bufbuild/connect-go"
|
||||
idomain "github.com/jsiebens/ionscale/internal/domain"
|
||||
api "github.com/jsiebens/ionscale/pkg/gen/ionscale/v1"
|
||||
"github.com/muesli/coral"
|
||||
"github.com/rodaine/table"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func tailnetCommand() *coral.Command {
|
||||
@@ -71,20 +73,62 @@ func createTailnetsCommand() *coral.Command {
|
||||
}
|
||||
|
||||
var name string
|
||||
var domain string
|
||||
var email string
|
||||
var target = Target{}
|
||||
target.prepareCommand(command)
|
||||
|
||||
command.Flags().StringVarP(&name, "name", "n", "", "")
|
||||
_ = command.MarkFlagRequired("name")
|
||||
command.Flags().StringVar(&domain, "domain", "", "")
|
||||
command.Flags().StringVar(&email, "email", "", "")
|
||||
|
||||
command.PreRunE = func(cmd *coral.Command, args []string) error {
|
||||
if name == "" && email == "" && domain == "" {
|
||||
return fmt.Errorf("at least flag --name, --email or --domain is required")
|
||||
}
|
||||
if domain != "" && email != "" {
|
||||
return fmt.Errorf("flags --email and --domain are mutually exclusive")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
command.RunE = func(command *coral.Command, args []string) error {
|
||||
|
||||
var tailnetName = ""
|
||||
var iamPolicy = api.IAMPolicy{}
|
||||
|
||||
if len(domain) != 0 {
|
||||
domainToLower := strings.ToLower(domain)
|
||||
tailnetName = domainToLower
|
||||
iamPolicy = api.IAMPolicy{
|
||||
Filters: []string{fmt.Sprintf("domain == %s", domainToLower)},
|
||||
}
|
||||
}
|
||||
|
||||
if len(email) != 0 {
|
||||
emailToLower := strings.ToLower(email)
|
||||
tailnetName = emailToLower
|
||||
iamPolicy = api.IAMPolicy{
|
||||
Emails: []string{emailToLower},
|
||||
Roles: map[string]string{
|
||||
emailToLower: string(idomain.UserRoleAdmin),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if len(name) != 0 {
|
||||
tailnetName = name
|
||||
}
|
||||
|
||||
client, err := target.createGRPCClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := client.CreateTailnet(context.Background(), connect.NewRequest(&api.CreateTailnetRequest{Name: name}))
|
||||
resp, err := client.CreateTailnet(context.Background(), connect.NewRequest(&api.CreateTailnetRequest{
|
||||
Name: tailnetName,
|
||||
IamPolicy: &iamPolicy,
|
||||
}))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
+61
-29
@@ -5,6 +5,7 @@ import (
|
||||
"github.com/caarlos0/env/v6"
|
||||
"github.com/caddyserver/certmagic"
|
||||
"github.com/imdario/mergo"
|
||||
"github.com/jsiebens/ionscale/internal/domain"
|
||||
"github.com/jsiebens/ionscale/internal/key"
|
||||
"github.com/jsiebens/ionscale/internal/util"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
@@ -16,11 +17,25 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
KeepAliveInterval = 1 * time.Minute
|
||||
const (
|
||||
defaultKeepAliveInterval = 1 * time.Minute
|
||||
defaultMagicDNSSuffix = "ionscale.net"
|
||||
)
|
||||
|
||||
func LoadConfig(path string, flagsCfg *Config) (*Config, error) {
|
||||
var (
|
||||
keepAliveInterval = defaultKeepAliveInterval
|
||||
magicDNSSuffix = defaultMagicDNSSuffix
|
||||
)
|
||||
|
||||
func KeepAliveInterval() time.Duration {
|
||||
return keepAliveInterval
|
||||
}
|
||||
|
||||
func MagicDNSSuffix() string {
|
||||
return magicDNSSuffix
|
||||
}
|
||||
|
||||
func LoadConfig(path string) (*Config, error) {
|
||||
cfg := defaultConfig()
|
||||
|
||||
if len(path) != 0 {
|
||||
@@ -49,16 +64,14 @@ func LoadConfig(path string, flagsCfg *Config) (*Config, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// merge flag configuration on top of the default/file configuration
|
||||
if err := mergo.Merge(cfg, flagsCfg, mergo.WithOverride); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// merge env configuration on top of the default/file configuration
|
||||
if err := mergo.Merge(cfg, envCfg, mergo.WithOverride); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keepAliveInterval = cfg.PollNet.KeepAliveInterval
|
||||
magicDNSSuffix = cfg.DNS.MagicDNSSuffix
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
@@ -79,8 +92,15 @@ func defaultConfig() *Config {
|
||||
AcmeCA: certmagic.LetsEncryptProductionCA,
|
||||
AcmePath: "./acme",
|
||||
},
|
||||
PollNet: PollNet{KeepAliveInterval: 1 * time.Minute},
|
||||
Logging: Logging{Level: "info"},
|
||||
PollNet: PollNet{
|
||||
KeepAliveInterval: defaultKeepAliveInterval,
|
||||
},
|
||||
DNS: DNS{
|
||||
MagicDNSSuffix: defaultMagicDNSSuffix,
|
||||
},
|
||||
Logging: Logging{
|
||||
Level: "info",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +119,8 @@ type Config struct {
|
||||
PollNet PollNet `yaml:"poll_net,omitempty" envPrefix:"POLL_NET_"`
|
||||
Keys Keys `yaml:"keys,omitempty" envPrefix:"KEYS_"`
|
||||
Database Database `yaml:"database,omitempty" envPrefix:"DB_"`
|
||||
AuthProvider AuthProvider `yaml:"auth_provider,omitempty" envPrefix:"AUTH_PROVIDER_"`
|
||||
AuthProvider AuthProvider `yaml:"auth_provider,omitempty"`
|
||||
DNS DNS `yaml:"dns,omitempty"`
|
||||
Logging Logging `yaml:"logging,omitempty" envPrefix:"LOGGING_"`
|
||||
}
|
||||
|
||||
@@ -136,17 +157,21 @@ type Keys struct {
|
||||
}
|
||||
|
||||
type AuthProvider struct {
|
||||
Issuer string `yaml:"issuer" env:"ISSUER"`
|
||||
ClientID string `yaml:"client_id" env:"CLIENT_ID"`
|
||||
ClientSecret string `yaml:"client_secret" env:"CLIENT_SECRET"`
|
||||
Scopes []string `yaml:"additional_scopes" env:"ADDITIONAL_SCOPES"`
|
||||
SystemAdminPolicy SystemAdminPolicy `yaml:"system_admins" envPrefix:"SYSTEM_ADMINS_"`
|
||||
Issuer string `yaml:"issuer"`
|
||||
ClientID string `yaml:"client_id"`
|
||||
ClientSecret string `yaml:"client_secret"`
|
||||
Scopes []string `yaml:"additional_scopes"`
|
||||
SystemAdminPolicy SystemAdminPolicy `yaml:"system_admins"`
|
||||
}
|
||||
|
||||
type DNS struct {
|
||||
MagicDNSSuffix string `yaml:"magic_dns_suffix"`
|
||||
}
|
||||
|
||||
type SystemAdminPolicy struct {
|
||||
Subs []string `json:"subs,omitempty" env:"SUBS"`
|
||||
Emails []string `json:"emails,omitempty" env:"EMAILS"`
|
||||
Filters []string `json:"filters,omitempty" env:"FILTERS"`
|
||||
Subs []string `json:"subs,omitempty"`
|
||||
Emails []string `json:"emails,omitempty"`
|
||||
Filters []string `json:"filters,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Config) CreateUrl(format string, a ...interface{}) string {
|
||||
@@ -154,8 +179,11 @@ func (c *Config) CreateUrl(format string, a ...interface{}) string {
|
||||
return strings.TrimSuffix(c.ServerUrl, "/") + "/" + strings.TrimPrefix(path, "/")
|
||||
}
|
||||
|
||||
func (c *Config) ReadServerKeys() (*ServerKeys, error) {
|
||||
keys := &ServerKeys{}
|
||||
func (c *Config) ReadServerKeys(defaultKeys *domain.ControlKeys) (*ServerKeys, error) {
|
||||
keys := &ServerKeys{
|
||||
ControlKey: defaultKeys.ControlKey,
|
||||
LegacyControlKey: defaultKeys.LegacyControlKey,
|
||||
}
|
||||
|
||||
if len(c.Keys.SystemAdminKey) != 0 {
|
||||
systemAdminKey, err := key.ParsePrivateKey(c.Keys.SystemAdminKey)
|
||||
@@ -166,17 +194,21 @@ func (c *Config) ReadServerKeys() (*ServerKeys, error) {
|
||||
keys.SystemAdminKey = systemAdminKey
|
||||
}
|
||||
|
||||
controlKey, err := util.ParseMachinePrivateKey(c.Keys.ControlKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading control key: %v", err)
|
||||
if len(c.Keys.ControlKey) != 0 {
|
||||
controlKey, err := util.ParseMachinePrivateKey(c.Keys.ControlKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading control key: %v", err)
|
||||
}
|
||||
keys.ControlKey = *controlKey
|
||||
}
|
||||
keys.ControlKey = *controlKey
|
||||
|
||||
legacyControlKey, err := util.ParseMachinePrivateKey(c.Keys.LegacyControlKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading legacy control key: %v", err)
|
||||
if len(c.Keys.LegacyControlKey) != 0 {
|
||||
legacyControlKey, err := util.ParseMachinePrivateKey(c.Keys.LegacyControlKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading legacy control key: %v", err)
|
||||
}
|
||||
keys.LegacyControlKey = *legacyControlKey
|
||||
}
|
||||
keys.LegacyControlKey = *legacyControlKey
|
||||
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/jsiebens/ionscale/internal/broker"
|
||||
"github.com/jsiebens/ionscale/internal/database/migration"
|
||||
"tailscale.com/types/key"
|
||||
"time"
|
||||
|
||||
"github.com/jsiebens/ionscale/internal/config"
|
||||
@@ -77,6 +78,33 @@ func migrate(db *gorm.DB) error {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
repository := domain.NewRepository(db)
|
||||
|
||||
if err := createServerKey(ctx, repository); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createServerKey(ctx context.Context, repository domain.Repository) error {
|
||||
serverKey, err := repository.GetControlKeys(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if serverKey != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
keys := domain.ControlKeys{
|
||||
ControlKey: key.NewMachine(),
|
||||
LegacyControlKey: key.NewMachine(),
|
||||
}
|
||||
if err := repository.SetControlKeys(ctx, &keys); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package migration
|
||||
|
||||
import (
|
||||
"github.com/go-gormigrate/gormigrate/v2"
|
||||
"github.com/jsiebens/ionscale/internal/domain"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func m202209251530_add_autoallowips_column() *gormigrate.Migration {
|
||||
return &gormigrate.Migration{
|
||||
ID: "202209251530",
|
||||
Migrate: func(db *gorm.DB) error {
|
||||
type Machine struct {
|
||||
AutoAllowIPs domain.AllowIPs
|
||||
}
|
||||
|
||||
return db.AutoMigrate(
|
||||
&Machine{},
|
||||
)
|
||||
},
|
||||
Rollback: nil,
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
func Migrations() []*gormigrate.Migration {
|
||||
var migrations = []*gormigrate.Migration{
|
||||
m202209070900_initial_schema(),
|
||||
m202209251530_add_autoallowips_column(),
|
||||
}
|
||||
return migrations
|
||||
}
|
||||
|
||||
+203
-45
@@ -8,16 +8,29 @@ import (
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/schema"
|
||||
"net/netip"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"tailscale.com/tailcfg"
|
||||
)
|
||||
|
||||
const (
|
||||
AutoGroupSelf = "autogroup:self"
|
||||
AutoGroupMembers = "autogroup:members"
|
||||
AutoGroupInternet = "autogroup:internet"
|
||||
)
|
||||
|
||||
type AutoApprovers struct {
|
||||
Routes map[string][]string `json:"routes"`
|
||||
ExitNode []string `json:"exitNode"`
|
||||
}
|
||||
|
||||
type ACLPolicy struct {
|
||||
Groups map[string][]string `json:"groups,omitempty"`
|
||||
Hosts map[string]string `json:"hosts,omitempty"`
|
||||
ACLs []ACL `json:"acls"`
|
||||
TagOwners map[string][]string `json:"tagowners"`
|
||||
Groups map[string][]string `json:"groups,omitempty"`
|
||||
Hosts map[string]string `json:"hosts,omitempty"`
|
||||
ACLs []ACL `json:"acls"`
|
||||
TagOwners map[string][]string `json:"tagowners"`
|
||||
AutoApprovers AutoApprovers `json:"autoApprovers"`
|
||||
}
|
||||
|
||||
type ACL struct {
|
||||
@@ -38,14 +51,69 @@ func DefaultPolicy() ACLPolicy {
|
||||
}
|
||||
}
|
||||
|
||||
func (a ACLPolicy) CheckTags(tags []string) error {
|
||||
var result *multierror.Error
|
||||
for _, t := range tags {
|
||||
if _, ok := a.TagOwners[t]; !ok {
|
||||
result = multierror.Append(result, fmt.Errorf("tag [%s] is invalid or not permitted", t))
|
||||
func (a ACLPolicy) FindAutoApprovedIPs(routableIPs []netip.Prefix, tags []string, u *User) []netip.Prefix {
|
||||
if len(routableIPs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
matches := func(values []string) bool {
|
||||
for _, alias := range values {
|
||||
if alias == u.Name {
|
||||
return true
|
||||
}
|
||||
|
||||
group, ok := a.Groups[alias]
|
||||
if ok {
|
||||
for _, g := range group {
|
||||
if g == u.Name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(alias, "tag:") {
|
||||
for _, tag := range tags {
|
||||
if alias == tag {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
isAutoApproved := func(candidate netip.Prefix, approvedIPs []netip.Prefix) bool {
|
||||
for _, approvedIP := range approvedIPs {
|
||||
if candidate.Bits() >= approvedIP.Bits() && approvedIP.Contains(candidate.Masked().Addr()) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
autoApprovedIPs := []netip.Prefix{}
|
||||
for route, autoApprovers := range a.AutoApprovers.Routes {
|
||||
candidate, err := netip.ParsePrefix(route)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if matches(autoApprovers) {
|
||||
autoApprovedIPs = append(autoApprovedIPs, candidate)
|
||||
}
|
||||
}
|
||||
return result.ErrorOrNil()
|
||||
|
||||
result := []netip.Prefix{}
|
||||
for _, c := range routableIPs {
|
||||
if c.Bits() == 0 && matches(a.AutoApprovers.ExitNode) {
|
||||
result = append(result, c)
|
||||
}
|
||||
if isAutoApproved(c, autoApprovedIPs) {
|
||||
result = append(result, c)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (a ACLPolicy) CheckTagOwners(tags []string, p *User) error {
|
||||
@@ -93,33 +161,34 @@ func (a ACLPolicy) IsValidPeer(src *Machine, dest *Machine) bool {
|
||||
}
|
||||
|
||||
for _, acl := range a.ACLs {
|
||||
allDestPorts := a.expandMachineToDstPorts(dest, acl.Dst)
|
||||
if len(allDestPorts) == 0 {
|
||||
continue
|
||||
selfDestPorts, allDestPorts := a.expandMachineToDstPorts(dest, acl.Dst)
|
||||
if len(selfDestPorts) != 0 {
|
||||
for _, alias := range acl.Src {
|
||||
if len(a.expandMachineAlias(src, alias, true, &dest.User)) != 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, alias := range acl.Src {
|
||||
if len(a.expandMachineAlias(src, alias, true)) != 0 {
|
||||
return true
|
||||
if len(allDestPorts) != 0 {
|
||||
for _, alias := range acl.Src {
|
||||
if len(a.expandMachineAlias(src, alias, true, nil)) != 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (a ACLPolicy) BuildFilterRules(srcs []Machine, dst *Machine) []tailcfg.FilterRule {
|
||||
var rules []tailcfg.FilterRule
|
||||
|
||||
for _, acl := range a.ACLs {
|
||||
allDestPorts := a.expandMachineToDstPorts(dst, acl.Dst)
|
||||
if len(allDestPorts) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
transform := func(src []string, destPorts []tailcfg.NetPortRange, u *User) tailcfg.FilterRule {
|
||||
var allSrcIPsSet = &StringSet{}
|
||||
for _, alias := range acl.Src {
|
||||
for _, alias := range src {
|
||||
for _, src := range srcs {
|
||||
srcIPs := a.expandMachineAlias(&src, alias, true)
|
||||
srcIPs := a.expandMachineAlias(&src, alias, true, u)
|
||||
allSrcIPsSet.Add(srcIPs...)
|
||||
}
|
||||
}
|
||||
@@ -130,12 +199,20 @@ func (a ACLPolicy) BuildFilterRules(srcs []Machine, dst *Machine) []tailcfg.Filt
|
||||
allSrcIPs = nil
|
||||
}
|
||||
|
||||
rule := tailcfg.FilterRule{
|
||||
return tailcfg.FilterRule{
|
||||
SrcIPs: allSrcIPs,
|
||||
DstPorts: allDestPorts,
|
||||
DstPorts: destPorts,
|
||||
}
|
||||
}
|
||||
|
||||
rules = append(rules, rule)
|
||||
for _, acl := range a.ACLs {
|
||||
selfDestPorts, allDestPorts := a.expandMachineToDstPorts(dst, acl.Dst)
|
||||
if len(selfDestPorts) != 0 {
|
||||
rules = append(rules, transform(acl.Src, selfDestPorts, &dst.User))
|
||||
}
|
||||
if len(allDestPorts) != 0 {
|
||||
rules = append(rules, transform(acl.Src, allDestPorts, nil))
|
||||
}
|
||||
}
|
||||
|
||||
if len(rules) == 0 {
|
||||
@@ -145,19 +222,24 @@ func (a ACLPolicy) BuildFilterRules(srcs []Machine, dst *Machine) []tailcfg.Filt
|
||||
return rules
|
||||
}
|
||||
|
||||
func (a ACLPolicy) expandMachineToDstPorts(m *Machine, ports []string) []tailcfg.NetPortRange {
|
||||
allDestRanges := []tailcfg.NetPortRange{}
|
||||
func (a ACLPolicy) expandMachineToDstPorts(m *Machine, ports []string) ([]tailcfg.NetPortRange, []tailcfg.NetPortRange) {
|
||||
selfDestRanges := []tailcfg.NetPortRange{}
|
||||
otherDestRanges := []tailcfg.NetPortRange{}
|
||||
for _, d := range ports {
|
||||
ranges := a.expandMachineDestToNetPortRanges(m, d)
|
||||
allDestRanges = append(allDestRanges, ranges...)
|
||||
self, ranges := a.expandMachineDestToNetPortRanges(m, d)
|
||||
if self {
|
||||
selfDestRanges = append(selfDestRanges, ranges...)
|
||||
} else {
|
||||
otherDestRanges = append(otherDestRanges, ranges...)
|
||||
}
|
||||
}
|
||||
return allDestRanges
|
||||
return selfDestRanges, otherDestRanges
|
||||
}
|
||||
|
||||
func (a ACLPolicy) expandMachineDestToNetPortRanges(m *Machine, dest string) []tailcfg.NetPortRange {
|
||||
func (a ACLPolicy) expandMachineDestToNetPortRanges(m *Machine, dest string) (bool, []tailcfg.NetPortRange) {
|
||||
tokens := strings.Split(dest, ":")
|
||||
if len(tokens) < 2 || len(tokens) > 3 {
|
||||
return nil
|
||||
return false, nil
|
||||
}
|
||||
|
||||
var alias string
|
||||
@@ -169,12 +251,12 @@ func (a ACLPolicy) expandMachineDestToNetPortRanges(m *Machine, dest string) []t
|
||||
|
||||
ports, err := a.expandValuePortToPortRange(tokens[len(tokens)-1])
|
||||
if err != nil {
|
||||
return nil
|
||||
return false, nil
|
||||
}
|
||||
|
||||
ips := a.expandMachineAlias(m, alias, false)
|
||||
ips := a.expandMachineAlias(m, alias, false, nil)
|
||||
if len(ips) == 0 {
|
||||
return nil
|
||||
return false, nil
|
||||
}
|
||||
|
||||
dests := []tailcfg.NetPortRange{}
|
||||
@@ -188,18 +270,40 @@ func (a ACLPolicy) expandMachineDestToNetPortRanges(m *Machine, dest string) []t
|
||||
}
|
||||
}
|
||||
|
||||
return dests
|
||||
return alias == AutoGroupSelf, dests
|
||||
}
|
||||
|
||||
func (a ACLPolicy) expandMachineAlias(m *Machine, alias string, src bool) []string {
|
||||
func (a ACLPolicy) expandMachineAlias(m *Machine, alias string, src bool, u *User) []string {
|
||||
if u != nil && m.HasTags() {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
if u != nil && !m.HasUser(u.Name) {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
if alias == "*" && u != nil {
|
||||
return m.IPs()
|
||||
}
|
||||
|
||||
if alias == "*" {
|
||||
if alias == "*" {
|
||||
return []string{"*"}
|
||||
return []string{"*"}
|
||||
}
|
||||
|
||||
if alias == AutoGroupMembers || alias == AutoGroupSelf {
|
||||
if !m.HasTags() {
|
||||
return m.IPs()
|
||||
} else {
|
||||
return []string{}
|
||||
}
|
||||
}
|
||||
|
||||
if alias == AutoGroupInternet && m.IsExitNode() {
|
||||
return autogroupInternetRanges()
|
||||
}
|
||||
|
||||
if strings.Contains(alias, "@") && !m.HasTags() && m.HasUser(alias) {
|
||||
return []string{m.IPv4.String(), m.IPv6.String()}
|
||||
return m.IPs()
|
||||
}
|
||||
|
||||
if strings.HasPrefix(alias, "group:") && !m.HasTags() {
|
||||
@@ -211,7 +315,7 @@ func (a ACLPolicy) expandMachineAlias(m *Machine, alias string, src bool) []stri
|
||||
|
||||
for _, u := range users {
|
||||
if m.HasUser(u) {
|
||||
return []string{m.IPv4.String(), m.IPv6.String()}
|
||||
return m.IPs()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,7 +323,7 @@ func (a ACLPolicy) expandMachineAlias(m *Machine, alias string, src bool) []stri
|
||||
}
|
||||
|
||||
if strings.HasPrefix(alias, "tag:") && m.HasTag(alias) {
|
||||
return []string{m.IPv4.String(), m.IPv6.String()}
|
||||
return m.IPs()
|
||||
}
|
||||
|
||||
if h, ok := a.Hosts[alias]; ok {
|
||||
@@ -332,5 +436,59 @@ func (s *StringSet) Items() []string {
|
||||
for i := range s.items {
|
||||
items = append(items, i)
|
||||
}
|
||||
sort.Strings(items)
|
||||
return items
|
||||
}
|
||||
|
||||
func autogroupInternetRanges() []string {
|
||||
return []string{
|
||||
"0.0.0.0/5",
|
||||
"8.0.0.0/7",
|
||||
"11.0.0.0/8",
|
||||
"12.0.0.0/6",
|
||||
"16.0.0.0/4",
|
||||
"32.0.0.0/3",
|
||||
"64.0.0.0/3",
|
||||
"96.0.0.0/6",
|
||||
"100.0.0.0/10",
|
||||
"100.128.0.0/9",
|
||||
"101.0.0.0/8",
|
||||
"102.0.0.0/7",
|
||||
"104.0.0.0/5",
|
||||
"112.0.0.0/4",
|
||||
"128.0.0.0/3",
|
||||
"160.0.0.0/5",
|
||||
"168.0.0.0/8",
|
||||
"169.0.0.0/9",
|
||||
"169.128.0.0/10",
|
||||
"169.192.0.0/11",
|
||||
"169.224.0.0/12",
|
||||
"169.240.0.0/13",
|
||||
"169.248.0.0/14",
|
||||
"169.252.0.0/15",
|
||||
"169.255.0.0/16",
|
||||
"170.0.0.0/7",
|
||||
"172.0.0.0/12",
|
||||
"172.32.0.0/11",
|
||||
"172.64.0.0/10",
|
||||
"172.128.0.0/9",
|
||||
"173.0.0.0/8",
|
||||
"174.0.0.0/7",
|
||||
"176.0.0.0/4",
|
||||
"192.0.0.0/9",
|
||||
"192.128.0.0/11",
|
||||
"192.160.0.0/13",
|
||||
"192.169.0.0/16",
|
||||
"192.170.0.0/15",
|
||||
"192.172.0.0/14",
|
||||
"192.176.0.0/12",
|
||||
"192.192.0.0/10",
|
||||
"193.0.0.0/8",
|
||||
"194.0.0.0/7",
|
||||
"196.0.0.0/6",
|
||||
"200.0.0.0/5",
|
||||
"208.0.0.0/4",
|
||||
"224.0.0.0/3",
|
||||
"2000::/3",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,493 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/jsiebens/ionscale/internal/addr"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"net/netip"
|
||||
"sort"
|
||||
"tailscale.com/tailcfg"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func printRules(rules []tailcfg.FilterRule) {
|
||||
indent, err := json.MarshalIndent(rules, "", " ")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(string(indent))
|
||||
}
|
||||
|
||||
func TestACLPolicy_BuildFilterRulesWildcards(t *testing.T) {
|
||||
p1 := createMachine("john@example.com")
|
||||
p2 := createMachine("jane@example.com")
|
||||
|
||||
policy := ACLPolicy{
|
||||
ACLs: []ACL{
|
||||
{
|
||||
Action: "accept",
|
||||
Src: []string{"*"},
|
||||
Dst: []string{"*:*"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
dst := createMachine("john@example.com")
|
||||
|
||||
actualRules := policy.BuildFilterRules([]Machine{*p1, *p2}, dst)
|
||||
expectedRules := []tailcfg.FilterRule{
|
||||
{
|
||||
SrcIPs: []string{"*"},
|
||||
DstPorts: []tailcfg.NetPortRange{
|
||||
{
|
||||
IP: "*",
|
||||
Ports: tailcfg.PortRange{
|
||||
First: 0,
|
||||
Last: 65535,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert.Equal(t, expectedRules, actualRules)
|
||||
}
|
||||
|
||||
func TestACLPolicy_BuildFilterRulesWithGroups(t *testing.T) {
|
||||
p1 := createMachine("jane@example.com")
|
||||
p2 := createMachine("nick@example.com")
|
||||
p3 := createMachine("joe@example.com")
|
||||
|
||||
policy := ACLPolicy{
|
||||
Groups: map[string][]string{
|
||||
"group:admin": []string{"jane@example.com"},
|
||||
"group:audit": []string{"nick@example.com"},
|
||||
},
|
||||
ACLs: []ACL{
|
||||
{
|
||||
Action: "accept",
|
||||
Src: []string{"group:admin"},
|
||||
Dst: []string{"*:22"},
|
||||
},
|
||||
{
|
||||
Action: "accept",
|
||||
Src: []string{"group:audit"},
|
||||
Dst: []string{"*:8000-8080"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
dst := createMachine("john@example.com")
|
||||
|
||||
actualRules := policy.BuildFilterRules([]Machine{*p1, *p2, *p3}, dst)
|
||||
expectedRules := []tailcfg.FilterRule{
|
||||
{
|
||||
SrcIPs: []string{
|
||||
p1.IPv4.String(),
|
||||
p1.IPv6.String(),
|
||||
},
|
||||
DstPorts: []tailcfg.NetPortRange{
|
||||
{
|
||||
IP: "*",
|
||||
Ports: tailcfg.PortRange{
|
||||
First: 22,
|
||||
Last: 22,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
SrcIPs: []string{
|
||||
p2.IPv4.String(),
|
||||
p2.IPv6.String(),
|
||||
},
|
||||
DstPorts: []tailcfg.NetPortRange{
|
||||
{
|
||||
IP: "*",
|
||||
Ports: tailcfg.PortRange{
|
||||
First: 8000,
|
||||
Last: 8080,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert.Equal(t, expectedRules, actualRules)
|
||||
}
|
||||
|
||||
func TestACLPolicy_BuildFilterRulesWithAutoGroupMembers(t *testing.T) {
|
||||
p1 := createMachine("jane@example.com")
|
||||
p2 := createMachine("nick@example.com")
|
||||
p3 := createMachine("joe@example.com", "tag:web")
|
||||
|
||||
policy := ACLPolicy{
|
||||
ACLs: []ACL{
|
||||
{
|
||||
Action: "accept",
|
||||
Src: []string{"autogroup:members"},
|
||||
Dst: []string{"*:22"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
dst := createMachine("john@example.com")
|
||||
|
||||
actualRules := policy.BuildFilterRules([]Machine{*p1, *p2, *p3}, dst)
|
||||
|
||||
expectedSrcIPs := []string{
|
||||
p1.IPv4.String(), p1.IPv6.String(),
|
||||
p2.IPv4.String(), p2.IPv6.String(),
|
||||
}
|
||||
sort.Strings(expectedSrcIPs)
|
||||
|
||||
expectedRules := []tailcfg.FilterRule{
|
||||
{
|
||||
SrcIPs: expectedSrcIPs,
|
||||
DstPorts: []tailcfg.NetPortRange{
|
||||
{
|
||||
IP: "*",
|
||||
Ports: tailcfg.PortRange{
|
||||
First: 22,
|
||||
Last: 22,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert.Equal(t, expectedRules, actualRules)
|
||||
}
|
||||
|
||||
func TestACLPolicy_BuildFilterRulesAutogroupSelf(t *testing.T) {
|
||||
p1 := createMachine("john@example.com")
|
||||
p2 := createMachine("jane@example.com")
|
||||
|
||||
policy := ACLPolicy{
|
||||
ACLs: []ACL{
|
||||
{
|
||||
Action: "accept",
|
||||
Src: []string{"*"},
|
||||
Dst: []string{"autogroup:self:*"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
dst := createMachine("john@example.com")
|
||||
|
||||
actualRules := policy.BuildFilterRules([]Machine{*p1, *p2}, dst)
|
||||
expectedRules := []tailcfg.FilterRule{
|
||||
{
|
||||
SrcIPs: []string{
|
||||
p1.IPv4.String(),
|
||||
p1.IPv6.String(),
|
||||
},
|
||||
DstPorts: []tailcfg.NetPortRange{
|
||||
{
|
||||
IP: dst.IPv4.String(),
|
||||
Ports: tailcfg.PortRange{
|
||||
First: 0,
|
||||
Last: 65535,
|
||||
},
|
||||
},
|
||||
{
|
||||
IP: dst.IPv6.String(),
|
||||
Ports: tailcfg.PortRange{
|
||||
First: 0,
|
||||
Last: 65535,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert.Equal(t, expectedRules, actualRules)
|
||||
}
|
||||
|
||||
func TestACLPolicy_BuildFilterRulesAutogroupSelfAndTags(t *testing.T) {
|
||||
p1 := createMachine("john@example.com")
|
||||
p2 := createMachine("john@example.com", "tag:web")
|
||||
|
||||
policy := ACLPolicy{
|
||||
ACLs: []ACL{
|
||||
{
|
||||
Action: "accept",
|
||||
Src: []string{"*"},
|
||||
Dst: []string{"autogroup:self:*"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
dst := createMachine("john@example.com")
|
||||
|
||||
actualRules := policy.BuildFilterRules([]Machine{*p1, *p2}, dst)
|
||||
expectedRules := []tailcfg.FilterRule{
|
||||
{
|
||||
SrcIPs: []string{
|
||||
p1.IPv4.String(),
|
||||
p1.IPv6.String(),
|
||||
},
|
||||
DstPorts: []tailcfg.NetPortRange{
|
||||
{
|
||||
IP: dst.IPv4.String(),
|
||||
Ports: tailcfg.PortRange{
|
||||
First: 0,
|
||||
Last: 65535,
|
||||
},
|
||||
},
|
||||
{
|
||||
IP: dst.IPv6.String(),
|
||||
Ports: tailcfg.PortRange{
|
||||
First: 0,
|
||||
Last: 65535,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert.Equal(t, expectedRules, actualRules)
|
||||
}
|
||||
|
||||
func TestACLPolicy_BuildFilterRulesAutogroupSelfAndOtherDestinations(t *testing.T) {
|
||||
p1 := createMachine("john@example.com")
|
||||
p2 := createMachine("john@example.com", "tag:web")
|
||||
p3 := createMachine("jane@example.com")
|
||||
|
||||
policy := ACLPolicy{
|
||||
ACLs: []ACL{
|
||||
{
|
||||
Action: "accept",
|
||||
Src: []string{"*"},
|
||||
Dst: []string{"autogroup:self:22", "john@example.com:80"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
dst := createMachine("john@example.com")
|
||||
|
||||
actualRules := policy.BuildFilterRules([]Machine{*p1, *p2, *p3}, dst)
|
||||
expectedRules := []tailcfg.FilterRule{
|
||||
{
|
||||
SrcIPs: p1.IPs(),
|
||||
DstPorts: []tailcfg.NetPortRange{
|
||||
{
|
||||
IP: dst.IPv4.String(),
|
||||
Ports: tailcfg.PortRange{
|
||||
First: 22,
|
||||
Last: 22,
|
||||
},
|
||||
},
|
||||
{
|
||||
IP: dst.IPv6.String(),
|
||||
Ports: tailcfg.PortRange{
|
||||
First: 22,
|
||||
Last: 22,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
SrcIPs: []string{"*"},
|
||||
DstPorts: []tailcfg.NetPortRange{
|
||||
{
|
||||
IP: dst.IPv4.String(),
|
||||
Ports: tailcfg.PortRange{
|
||||
First: 80,
|
||||
Last: 80,
|
||||
},
|
||||
},
|
||||
{
|
||||
IP: dst.IPv6.String(),
|
||||
Ports: tailcfg.PortRange{
|
||||
First: 80,
|
||||
Last: 80,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert.Equal(t, expectedRules, actualRules)
|
||||
}
|
||||
|
||||
func TestACLPolicy_BuildFilterRulesAutogroupMember(t *testing.T) {
|
||||
p1 := createMachine("jane@example.com")
|
||||
p2 := createMachine("jane@example.com", "tag:web")
|
||||
|
||||
policy := ACLPolicy{
|
||||
ACLs: []ACL{
|
||||
{
|
||||
Action: "accept",
|
||||
Src: []string{"autogroup:members"},
|
||||
Dst: []string{"*:*"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
dst := createMachine("john@example.com")
|
||||
|
||||
actualRules := policy.BuildFilterRules([]Machine{*p1, *p2}, dst)
|
||||
expectedRules := []tailcfg.FilterRule{
|
||||
{
|
||||
SrcIPs: []string{
|
||||
p1.IPv4.String(),
|
||||
p1.IPv6.String(),
|
||||
},
|
||||
DstPorts: []tailcfg.NetPortRange{
|
||||
{
|
||||
IP: "*",
|
||||
Ports: tailcfg.PortRange{
|
||||
First: 0,
|
||||
Last: 65535,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert.Equal(t, expectedRules, actualRules)
|
||||
}
|
||||
|
||||
func TestACLPolicy_BuildFilterRulesAutogroupInternet(t *testing.T) {
|
||||
p1 := createMachine("nick@example.com")
|
||||
p2 := createMachine("jane@example.com")
|
||||
|
||||
policy := ACLPolicy{
|
||||
ACLs: []ACL{
|
||||
{
|
||||
Action: "accept",
|
||||
Src: []string{"nick@example.com"},
|
||||
Dst: []string{"autogroup:internet:*"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
dst := createMachine("john@example.com")
|
||||
dst.AllowIPs = []netip.Prefix{
|
||||
netip.MustParsePrefix("0.0.0.0/0"),
|
||||
}
|
||||
|
||||
expectedDstPorts := []tailcfg.NetPortRange{}
|
||||
for _, r := range autogroupInternetRanges() {
|
||||
expectedDstPorts = append(expectedDstPorts, tailcfg.NetPortRange{
|
||||
IP: r,
|
||||
Ports: tailcfg.PortRange{
|
||||
First: 0,
|
||||
Last: 65535,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
actualRules := policy.BuildFilterRules([]Machine{*p1, *p2}, dst)
|
||||
expectedRules := []tailcfg.FilterRule{
|
||||
{
|
||||
SrcIPs: []string{
|
||||
p1.IPv4.String(),
|
||||
p1.IPv6.String(),
|
||||
},
|
||||
DstPorts: expectedDstPorts,
|
||||
},
|
||||
}
|
||||
|
||||
assert.Equal(t, expectedRules, actualRules)
|
||||
}
|
||||
|
||||
func TestWithUser(t *testing.T) {
|
||||
policy := ACLPolicy{
|
||||
ACLs: []ACL{
|
||||
{
|
||||
Action: "accept",
|
||||
Src: []string{"*"},
|
||||
Dst: []string{"john@example.com:*"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
src := createMachine("john@example.com")
|
||||
assert.True(t, policy.IsValidPeer(src, createMachine("john@example.com")))
|
||||
assert.False(t, policy.IsValidPeer(src, createMachine("john@example.com", "tag:web")))
|
||||
assert.False(t, policy.IsValidPeer(src, createMachine("jane@example.com")))
|
||||
}
|
||||
|
||||
func TestWithGroup(t *testing.T) {
|
||||
policy := ACLPolicy{
|
||||
Groups: map[string][]string{
|
||||
"group:admin": {"john@example.com"},
|
||||
},
|
||||
ACLs: []ACL{
|
||||
{
|
||||
Action: "accept",
|
||||
Src: []string{"*"},
|
||||
Dst: []string{"group:admin:*"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
src := createMachine("john@example.com")
|
||||
assert.True(t, policy.IsValidPeer(src, createMachine("john@example.com")))
|
||||
assert.False(t, policy.IsValidPeer(src, createMachine("jane@example.com")))
|
||||
}
|
||||
|
||||
func TestWithTags(t *testing.T) {
|
||||
policy := ACLPolicy{
|
||||
ACLs: []ACL{
|
||||
{
|
||||
Action: "accept",
|
||||
Src: []string{"*"},
|
||||
Dst: []string{"tag:web:*"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
src := createMachine("john@example.com")
|
||||
|
||||
assert.True(t, policy.IsValidPeer(src, createMachine("john@example.com", "tag:web")))
|
||||
assert.False(t, policy.IsValidPeer(src, createMachine("john@example.com", "tag:ci")))
|
||||
}
|
||||
|
||||
func TestWithHosts(t *testing.T) {
|
||||
dst1 := createMachine("john@example.com")
|
||||
dst2 := createMachine("john@example.com")
|
||||
|
||||
policy := ACLPolicy{
|
||||
Hosts: map[string]string{
|
||||
"dst1": dst1.IPv4.String(),
|
||||
},
|
||||
ACLs: []ACL{
|
||||
|
||||
{
|
||||
Action: "accept",
|
||||
Src: []string{"*"},
|
||||
Dst: []string{"dst1:*"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
src := createMachine("jane@example.com")
|
||||
|
||||
assert.True(t, policy.IsValidPeer(src, dst1))
|
||||
assert.False(t, policy.IsValidPeer(src, dst2))
|
||||
}
|
||||
|
||||
func createMachine(user string, tags ...string) *Machine {
|
||||
ipv4, ipv6, err := addr.SelectIP(func(addr netip.Addr) (bool, error) {
|
||||
return true, nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return &Machine{
|
||||
IPv4: IP{ipv4},
|
||||
IPv6: IP{ipv6},
|
||||
User: User{
|
||||
Name: user,
|
||||
},
|
||||
Tags: tags,
|
||||
}
|
||||
}
|
||||
|
||||
func TestACLPolicy_IsTagOwner(t *testing.T) {
|
||||
policy := ACLPolicy{
|
||||
Groups: map[string][]string{
|
||||
@@ -76,3 +559,96 @@ func TestACLPolicy_IsTagOwner(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestACLPolicy_FindAutoApprovedIPs(t *testing.T) {
|
||||
route1 := netip.MustParsePrefix("10.160.0.0/20")
|
||||
route2 := netip.MustParsePrefix("10.161.0.0/20")
|
||||
route3 := netip.MustParsePrefix("10.162.0.0/20")
|
||||
|
||||
policy := ACLPolicy{
|
||||
Groups: map[string][]string{
|
||||
"group:admins": {"jane@example.com"},
|
||||
},
|
||||
AutoApprovers: AutoApprovers{
|
||||
Routes: map[string][]string{
|
||||
route1.String(): {"group:admins"},
|
||||
route2.String(): {"john@example.com", "tag:router"},
|
||||
},
|
||||
ExitNode: []string{"nick@example.com"},
|
||||
},
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
tag []string
|
||||
userName string
|
||||
routableIPs []netip.Prefix
|
||||
expected []netip.Prefix
|
||||
}{
|
||||
{
|
||||
name: "nil",
|
||||
tag: []string{},
|
||||
userName: "john@example.com",
|
||||
routableIPs: nil,
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "empty",
|
||||
tag: []string{},
|
||||
userName: "john@example.com",
|
||||
routableIPs: []netip.Prefix{},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "by user",
|
||||
tag: []string{},
|
||||
userName: "john@example.com",
|
||||
routableIPs: []netip.Prefix{route1, route2, route3},
|
||||
expected: []netip.Prefix{route2},
|
||||
},
|
||||
{
|
||||
name: "partial by user",
|
||||
tag: []string{},
|
||||
userName: "john@example.com",
|
||||
routableIPs: []netip.Prefix{netip.MustParsePrefix("10.161.4.0/22")},
|
||||
expected: []netip.Prefix{netip.MustParsePrefix("10.161.4.0/22")},
|
||||
},
|
||||
{
|
||||
name: "by tag",
|
||||
tag: []string{"tag:router"},
|
||||
routableIPs: []netip.Prefix{route1, route2, route3},
|
||||
expected: []netip.Prefix{route2},
|
||||
},
|
||||
{
|
||||
name: "by group",
|
||||
userName: "jane@example.com",
|
||||
routableIPs: []netip.Prefix{route1, route2, route3},
|
||||
expected: []netip.Prefix{route1},
|
||||
},
|
||||
{
|
||||
name: "no match",
|
||||
userName: "nick@example.com",
|
||||
routableIPs: []netip.Prefix{route1, route2, route3},
|
||||
expected: []netip.Prefix{},
|
||||
},
|
||||
{
|
||||
name: "exit",
|
||||
userName: "nick@example.com",
|
||||
routableIPs: []netip.Prefix{netip.MustParsePrefix("0.0.0.0/0")},
|
||||
expected: []netip.Prefix{netip.MustParsePrefix("0.0.0.0/0")},
|
||||
},
|
||||
{
|
||||
name: "exit no match",
|
||||
userName: "john@example.com",
|
||||
routableIPs: []netip.Prefix{netip.MustParsePrefix("0.0.0.0/0")},
|
||||
expected: []netip.Prefix{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
actualAllowedIPs := policy.FindAutoApprovedIPs(tc.routableIPs, tc.tag, &User{Name: tc.userName})
|
||||
assert.Equal(t, tc.expected, actualAllowedIPs)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,9 +25,10 @@ type Machine struct {
|
||||
Tags Tags
|
||||
KeyExpiryDisabled bool
|
||||
|
||||
HostInfo HostInfo
|
||||
Endpoints Endpoints
|
||||
AllowIPs AllowIPs
|
||||
HostInfo HostInfo
|
||||
Endpoints Endpoints
|
||||
AllowIPs AllowIPs
|
||||
AutoAllowIPs AllowIPs
|
||||
|
||||
IPv4 IP
|
||||
IPv6 IP
|
||||
@@ -45,6 +46,10 @@ type Machine struct {
|
||||
|
||||
type Machines []Machine
|
||||
|
||||
func (m *Machine) IPs() []string {
|
||||
return []string{m.IPv4.String(), m.IPv6.String()}
|
||||
}
|
||||
|
||||
func (m *Machine) IsExpired() bool {
|
||||
return !m.KeyExpiryDisabled && !m.ExpiresAt.IsZero() && m.ExpiresAt.Before(time.Now())
|
||||
}
|
||||
@@ -70,6 +75,54 @@ func (m *Machine) HasTags() bool {
|
||||
return len(m.Tags) != 0
|
||||
}
|
||||
|
||||
func (m *Machine) IsAdvertisedExitNode() bool {
|
||||
for _, r := range m.HostInfo.RoutableIPs {
|
||||
if r.Bits() == 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *Machine) IsAllowedExitNode() bool {
|
||||
for _, r := range m.AllowIPs {
|
||||
if r.Bits() == 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for _, r := range m.AutoAllowIPs {
|
||||
if r.Bits() == 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *Machine) AdvertisedPrefixes() []string {
|
||||
result := []string{}
|
||||
for _, r := range m.HostInfo.RoutableIPs {
|
||||
if r.Bits() != 0 {
|
||||
result = append(result, r.String())
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (m *Machine) AllowedPrefixes() []string {
|
||||
result := StringSet{}
|
||||
for _, r := range m.AllowIPs {
|
||||
if r.Bits() != 0 {
|
||||
result.Add(r.String())
|
||||
}
|
||||
}
|
||||
for _, r := range m.AutoAllowIPs {
|
||||
if r.Bits() != 0 {
|
||||
result.Add(r.String())
|
||||
}
|
||||
}
|
||||
return result.Items()
|
||||
}
|
||||
|
||||
func (m *Machine) IsAllowedIP(i netip.Addr) bool {
|
||||
if m.HasIP(i) {
|
||||
return true
|
||||
@@ -79,6 +132,11 @@ func (m *Machine) IsAllowedIP(i netip.Addr) bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for _, t := range m.AutoAllowIPs {
|
||||
if t.Contains(i) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -88,6 +146,25 @@ func (m *Machine) IsAllowedIPPrefix(i netip.Prefix) bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for _, t := range m.AutoAllowIPs {
|
||||
if t.Overlaps(i) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *Machine) IsExitNode() bool {
|
||||
for _, t := range m.AllowIPs {
|
||||
if t.Bits() == 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for _, t := range m.AutoAllowIPs {
|
||||
if t.Bits() == 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,9 @@ import (
|
||||
)
|
||||
|
||||
type Repository interface {
|
||||
GetControlKeys(ctx context.Context) (*ControlKeys, error)
|
||||
SetControlKeys(ctx context.Context, keys *ControlKeys) error
|
||||
|
||||
GetDERPMap(ctx context.Context) (*tailcfg.DERPMap, error)
|
||||
SetDERPMap(ctx context.Context, v *tailcfg.DERPMap) error
|
||||
|
||||
@@ -18,7 +21,7 @@ type Repository interface {
|
||||
GetOrCreateAccount(ctx context.Context, externalID, loginName string) (*Account, bool, error)
|
||||
|
||||
SaveTailnet(ctx context.Context, tailnet *Tailnet) error
|
||||
GetOrCreateTailnet(ctx context.Context, name string) (*Tailnet, bool, error)
|
||||
GetOrCreateTailnet(ctx context.Context, name string, iamPolicy IAMPolicy) (*Tailnet, bool, error)
|
||||
GetTailnet(ctx context.Context, id uint64) (*Tailnet, error)
|
||||
ListTailnets(ctx context.Context) ([]Tailnet, error)
|
||||
DeleteTailnet(ctx context.Context, id uint64) error
|
||||
|
||||
@@ -6,12 +6,14 @@ import (
|
||||
"errors"
|
||||
"gorm.io/gorm"
|
||||
"tailscale.com/tailcfg"
|
||||
tkey "tailscale.com/types/key"
|
||||
)
|
||||
|
||||
type configKey string
|
||||
|
||||
const (
|
||||
derpMapConfigKey configKey = "derp_map"
|
||||
derpMapConfigKey configKey = "derp_map"
|
||||
controlKeysConfigKey configKey = "control_keys"
|
||||
)
|
||||
|
||||
type ServerConfig struct {
|
||||
@@ -19,6 +21,30 @@ type ServerConfig struct {
|
||||
Value []byte
|
||||
}
|
||||
|
||||
type ControlKeys struct {
|
||||
ControlKey tkey.MachinePrivate
|
||||
LegacyControlKey tkey.MachinePrivate
|
||||
}
|
||||
|
||||
func (r *repository) GetControlKeys(ctx context.Context) (*ControlKeys, error) {
|
||||
var m ControlKeys
|
||||
err := r.getServerConfig(ctx, controlKeysConfigKey, &m)
|
||||
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
func (r *repository) SetControlKeys(ctx context.Context, v *ControlKeys) error {
|
||||
return r.setServerConfig(ctx, controlKeysConfigKey, v)
|
||||
}
|
||||
|
||||
func (r *repository) GetDERPMap(ctx context.Context) (*tailcfg.DERPMap, error) {
|
||||
var m tailcfg.DERPMap
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@ import (
|
||||
"errors"
|
||||
"github.com/jsiebens/ionscale/internal/util"
|
||||
"gorm.io/gorm"
|
||||
"net/mail"
|
||||
"strings"
|
||||
"tailscale.com/util/dnsname"
|
||||
)
|
||||
|
||||
type Tailnet struct {
|
||||
@@ -15,6 +18,23 @@ type Tailnet struct {
|
||||
ACLPolicy ACLPolicy
|
||||
}
|
||||
|
||||
func SanitizeTailnetName(name string) string {
|
||||
name = strings.ToLower(name)
|
||||
|
||||
a, err := mail.ParseAddress(name)
|
||||
if err == nil && a.Address == name {
|
||||
s := strings.Split(name, "@")
|
||||
return strings.Join([]string{dnsname.SanitizeLabel(s[0]), s[1]}, ".")
|
||||
}
|
||||
|
||||
labels := strings.Split(name, ".")
|
||||
for i, s := range labels {
|
||||
labels[i] = dnsname.SanitizeLabel(s)
|
||||
}
|
||||
|
||||
return strings.Join(labels, ".")
|
||||
}
|
||||
|
||||
func (r *repository) SaveTailnet(ctx context.Context, tailnet *Tailnet) error {
|
||||
tx := r.withContext(ctx).Save(tailnet)
|
||||
|
||||
@@ -25,13 +45,13 @@ func (r *repository) SaveTailnet(ctx context.Context, tailnet *Tailnet) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *repository) GetOrCreateTailnet(ctx context.Context, name string) (*Tailnet, bool, error) {
|
||||
func (r *repository) GetOrCreateTailnet(ctx context.Context, name string, iamPolicy IAMPolicy) (*Tailnet, bool, error) {
|
||||
tailnet := &Tailnet{}
|
||||
id := util.NextID()
|
||||
|
||||
tx := r.withContext(ctx).
|
||||
Where(Tailnet{Name: name}).
|
||||
Attrs(Tailnet{ID: id, ACLPolicy: DefaultPolicy()}).
|
||||
Attrs(Tailnet{ID: id, ACLPolicy: DefaultPolicy(), IAMPolicy: iamPolicy}).
|
||||
FirstOrCreate(tailnet)
|
||||
|
||||
if tx.Error != nil {
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSanitizeTailnetName(t *testing.T) {
|
||||
assert.Equal(t, "john.example.com", SanitizeTailnetName("john@example.com"))
|
||||
assert.Equal(t, "john.example.com", SanitizeTailnetName("john@examPle.Com"))
|
||||
assert.Equal(t, "john-doe.example.com", SanitizeTailnetName("john.doe@example.com"))
|
||||
assert.Equal(t, "johns-network", SanitizeTailnetName("John's Network"))
|
||||
assert.Equal(t, "example.com", SanitizeTailnetName("example.com"))
|
||||
assert.Equal(t, "johns-example.com", SanitizeTailnetName("John's example.com"))
|
||||
}
|
||||
@@ -393,6 +393,8 @@ func (h *AuthenticationHandlers) endMachineRegistrationFlow(c echo.Context, regi
|
||||
return c.Redirect(http.StatusFound, "/a/error?e=nto")
|
||||
}
|
||||
|
||||
autoAllowIPs := tailnet.ACLPolicy.FindAutoApprovedIPs(req.Hostinfo.RoutableIPs, tags, user)
|
||||
|
||||
var m *domain.Machine
|
||||
|
||||
m, err := h.repository.GetMachineByKey(ctx, tailnet.ID, machineKey)
|
||||
@@ -419,9 +421,10 @@ func (h *AuthenticationHandlers) endMachineRegistrationFlow(c echo.Context, regi
|
||||
NameIdx: nameIdx,
|
||||
MachineKey: machineKey,
|
||||
NodeKey: nodeKey,
|
||||
Ephemeral: ephemeral,
|
||||
Ephemeral: ephemeral || req.Ephemeral,
|
||||
RegisteredTags: registeredTags,
|
||||
Tags: domain.SanitizeTags(tags),
|
||||
AutoAllowIPs: autoAllowIPs,
|
||||
CreatedAt: now,
|
||||
ExpiresAt: now.Add(180 * 24 * time.Hour).UTC(),
|
||||
KeyExpiryDisabled: len(tags) != 0,
|
||||
@@ -451,9 +454,10 @@ func (h *AuthenticationHandlers) endMachineRegistrationFlow(c echo.Context, regi
|
||||
m.NameIdx = nameIdx
|
||||
}
|
||||
m.NodeKey = nodeKey
|
||||
m.Ephemeral = ephemeral
|
||||
m.Ephemeral = ephemeral || req.Ephemeral
|
||||
m.RegisteredTags = registeredTags
|
||||
m.Tags = domain.SanitizeTags(tags)
|
||||
m.AutoAllowIPs = autoAllowIPs
|
||||
m.UserID = user.ID
|
||||
m.User = *user
|
||||
m.TailnetID = tailnet.ID
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/labstack/echo/v4"
|
||||
"golang.org/x/net/http2"
|
||||
"golang.org/x/net/http2/h2c"
|
||||
@@ -26,7 +25,7 @@ func NewNoiseHandlers(controlKey key.MachinePrivate, createPeerHandler CreatePee
|
||||
}
|
||||
|
||||
func (h *NoiseHandlers) Upgrade(c echo.Context) error {
|
||||
conn, err := controlhttp.AcceptHTTP(context.Background(), c.Response(), c.Request(), h.controlKey)
|
||||
conn, err := controlhttp.AcceptHTTP(c.Request().Context(), c.Response(), c.Request(), h.controlKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"github.com/labstack/echo/v4"
|
||||
"net/http"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/util/dnsname"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -114,7 +113,7 @@ func (h *PollNetMapHandler) handleUpdate(c echo.Context, binder bind.Binder, m *
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
keepAliveTicker := time.NewTicker(config.KeepAliveInterval)
|
||||
keepAliveTicker := time.NewTicker(config.KeepAliveInterval())
|
||||
syncTicker := time.NewTicker(5 * time.Second)
|
||||
|
||||
c.Response().WriteHeader(http.StatusOK)
|
||||
@@ -286,7 +285,7 @@ func (h *PollNetMapHandler) createMapResponse(m *domain.Machine, binder bind.Bin
|
||||
DNSConfig: mapping.ToDNSConfig(&m.Tailnet, &dnsConfig),
|
||||
PacketFilter: rules,
|
||||
DERPMap: derpMap,
|
||||
Domain: dnsname.SanitizeHostname(m.Tailnet.Name),
|
||||
Domain: domain.SanitizeTailnetName(m.Tailnet.Name),
|
||||
Peers: changedPeers,
|
||||
UserProfiles: users,
|
||||
ControlTime: &controlTime,
|
||||
@@ -300,7 +299,7 @@ func (h *PollNetMapHandler) createMapResponse(m *domain.Machine, binder bind.Bin
|
||||
DNSConfig: mapping.ToDNSConfig(&m.Tailnet, &dnsConfig),
|
||||
PacketFilter: rules,
|
||||
DERPMap: derpMap,
|
||||
Domain: dnsname.SanitizeHostname(m.Tailnet.Name),
|
||||
Domain: domain.SanitizeTailnetName(m.Tailnet.Name),
|
||||
PeersChanged: changedPeers,
|
||||
PeersRemoved: removedPeers,
|
||||
UserProfiles: users,
|
||||
@@ -355,7 +354,7 @@ func (o *OfflineTimers) scheduleOfflineMessage(tailnetID, machineID uint64) {
|
||||
delete(o.data, machineID)
|
||||
}
|
||||
|
||||
timer := time.NewTimer(config.KeepAliveInterval)
|
||||
timer := time.NewTimer(config.KeepAliveInterval())
|
||||
go func() {
|
||||
<-timer.C
|
||||
o.pubsub.Publish(tailnetID, &broker.Signal{PeerUpdated: &machineID})
|
||||
|
||||
@@ -156,6 +156,12 @@ func (h *RegistrationHandlers) authenticateMachineWithAuthKey(c echo.Context, bi
|
||||
return binder.WriteResponse(c, http.StatusOK, response)
|
||||
}
|
||||
|
||||
registeredTags := authKey.Tags
|
||||
advertisedTags := domain.SanitizeTags(req.Hostinfo.RequestTags)
|
||||
tags := append(registeredTags, advertisedTags...)
|
||||
|
||||
autoAllowIPs := tailnet.ACLPolicy.FindAutoApprovedIPs(req.Hostinfo.RoutableIPs, tags, &user)
|
||||
|
||||
var m *domain.Machine
|
||||
|
||||
m, err = h.repository.GetMachineByKey(ctx, tailnet.ID, machineKey)
|
||||
@@ -166,10 +172,6 @@ func (h *RegistrationHandlers) authenticateMachineWithAuthKey(c echo.Context, bi
|
||||
now := time.Now().UTC()
|
||||
|
||||
if m == nil {
|
||||
registeredTags := authKey.Tags
|
||||
advertisedTags := domain.SanitizeTags(req.Hostinfo.RequestTags)
|
||||
tags := append(registeredTags, advertisedTags...)
|
||||
|
||||
sanitizeHostname := dnsname.SanitizeHostname(req.Hostinfo.Hostname)
|
||||
nameIdx, err := h.repository.GetNextMachineNameIndex(ctx, tailnet.ID, sanitizeHostname)
|
||||
if err != nil {
|
||||
@@ -182,9 +184,10 @@ func (h *RegistrationHandlers) authenticateMachineWithAuthKey(c echo.Context, bi
|
||||
NameIdx: nameIdx,
|
||||
MachineKey: machineKey,
|
||||
NodeKey: nodeKey,
|
||||
Ephemeral: authKey.Ephemeral,
|
||||
Ephemeral: authKey.Ephemeral || req.Ephemeral,
|
||||
RegisteredTags: registeredTags,
|
||||
Tags: domain.SanitizeTags(tags),
|
||||
AutoAllowIPs: autoAllowIPs,
|
||||
CreatedAt: now,
|
||||
ExpiresAt: now.Add(180 * 24 * time.Hour).UTC(),
|
||||
KeyExpiryDisabled: len(tags) != 0,
|
||||
@@ -204,10 +207,6 @@ func (h *RegistrationHandlers) authenticateMachineWithAuthKey(c echo.Context, bi
|
||||
m.IPv4 = domain.IP{Addr: ipv4}
|
||||
m.IPv6 = domain.IP{Addr: ipv6}
|
||||
} else {
|
||||
registeredTags := authKey.Tags
|
||||
advertisedTags := domain.SanitizeTags(req.Hostinfo.RequestTags)
|
||||
tags := append(registeredTags, advertisedTags...)
|
||||
|
||||
sanitizeHostname := dnsname.SanitizeHostname(req.Hostinfo.Hostname)
|
||||
if m.Name != sanitizeHostname {
|
||||
nameIdx, err := h.repository.GetNextMachineNameIndex(ctx, tailnet.ID, sanitizeHostname)
|
||||
@@ -218,9 +217,10 @@ func (h *RegistrationHandlers) authenticateMachineWithAuthKey(c echo.Context, bi
|
||||
m.NameIdx = nameIdx
|
||||
}
|
||||
m.NodeKey = nodeKey
|
||||
m.Ephemeral = authKey.Ephemeral
|
||||
m.Ephemeral = authKey.Ephemeral || req.Ephemeral
|
||||
m.RegisteredTags = registeredTags
|
||||
m.Tags = domain.SanitizeTags(tags)
|
||||
m.AutoAllowIPs = autoAllowIPs
|
||||
m.UserID = user.ID
|
||||
m.User = user
|
||||
m.TailnetID = tailnet.ID
|
||||
|
||||
+13
-15
@@ -11,12 +11,9 @@ import (
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/dnstype"
|
||||
"tailscale.com/types/key"
|
||||
"tailscale.com/util/dnsname"
|
||||
"time"
|
||||
)
|
||||
|
||||
const NetworkMagicDNSSuffix = "ionscale.net"
|
||||
|
||||
func CopyViaJson[F any, T any](f F, t T) error {
|
||||
raw, err := json.Marshal(f)
|
||||
if err != nil {
|
||||
@@ -31,7 +28,7 @@ func CopyViaJson[F any, T any](f F, t T) error {
|
||||
}
|
||||
|
||||
func ToDNSConfig(tailnet *domain.Tailnet, c *domain.DNSConfig) *tailcfg.DNSConfig {
|
||||
tailnetDomain := dnsname.SanitizeHostname(tailnet.Name)
|
||||
tailnetDomain := domain.SanitizeTailnetName(tailnet.Name)
|
||||
resolvers := []*dnstype.Resolver{}
|
||||
for _, r := range c.Nameservers {
|
||||
resolver := &dnstype.Resolver{
|
||||
@@ -40,19 +37,19 @@ func ToDNSConfig(tailnet *domain.Tailnet, c *domain.DNSConfig) *tailcfg.DNSConfi
|
||||
resolvers = append(resolvers, resolver)
|
||||
}
|
||||
|
||||
config := &tailcfg.DNSConfig{}
|
||||
dnsConfig := &tailcfg.DNSConfig{}
|
||||
|
||||
var domains []string
|
||||
|
||||
if c.MagicDNS {
|
||||
domains = append(domains, fmt.Sprintf("%s.%s", tailnetDomain, NetworkMagicDNSSuffix))
|
||||
config.Proxied = true
|
||||
domains = append(domains, fmt.Sprintf("%s.%s", tailnetDomain, config.MagicDNSSuffix()))
|
||||
dnsConfig.Proxied = true
|
||||
}
|
||||
|
||||
if c.OverrideLocalDNS {
|
||||
config.Resolvers = resolvers
|
||||
dnsConfig.Resolvers = resolvers
|
||||
} else {
|
||||
config.FallbackResolvers = resolvers
|
||||
dnsConfig.FallbackResolvers = resolvers
|
||||
}
|
||||
|
||||
if len(c.Routes) != 0 {
|
||||
@@ -66,12 +63,12 @@ func ToDNSConfig(tailnet *domain.Tailnet, c *domain.DNSConfig) *tailcfg.DNSConfi
|
||||
routes[r] = routeResolver
|
||||
domains = append(domains, r)
|
||||
}
|
||||
config.Routes = routes
|
||||
dnsConfig.Routes = routes
|
||||
}
|
||||
|
||||
config.Domains = domains
|
||||
dnsConfig.Domains = domains
|
||||
|
||||
return config
|
||||
return dnsConfig
|
||||
}
|
||||
|
||||
func ToNode(m *domain.Machine) (*tailcfg.Node, *tailcfg.UserProfile, error) {
|
||||
@@ -119,6 +116,7 @@ func ToNode(m *domain.Machine) (*tailcfg.Node, *tailcfg.UserProfile, error) {
|
||||
}
|
||||
|
||||
allowedIPs = append(allowedIPs, m.AllowIPs...)
|
||||
allowedIPs = append(allowedIPs, m.AutoAllowIPs...)
|
||||
|
||||
var derp string
|
||||
if hostinfo.NetInfo != nil {
|
||||
@@ -132,7 +130,7 @@ func ToNode(m *domain.Machine) (*tailcfg.Node, *tailcfg.UserProfile, error) {
|
||||
name = fmt.Sprintf("%s-%d", m.Name, m.NameIdx)
|
||||
}
|
||||
|
||||
sanitizedTailnetName := dnsname.SanitizeHostname(m.Tailnet.Name)
|
||||
sanitizedTailnetName := domain.SanitizeTailnetName(m.Tailnet.Name)
|
||||
|
||||
hostInfo := tailcfg.Hostinfo{
|
||||
OS: hostinfo.OS,
|
||||
@@ -143,7 +141,7 @@ func ToNode(m *domain.Machine) (*tailcfg.Node, *tailcfg.UserProfile, error) {
|
||||
n := tailcfg.Node{
|
||||
ID: tailcfg.NodeID(m.ID),
|
||||
StableID: tailcfg.StableNodeID(strconv.FormatUint(m.ID, 10)),
|
||||
Name: fmt.Sprintf("%s.%s.%s.", name, sanitizedTailnetName, NetworkMagicDNSSuffix),
|
||||
Name: fmt.Sprintf("%s.%s.%s.", name, sanitizedTailnetName, config.MagicDNSSuffix()),
|
||||
Key: *nKey,
|
||||
Machine: *mKey,
|
||||
DiscoKey: discoKey,
|
||||
@@ -171,7 +169,7 @@ func ToNode(m *domain.Machine) (*tailcfg.Node, *tailcfg.UserProfile, error) {
|
||||
|
||||
if m.LastSeen != nil {
|
||||
l := m.LastSeen.UTC()
|
||||
online := m.LastSeen.After(time.Now().Add(-config.KeepAliveInterval))
|
||||
online := m.LastSeen.After(time.Now().Add(-config.KeepAliveInterval()))
|
||||
n.LastSeen = &l
|
||||
n.Online = &online
|
||||
}
|
||||
|
||||
@@ -85,10 +85,14 @@ func (p *OIDCProvider) Exchange(redirectURI, code string) (*User, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
domain := strings.Split(email, "@")[1]
|
||||
|
||||
return &User{
|
||||
ID: sub,
|
||||
Name: email,
|
||||
Attr: map[string]interface{}{
|
||||
"email": email,
|
||||
"domain": domain,
|
||||
"token": tokenClaims,
|
||||
"userinfo": userInfoClaims,
|
||||
},
|
||||
|
||||
@@ -37,12 +37,17 @@ func Start(c *config.Config) error {
|
||||
|
||||
logger.Info("Starting ionscale server")
|
||||
|
||||
serverKey, err := c.ReadServerKeys()
|
||||
repository, brokers, err := database.OpenDB(&c.Database, logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
repository, brokers, err := database.OpenDB(&c.Database, logger)
|
||||
defaultControlKeys, err := repository.GetControlKeys(context.Background())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
serverKey, err := c.ReadServerKeys(defaultControlKeys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -134,11 +134,7 @@ func (s *Service) CreateAuthKey(ctx context.Context, req *connect.Request[api.Cr
|
||||
return nil, connect.NewError(connect.CodeNotFound, errors.New("tailnet not found"))
|
||||
}
|
||||
|
||||
if principal.IsSystemAdmin() {
|
||||
if err := tailnet.ACLPolicy.CheckTags(req.Msg.Tags); err != nil {
|
||||
return nil, connect.NewError(connect.CodeInvalidArgument, err)
|
||||
}
|
||||
} else {
|
||||
if !principal.IsSystemAdmin() {
|
||||
if err := tailnet.ACLPolicy.CheckTagOwners(req.Msg.Tags, principal.User); err != nil {
|
||||
return nil, connect.NewError(connect.CodeInvalidArgument, err)
|
||||
}
|
||||
|
||||
@@ -6,10 +6,9 @@ import (
|
||||
"fmt"
|
||||
"github.com/bufbuild/connect-go"
|
||||
"github.com/jsiebens/ionscale/internal/broker"
|
||||
"github.com/jsiebens/ionscale/internal/config"
|
||||
"github.com/jsiebens/ionscale/internal/domain"
|
||||
"github.com/jsiebens/ionscale/internal/mapping"
|
||||
api "github.com/jsiebens/ionscale/pkg/gen/ionscale/v1"
|
||||
"tailscale.com/util/dnsname"
|
||||
)
|
||||
|
||||
func (s *Service) GetDNSConfig(ctx context.Context, req *connect.Request[api.GetDNSConfigRequest]) (*connect.Response[api.GetDNSConfigResponse], error) {
|
||||
@@ -26,16 +25,16 @@ func (s *Service) GetDNSConfig(ctx context.Context, req *connect.Request[api.Get
|
||||
return nil, connect.NewError(connect.CodeNotFound, errors.New("tailnet not found"))
|
||||
}
|
||||
|
||||
config := tailnet.DNSConfig
|
||||
tailnetDomain := dnsname.SanitizeHostname(tailnet.Name)
|
||||
dnsConfig := tailnet.DNSConfig
|
||||
tailnetDomain := domain.SanitizeTailnetName(tailnet.Name)
|
||||
|
||||
resp := &api.GetDNSConfigResponse{
|
||||
Config: &api.DNSConfig{
|
||||
MagicDns: config.MagicDNS,
|
||||
MagicDnsSuffix: fmt.Sprintf("%s.%s", tailnetDomain, mapping.NetworkMagicDNSSuffix),
|
||||
OverrideLocalDns: config.OverrideLocalDNS,
|
||||
Nameservers: config.Nameservers,
|
||||
Routes: domainRoutesToApiRoutes(config.Routes),
|
||||
MagicDns: dnsConfig.MagicDNS,
|
||||
MagicDnsSuffix: fmt.Sprintf("%s.%s", tailnetDomain, config.MagicDNSSuffix()),
|
||||
OverrideLocalDns: dnsConfig.OverrideLocalDNS,
|
||||
Nameservers: dnsConfig.Nameservers,
|
||||
Routes: domainRoutesToApiRoutes(dnsConfig.Routes),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
+100
-36
@@ -25,17 +25,7 @@ func (s *Service) machineToApi(m *domain.Machine) *api.Machine {
|
||||
online := false
|
||||
if m.LastSeen != nil {
|
||||
lastSeen = timestamppb.New(*m.LastSeen)
|
||||
online = m.LastSeen.After(time.Now().Add(-config.KeepAliveInterval))
|
||||
}
|
||||
|
||||
var advertisedRoutes []string
|
||||
for _, r := range m.HostInfo.RoutableIPs {
|
||||
advertisedRoutes = append(advertisedRoutes, r.String())
|
||||
}
|
||||
|
||||
var enabledRoutes []string
|
||||
for _, r := range m.AllowIPs {
|
||||
enabledRoutes = append(enabledRoutes, r.String())
|
||||
online = m.LastSeen.After(time.Now().Add(-config.KeepAliveInterval()))
|
||||
}
|
||||
|
||||
return &api.Machine{
|
||||
@@ -63,8 +53,10 @@ func (s *Service) machineToApi(m *domain.Machine) *api.Machine {
|
||||
ClientConnectivity: &api.ClientConnectivity{
|
||||
Endpoints: m.Endpoints,
|
||||
},
|
||||
AdvertisedRoutes: advertisedRoutes,
|
||||
EnabledRoutes: enabledRoutes,
|
||||
AdvertisedRoutes: m.AdvertisedPrefixes(),
|
||||
EnabledRoutes: m.AllowedPrefixes(),
|
||||
AdvertisedExitNode: m.IsAdvertisedExitNode(),
|
||||
EnabledExitNode: m.IsAllowedExitNode(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,19 +161,11 @@ func (s *Service) ExpireMachine(ctx context.Context, req *connect.Request[api.Ex
|
||||
}
|
||||
|
||||
func (s *Service) createMachineRoutesResponse(m *domain.Machine) (*connect.Response[api.GetMachineRoutesResponse], error) {
|
||||
var advertisedRoutes []string
|
||||
for _, r := range m.HostInfo.RoutableIPs {
|
||||
advertisedRoutes = append(advertisedRoutes, r.String())
|
||||
}
|
||||
|
||||
var enabledRoutes []string
|
||||
for _, r := range m.AllowIPs {
|
||||
enabledRoutes = append(enabledRoutes, r.String())
|
||||
}
|
||||
|
||||
response := api.GetMachineRoutesResponse{
|
||||
AdvertisedRoutes: advertisedRoutes,
|
||||
EnabledRoutes: enabledRoutes,
|
||||
AdvertisedRoutes: m.AdvertisedPrefixes(),
|
||||
EnabledRoutes: m.AllowedPrefixes(),
|
||||
AdvertisedExitNode: m.IsAdvertisedExitNode(),
|
||||
EnabledExitNode: m.IsAllowedExitNode(),
|
||||
}
|
||||
|
||||
return connect.NewResponse(&response), nil
|
||||
@@ -222,23 +206,24 @@ func (s *Service) EnableMachineRoutes(ctx context.Context, req *connect.Request[
|
||||
return nil, connect.NewError(connect.CodePermissionDenied, errors.New("permission denied"))
|
||||
}
|
||||
|
||||
var enabledRoutes = domain.NewAllowIPsSet(m.AllowIPs)
|
||||
var allowIPs = domain.NewAllowIPsSet(m.AllowIPs)
|
||||
var autoAllowIPs = domain.NewAllowIPsSet(m.AutoAllowIPs)
|
||||
|
||||
if req.Msg.Replace {
|
||||
enabledRoutes = domain.NewAllowIPsSet([]netip.Prefix{})
|
||||
allowIPs = domain.NewAllowIPsSet([]netip.Prefix{})
|
||||
autoAllowIPs = domain.NewAllowIPsSet([]netip.Prefix{})
|
||||
}
|
||||
|
||||
var routesToBeRemoved []netip.Prefix
|
||||
for _, r := range req.Msg.Routes {
|
||||
prefix, err := netip.ParsePrefix(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
enabledRoutes.Add(prefix)
|
||||
routesToBeRemoved = append(routesToBeRemoved, prefix)
|
||||
allowIPs.Add(prefix)
|
||||
}
|
||||
|
||||
m.AllowIPs = enabledRoutes.Items()
|
||||
m.AllowIPs = allowIPs.Items()
|
||||
m.AutoAllowIPs = autoAllowIPs.Items()
|
||||
if err := s.repository.SaveMachine(ctx, m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -264,19 +249,98 @@ func (s *Service) DisableMachineRoutes(ctx context.Context, req *connect.Request
|
||||
return nil, connect.NewError(connect.CodePermissionDenied, errors.New("permission denied"))
|
||||
}
|
||||
|
||||
enabledRoutes := domain.NewAllowIPsSet(m.AllowIPs)
|
||||
allowIPs := domain.NewAllowIPsSet(m.AllowIPs)
|
||||
autoAllowIPs := domain.NewAllowIPsSet(m.AutoAllowIPs)
|
||||
|
||||
var routesToBeRemoved []netip.Prefix
|
||||
for _, r := range req.Msg.Routes {
|
||||
prefix, err := netip.ParsePrefix(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
enabledRoutes.Remove(prefix)
|
||||
routesToBeRemoved = append(routesToBeRemoved, prefix)
|
||||
allowIPs.Remove(prefix)
|
||||
autoAllowIPs.Remove(prefix)
|
||||
}
|
||||
|
||||
m.AllowIPs = enabledRoutes.Items()
|
||||
m.AllowIPs = allowIPs.Items()
|
||||
m.AutoAllowIPs = autoAllowIPs.Items()
|
||||
if err := s.repository.SaveMachine(ctx, m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.pubsub.Publish(m.TailnetID, &broker.Signal{PeerUpdated: &m.ID})
|
||||
|
||||
return s.createMachineRoutesResponse(m)
|
||||
}
|
||||
|
||||
func (s *Service) EnableExitNode(ctx context.Context, req *connect.Request[api.EnableExitNodeRequest]) (*connect.Response[api.GetMachineRoutesResponse], error) {
|
||||
principal := CurrentPrincipal(ctx)
|
||||
|
||||
m, err := s.repository.GetMachine(ctx, req.Msg.MachineId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if m == nil {
|
||||
return nil, connect.NewError(connect.CodeNotFound, errors.New("machine not found"))
|
||||
}
|
||||
|
||||
if !principal.IsSystemAdmin() && !principal.IsTailnetAdmin(m.TailnetID) {
|
||||
return nil, connect.NewError(connect.CodePermissionDenied, errors.New("permission denied"))
|
||||
}
|
||||
|
||||
if !m.IsAdvertisedExitNode() {
|
||||
return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("machine is not a valid exit node"))
|
||||
}
|
||||
|
||||
prefix4 := netip.MustParsePrefix("0.0.0.0/0")
|
||||
prefix6 := netip.MustParsePrefix("::/0")
|
||||
|
||||
allowIPs := domain.NewAllowIPsSet(m.AllowIPs)
|
||||
allowIPs.Add(prefix4, prefix6)
|
||||
|
||||
m.AllowIPs = allowIPs.Items()
|
||||
|
||||
if err := s.repository.SaveMachine(ctx, m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.pubsub.Publish(m.TailnetID, &broker.Signal{PeerUpdated: &m.ID})
|
||||
|
||||
return s.createMachineRoutesResponse(m)
|
||||
}
|
||||
|
||||
func (s *Service) DisableExitNode(ctx context.Context, req *connect.Request[api.DisableExitNodeRequest]) (*connect.Response[api.GetMachineRoutesResponse], error) {
|
||||
principal := CurrentPrincipal(ctx)
|
||||
|
||||
m, err := s.repository.GetMachine(ctx, req.Msg.MachineId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if m == nil {
|
||||
return nil, connect.NewError(connect.CodeNotFound, errors.New("machine not found"))
|
||||
}
|
||||
|
||||
if !principal.IsSystemAdmin() && !principal.IsTailnetAdmin(m.TailnetID) {
|
||||
return nil, connect.NewError(connect.CodePermissionDenied, errors.New("permission denied"))
|
||||
}
|
||||
|
||||
if !m.IsAdvertisedExitNode() {
|
||||
return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("machine is not a valid exit node"))
|
||||
}
|
||||
|
||||
prefix4 := netip.MustParsePrefix("0.0.0.0/0")
|
||||
prefix6 := netip.MustParsePrefix("::/0")
|
||||
|
||||
allowIPs := domain.NewAllowIPsSet(m.AllowIPs)
|
||||
allowIPs.Remove(prefix4, prefix6)
|
||||
|
||||
autoAllowIPs := domain.NewAllowIPsSet(m.AutoAllowIPs)
|
||||
autoAllowIPs.Remove(prefix4, prefix6)
|
||||
|
||||
m.AllowIPs = allowIPs.Items()
|
||||
m.AutoAllowIPs = autoAllowIPs.Items()
|
||||
|
||||
if err := s.repository.SaveMachine(ctx, m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -16,7 +16,15 @@ func (s *Service) CreateTailnet(ctx context.Context, req *connect.Request[api.Cr
|
||||
return nil, connect.NewError(connect.CodePermissionDenied, errors.New("permission denied"))
|
||||
}
|
||||
|
||||
tailnet, created, err := s.repository.GetOrCreateTailnet(ctx, req.Msg.Name)
|
||||
name := req.Msg.Name
|
||||
iamPolicy := domain.IAMPolicy{
|
||||
Subs: req.Msg.IamPolicy.Subs,
|
||||
Emails: req.Msg.IamPolicy.Emails,
|
||||
Filters: req.Msg.IamPolicy.Filters,
|
||||
Roles: apiRolesMapToDomainRolesMap(req.Msg.IamPolicy.Roles),
|
||||
}
|
||||
|
||||
tailnet, created, err := s.repository.GetOrCreateTailnet(ctx, name, iamPolicy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
+144
-48
@@ -213,10 +213,11 @@ type ACLPolicy struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Hosts map[string]string `protobuf:"bytes,1,rep,name=hosts,proto3" json:"hosts,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
Groups map[string]*structpb.ListValue `protobuf:"bytes,2,rep,name=groups,proto3" json:"groups,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
Acls []*ACL `protobuf:"bytes,3,rep,name=acls,proto3" json:"acls,omitempty"`
|
||||
Tagowners map[string]*structpb.ListValue `protobuf:"bytes,4,rep,name=tagowners,proto3" json:"tagowners,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
Hosts map[string]string `protobuf:"bytes,1,rep,name=hosts,proto3" json:"hosts,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
Groups map[string]*structpb.ListValue `protobuf:"bytes,2,rep,name=groups,proto3" json:"groups,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
Acls []*ACL `protobuf:"bytes,3,rep,name=acls,proto3" json:"acls,omitempty"`
|
||||
Tagowners map[string]*structpb.ListValue `protobuf:"bytes,4,rep,name=tagowners,proto3" json:"tagowners,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
Autoapprovers *AutoApprovers `protobuf:"bytes,5,opt,name=autoapprovers,proto3" json:"autoapprovers,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ACLPolicy) Reset() {
|
||||
@@ -279,6 +280,13 @@ func (x *ACLPolicy) GetTagowners() map[string]*structpb.ListValue {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ACLPolicy) GetAutoapprovers() *AutoApprovers {
|
||||
if x != nil {
|
||||
return x.Autoapprovers
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ACL struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -342,6 +350,61 @@ func (x *ACL) GetDst() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
type AutoApprovers struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Routes map[string]*structpb.ListValue `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
Exitnode []string `protobuf:"bytes,2,rep,name=exitnode,proto3" json:"exitnode,omitempty"`
|
||||
}
|
||||
|
||||
func (x *AutoApprovers) Reset() {
|
||||
*x = AutoApprovers{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_ionscale_v1_acl_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *AutoApprovers) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AutoApprovers) ProtoMessage() {}
|
||||
|
||||
func (x *AutoApprovers) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_ionscale_v1_acl_proto_msgTypes[6]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use AutoApprovers.ProtoReflect.Descriptor instead.
|
||||
func (*AutoApprovers) Descriptor() ([]byte, []int) {
|
||||
return file_ionscale_v1_acl_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *AutoApprovers) GetRoutes() map[string]*structpb.ListValue {
|
||||
if x != nil {
|
||||
return x.Routes
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *AutoApprovers) GetExitnode() []string {
|
||||
if x != nil {
|
||||
return x.Exitnode
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_ionscale_v1_acl_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_ionscale_v1_acl_proto_rawDesc = []byte{
|
||||
@@ -366,7 +429,7 @@ var file_ionscale_v1_acl_proto_rawDesc = []byte{
|
||||
0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x43, 0x4c, 0x50,
|
||||
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x16, 0x0a,
|
||||
0x14, 0x53, 0x65, 0x74, 0x41, 0x43, 0x4c, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xd6, 0x03, 0x0a, 0x09, 0x41, 0x43, 0x4c, 0x50, 0x6f, 0x6c,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x98, 0x04, 0x0a, 0x09, 0x41, 0x43, 0x4c, 0x50, 0x6f, 0x6c,
|
||||
0x69, 0x63, 0x79, 0x12, 0x37, 0x0a, 0x05, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x21, 0x2e, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x41, 0x43, 0x4c, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x73,
|
||||
@@ -381,30 +444,46 @@ var file_ionscale_v1_acl_proto_rawDesc = []byte{
|
||||
0x0b, 0x32, 0x25, 0x2e, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x41, 0x43, 0x4c, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x54, 0x61, 0x67, 0x6f, 0x77, 0x6e,
|
||||
0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x74, 0x61, 0x67, 0x6f, 0x77, 0x6e,
|
||||
0x65, 0x72, 0x73, 0x1a, 0x38, 0x0a, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72,
|
||||
0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
|
||||
0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x55, 0x0a,
|
||||
0x0b, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
|
||||
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30,
|
||||
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
|
||||
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
|
||||
0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
||||
0x3a, 0x02, 0x38, 0x01, 0x1a, 0x58, 0x0a, 0x0e, 0x54, 0x61, 0x67, 0x6f, 0x77, 0x6e, 0x65, 0x72,
|
||||
0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
|
||||
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61,
|
||||
0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x41,
|
||||
0x0a, 0x03, 0x41, 0x43, 0x4c, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a,
|
||||
0x03, 0x73, 0x72, 0x63, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x73, 0x72, 0x63, 0x12,
|
||||
0x10, 0x0a, 0x03, 0x64, 0x73, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x64, 0x73,
|
||||
0x74, 0x42, 0x3d, 0x5a, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
|
||||
0x6a, 0x73, 0x69, 0x65, 0x62, 0x65, 0x6e, 0x73, 0x2f, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c,
|
||||
0x65, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61,
|
||||
0x6c, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x76, 0x31,
|
||||
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x65, 0x72, 0x73, 0x12, 0x40, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x6f, 0x61, 0x70, 0x70, 0x72, 0x6f,
|
||||
0x76, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x69, 0x6f, 0x6e,
|
||||
0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x41, 0x70, 0x70,
|
||||
0x72, 0x6f, 0x76, 0x65, 0x72, 0x73, 0x52, 0x0d, 0x61, 0x75, 0x74, 0x6f, 0x61, 0x70, 0x70, 0x72,
|
||||
0x6f, 0x76, 0x65, 0x72, 0x73, 0x1a, 0x38, 0x0a, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x45, 0x6e,
|
||||
0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a,
|
||||
0x55, 0x0a, 0x0b, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
|
||||
0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
|
||||
0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
|
||||
0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c,
|
||||
0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x58, 0x0a, 0x0e, 0x54, 0x61, 0x67, 0x6f, 0x77, 0x6e,
|
||||
0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61,
|
||||
0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
|
||||
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74,
|
||||
0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
|
||||
0x22, 0x41, 0x0a, 0x03, 0x41, 0x43, 0x4c, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12,
|
||||
0x10, 0x0a, 0x03, 0x73, 0x72, 0x63, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x73, 0x72,
|
||||
0x63, 0x12, 0x10, 0x0a, 0x03, 0x64, 0x73, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03,
|
||||
0x64, 0x73, 0x74, 0x22, 0xc2, 0x01, 0x0a, 0x0d, 0x41, 0x75, 0x74, 0x6f, 0x41, 0x70, 0x70, 0x72,
|
||||
0x6f, 0x76, 0x65, 0x72, 0x73, 0x12, 0x3e, 0x0a, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18,
|
||||
0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72,
|
||||
0x73, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x72,
|
||||
0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x69, 0x74, 0x6e, 0x6f, 0x64,
|
||||
0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x65, 0x78, 0x69, 0x74, 0x6e, 0x6f, 0x64,
|
||||
0x65, 0x1a, 0x55, 0x0a, 0x0b, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
|
||||
0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
|
||||
0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76,
|
||||
0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x3d, 0x5a, 0x3b, 0x67, 0x69, 0x74, 0x68,
|
||||
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6a, 0x73, 0x69, 0x65, 0x62, 0x65, 0x6e, 0x73, 0x2f,
|
||||
0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x65, 0x6e,
|
||||
0x2f, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x69, 0x6f, 0x6e,
|
||||
0x73, 0x63, 0x61, 0x6c, 0x65, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -419,7 +498,7 @@ func file_ionscale_v1_acl_proto_rawDescGZIP() []byte {
|
||||
return file_ionscale_v1_acl_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_ionscale_v1_acl_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
|
||||
var file_ionscale_v1_acl_proto_msgTypes = make([]protoimpl.MessageInfo, 11)
|
||||
var file_ionscale_v1_acl_proto_goTypes = []interface{}{
|
||||
(*GetACLPolicyRequest)(nil), // 0: ionscale.v1.GetACLPolicyRequest
|
||||
(*GetACLPolicyResponse)(nil), // 1: ionscale.v1.GetACLPolicyResponse
|
||||
@@ -427,25 +506,30 @@ var file_ionscale_v1_acl_proto_goTypes = []interface{}{
|
||||
(*SetACLPolicyResponse)(nil), // 3: ionscale.v1.SetACLPolicyResponse
|
||||
(*ACLPolicy)(nil), // 4: ionscale.v1.ACLPolicy
|
||||
(*ACL)(nil), // 5: ionscale.v1.ACL
|
||||
nil, // 6: ionscale.v1.ACLPolicy.HostsEntry
|
||||
nil, // 7: ionscale.v1.ACLPolicy.GroupsEntry
|
||||
nil, // 8: ionscale.v1.ACLPolicy.TagownersEntry
|
||||
(*structpb.ListValue)(nil), // 9: google.protobuf.ListValue
|
||||
(*AutoApprovers)(nil), // 6: ionscale.v1.AutoApprovers
|
||||
nil, // 7: ionscale.v1.ACLPolicy.HostsEntry
|
||||
nil, // 8: ionscale.v1.ACLPolicy.GroupsEntry
|
||||
nil, // 9: ionscale.v1.ACLPolicy.TagownersEntry
|
||||
nil, // 10: ionscale.v1.AutoApprovers.RoutesEntry
|
||||
(*structpb.ListValue)(nil), // 11: google.protobuf.ListValue
|
||||
}
|
||||
var file_ionscale_v1_acl_proto_depIdxs = []int32{
|
||||
4, // 0: ionscale.v1.GetACLPolicyResponse.policy:type_name -> ionscale.v1.ACLPolicy
|
||||
4, // 1: ionscale.v1.SetACLPolicyRequest.policy:type_name -> ionscale.v1.ACLPolicy
|
||||
6, // 2: ionscale.v1.ACLPolicy.hosts:type_name -> ionscale.v1.ACLPolicy.HostsEntry
|
||||
7, // 3: ionscale.v1.ACLPolicy.groups:type_name -> ionscale.v1.ACLPolicy.GroupsEntry
|
||||
5, // 4: ionscale.v1.ACLPolicy.acls:type_name -> ionscale.v1.ACL
|
||||
8, // 5: ionscale.v1.ACLPolicy.tagowners:type_name -> ionscale.v1.ACLPolicy.TagownersEntry
|
||||
9, // 6: ionscale.v1.ACLPolicy.GroupsEntry.value:type_name -> google.protobuf.ListValue
|
||||
9, // 7: ionscale.v1.ACLPolicy.TagownersEntry.value:type_name -> google.protobuf.ListValue
|
||||
8, // [8:8] is the sub-list for method output_type
|
||||
8, // [8:8] is the sub-list for method input_type
|
||||
8, // [8:8] is the sub-list for extension type_name
|
||||
8, // [8:8] is the sub-list for extension extendee
|
||||
0, // [0:8] is the sub-list for field type_name
|
||||
4, // 0: ionscale.v1.GetACLPolicyResponse.policy:type_name -> ionscale.v1.ACLPolicy
|
||||
4, // 1: ionscale.v1.SetACLPolicyRequest.policy:type_name -> ionscale.v1.ACLPolicy
|
||||
7, // 2: ionscale.v1.ACLPolicy.hosts:type_name -> ionscale.v1.ACLPolicy.HostsEntry
|
||||
8, // 3: ionscale.v1.ACLPolicy.groups:type_name -> ionscale.v1.ACLPolicy.GroupsEntry
|
||||
5, // 4: ionscale.v1.ACLPolicy.acls:type_name -> ionscale.v1.ACL
|
||||
9, // 5: ionscale.v1.ACLPolicy.tagowners:type_name -> ionscale.v1.ACLPolicy.TagownersEntry
|
||||
6, // 6: ionscale.v1.ACLPolicy.autoapprovers:type_name -> ionscale.v1.AutoApprovers
|
||||
10, // 7: ionscale.v1.AutoApprovers.routes:type_name -> ionscale.v1.AutoApprovers.RoutesEntry
|
||||
11, // 8: ionscale.v1.ACLPolicy.GroupsEntry.value:type_name -> google.protobuf.ListValue
|
||||
11, // 9: ionscale.v1.ACLPolicy.TagownersEntry.value:type_name -> google.protobuf.ListValue
|
||||
11, // 10: ionscale.v1.AutoApprovers.RoutesEntry.value:type_name -> google.protobuf.ListValue
|
||||
11, // [11:11] is the sub-list for method output_type
|
||||
11, // [11:11] is the sub-list for method input_type
|
||||
11, // [11:11] is the sub-list for extension type_name
|
||||
11, // [11:11] is the sub-list for extension extendee
|
||||
0, // [0:11] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_ionscale_v1_acl_proto_init() }
|
||||
@@ -527,6 +611,18 @@ func file_ionscale_v1_acl_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_ionscale_v1_acl_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*AutoApprovers); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
@@ -534,7 +630,7 @@ func file_ionscale_v1_acl_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_ionscale_v1_acl_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 9,
|
||||
NumMessages: 11,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
||||
@@ -48,7 +48,7 @@ var file_ionscale_v1_ionscale_proto_rawDesc = []byte{
|
||||
0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31,
|
||||
0x2f, 0x61, 0x63, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x16, 0x69, 0x6f, 0x6e, 0x73,
|
||||
0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x65, 0x72, 0x70, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x32, 0xbf, 0x13, 0x0a, 0x0f, 0x49, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x53,
|
||||
0x74, 0x6f, 0x32, 0xff, 0x14, 0x0a, 0x0f, 0x49, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x53,
|
||||
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4f, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72,
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71,
|
||||
@@ -204,6 +204,18 @@ var file_ionscale_v1_ionscale_proto_rawDesc = []byte{
|
||||
0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x69, 0x6f,
|
||||
0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63,
|
||||
0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x0e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x78,
|
||||
0x69, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x2e, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c,
|
||||
0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x78, 0x69, 0x74, 0x4e,
|
||||
0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x69, 0x6f, 0x6e,
|
||||
0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, 0x68,
|
||||
0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x22, 0x00, 0x12, 0x5f, 0x0a, 0x0f, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x78,
|
||||
0x69, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x23, 0x2e, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c,
|
||||
0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x78, 0x69, 0x74,
|
||||
0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x69, 0x6f,
|
||||
0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63,
|
||||
0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x22, 0x00, 0x42, 0x3d, 0x5a, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
|
||||
0x6f, 0x6d, 0x2f, 0x6a, 0x73, 0x69, 0x65, 0x62, 0x65, 0x6e, 0x73, 0x2f, 0x69, 0x6f, 0x6e, 0x73,
|
||||
0x63, 0x61, 0x6c, 0x65, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x69, 0x6f, 0x6e,
|
||||
@@ -240,32 +252,34 @@ var file_ionscale_v1_ionscale_proto_goTypes = []interface{}{
|
||||
(*GetMachineRoutesRequest)(nil), // 25: ionscale.v1.GetMachineRoutesRequest
|
||||
(*EnableMachineRoutesRequest)(nil), // 26: ionscale.v1.EnableMachineRoutesRequest
|
||||
(*DisableMachineRoutesRequest)(nil), // 27: ionscale.v1.DisableMachineRoutesRequest
|
||||
(*GetVersionResponse)(nil), // 28: ionscale.v1.GetVersionResponse
|
||||
(*AuthenticationResponse)(nil), // 29: ionscale.v1.AuthenticationResponse
|
||||
(*GetDERPMapResponse)(nil), // 30: ionscale.v1.GetDERPMapResponse
|
||||
(*SetDERPMapResponse)(nil), // 31: ionscale.v1.SetDERPMapResponse
|
||||
(*CreateTailnetResponse)(nil), // 32: ionscale.v1.CreateTailnetResponse
|
||||
(*GetTailnetResponse)(nil), // 33: ionscale.v1.GetTailnetResponse
|
||||
(*ListTailnetResponse)(nil), // 34: ionscale.v1.ListTailnetResponse
|
||||
(*DeleteTailnetResponse)(nil), // 35: ionscale.v1.DeleteTailnetResponse
|
||||
(*GetDNSConfigResponse)(nil), // 36: ionscale.v1.GetDNSConfigResponse
|
||||
(*SetDNSConfigResponse)(nil), // 37: ionscale.v1.SetDNSConfigResponse
|
||||
(*GetIAMPolicyResponse)(nil), // 38: ionscale.v1.GetIAMPolicyResponse
|
||||
(*SetIAMPolicyResponse)(nil), // 39: ionscale.v1.SetIAMPolicyResponse
|
||||
(*GetACLPolicyResponse)(nil), // 40: ionscale.v1.GetACLPolicyResponse
|
||||
(*SetACLPolicyResponse)(nil), // 41: ionscale.v1.SetACLPolicyResponse
|
||||
(*GetAuthKeyResponse)(nil), // 42: ionscale.v1.GetAuthKeyResponse
|
||||
(*CreateAuthKeyResponse)(nil), // 43: ionscale.v1.CreateAuthKeyResponse
|
||||
(*DeleteAuthKeyResponse)(nil), // 44: ionscale.v1.DeleteAuthKeyResponse
|
||||
(*ListAuthKeysResponse)(nil), // 45: ionscale.v1.ListAuthKeysResponse
|
||||
(*ListUsersResponse)(nil), // 46: ionscale.v1.ListUsersResponse
|
||||
(*DeleteUserResponse)(nil), // 47: ionscale.v1.DeleteUserResponse
|
||||
(*GetMachineResponse)(nil), // 48: ionscale.v1.GetMachineResponse
|
||||
(*ListMachinesResponse)(nil), // 49: ionscale.v1.ListMachinesResponse
|
||||
(*ExpireMachineResponse)(nil), // 50: ionscale.v1.ExpireMachineResponse
|
||||
(*DeleteMachineResponse)(nil), // 51: ionscale.v1.DeleteMachineResponse
|
||||
(*SetMachineKeyExpiryResponse)(nil), // 52: ionscale.v1.SetMachineKeyExpiryResponse
|
||||
(*GetMachineRoutesResponse)(nil), // 53: ionscale.v1.GetMachineRoutesResponse
|
||||
(*EnableExitNodeRequest)(nil), // 28: ionscale.v1.EnableExitNodeRequest
|
||||
(*DisableExitNodeRequest)(nil), // 29: ionscale.v1.DisableExitNodeRequest
|
||||
(*GetVersionResponse)(nil), // 30: ionscale.v1.GetVersionResponse
|
||||
(*AuthenticationResponse)(nil), // 31: ionscale.v1.AuthenticationResponse
|
||||
(*GetDERPMapResponse)(nil), // 32: ionscale.v1.GetDERPMapResponse
|
||||
(*SetDERPMapResponse)(nil), // 33: ionscale.v1.SetDERPMapResponse
|
||||
(*CreateTailnetResponse)(nil), // 34: ionscale.v1.CreateTailnetResponse
|
||||
(*GetTailnetResponse)(nil), // 35: ionscale.v1.GetTailnetResponse
|
||||
(*ListTailnetResponse)(nil), // 36: ionscale.v1.ListTailnetResponse
|
||||
(*DeleteTailnetResponse)(nil), // 37: ionscale.v1.DeleteTailnetResponse
|
||||
(*GetDNSConfigResponse)(nil), // 38: ionscale.v1.GetDNSConfigResponse
|
||||
(*SetDNSConfigResponse)(nil), // 39: ionscale.v1.SetDNSConfigResponse
|
||||
(*GetIAMPolicyResponse)(nil), // 40: ionscale.v1.GetIAMPolicyResponse
|
||||
(*SetIAMPolicyResponse)(nil), // 41: ionscale.v1.SetIAMPolicyResponse
|
||||
(*GetACLPolicyResponse)(nil), // 42: ionscale.v1.GetACLPolicyResponse
|
||||
(*SetACLPolicyResponse)(nil), // 43: ionscale.v1.SetACLPolicyResponse
|
||||
(*GetAuthKeyResponse)(nil), // 44: ionscale.v1.GetAuthKeyResponse
|
||||
(*CreateAuthKeyResponse)(nil), // 45: ionscale.v1.CreateAuthKeyResponse
|
||||
(*DeleteAuthKeyResponse)(nil), // 46: ionscale.v1.DeleteAuthKeyResponse
|
||||
(*ListAuthKeysResponse)(nil), // 47: ionscale.v1.ListAuthKeysResponse
|
||||
(*ListUsersResponse)(nil), // 48: ionscale.v1.ListUsersResponse
|
||||
(*DeleteUserResponse)(nil), // 49: ionscale.v1.DeleteUserResponse
|
||||
(*GetMachineResponse)(nil), // 50: ionscale.v1.GetMachineResponse
|
||||
(*ListMachinesResponse)(nil), // 51: ionscale.v1.ListMachinesResponse
|
||||
(*ExpireMachineResponse)(nil), // 52: ionscale.v1.ExpireMachineResponse
|
||||
(*DeleteMachineResponse)(nil), // 53: ionscale.v1.DeleteMachineResponse
|
||||
(*SetMachineKeyExpiryResponse)(nil), // 54: ionscale.v1.SetMachineKeyExpiryResponse
|
||||
(*GetMachineRoutesResponse)(nil), // 55: ionscale.v1.GetMachineRoutesResponse
|
||||
}
|
||||
var file_ionscale_v1_ionscale_proto_depIdxs = []int32{
|
||||
0, // 0: ionscale.v1.IonscaleService.GetVersion:input_type -> ionscale.v1.GetVersionRequest
|
||||
@@ -296,36 +310,40 @@ var file_ionscale_v1_ionscale_proto_depIdxs = []int32{
|
||||
25, // 25: ionscale.v1.IonscaleService.GetMachineRoutes:input_type -> ionscale.v1.GetMachineRoutesRequest
|
||||
26, // 26: ionscale.v1.IonscaleService.EnableMachineRoutes:input_type -> ionscale.v1.EnableMachineRoutesRequest
|
||||
27, // 27: ionscale.v1.IonscaleService.DisableMachineRoutes:input_type -> ionscale.v1.DisableMachineRoutesRequest
|
||||
28, // 28: ionscale.v1.IonscaleService.GetVersion:output_type -> ionscale.v1.GetVersionResponse
|
||||
29, // 29: ionscale.v1.IonscaleService.Authenticate:output_type -> ionscale.v1.AuthenticationResponse
|
||||
30, // 30: ionscale.v1.IonscaleService.GetDERPMap:output_type -> ionscale.v1.GetDERPMapResponse
|
||||
31, // 31: ionscale.v1.IonscaleService.SetDERPMap:output_type -> ionscale.v1.SetDERPMapResponse
|
||||
32, // 32: ionscale.v1.IonscaleService.CreateTailnet:output_type -> ionscale.v1.CreateTailnetResponse
|
||||
33, // 33: ionscale.v1.IonscaleService.GetTailnet:output_type -> ionscale.v1.GetTailnetResponse
|
||||
34, // 34: ionscale.v1.IonscaleService.ListTailnets:output_type -> ionscale.v1.ListTailnetResponse
|
||||
35, // 35: ionscale.v1.IonscaleService.DeleteTailnet:output_type -> ionscale.v1.DeleteTailnetResponse
|
||||
36, // 36: ionscale.v1.IonscaleService.GetDNSConfig:output_type -> ionscale.v1.GetDNSConfigResponse
|
||||
37, // 37: ionscale.v1.IonscaleService.SetDNSConfig:output_type -> ionscale.v1.SetDNSConfigResponse
|
||||
38, // 38: ionscale.v1.IonscaleService.GetIAMPolicy:output_type -> ionscale.v1.GetIAMPolicyResponse
|
||||
39, // 39: ionscale.v1.IonscaleService.SetIAMPolicy:output_type -> ionscale.v1.SetIAMPolicyResponse
|
||||
40, // 40: ionscale.v1.IonscaleService.GetACLPolicy:output_type -> ionscale.v1.GetACLPolicyResponse
|
||||
41, // 41: ionscale.v1.IonscaleService.SetACLPolicy:output_type -> ionscale.v1.SetACLPolicyResponse
|
||||
42, // 42: ionscale.v1.IonscaleService.GetAuthKey:output_type -> ionscale.v1.GetAuthKeyResponse
|
||||
43, // 43: ionscale.v1.IonscaleService.CreateAuthKey:output_type -> ionscale.v1.CreateAuthKeyResponse
|
||||
44, // 44: ionscale.v1.IonscaleService.DeleteAuthKey:output_type -> ionscale.v1.DeleteAuthKeyResponse
|
||||
45, // 45: ionscale.v1.IonscaleService.ListAuthKeys:output_type -> ionscale.v1.ListAuthKeysResponse
|
||||
46, // 46: ionscale.v1.IonscaleService.ListUsers:output_type -> ionscale.v1.ListUsersResponse
|
||||
47, // 47: ionscale.v1.IonscaleService.DeleteUser:output_type -> ionscale.v1.DeleteUserResponse
|
||||
48, // 48: ionscale.v1.IonscaleService.GetMachine:output_type -> ionscale.v1.GetMachineResponse
|
||||
49, // 49: ionscale.v1.IonscaleService.ListMachines:output_type -> ionscale.v1.ListMachinesResponse
|
||||
50, // 50: ionscale.v1.IonscaleService.ExpireMachine:output_type -> ionscale.v1.ExpireMachineResponse
|
||||
51, // 51: ionscale.v1.IonscaleService.DeleteMachine:output_type -> ionscale.v1.DeleteMachineResponse
|
||||
52, // 52: ionscale.v1.IonscaleService.SetMachineKeyExpiry:output_type -> ionscale.v1.SetMachineKeyExpiryResponse
|
||||
53, // 53: ionscale.v1.IonscaleService.GetMachineRoutes:output_type -> ionscale.v1.GetMachineRoutesResponse
|
||||
53, // 54: ionscale.v1.IonscaleService.EnableMachineRoutes:output_type -> ionscale.v1.GetMachineRoutesResponse
|
||||
53, // 55: ionscale.v1.IonscaleService.DisableMachineRoutes:output_type -> ionscale.v1.GetMachineRoutesResponse
|
||||
28, // [28:56] is the sub-list for method output_type
|
||||
0, // [0:28] is the sub-list for method input_type
|
||||
28, // 28: ionscale.v1.IonscaleService.EnableExitNode:input_type -> ionscale.v1.EnableExitNodeRequest
|
||||
29, // 29: ionscale.v1.IonscaleService.DisableExitNode:input_type -> ionscale.v1.DisableExitNodeRequest
|
||||
30, // 30: ionscale.v1.IonscaleService.GetVersion:output_type -> ionscale.v1.GetVersionResponse
|
||||
31, // 31: ionscale.v1.IonscaleService.Authenticate:output_type -> ionscale.v1.AuthenticationResponse
|
||||
32, // 32: ionscale.v1.IonscaleService.GetDERPMap:output_type -> ionscale.v1.GetDERPMapResponse
|
||||
33, // 33: ionscale.v1.IonscaleService.SetDERPMap:output_type -> ionscale.v1.SetDERPMapResponse
|
||||
34, // 34: ionscale.v1.IonscaleService.CreateTailnet:output_type -> ionscale.v1.CreateTailnetResponse
|
||||
35, // 35: ionscale.v1.IonscaleService.GetTailnet:output_type -> ionscale.v1.GetTailnetResponse
|
||||
36, // 36: ionscale.v1.IonscaleService.ListTailnets:output_type -> ionscale.v1.ListTailnetResponse
|
||||
37, // 37: ionscale.v1.IonscaleService.DeleteTailnet:output_type -> ionscale.v1.DeleteTailnetResponse
|
||||
38, // 38: ionscale.v1.IonscaleService.GetDNSConfig:output_type -> ionscale.v1.GetDNSConfigResponse
|
||||
39, // 39: ionscale.v1.IonscaleService.SetDNSConfig:output_type -> ionscale.v1.SetDNSConfigResponse
|
||||
40, // 40: ionscale.v1.IonscaleService.GetIAMPolicy:output_type -> ionscale.v1.GetIAMPolicyResponse
|
||||
41, // 41: ionscale.v1.IonscaleService.SetIAMPolicy:output_type -> ionscale.v1.SetIAMPolicyResponse
|
||||
42, // 42: ionscale.v1.IonscaleService.GetACLPolicy:output_type -> ionscale.v1.GetACLPolicyResponse
|
||||
43, // 43: ionscale.v1.IonscaleService.SetACLPolicy:output_type -> ionscale.v1.SetACLPolicyResponse
|
||||
44, // 44: ionscale.v1.IonscaleService.GetAuthKey:output_type -> ionscale.v1.GetAuthKeyResponse
|
||||
45, // 45: ionscale.v1.IonscaleService.CreateAuthKey:output_type -> ionscale.v1.CreateAuthKeyResponse
|
||||
46, // 46: ionscale.v1.IonscaleService.DeleteAuthKey:output_type -> ionscale.v1.DeleteAuthKeyResponse
|
||||
47, // 47: ionscale.v1.IonscaleService.ListAuthKeys:output_type -> ionscale.v1.ListAuthKeysResponse
|
||||
48, // 48: ionscale.v1.IonscaleService.ListUsers:output_type -> ionscale.v1.ListUsersResponse
|
||||
49, // 49: ionscale.v1.IonscaleService.DeleteUser:output_type -> ionscale.v1.DeleteUserResponse
|
||||
50, // 50: ionscale.v1.IonscaleService.GetMachine:output_type -> ionscale.v1.GetMachineResponse
|
||||
51, // 51: ionscale.v1.IonscaleService.ListMachines:output_type -> ionscale.v1.ListMachinesResponse
|
||||
52, // 52: ionscale.v1.IonscaleService.ExpireMachine:output_type -> ionscale.v1.ExpireMachineResponse
|
||||
53, // 53: ionscale.v1.IonscaleService.DeleteMachine:output_type -> ionscale.v1.DeleteMachineResponse
|
||||
54, // 54: ionscale.v1.IonscaleService.SetMachineKeyExpiry:output_type -> ionscale.v1.SetMachineKeyExpiryResponse
|
||||
55, // 55: ionscale.v1.IonscaleService.GetMachineRoutes:output_type -> ionscale.v1.GetMachineRoutesResponse
|
||||
55, // 56: ionscale.v1.IonscaleService.EnableMachineRoutes:output_type -> ionscale.v1.GetMachineRoutesResponse
|
||||
55, // 57: ionscale.v1.IonscaleService.DisableMachineRoutes:output_type -> ionscale.v1.GetMachineRoutesResponse
|
||||
55, // 58: ionscale.v1.IonscaleService.EnableExitNode:output_type -> ionscale.v1.GetMachineRoutesResponse
|
||||
55, // 59: ionscale.v1.IonscaleService.DisableExitNode:output_type -> ionscale.v1.GetMachineRoutesResponse
|
||||
30, // [30:60] is the sub-list for method output_type
|
||||
0, // [0:30] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
|
||||
@@ -55,6 +55,8 @@ type IonscaleServiceClient interface {
|
||||
GetMachineRoutes(context.Context, *connect_go.Request[v1.GetMachineRoutesRequest]) (*connect_go.Response[v1.GetMachineRoutesResponse], error)
|
||||
EnableMachineRoutes(context.Context, *connect_go.Request[v1.EnableMachineRoutesRequest]) (*connect_go.Response[v1.GetMachineRoutesResponse], error)
|
||||
DisableMachineRoutes(context.Context, *connect_go.Request[v1.DisableMachineRoutesRequest]) (*connect_go.Response[v1.GetMachineRoutesResponse], error)
|
||||
EnableExitNode(context.Context, *connect_go.Request[v1.EnableExitNodeRequest]) (*connect_go.Response[v1.GetMachineRoutesResponse], error)
|
||||
DisableExitNode(context.Context, *connect_go.Request[v1.DisableExitNodeRequest]) (*connect_go.Response[v1.GetMachineRoutesResponse], error)
|
||||
}
|
||||
|
||||
// NewIonscaleServiceClient constructs a client for the ionscale.v1.IonscaleService service. By
|
||||
@@ -207,6 +209,16 @@ func NewIonscaleServiceClient(httpClient connect_go.HTTPClient, baseURL string,
|
||||
baseURL+"/ionscale.v1.IonscaleService/DisableMachineRoutes",
|
||||
opts...,
|
||||
),
|
||||
enableExitNode: connect_go.NewClient[v1.EnableExitNodeRequest, v1.GetMachineRoutesResponse](
|
||||
httpClient,
|
||||
baseURL+"/ionscale.v1.IonscaleService/EnableExitNode",
|
||||
opts...,
|
||||
),
|
||||
disableExitNode: connect_go.NewClient[v1.DisableExitNodeRequest, v1.GetMachineRoutesResponse](
|
||||
httpClient,
|
||||
baseURL+"/ionscale.v1.IonscaleService/DisableExitNode",
|
||||
opts...,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,6 +252,8 @@ type ionscaleServiceClient struct {
|
||||
getMachineRoutes *connect_go.Client[v1.GetMachineRoutesRequest, v1.GetMachineRoutesResponse]
|
||||
enableMachineRoutes *connect_go.Client[v1.EnableMachineRoutesRequest, v1.GetMachineRoutesResponse]
|
||||
disableMachineRoutes *connect_go.Client[v1.DisableMachineRoutesRequest, v1.GetMachineRoutesResponse]
|
||||
enableExitNode *connect_go.Client[v1.EnableExitNodeRequest, v1.GetMachineRoutesResponse]
|
||||
disableExitNode *connect_go.Client[v1.DisableExitNodeRequest, v1.GetMachineRoutesResponse]
|
||||
}
|
||||
|
||||
// GetVersion calls ionscale.v1.IonscaleService.GetVersion.
|
||||
@@ -382,6 +396,16 @@ func (c *ionscaleServiceClient) DisableMachineRoutes(ctx context.Context, req *c
|
||||
return c.disableMachineRoutes.CallUnary(ctx, req)
|
||||
}
|
||||
|
||||
// EnableExitNode calls ionscale.v1.IonscaleService.EnableExitNode.
|
||||
func (c *ionscaleServiceClient) EnableExitNode(ctx context.Context, req *connect_go.Request[v1.EnableExitNodeRequest]) (*connect_go.Response[v1.GetMachineRoutesResponse], error) {
|
||||
return c.enableExitNode.CallUnary(ctx, req)
|
||||
}
|
||||
|
||||
// DisableExitNode calls ionscale.v1.IonscaleService.DisableExitNode.
|
||||
func (c *ionscaleServiceClient) DisableExitNode(ctx context.Context, req *connect_go.Request[v1.DisableExitNodeRequest]) (*connect_go.Response[v1.GetMachineRoutesResponse], error) {
|
||||
return c.disableExitNode.CallUnary(ctx, req)
|
||||
}
|
||||
|
||||
// IonscaleServiceHandler is an implementation of the ionscale.v1.IonscaleService service.
|
||||
type IonscaleServiceHandler interface {
|
||||
GetVersion(context.Context, *connect_go.Request[v1.GetVersionRequest]) (*connect_go.Response[v1.GetVersionResponse], error)
|
||||
@@ -412,6 +436,8 @@ type IonscaleServiceHandler interface {
|
||||
GetMachineRoutes(context.Context, *connect_go.Request[v1.GetMachineRoutesRequest]) (*connect_go.Response[v1.GetMachineRoutesResponse], error)
|
||||
EnableMachineRoutes(context.Context, *connect_go.Request[v1.EnableMachineRoutesRequest]) (*connect_go.Response[v1.GetMachineRoutesResponse], error)
|
||||
DisableMachineRoutes(context.Context, *connect_go.Request[v1.DisableMachineRoutesRequest]) (*connect_go.Response[v1.GetMachineRoutesResponse], error)
|
||||
EnableExitNode(context.Context, *connect_go.Request[v1.EnableExitNodeRequest]) (*connect_go.Response[v1.GetMachineRoutesResponse], error)
|
||||
DisableExitNode(context.Context, *connect_go.Request[v1.DisableExitNodeRequest]) (*connect_go.Response[v1.GetMachineRoutesResponse], error)
|
||||
}
|
||||
|
||||
// NewIonscaleServiceHandler builds an HTTP handler from the service implementation. It returns the
|
||||
@@ -561,6 +587,16 @@ func NewIonscaleServiceHandler(svc IonscaleServiceHandler, opts ...connect_go.Ha
|
||||
svc.DisableMachineRoutes,
|
||||
opts...,
|
||||
))
|
||||
mux.Handle("/ionscale.v1.IonscaleService/EnableExitNode", connect_go.NewUnaryHandler(
|
||||
"/ionscale.v1.IonscaleService/EnableExitNode",
|
||||
svc.EnableExitNode,
|
||||
opts...,
|
||||
))
|
||||
mux.Handle("/ionscale.v1.IonscaleService/DisableExitNode", connect_go.NewUnaryHandler(
|
||||
"/ionscale.v1.IonscaleService/DisableExitNode",
|
||||
svc.DisableExitNode,
|
||||
opts...,
|
||||
))
|
||||
return "/ionscale.v1.IonscaleService/", mux
|
||||
}
|
||||
|
||||
@@ -678,3 +714,11 @@ func (UnimplementedIonscaleServiceHandler) EnableMachineRoutes(context.Context,
|
||||
func (UnimplementedIonscaleServiceHandler) DisableMachineRoutes(context.Context, *connect_go.Request[v1.DisableMachineRoutesRequest]) (*connect_go.Response[v1.GetMachineRoutesResponse], error) {
|
||||
return nil, connect_go.NewError(connect_go.CodeUnimplemented, errors.New("ionscale.v1.IonscaleService.DisableMachineRoutes is not implemented"))
|
||||
}
|
||||
|
||||
func (UnimplementedIonscaleServiceHandler) EnableExitNode(context.Context, *connect_go.Request[v1.EnableExitNodeRequest]) (*connect_go.Response[v1.GetMachineRoutesResponse], error) {
|
||||
return nil, connect_go.NewError(connect_go.CodeUnimplemented, errors.New("ionscale.v1.IonscaleService.EnableExitNode is not implemented"))
|
||||
}
|
||||
|
||||
func (UnimplementedIonscaleServiceHandler) DisableExitNode(context.Context, *connect_go.Request[v1.DisableExitNodeRequest]) (*connect_go.Response[v1.GetMachineRoutesResponse], error) {
|
||||
return nil, connect_go.NewError(connect_go.CodeUnimplemented, errors.New("ionscale.v1.IonscaleService.DisableExitNode is not implemented"))
|
||||
}
|
||||
|
||||
@@ -496,6 +496,8 @@ type Machine struct {
|
||||
KeyExpiryDisabled bool `protobuf:"varint,16,opt,name=key_expiry_disabled,json=keyExpiryDisabled,proto3" json:"key_expiry_disabled,omitempty"`
|
||||
EnabledRoutes []string `protobuf:"bytes,17,rep,name=enabled_routes,json=enabledRoutes,proto3" json:"enabled_routes,omitempty"`
|
||||
AdvertisedRoutes []string `protobuf:"bytes,18,rep,name=advertised_routes,json=advertisedRoutes,proto3" json:"advertised_routes,omitempty"`
|
||||
AdvertisedExitNode bool `protobuf:"varint,19,opt,name=advertised_exit_node,json=advertisedExitNode,proto3" json:"advertised_exit_node,omitempty"`
|
||||
EnabledExitNode bool `protobuf:"varint,20,opt,name=enabled_exit_node,json=enabledExitNode,proto3" json:"enabled_exit_node,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Machine) Reset() {
|
||||
@@ -656,6 +658,20 @@ func (x *Machine) GetAdvertisedRoutes() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Machine) GetAdvertisedExitNode() bool {
|
||||
if x != nil {
|
||||
return x.AdvertisedExitNode
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *Machine) GetEnabledExitNode() bool {
|
||||
if x != nil {
|
||||
return x.EnabledExitNode
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type ClientConnectivity struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -747,7 +763,7 @@ var file_ionscale_v1_machines_proto_rawDesc = []byte{
|
||||
0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x07, 0x6d, 0x61, 0x63, 0x68,
|
||||
0x69, 0x6e, 0x65, 0x22, 0xb3, 0x05, 0x0a, 0x07, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12,
|
||||
0x69, 0x6e, 0x65, 0x22, 0x91, 0x06, 0x0a, 0x07, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12,
|
||||
0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12,
|
||||
0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x70, 0x76, 0x34, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||
@@ -790,15 +806,21 @@ var file_ionscale_v1_machines_proto_rawDesc = []byte{
|
||||
0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x2b, 0x0a, 0x11,
|
||||
0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x73, 0x18, 0x12, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69,
|
||||
0x73, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x22, 0x32, 0x0a, 0x12, 0x43, 0x6c, 0x69,
|
||||
0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x12,
|
||||
0x1c, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03,
|
||||
0x28, 0x09, 0x52, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x42, 0x3d, 0x5a,
|
||||
0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6a, 0x73, 0x69, 0x65,
|
||||
0x62, 0x65, 0x6e, 0x73, 0x2f, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x70, 0x6b,
|
||||
0x67, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76,
|
||||
0x31, 0x3b, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x33,
|
||||
0x73, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x61, 0x64, 0x76,
|
||||
0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x6e, 0x6f, 0x64,
|
||||
0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69,
|
||||
0x73, 0x65, 0x64, 0x45, 0x78, 0x69, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x65,
|
||||
0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x6e, 0x6f, 0x64, 0x65,
|
||||
0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x45,
|
||||
0x78, 0x69, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x22, 0x32, 0x0a, 0x12, 0x43, 0x6c, 0x69, 0x65, 0x6e,
|
||||
0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x12, 0x1c, 0x0a,
|
||||
0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09,
|
||||
0x52, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x42, 0x3d, 0x5a, 0x3b, 0x67,
|
||||
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6a, 0x73, 0x69, 0x65, 0x62, 0x65,
|
||||
0x6e, 0x73, 0x2f, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x70, 0x6b, 0x67, 0x2f,
|
||||
0x67, 0x65, 0x6e, 0x2f, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x3b,
|
||||
0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -72,8 +72,10 @@ type GetMachineRoutesResponse struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
AdvertisedRoutes []string `protobuf:"bytes,1,rep,name=advertised_routes,json=advertisedRoutes,proto3" json:"advertised_routes,omitempty"`
|
||||
EnabledRoutes []string `protobuf:"bytes,2,rep,name=enabled_routes,json=enabledRoutes,proto3" json:"enabled_routes,omitempty"`
|
||||
AdvertisedRoutes []string `protobuf:"bytes,1,rep,name=advertised_routes,json=advertisedRoutes,proto3" json:"advertised_routes,omitempty"`
|
||||
EnabledRoutes []string `protobuf:"bytes,2,rep,name=enabled_routes,json=enabledRoutes,proto3" json:"enabled_routes,omitempty"`
|
||||
AdvertisedExitNode bool `protobuf:"varint,3,opt,name=advertised_exit_node,json=advertisedExitNode,proto3" json:"advertised_exit_node,omitempty"`
|
||||
EnabledExitNode bool `protobuf:"varint,4,opt,name=enabled_exit_node,json=enabledExitNode,proto3" json:"enabled_exit_node,omitempty"`
|
||||
}
|
||||
|
||||
func (x *GetMachineRoutesResponse) Reset() {
|
||||
@@ -122,6 +124,20 @@ func (x *GetMachineRoutesResponse) GetEnabledRoutes() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *GetMachineRoutesResponse) GetAdvertisedExitNode() bool {
|
||||
if x != nil {
|
||||
return x.AdvertisedExitNode
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *GetMachineRoutesResponse) GetEnabledExitNode() bool {
|
||||
if x != nil {
|
||||
return x.EnabledExitNode
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type EnableMachineRoutesRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -240,6 +256,100 @@ func (x *DisableMachineRoutesRequest) GetRoutes() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
type EnableExitNodeRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
MachineId uint64 `protobuf:"varint,1,opt,name=machine_id,json=machineId,proto3" json:"machine_id,omitempty"`
|
||||
}
|
||||
|
||||
func (x *EnableExitNodeRequest) Reset() {
|
||||
*x = EnableExitNodeRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_ionscale_v1_routes_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *EnableExitNodeRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*EnableExitNodeRequest) ProtoMessage() {}
|
||||
|
||||
func (x *EnableExitNodeRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_ionscale_v1_routes_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use EnableExitNodeRequest.ProtoReflect.Descriptor instead.
|
||||
func (*EnableExitNodeRequest) Descriptor() ([]byte, []int) {
|
||||
return file_ionscale_v1_routes_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *EnableExitNodeRequest) GetMachineId() uint64 {
|
||||
if x != nil {
|
||||
return x.MachineId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type DisableExitNodeRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
MachineId uint64 `protobuf:"varint,1,opt,name=machine_id,json=machineId,proto3" json:"machine_id,omitempty"`
|
||||
}
|
||||
|
||||
func (x *DisableExitNodeRequest) Reset() {
|
||||
*x = DisableExitNodeRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_ionscale_v1_routes_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *DisableExitNodeRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*DisableExitNodeRequest) ProtoMessage() {}
|
||||
|
||||
func (x *DisableExitNodeRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_ionscale_v1_routes_proto_msgTypes[5]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use DisableExitNodeRequest.ProtoReflect.Descriptor instead.
|
||||
func (*DisableExitNodeRequest) Descriptor() ([]byte, []int) {
|
||||
return file_ionscale_v1_routes_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *DisableExitNodeRequest) GetMachineId() uint64 {
|
||||
if x != nil {
|
||||
return x.MachineId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var File_ionscale_v1_routes_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_ionscale_v1_routes_proto_rawDesc = []byte{
|
||||
@@ -249,26 +359,39 @@ var file_ionscale_v1_routes_proto_rawDesc = []byte{
|
||||
0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49,
|
||||
0x64, 0x22, 0x6e, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52,
|
||||
0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a,
|
||||
0x11, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x5f, 0x72, 0x6f, 0x75, 0x74,
|
||||
0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74,
|
||||
0x69, 0x73, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x6e,
|
||||
0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03,
|
||||
0x28, 0x09, 0x52, 0x0d, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x73, 0x22, 0x6d, 0x0a, 0x1a, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69,
|
||||
0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
|
||||
0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x04, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x64, 0x12, 0x16,
|
||||
0x0a, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06,
|
||||
0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63,
|
||||
0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65,
|
||||
0x22, 0x54, 0x0a, 0x1b, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69,
|
||||
0x6e, 0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
|
||||
0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x04, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x64, 0x12, 0x16,
|
||||
0x0a, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06,
|
||||
0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x42, 0x3d, 0x5a, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
|
||||
0x64, 0x22, 0xcc, 0x01, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65,
|
||||
0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b,
|
||||
0x0a, 0x11, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x5f, 0x72, 0x6f, 0x75,
|
||||
0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x61, 0x64, 0x76, 0x65, 0x72,
|
||||
0x74, 0x69, 0x73, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x65,
|
||||
0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20,
|
||||
0x03, 0x28, 0x09, 0x52, 0x0d, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74,
|
||||
0x65, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64,
|
||||
0x5f, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08,
|
||||
0x52, 0x12, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x45, 0x78, 0x69, 0x74,
|
||||
0x4e, 0x6f, 0x64, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f,
|
||||
0x65, 0x78, 0x69, 0x74, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||
0x0f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x45, 0x78, 0x69, 0x74, 0x4e, 0x6f, 0x64, 0x65,
|
||||
0x22, 0x6d, 0x0a, 0x1a, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e,
|
||||
0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d,
|
||||
0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x04, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a,
|
||||
0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x72,
|
||||
0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65,
|
||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x22,
|
||||
0x54, 0x0a, 0x1b, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e,
|
||||
0x65, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d,
|
||||
0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x04, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a,
|
||||
0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x72,
|
||||
0x6f, 0x75, 0x74, 0x65, 0x73, 0x22, 0x36, 0x0a, 0x15, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x45,
|
||||
0x78, 0x69, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d,
|
||||
0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x04, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x64, 0x22, 0x37, 0x0a,
|
||||
0x16, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x78, 0x69, 0x74, 0x4e, 0x6f, 0x64, 0x65,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69,
|
||||
0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6d, 0x61, 0x63,
|
||||
0x68, 0x69, 0x6e, 0x65, 0x49, 0x64, 0x42, 0x3d, 0x5a, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6a, 0x73, 0x69, 0x65, 0x62, 0x65, 0x6e, 0x73, 0x2f, 0x69, 0x6f,
|
||||
0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x69,
|
||||
0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x69, 0x6f, 0x6e, 0x73, 0x63,
|
||||
@@ -287,12 +410,14 @@ func file_ionscale_v1_routes_proto_rawDescGZIP() []byte {
|
||||
return file_ionscale_v1_routes_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_ionscale_v1_routes_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
||||
var file_ionscale_v1_routes_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
||||
var file_ionscale_v1_routes_proto_goTypes = []interface{}{
|
||||
(*GetMachineRoutesRequest)(nil), // 0: ionscale.v1.GetMachineRoutesRequest
|
||||
(*GetMachineRoutesResponse)(nil), // 1: ionscale.v1.GetMachineRoutesResponse
|
||||
(*EnableMachineRoutesRequest)(nil), // 2: ionscale.v1.EnableMachineRoutesRequest
|
||||
(*DisableMachineRoutesRequest)(nil), // 3: ionscale.v1.DisableMachineRoutesRequest
|
||||
(*EnableExitNodeRequest)(nil), // 4: ionscale.v1.EnableExitNodeRequest
|
||||
(*DisableExitNodeRequest)(nil), // 5: ionscale.v1.DisableExitNodeRequest
|
||||
}
|
||||
var file_ionscale_v1_routes_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
@@ -356,6 +481,30 @@ func file_ionscale_v1_routes_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_ionscale_v1_routes_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*EnableExitNodeRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_ionscale_v1_routes_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*DisableExitNodeRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
@@ -363,7 +512,7 @@ func file_ionscale_v1_routes_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_ionscale_v1_routes_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 4,
|
||||
NumMessages: 6,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
||||
@@ -80,7 +80,8 @@ type CreateTailnetRequest struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
IamPolicy *IAMPolicy `protobuf:"bytes,2,opt,name=iam_policy,json=iamPolicy,proto3" json:"iam_policy,omitempty"`
|
||||
}
|
||||
|
||||
func (x *CreateTailnetRequest) Reset() {
|
||||
@@ -122,6 +123,13 @@ func (x *CreateTailnetRequest) GetName() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *CreateTailnetRequest) GetIamPolicy() *IAMPolicy {
|
||||
if x != nil {
|
||||
return x.IamPolicy
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type CreateTailnetResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -446,41 +454,45 @@ var File_ionscale_v1_tailnets_proto protoreflect.FileDescriptor
|
||||
var file_ionscale_v1_tailnets_proto_rawDesc = []byte{
|
||||
0x0a, 0x1a, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61,
|
||||
0x69, 0x6c, 0x6e, 0x65, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x69, 0x6f,
|
||||
0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x22, 0x2d, 0x0a, 0x07, 0x54, 0x61, 0x69,
|
||||
0x6c, 0x6e, 0x65, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04,
|
||||
0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x2a, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61,
|
||||
0x74, 0x65, 0x54, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
|
||||
0x6e, 0x61, 0x6d, 0x65, 0x22, 0x47, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61,
|
||||
0x69, 0x6c, 0x6e, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a,
|
||||
0x07, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14,
|
||||
0x2e, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x69,
|
||||
0x6c, 0x6e, 0x65, 0x74, 0x52, 0x07, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x22, 0x23, 0x0a,
|
||||
0x11, 0x47, 0x65, 0x74, 0x54, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02,
|
||||
0x69, 0x64, 0x22, 0x44, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x54, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x74, 0x61, 0x69, 0x6c,
|
||||
0x6e, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x69, 0x6f, 0x6e, 0x73,
|
||||
0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x52,
|
||||
0x07, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x22, 0x14, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74,
|
||||
0x54, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x45,
|
||||
0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74,
|
||||
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c,
|
||||
0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x52, 0x07, 0x74, 0x61,
|
||||
0x69, 0x6c, 0x6e, 0x65, 0x74, 0x22, 0x4b, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54,
|
||||
0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a,
|
||||
0x0a, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x04, 0x52, 0x09, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05,
|
||||
0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72,
|
||||
0x63, 0x65, 0x22, 0x17, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x61, 0x69, 0x6c,
|
||||
0x6e, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3d, 0x5a, 0x3b, 0x67,
|
||||
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6a, 0x73, 0x69, 0x65, 0x62, 0x65,
|
||||
0x6e, 0x73, 0x2f, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x70, 0x6b, 0x67, 0x2f,
|
||||
0x67, 0x65, 0x6e, 0x2f, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x3b,
|
||||
0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x33,
|
||||
0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x15, 0x69, 0x6f, 0x6e, 0x73, 0x63,
|
||||
0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x61, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x22, 0x2d, 0x0a, 0x07, 0x54, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69,
|
||||
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22,
|
||||
0x61, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x35, 0x0a, 0x0a, 0x69,
|
||||
0x61, 0x6d, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x16, 0x2e, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x41,
|
||||
0x4d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x09, 0x69, 0x61, 0x6d, 0x50, 0x6f, 0x6c, 0x69,
|
||||
0x63, 0x79, 0x22, 0x47, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, 0x69, 0x6c,
|
||||
0x6e, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x74,
|
||||
0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x69,
|
||||
0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x69, 0x6c, 0x6e,
|
||||
0x65, 0x74, 0x52, 0x07, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x22, 0x23, 0x0a, 0x11, 0x47,
|
||||
0x65, 0x74, 0x54, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64,
|
||||
0x22, 0x44, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x54, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65,
|
||||
0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61,
|
||||
0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x52, 0x07, 0x74,
|
||||
0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x22, 0x14, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x61,
|
||||
0x69, 0x6c, 0x6e, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x45, 0x0a, 0x13,
|
||||
0x4c, 0x69, 0x73, 0x74, 0x54, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x18, 0x01,
|
||||
0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x54, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x52, 0x07, 0x74, 0x61, 0x69, 0x6c,
|
||||
0x6e, 0x65, 0x74, 0x22, 0x4b, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x61, 0x69,
|
||||
0x6c, 0x6e, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x74,
|
||||
0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52,
|
||||
0x09, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f,
|
||||
0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65,
|
||||
0x22, 0x17, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x61, 0x69, 0x6c, 0x6e, 0x65,
|
||||
0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3d, 0x5a, 0x3b, 0x67, 0x69, 0x74,
|
||||
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6a, 0x73, 0x69, 0x65, 0x62, 0x65, 0x6e, 0x73,
|
||||
0x2f, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x65,
|
||||
0x6e, 0x2f, 0x69, 0x6f, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x69, 0x6f,
|
||||
0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -506,16 +518,18 @@ var file_ionscale_v1_tailnets_proto_goTypes = []interface{}{
|
||||
(*ListTailnetResponse)(nil), // 6: ionscale.v1.ListTailnetResponse
|
||||
(*DeleteTailnetRequest)(nil), // 7: ionscale.v1.DeleteTailnetRequest
|
||||
(*DeleteTailnetResponse)(nil), // 8: ionscale.v1.DeleteTailnetResponse
|
||||
(*IAMPolicy)(nil), // 9: ionscale.v1.IAMPolicy
|
||||
}
|
||||
var file_ionscale_v1_tailnets_proto_depIdxs = []int32{
|
||||
0, // 0: ionscale.v1.CreateTailnetResponse.tailnet:type_name -> ionscale.v1.Tailnet
|
||||
0, // 1: ionscale.v1.GetTailnetResponse.tailnet:type_name -> ionscale.v1.Tailnet
|
||||
0, // 2: ionscale.v1.ListTailnetResponse.tailnet:type_name -> ionscale.v1.Tailnet
|
||||
3, // [3:3] is the sub-list for method output_type
|
||||
3, // [3:3] is the sub-list for method input_type
|
||||
3, // [3:3] is the sub-list for extension type_name
|
||||
3, // [3:3] is the sub-list for extension extendee
|
||||
0, // [0:3] is the sub-list for field type_name
|
||||
9, // 0: ionscale.v1.CreateTailnetRequest.iam_policy:type_name -> ionscale.v1.IAMPolicy
|
||||
0, // 1: ionscale.v1.CreateTailnetResponse.tailnet:type_name -> ionscale.v1.Tailnet
|
||||
0, // 2: ionscale.v1.GetTailnetResponse.tailnet:type_name -> ionscale.v1.Tailnet
|
||||
0, // 3: ionscale.v1.ListTailnetResponse.tailnet:type_name -> ionscale.v1.Tailnet
|
||||
4, // [4:4] is the sub-list for method output_type
|
||||
4, // [4:4] is the sub-list for method input_type
|
||||
4, // [4:4] is the sub-list for extension type_name
|
||||
4, // [4:4] is the sub-list for extension extendee
|
||||
0, // [0:4] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_ionscale_v1_tailnets_proto_init() }
|
||||
@@ -523,6 +537,7 @@ func file_ionscale_v1_tailnets_proto_init() {
|
||||
if File_ionscale_v1_tailnets_proto != nil {
|
||||
return
|
||||
}
|
||||
file_ionscale_v1_iam_proto_init()
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_ionscale_v1_tailnets_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Tailnet); i {
|
||||
|
||||
@@ -28,10 +28,16 @@ message ACLPolicy {
|
||||
map<string, google.protobuf.ListValue> groups = 2;
|
||||
repeated ACL acls = 3;
|
||||
map<string, google.protobuf.ListValue> tagowners = 4;
|
||||
AutoApprovers autoapprovers = 5;
|
||||
}
|
||||
|
||||
message ACL {
|
||||
string action = 1;
|
||||
repeated string src = 2;
|
||||
repeated string dst = 3;
|
||||
}
|
||||
|
||||
message AutoApprovers {
|
||||
map<string, google.protobuf.ListValue> routes = 1;
|
||||
repeated string exitnode = 2;
|
||||
}
|
||||
@@ -56,4 +56,6 @@ service IonscaleService {
|
||||
rpc GetMachineRoutes (GetMachineRoutesRequest) returns (GetMachineRoutesResponse) {}
|
||||
rpc EnableMachineRoutes (EnableMachineRoutesRequest) returns (GetMachineRoutesResponse) {}
|
||||
rpc DisableMachineRoutes (DisableMachineRoutesRequest) returns (GetMachineRoutesResponse) {}
|
||||
rpc EnableExitNode (EnableExitNodeRequest) returns (GetMachineRoutesResponse) {}
|
||||
rpc DisableExitNode (DisableExitNodeRequest) returns (GetMachineRoutesResponse) {}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,8 @@ message Machine {
|
||||
bool key_expiry_disabled = 16;
|
||||
repeated string enabled_routes = 17;
|
||||
repeated string advertised_routes = 18;
|
||||
bool advertised_exit_node = 19;
|
||||
bool enabled_exit_node = 20;
|
||||
}
|
||||
|
||||
message ClientConnectivity {
|
||||
|
||||
@@ -10,6 +10,8 @@ message GetMachineRoutesRequest {
|
||||
message GetMachineRoutesResponse {
|
||||
repeated string advertised_routes = 1;
|
||||
repeated string enabled_routes = 2;
|
||||
bool advertised_exit_node = 3;
|
||||
bool enabled_exit_node = 4;
|
||||
}
|
||||
|
||||
message EnableMachineRoutesRequest {
|
||||
@@ -22,3 +24,11 @@ message DisableMachineRoutesRequest {
|
||||
uint64 machine_id = 1;
|
||||
repeated string routes = 2;
|
||||
}
|
||||
|
||||
message EnableExitNodeRequest {
|
||||
uint64 machine_id = 1;
|
||||
}
|
||||
|
||||
message DisableExitNodeRequest {
|
||||
uint64 machine_id = 1;
|
||||
}
|
||||
@@ -3,6 +3,8 @@ syntax = "proto3";
|
||||
package ionscale.v1;
|
||||
option go_package = "github.com/jsiebens/ionscale/pkg/gen/ionscale/v1;ionscalev1";
|
||||
|
||||
import "ionscale/v1/iam.proto";
|
||||
|
||||
message Tailnet {
|
||||
uint64 id = 1;
|
||||
string name = 2;
|
||||
@@ -10,6 +12,7 @@ message Tailnet {
|
||||
|
||||
message CreateTailnetRequest {
|
||||
string name = 1;
|
||||
IAMPolicy iam_policy = 2;
|
||||
}
|
||||
|
||||
message CreateTailnetResponse {
|
||||
|
||||
Reference in New Issue
Block a user