mirror of
https://github.com/jsiebens/ionscale.git
synced 2026-03-31 15:07:49 +01:00
feat: generate and store control keys
This commit is contained in:
@@ -37,8 +37,7 @@ const (
|
||||
httpsListenAddrKey = "IONSCALE_HTTPS_LISTEN_ADDR"
|
||||
serverUrlKey = "IONSCALE_SERVER_URL"
|
||||
keysSystemAdminKeyKey = "IONSCALE_SYSTEM_ADMIN_KEY"
|
||||
keysControlKeyKey = "IONSCALE_CONTROL_KEY"
|
||||
keysLegacyControlKeyKey = "IONSCALE_LEGACY_CONTROL_KEY"
|
||||
keysEncryptionKeyKey = "IONSCALE_ENCRYPTION_KEY"
|
||||
databaseUrlKey = "IONSCALE_DB_URL"
|
||||
tlsDisableKey = "IONSCALE_TLS_DISABLE"
|
||||
tlsCertFileKey = "IONSCALE_TLS_CERT_FILE"
|
||||
@@ -60,9 +59,8 @@ func defaultConfig() *Config {
|
||||
MetricsListenAddr: GetString(metricsListenAddrKey, ":8081"),
|
||||
ServerUrl: GetString(serverUrlKey, "https://localhost:8443"),
|
||||
Keys: Keys{
|
||||
SystemAdminKey: GetString(keysSystemAdminKeyKey, ""),
|
||||
ControlKey: GetString(keysControlKeyKey, ""),
|
||||
LegacyControlKey: GetString(keysLegacyControlKeyKey, ""),
|
||||
SystemAdminKey: GetString(keysSystemAdminKeyKey, ""),
|
||||
EncryptionKey: GetString(keysEncryptionKeyKey, ""),
|
||||
},
|
||||
Database: Database{
|
||||
Url: GetString(databaseUrlKey, "ionscale.db"),
|
||||
@@ -85,9 +83,7 @@ func defaultConfig() *Config {
|
||||
}
|
||||
|
||||
type ServerKeys struct {
|
||||
SystemAdminKey key.MachinePrivate
|
||||
ControlKey key.MachinePrivate
|
||||
LegacyControlKey key.MachinePrivate
|
||||
SystemAdminKey key.MachinePrivate
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
@@ -122,9 +118,8 @@ type Database struct {
|
||||
}
|
||||
|
||||
type Keys struct {
|
||||
SystemAdminKey string `yaml:"system_admin_key"`
|
||||
ControlKey string `yaml:"control_key"`
|
||||
LegacyControlKey string `yaml:"legacy_control_key"`
|
||||
SystemAdminKey string `yaml:"system_admin_key"`
|
||||
EncryptionKey string `yaml:"encryption_key"`
|
||||
}
|
||||
|
||||
func (c *Config) CreateUrl(format string, a ...interface{}) string {
|
||||
@@ -138,19 +133,7 @@ func (c *Config) ReadServerKeys() (*ServerKeys, error) {
|
||||
return nil, fmt.Errorf("error reading system admin key: %v", err)
|
||||
}
|
||||
|
||||
controlKey, err := util.ParseMachinePrivateKey(c.Keys.ControlKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading control key: %v", err)
|
||||
}
|
||||
|
||||
legacyControlKey, err := util.ParseMachinePrivateKey(c.Keys.LegacyControlKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading legacy control key: %v", err)
|
||||
}
|
||||
|
||||
return &ServerKeys{
|
||||
SystemAdminKey: *systemAdminKey,
|
||||
ControlKey: *controlKey,
|
||||
LegacyControlKey: *legacyControlKey,
|
||||
SystemAdminKey: *systemAdminKey,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"net/http"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/key"
|
||||
"time"
|
||||
|
||||
"github.com/jsiebens/ionscale/internal/config"
|
||||
@@ -53,6 +54,10 @@ func migrate(db *gorm.DB, repository domain.Repository) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := initializeControlKeys(repository); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := initializeDERPMap(repository); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -93,6 +98,21 @@ func initializeDERPMap(repository domain.Repository) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func initializeControlKeys(repository domain.Repository) error {
|
||||
ctx := context.Background()
|
||||
keys, err := repository.GetControlKeys(ctx)
|
||||
if keys != nil || err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
keys = &domain.ControlKeys{
|
||||
ControlKey: key.NewMachine(),
|
||||
LegacyControlKey: key.NewMachine(),
|
||||
}
|
||||
|
||||
return repository.SetControlKeys(ctx, keys)
|
||||
}
|
||||
|
||||
type GormLoggerAdapter struct {
|
||||
logger hclog.Logger
|
||||
}
|
||||
|
||||
@@ -8,6 +8,9 @@ import (
|
||||
)
|
||||
|
||||
type Repository interface {
|
||||
GetControlKeys(ctx context.Context) (*ControlKeys, error)
|
||||
SetControlKeys(ctx context.Context, v *ControlKeys) error
|
||||
|
||||
GetDERPMap(ctx context.Context) (*tailcfg.DERPMap, error)
|
||||
SetDERPMap(ctx context.Context, v *tailcfg.DERPMap) error
|
||||
|
||||
|
||||
@@ -6,16 +6,50 @@ import (
|
||||
"errors"
|
||||
"gorm.io/gorm"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/key"
|
||||
)
|
||||
|
||||
type configKey string
|
||||
|
||||
const (
|
||||
controlKeysConfigKey configKey = "control_keys"
|
||||
derpMapConfigKey configKey = "derp_map"
|
||||
)
|
||||
|
||||
type ControlKeys struct {
|
||||
ControlKey key.MachinePrivate
|
||||
LegacyControlKey key.MachinePrivate
|
||||
}
|
||||
|
||||
type ServerConfig struct {
|
||||
Key string `gorm:"primary_key"`
|
||||
Key configKey `gorm:"primary_key"`
|
||||
Value []byte
|
||||
}
|
||||
|
||||
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
|
||||
err := r.getServerConfig(ctx, "derp_map", &m)
|
||||
|
||||
err := r.getServerConfig(ctx, derpMapConfigKey, &m)
|
||||
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil
|
||||
@@ -32,7 +66,7 @@ func (r *repository) SetDERPMap(ctx context.Context, v *tailcfg.DERPMap) error {
|
||||
return r.setServerConfig(ctx, "derp_map", v)
|
||||
}
|
||||
|
||||
func (r *repository) getServerConfig(ctx context.Context, s string, v interface{}) error {
|
||||
func (r *repository) getServerConfig(ctx context.Context, s configKey, v interface{}) error {
|
||||
var m ServerConfig
|
||||
tx := r.withContext(ctx).Take(&m, "key = ?", s)
|
||||
|
||||
@@ -48,7 +82,7 @@ func (r *repository) getServerConfig(ctx context.Context, s string, v interface{
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *repository) setServerConfig(ctx context.Context, s string, v interface{}) error {
|
||||
func (r *repository) setServerConfig(ctx context.Context, s configKey, v interface{}) error {
|
||||
marshal, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/jsiebens/ionscale/internal/version"
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
@@ -10,7 +9,8 @@ func IndexHandler(code int) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
info, s := version.GetReleaseInfo()
|
||||
data := map[string]interface{}{
|
||||
"Version": fmt.Sprintf("%s - %s", info, s),
|
||||
"Version": info,
|
||||
"Revision": s,
|
||||
}
|
||||
return c.Render(code, "index.html", data)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/jsiebens/ionscale/internal/config"
|
||||
"github.com/jsiebens/ionscale/internal/domain"
|
||||
"github.com/labstack/echo/v4"
|
||||
"net/http"
|
||||
"strconv"
|
||||
@@ -12,7 +12,7 @@ const (
|
||||
NoiseCapabilityVersion = 28
|
||||
)
|
||||
|
||||
func KeyHandler(keys *config.ServerKeys) echo.HandlerFunc {
|
||||
func KeyHandler(keys *domain.ControlKeys) echo.HandlerFunc {
|
||||
legacyPublicKey := keys.LegacyControlKey.Public()
|
||||
publicKey := keys.ControlKey.Public()
|
||||
|
||||
|
||||
@@ -39,12 +39,17 @@ func Start(config *config.Config) error {
|
||||
|
||||
logger.Info("Starting ionscale server")
|
||||
|
||||
serverKey, err := config.ReadServerKeys()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, repository, err := database.OpenDB(&config.Database, logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
serverKey, err := config.ReadServerKeys()
|
||||
controlKeys, err := repository.GetControlKeys(context.Background())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -88,9 +93,9 @@ func Start(config *config.Config) error {
|
||||
return e
|
||||
}
|
||||
|
||||
noiseHandlers := handlers.NewNoiseHandlers(serverKey.ControlKey, createPeerHandler)
|
||||
registrationHandlers := handlers.NewRegistrationHandlers(bind.BoxBinder(serverKey.LegacyControlKey), config, repository, pendingMachineRegistrationRequests)
|
||||
pollNetMapHandler := handlers.NewPollNetMapHandler(bind.BoxBinder(serverKey.LegacyControlKey), brokers, repository, offlineTimers)
|
||||
noiseHandlers := handlers.NewNoiseHandlers(controlKeys.ControlKey, createPeerHandler)
|
||||
registrationHandlers := handlers.NewRegistrationHandlers(bind.BoxBinder(controlKeys.LegacyControlKey), config, repository, pendingMachineRegistrationRequests)
|
||||
pollNetMapHandler := handlers.NewPollNetMapHandler(bind.BoxBinder(controlKeys.LegacyControlKey), brokers, repository, offlineTimers)
|
||||
authenticationHandlers := handlers.NewAuthenticationHandlers(
|
||||
config,
|
||||
repository,
|
||||
@@ -118,7 +123,7 @@ func Start(config *config.Config) error {
|
||||
tlsAppHandler.Any("/*", handlers.IndexHandler(http.StatusNotFound))
|
||||
tlsAppHandler.Any("/", handlers.IndexHandler(http.StatusOK))
|
||||
tlsAppHandler.GET("/version", handlers.Version)
|
||||
tlsAppHandler.GET("/key", handlers.KeyHandler(serverKey))
|
||||
tlsAppHandler.GET("/key", handlers.KeyHandler(controlKeys))
|
||||
tlsAppHandler.POST("/ts2021", noiseHandlers.Upgrade)
|
||||
tlsAppHandler.POST("/machine/:id", registrationHandlers.Register)
|
||||
tlsAppHandler.POST("/machine/:id/map", pollNetMapHandler.PollNetMap)
|
||||
|
||||
@@ -56,7 +56,8 @@
|
||||
<div class="wrapper">
|
||||
<div style="text-align: center">
|
||||
<p><b>ionscale</b></p>
|
||||
<small>{{.Version}}</small>
|
||||
<p><small>{{.Version}}</small></p>
|
||||
<p><small>{{.Revision}}</small></p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user