mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-25 11:05:45 +00:00
cmd/tailscaled, ipn/conffile: support ec2 user-data config file
Updates #1412 Updates #1866 Change-Id: I4d08fb233b80c2078b3b28ffc18559baabb4a081 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
2d2b62c400
commit
1ea100e2e5
@ -320,6 +320,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
|||||||
💣 tailscale.com/net/tshttpproxy from tailscale.com/clientupdate/distsign+
|
💣 tailscale.com/net/tshttpproxy from tailscale.com/clientupdate/distsign+
|
||||||
tailscale.com/net/tstun from tailscale.com/cmd/tailscaled+
|
tailscale.com/net/tstun from tailscale.com/cmd/tailscaled+
|
||||||
tailscale.com/net/wsconn from tailscale.com/control/controlhttp+
|
tailscale.com/net/wsconn from tailscale.com/control/controlhttp+
|
||||||
|
tailscale.com/omit from tailscale.com/ipn/conffile
|
||||||
tailscale.com/paths from tailscale.com/client/tailscale+
|
tailscale.com/paths from tailscale.com/client/tailscale+
|
||||||
💣 tailscale.com/portlist from tailscale.com/ipn/ipnlocal
|
💣 tailscale.com/portlist from tailscale.com/ipn/ipnlocal
|
||||||
tailscale.com/posture from tailscale.com/ipn/ipnlocal
|
tailscale.com/posture from tailscale.com/ipn/ipnlocal
|
||||||
|
@ -118,7 +118,7 @@ func defaultPort() uint16 {
|
|||||||
tunname string
|
tunname string
|
||||||
|
|
||||||
cleanUp bool
|
cleanUp bool
|
||||||
confFile string
|
confFile string // empty, file path, or "vm:user-data"
|
||||||
debug string
|
debug string
|
||||||
port uint16
|
port uint16
|
||||||
statepath string
|
statepath string
|
||||||
@ -169,7 +169,7 @@ func main() {
|
|||||||
flag.StringVar(&args.birdSocketPath, "bird-socket", "", "path of the bird unix socket")
|
flag.StringVar(&args.birdSocketPath, "bird-socket", "", "path of the bird unix socket")
|
||||||
flag.BoolVar(&printVersion, "version", false, "print version information and exit")
|
flag.BoolVar(&printVersion, "version", false, "print version information and exit")
|
||||||
flag.BoolVar(&args.disableLogs, "no-logs-no-support", false, "disable log uploads; this also disables any technical support")
|
flag.BoolVar(&args.disableLogs, "no-logs-no-support", false, "disable log uploads; this also disables any technical support")
|
||||||
flag.StringVar(&args.confFile, "config", "", "path to config file")
|
flag.StringVar(&args.confFile, "config", "", "path to config file, or 'vm:user-data' to use the VM's user-data (EC2)")
|
||||||
|
|
||||||
if len(os.Args) > 0 && filepath.Base(os.Args[0]) == "tailscale" && beCLI != nil {
|
if len(os.Args) > 0 && filepath.Base(os.Args[0]) == "tailscale" && beCLI != nil {
|
||||||
beCLI()
|
beCLI()
|
||||||
|
59
ipn/conffile/cloudconf.go
Normal file
59
ipn/conffile/cloudconf.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
package conffile
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"tailscale.com/omit"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getEC2MetadataToken() (string, error) {
|
||||||
|
if omit.AWS {
|
||||||
|
return "", omit.Err
|
||||||
|
}
|
||||||
|
req, _ := http.NewRequest("PUT", "http://169.254.169.254/latest/api/token", nil)
|
||||||
|
req.Header.Add("X-aws-ec2-metadata-token-ttl-seconds", "300")
|
||||||
|
res, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to get metadata token: %w", err)
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
if res.StatusCode != 200 {
|
||||||
|
return "", fmt.Errorf("failed to get metadata token: %v", res.Status)
|
||||||
|
}
|
||||||
|
all, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to read metadata token: %w", err)
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(string(all)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readVMUserData() ([]byte, error) {
|
||||||
|
// TODO(bradfitz): support GCP, Azure, Proxmox/cloud-init
|
||||||
|
// (NoCloud/ConfigDrive ISO), etc.
|
||||||
|
|
||||||
|
if omit.AWS {
|
||||||
|
return nil, omit.Err
|
||||||
|
}
|
||||||
|
token, tokErr := getEC2MetadataToken()
|
||||||
|
req, _ := http.NewRequest("GET", "http://169.254.169.254/latest/user-data", nil)
|
||||||
|
req.Header.Add("X-aws-ec2-metadata-token", token)
|
||||||
|
res, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
if res.StatusCode != 200 {
|
||||||
|
if tokErr != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get VM user data: %v; also failed to get metadata token: %v", res.Status, tokErr)
|
||||||
|
}
|
||||||
|
return nil, errors.New(res.Status)
|
||||||
|
}
|
||||||
|
return io.ReadAll(res.Body)
|
||||||
|
}
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
// Config describes a config file.
|
// Config describes a config file.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Path string // disk path of HuJSON
|
Path string // disk path of HuJSON, or VMUserDataPath
|
||||||
Raw []byte // raw bytes from disk, in HuJSON form
|
Raw []byte // raw bytes from disk, in HuJSON form
|
||||||
Std []byte // standardized JSON form
|
Std []byte // standardized JSON form
|
||||||
Version string // "alpha0" for now
|
Version string // "alpha0" for now
|
||||||
@ -35,13 +35,22 @@ func (c *Config) WantRunning() bool {
|
|||||||
return c != nil && !c.Parsed.Enabled.EqualBool(false)
|
return c != nil && !c.Parsed.Enabled.EqualBool(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VMUserDataPath is a sentinel value for Load to use to get the data
|
||||||
|
// from the VM's metadata service's user-data field.
|
||||||
|
const VMUserDataPath = "vm:user-data"
|
||||||
|
|
||||||
// Load reads and parses the config file at the provided path on disk.
|
// Load reads and parses the config file at the provided path on disk.
|
||||||
func Load(path string) (*Config, error) {
|
func Load(path string) (*Config, error) {
|
||||||
var c Config
|
var c Config
|
||||||
c.Path = path
|
c.Path = path
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
c.Raw, err = os.ReadFile(path)
|
|
||||||
|
switch path {
|
||||||
|
case VMUserDataPath:
|
||||||
|
c.Raw, err = readVMUserData()
|
||||||
|
default:
|
||||||
|
c.Raw, err = os.ReadFile(path)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
9
omit/aws_def.go
Normal file
9
omit/aws_def.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
//go:build !ts_omit_aws
|
||||||
|
|
||||||
|
package omit
|
||||||
|
|
||||||
|
// AWS is whether AWS support should be omitted from the build.
|
||||||
|
const AWS = false
|
9
omit/aws_omit.go
Normal file
9
omit/aws_omit.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
//go:build ts_omit_aws
|
||||||
|
|
||||||
|
package omit
|
||||||
|
|
||||||
|
// AWS is whether AWS support should be omitted from the build.
|
||||||
|
const AWS = true
|
12
omit/omit.go
Normal file
12
omit/omit.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
// Package omit provides consts to access Tailscale ts_omit_FOO build tags.
|
||||||
|
// They're often more convenient to eliminate some away locally with a const
|
||||||
|
// rather than using build tags.
|
||||||
|
package omit
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
// Err is an error that can be returned by functions in this package.
|
||||||
|
var Err = errors.New("feature not linked into binary per ts_omit build tag")
|
Loading…
Reference in New Issue
Block a user