Add public_addr support for auth and ssh services.

This commit fixes #1803, fixes #1889

* Adds support for public_addr for Proxy and Auth
* Parameter advertise_ip now supports host:port format
* Fixes incorrect output for tctl get proxies
* Fixes duplicate output of some error messages.
This commit is contained in:
Sasha Klizhentas 2018-05-02 15:45:31 -07:00
parent 2d77a8c1e3
commit a4c86e0603
17 changed files with 231 additions and 68 deletions

View file

@ -539,8 +539,8 @@ func (i *Identity) HasTLSConfig() bool {
// HasPrincipals returns whether identity has principals
func (i *Identity) HasPrincipals(additionalPrincipals []string) bool {
set := utils.StringsSet(additionalPrincipals)
for _, principal := range i.Cert.ValidPrincipals {
set := utils.StringsSet(i.Cert.ValidPrincipals)
for _, principal := range additionalPrincipals {
if _, ok := set[principal]; !ok {
return false
}

View file

@ -60,7 +60,7 @@ type CommandLineFlags struct {
// --listen-ip flag
ListenIP net.IP
// --advertise-ip flag
AdvertiseIP net.IP
AdvertiseIP string
// --config flag
ConfigFile string
// ConfigString is a base64 encoded configuration string
@ -133,8 +133,8 @@ func ApplyFileConfig(fc *FileConfig, cfg *service.Config) error {
// apply "advertise_ip" setting:
advertiseIP := fc.AdvertiseIP
if advertiseIP != nil {
if err := validateAdvertiseIP(advertiseIP); err != nil {
if advertiseIP != "" {
if _, _, err := utils.ParseAdvertiseAddr(advertiseIP); err != nil {
return trace.Wrap(err)
}
cfg.AdvertiseIP = advertiseIP
@ -276,12 +276,12 @@ func ApplyFileConfig(fc *FileConfig, cfg *service.Config) error {
}
cfg.Proxy.ReverseTunnelListenAddr = *addr
}
if fc.Proxy.PublicAddr != "" {
addr, err := utils.ParseHostPortAddr(fc.Proxy.PublicAddr, int(defaults.HTTPListenPort))
if len(fc.Proxy.PublicAddr) != 0 {
addrs, err := fc.Proxy.PublicAddr.Addrs(defaults.HTTPListenPort)
if err != nil {
return trace.Wrap(err)
}
cfg.Proxy.PublicAddr = *addr
cfg.Proxy.PublicAddrs = addrs
}
if fc.Proxy.KeyFile != "" {
if !fileExists(fc.Proxy.KeyFile) {
@ -362,6 +362,13 @@ func ApplyFileConfig(fc *FileConfig, cfg *service.Config) error {
}
cfg.ReverseTunnels = append(cfg.ReverseTunnels, tun)
}
if len(fc.Auth.PublicAddr) != 0 {
addrs, err := fc.Auth.PublicAddr.Addrs(defaults.AuthListenPort)
if err != nil {
return trace.Wrap(err)
}
cfg.Auth.PublicAddrs = addrs
}
// DELETE IN: 2.4.0
if len(fc.Auth.TrustedClusters) > 0 {
warningMessage := "Configuring Trusted Clusters using file configuration has " +
@ -481,7 +488,13 @@ func ApplyFileConfig(fc *FileConfig, cfg *service.Config) error {
}
}
}
if len(fc.SSH.PublicAddr) != 0 {
addrs, err := fc.SSH.PublicAddr.Addrs(defaults.SSHServerListenPort)
if err != nil {
return trace.Wrap(err)
}
cfg.SSH.PublicAddrs = addrs
}
return nil
}
@ -748,8 +761,8 @@ func Configure(clf *CommandLineFlags, cfg *service.Config) error {
}
// --advertise-ip flag
if clf.AdvertiseIP != nil {
if err := validateAdvertiseIP(clf.AdvertiseIP); err != nil {
if clf.AdvertiseIP != "" {
if _, _, err := utils.ParseAdvertiseAddr(clf.AdvertiseIP); err != nil {
return trace.Wrap(err)
}
cfg.AdvertiseIP = clf.AdvertiseIP
@ -901,10 +914,3 @@ func validateRoles(roles string) error {
}
return nil
}
func validateAdvertiseIP(advertiseIP net.IP) error {
if advertiseIP.IsLoopback() || advertiseIP.IsUnspecified() || advertiseIP.IsMulticast() {
return trace.BadParameter("unreachable advertise IP: %v", advertiseIP)
}
return nil
}

View file

@ -21,7 +21,6 @@ import (
"encoding/base64"
"fmt"
"io/ioutil"
"net"
"os"
"path/filepath"
"testing"
@ -313,6 +312,7 @@ func (s *ConfigTestSuite) TestApplyConfig(c *check.C) {
conf, err := ReadConfig(bytes.NewBufferString(SmallConfigString))
c.Assert(err, check.IsNil)
c.Assert(conf, check.NotNil)
c.Assert(conf.Proxy.PublicAddr, check.DeepEquals, Strings{"web3:443"})
cfg := service.MakeDefaultConfig()
err = ApplyFileConfig(conf, cfg)
@ -330,7 +330,7 @@ func (s *ConfigTestSuite) TestApplyConfig(c *check.C) {
},
})
c.Assert(cfg.Auth.ClusterName.GetClusterName(), check.Equals, "magadan")
c.Assert(cfg.AdvertiseIP, check.DeepEquals, net.ParseIP("10.10.10.1"))
c.Assert(cfg.AdvertiseIP, check.Equals, "10.10.10.1")
c.Assert(cfg.Proxy.Enabled, check.Equals, true)
c.Assert(cfg.Proxy.WebAddr.FullAddress(), check.Equals, "tcp://webhost:3080")
@ -406,7 +406,7 @@ func checkStaticConfig(c *check.C, conf *FileConfig) {
c.Assert(conf.Proxy.Configured(), check.Equals, false) // Missing "proxy_service" section must lead to 'not configured'
c.Assert(conf.Proxy.Enabled(), check.Equals, true) // Missing "proxy_service" section must lead to 'true'
c.Assert(conf.Proxy.Disabled(), check.Equals, false) // Missing "proxy_service" does NOT mean it's been disabled
c.Assert(conf.AdvertiseIP.String(), check.Equals, "10.10.10.1")
c.Assert(conf.AdvertiseIP, check.Equals, "10.10.10.1:3022")
c.Assert(conf.PIDFile, check.Equals, "/var/run/teleport.pid")
c.Assert(conf.Limits.MaxConnections, check.Equals, int64(90))
@ -427,6 +427,9 @@ func checkStaticConfig(c *check.C, conf *FileConfig) {
c.Assert(conf.SSH.Commands[1].Name, check.Equals, "date")
c.Assert(conf.SSH.Commands[1].Command, check.DeepEquals, []string{"/bin/date"})
c.Assert(conf.SSH.Commands[1].Period.Nanoseconds(), check.Equals, int64(20000000))
c.Assert(conf.SSH.PublicAddr, check.DeepEquals, Strings{
"luna3:22",
})
c.Assert(conf.Global.Keys[0].PrivateKey, check.Equals, "private key")
c.Assert(conf.Global.Keys[0].Cert, check.Equals, "node.cert")
@ -451,6 +454,10 @@ func checkStaticConfig(c *check.C, conf *FileConfig) {
c.Assert(conf.Auth.StaticTokens, check.DeepEquals,
StaticTokens{"proxy,node:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "auth:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"})
c.Assert(conf.Auth.PublicAddr, check.DeepEquals, Strings{
"auth.default.svc.cluster.local:3080",
})
policy, err := conf.CachePolicy.Parse()
c.Assert(err, check.IsNil)
c.Assert(policy.Enabled, check.Equals, true)

View file

@ -22,7 +22,6 @@ import (
"fmt"
"io"
"io/ioutil"
"net"
"os"
"strings"
"time"
@ -354,7 +353,7 @@ type Global struct {
Limits ConnectionLimits `yaml:"connection_limits,omitempty"`
Logger Log `yaml:"log,omitempty"`
Storage backend.Config `yaml:"storage,omitempty"`
AdvertiseIP net.IP `yaml:"advertise_ip,omitempty"`
AdvertiseIP string `yaml:"advertise_ip,omitempty"`
CachePolicy CachePolicy `yaml:"cache,omitempty"`
SeedConfig *bool `yaml:"seed_config,omitempty"`
@ -518,6 +517,10 @@ type Auth struct {
// it here overrides defaults.
// Deprecated: Remove in Teleport 2.4.1.
DynamicConfig *bool `yaml:"dynamic_config,omitempty"`
// PublicAddr sets SSH host principals and TLS DNS names to auth
// server certificates
PublicAddr Strings `yaml:"public_addr,omitempty"`
}
// TrustedCluster struct holds configuration values under "trusted_clusters" key
@ -651,6 +654,8 @@ type SSH struct {
Commands []CommandLabel `yaml:"commands,omitempty"`
PermitUserEnvironment bool `yaml:"permit_user_env,omitempty"`
PAM *PAM `yaml:"pam,omitempty"`
// PublicAddr sets SSH host principals for SSH service
PublicAddr Strings `yaml:"public_addr,omitempty"`
}
// CommandLabel is `command` section of `ssh_service` in the config file
@ -695,7 +700,7 @@ type Proxy struct {
// CertFile is a TLS Certificate file
CertFile string `yaml:"https_cert_file,omitempty"`
// PublicAddr is a publicly advertised address of the proxy
PublicAddr string `yaml:"public_addr,omitempty"`
PublicAddr Strings `yaml:"public_addr,omitempty"`
// ProxyProtocol turns on support for HAProxy proxy protocol
// this is the option that has be turned on only by administrator,
// as only admin knows whether service is in front of trusted load balancer
@ -938,3 +943,41 @@ func (u *U2F) Parse() (*services.U2F, error) {
Facets: facets,
}, nil
}
// Strings is a list of string that can unmarshal from list or a single yaml value
type Strings []string
// UnmarshalYAML is used to allow Strings to unmarshal from
// scalar string value or from the list
func (s *Strings) UnmarshalYAML(unmarshal func(interface{}) error) error {
// try unmarshal as string
var val string
err := unmarshal(&val)
if err == nil {
*s = []string{val}
return nil
}
// try unmarshal as slice
var slice []string
err = unmarshal(&slice)
if err == nil {
*s = slice
return nil
}
return err
}
// Addrs returns strings list converted to address list
func (s Strings) Addrs(defaultPort int) ([]utils.NetAddr, error) {
addrs := make([]utils.NetAddr, len(s))
for i, val := range s {
addr, err := utils.ParseHostPortAddr(val, defaultPort)
if err != nil {
return nil, trace.Wrap(err)
}
addrs[i] = *addr
}
return addrs, nil
}

View file

@ -21,7 +21,7 @@ const StaticConfigString = `
#
teleport:
nodename: edsger.example.com
advertise_ip: 10.10.10.1
advertise_ip: 10.10.10.1:3022
pid_file: /var/run/teleport.pid
auth_servers:
- auth0.server.example.org:3024
@ -77,6 +77,7 @@ auth_service:
addresses: ["com-1", "com-2"]
- domain_name: tunnel.example.org
addresses: ["org-1"]
public_addr: ["auth.default.svc.cluster.local:3080"]
ssh_service:
enabled: no
@ -91,6 +92,7 @@ ssh_service:
- name: date
command: [/bin/date]
period: 20ms
public_addr: "luna3:22"
`
const SmallConfigString = `
@ -129,6 +131,7 @@ proxy_service:
enabled: yes
web_listen_addr: webhost
tunnel_listen_addr: tunnelhost:1001
public_addr: web3:443
`
// LegacyAuthenticationSection is the deprecated format for authentication method. We still

View file

@ -19,7 +19,6 @@ package service
import (
"fmt"
"io"
"net"
"os"
"path/filepath"
"time"
@ -62,9 +61,9 @@ type Config struct {
// for teleport roles, this is helpful when server is preconfigured
Identities []*auth.Identity
// AdvertiseIP is used to "publish" an alternative IP address this node
// AdvertiseIP is used to "publish" an alternative IP address or hostname this node
// can be reached on, if running behind NAT
AdvertiseIP net.IP
AdvertiseIP string
// CachePolicy sets caching policy for nodes and proxies
// in case if they loose connection to auth servers
@ -275,8 +274,9 @@ type ProxyConfig struct {
Limiter limiter.LimiterConfig
// PublicAddr is the public address the Teleport UI can be accessed at.
PublicAddr utils.NetAddr
// PublicAddrs is a list of the public addresses the Teleport UI can be accessed at,
// it also affects the SSH host principals and DNS names added to the SSH and TLS certs.
PublicAddrs []utils.NetAddr
}
// AuthConfig is a configuration of the auth server
@ -324,6 +324,9 @@ type AuthConfig struct {
// LicenseFile is a full path to the license file
LicenseFile string
// PublicAddrs affects the SSH host principals and DNS names added to the SSH and TLS certs.
PublicAddrs []utils.NetAddr
}
// SSHConfig configures SSH server node role
@ -339,6 +342,9 @@ type SSHConfig struct {
// PAM holds PAM configuration for Teleport.
PAM *pam.Config
// PublicAddrs affects the SSH host principals and DNS names added to the SSH and TLS certs.
PublicAddrs []utils.NetAddr
}
// MakeDefaultConfig creates a new Config structure and populates it with defaults

View file

@ -219,7 +219,7 @@ func (process *TeleportProcess) periodicSyncRotationState() error {
process.WaitForEvent(process.ExitContext(), TeleportReadyEvent, eventC)
select {
case <-eventC:
process.Infof("The new service has started successfully. Starting syncing rotation status.")
process.Infof("The new service has started successfully. Starting syncing rotation status with period %v.", process.Config.PollingPeriod)
case <-process.ExitContext().Done():
process.Infof("Periodic rotation sync has exited.")
return nil
@ -296,15 +296,17 @@ func (process *TeleportProcess) syncServiceRotationState(ca services.CertAuthori
func (process *TeleportProcess) rotate(conn *Connector, localState auth.StateV2, remote services.Rotation) (bool, error) {
id := conn.ClientIdentity.ID
local := localState.Spec.Rotation
if local.Matches(remote) {
// nothing to do, local state and rotation state are in sync
return false, nil
}
additionalPrincipals, err := process.getAdditionalPrincipals(id.Role)
if err != nil {
return false, trace.Wrap(err)
}
principalsChanged := len(additionalPrincipals) != 0 && !conn.ServerIdentity.HasPrincipals(additionalPrincipals)
if local.Matches(remote) && !principalsChanged {
// nothing to do, local state and rotation state are in sync
return false, nil
}
storage := process.storage
@ -330,8 +332,8 @@ func (process *TeleportProcess) rotate(conn *Connector, localState auth.StateV2,
// that the old node came up and missed the whole rotation
// rollback cycle.
case "", services.RotationStateStandby:
if len(additionalPrincipals) != 0 && !conn.ServerIdentity.HasPrincipals(additionalPrincipals) {
process.Infof("%v has updated principals to %q, going to request new principals and update")
if principalsChanged {
process.Infof("Service %v has updated principals to %q, going to request new principals and update.", id.Role, additionalPrincipals)
identity, err := conn.ReRegister(additionalPrincipals)
if err != nil {
return false, trace.Wrap(err)

View file

@ -949,12 +949,20 @@ func (process *TeleportProcess) initAuthService() error {
},
}
host, port, err := net.SplitHostPort(srv.GetAddr())
if err != nil {
return trace.Wrap(err)
}
// advertise-ip is explicitly set:
if process.Config.AdvertiseIP != nil {
if process.Config.AdvertiseIP != "" {
ahost, aport, err := utils.ParseAdvertiseAddr(process.Config.AdvertiseIP)
if err != nil {
return trace.Wrap(err)
}
srv.SetAddr(fmt.Sprintf("%v:%v", process.Config.AdvertiseIP.String(), port))
// if port is not set in the advertise addr, use the default one
if aport == "" {
aport = port
}
srv.SetAddr(fmt.Sprintf("%v:%v", ahost, aport))
} else {
// advertise-ip is not set, while the CA is listening on 0.0.0.0? lets try
// to guess the 'advertise ip' then:
@ -1075,6 +1083,13 @@ func (process *TeleportProcess) getRotation(role teleport.Role) (*services.Rotat
return &state.Spec.Rotation, nil
}
func (process *TeleportProcess) proxyPublicAddr() utils.NetAddr {
if len(process.Config.Proxy.PublicAddrs) == 0 {
return utils.NetAddr{}
}
return process.Config.Proxy.PublicAddrs[0]
}
// initSSH initializes the "node" role, i.e. a simple SSH server connected to the auth server.
func (process *TeleportProcess) initSSH() error {
process.registerWithAuthServer(teleport.RoleNode, SSHIdentityEvent)
@ -1138,7 +1153,7 @@ func (process *TeleportProcess) initSSH() error {
authClient,
cfg.DataDir,
cfg.AdvertiseIP,
cfg.Proxy.PublicAddr,
process.proxyPublicAddr(),
regular.SetLimiter(limiter),
regular.SetShell(cfg.SSH.Shell),
regular.SetAuditLog(conn.Client),
@ -1349,14 +1364,23 @@ func (process *TeleportProcess) initDiagnosticService() error {
}
// getAdditionalPrincipals returns a list of additional principals to add
// to role's service certificate.
// to role's service certificates.
func (process *TeleportProcess) getAdditionalPrincipals(role teleport.Role) ([]string, error) {
var principals []string
if process.Config.Hostname != "" {
principals = append(principals, process.Config.Hostname)
}
if process.Config.Proxy.PublicAddr.Addr != "" {
host, err := utils.Host(process.Config.Proxy.PublicAddr.Addr)
var addrs []utils.NetAddr
switch role {
case teleport.RoleProxy:
addrs = process.Config.Proxy.PublicAddrs
case teleport.RoleAuth, teleport.RoleAdmin:
addrs = process.Config.Auth.PublicAddrs
case teleport.RoleNode:
addrs = process.Config.SSH.PublicAddrs
}
for _, addr := range addrs {
host, err := utils.Host(addr.Addr)
if err != nil {
return nil, trace.Wrap(err)
}
@ -1649,8 +1673,8 @@ func (process *TeleportProcess) initProxyEndpoint(conn *Connector) error {
[]ssh.Signer{conn.ServerIdentity.KeySigner},
accessPoint,
cfg.DataDir,
nil,
cfg.Proxy.PublicAddr,
"",
process.proxyPublicAddr(),
regular.SetLimiter(proxyLimiter),
regular.SetProxyMode(tsrv),
regular.SetSessionServer(conn.Client),

View file

@ -79,7 +79,7 @@ type Server struct {
proxyMode bool
proxyTun reversetunnel.Server
advertiseIP net.IP
advertiseIP string
proxyPublicAddr utils.NetAddr
// server UUID gets generated once on the first start and never changes
@ -344,7 +344,7 @@ func New(addr utils.NetAddr,
signers []ssh.Signer,
authService auth.AccessPoint,
dataDir string,
advertiseIP net.IP,
advertiseIP string,
proxyPublicAddr utils.NetAddr,
options ...ServerOption) (*Server, error) {
@ -458,13 +458,13 @@ func (s *Server) PermitUserEnvironment() bool {
return s.permitUserEnvironment
}
func (s *Server) setAdvertiseIP(ip net.IP) {
func (s *Server) setAdvertiseIP(ip string) {
s.Lock()
defer s.Unlock()
s.advertiseIP = ip
}
func (s *Server) getAdvertiseIP() net.IP {
func (s *Server) getAdvertiseIP() string {
s.Lock()
defer s.Unlock()
return s.advertiseIP
@ -474,11 +474,20 @@ func (s *Server) getAdvertiseIP() net.IP {
// as, in "ip:host" form
func (s *Server) AdvertiseAddr() string {
// set if we have explicit --advertise-ip option
if s.getAdvertiseIP() == nil {
advertiseIP := s.getAdvertiseIP()
if advertiseIP == "" {
return s.addr.Addr
}
_, port, _ := net.SplitHostPort(s.addr.Addr)
return net.JoinHostPort(s.getAdvertiseIP().String(), port)
ahost, aport, err := utils.ParseAdvertiseAddr(advertiseIP)
if err != nil {
log.Warningf("Failed to parse advertise address %q, %v, using default value %q.", advertiseIP, err, s.addr.Addr)
return s.addr.Addr
}
if aport == "" {
aport = port
}
return fmt.Sprintf("%v:%v", ahost, aport)
}
func (s *Server) getRole() teleport.Role {

View file

@ -137,7 +137,7 @@ func (s *SrvSuite) SetUpTest(c *C) {
[]ssh.Signer{s.signer},
s.nodeClient,
nodeDir,
nil,
"",
utils.NetAddr{},
SetNamespace(defaults.Namespace),
SetAuditLog(s.nodeClient),
@ -188,9 +188,9 @@ func (s *SrvSuite) TearDownTest(c *C) {
func (s *SrvSuite) TestAdvertiseAddr(c *C) {
c.Assert(strings.Index(s.srv.AdvertiseAddr(), "127.0.0.1:"), Equals, 0)
s.srv.setAdvertiseIP(net.ParseIP("10.10.10.1"))
s.srv.setAdvertiseIP("10.10.10.1")
c.Assert(strings.Index(s.srv.AdvertiseAddr(), "10.10.10.1:"), Equals, 0)
s.srv.setAdvertiseIP(nil)
s.srv.setAdvertiseIP("")
}
// TestAgentForwardPermission makes sure if RBAC rules don't allow agent
@ -492,7 +492,7 @@ func (s *SrvSuite) TestProxyReverseTunnel(c *C) {
[]ssh.Signer{s.signer},
s.proxyClient,
c.MkDir(),
nil,
"",
utils.NetAddr{},
SetProxyMode(reverseTunnelServer),
SetSessionServer(s.proxyClient),
@ -564,7 +564,7 @@ func (s *SrvSuite) TestProxyReverseTunnel(c *C) {
[]ssh.Signer{s.signer},
s.nodeClient,
c.MkDir(),
nil,
"",
utils.NetAddr{},
SetShell("/bin/sh"),
SetLabels(
@ -666,7 +666,7 @@ func (s *SrvSuite) TestProxyRoundRobin(c *C) {
[]ssh.Signer{s.signer},
s.proxyClient,
c.MkDir(),
nil,
"",
utils.NetAddr{},
SetProxyMode(reverseTunnelServer),
SetSessionServer(s.proxyClient),
@ -767,7 +767,7 @@ func (s *SrvSuite) TestProxyDirectAccess(c *C) {
[]ssh.Signer{s.signer},
s.proxyClient,
c.MkDir(),
nil,
"",
utils.NetAddr{},
SetProxyMode(reverseTunnelServer),
SetSessionServer(s.proxyClient),
@ -876,7 +876,7 @@ func (s *SrvSuite) TestLimiter(c *C) {
[]ssh.Signer{s.signer},
s.nodeClient,
nodeStateDir,
nil,
"",
utils.NetAddr{},
SetLimiter(limiter),
SetShell("/bin/sh"),

View file

@ -139,10 +139,10 @@ func UserMessageFromError(err error) string {
// error occured" message.
if er, ok := err.(*trace.TraceErr); ok {
if er.Message != "" {
return fmt.Sprintf("%v: %v", er.Message, er.Err.Error())
return fmt.Sprintf("error: %v", er.Message)
}
}
return fmt.Sprintf("A fatal error occurred: %v", err.Error())
return fmt.Sprintf("error: %v", err.Error())
}
return ""
}

View file

@ -32,6 +32,36 @@ import (
"github.com/pborman/uuid"
)
// ParseAdvertiseAddress validates advertise address,
// makes sure it's not an unreachable or multicast address
// returns address split into host and port, port could be empty
// if not specified
func ParseAdvertiseAddr(advertiseIP string) (string, string, error) {
advertiseIP = strings.TrimSpace(advertiseIP)
host := advertiseIP
port := ""
if len(net.ParseIP(host)) == 0 && strings.Contains(advertiseIP, ":") {
var err error
host, port, err = net.SplitHostPort(advertiseIP)
if err != nil {
return "", "", trace.BadParameter("failed to parse address %q", advertiseIP)
}
if _, err := strconv.Atoi(port); err != nil {
return "", "", trace.BadParameter("bad port %q, expected integer", port)
}
if host == "" {
return "", "", trace.BadParameter("missing host parameter")
}
}
ip := net.ParseIP(host)
if len(ip) != 0 {
if ip.IsLoopback() || ip.IsUnspecified() || ip.IsMulticast() {
return "", "", trace.BadParameter("unreachable advertise IP: %v", advertiseIP)
}
}
return host, port, nil
}
// StringsSet creates set of string (map[string]struct{})
// from a list of strings
func StringsSet(in []string) map[string]struct{} {

View file

@ -142,3 +142,38 @@ func (s *UtilsSuite) TestParseSessionsURI(c *check.C) {
}
}
}
// TestParseAdvertiseAddr tests parsing of advertise address
func (s *UtilsSuite) TestParseAdvertiseAddr(c *check.C) {
testCases := []struct {
info string
in string
host string
port string
err error
}{
{info: "ok address", in: "192.168.1.1", host: "192.168.1.1"},
{info: "trim space", in: " 192.168.1.1 ", host: "192.168.1.1"},
{info: "multicast address", in: "224.0.0.0", err: trace.BadParameter("")},
{info: "multicast address", in: " 224.0.0.0 ", err: trace.BadParameter("")},
{info: "ok address and port", in: "192.168.1.1:22", host: "192.168.1.1", port: "22"},
{info: "ok address and bad port", in: "192.168.1.1:b", err: trace.BadParameter("")},
{info: "ok host", in: "localhost", host: "localhost"},
{info: "ok host and port", in: "localhost:33", host: "localhost", port: "33"},
{info: "missing host ", in: ":33", err: trace.BadParameter("")},
{info: "missing port", in: "localhost:", err: trace.BadParameter("")},
{info: "ipv6 address", in: "2001:0db8:85a3:0000:0000:8a2e:0370:7334", host: "2001:0db8:85a3:0000:0000:8a2e:0370:7334"},
{info: "ipv6 address and port", in: "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:443", host: "2001:0db8:85a3:0000:0000:8a2e:0370:7334", port: "443"},
}
for i, testCase := range testCases {
comment := check.Commentf("test case %v %q", i, testCase.info)
host, port, err := ParseAdvertiseAddr(testCase.in)
if testCase.err == nil {
c.Assert(err, check.IsNil, comment)
c.Assert(host, check.Equals, testCase.host)
c.Assert(port, check.Equals, testCase.port)
} else {
c.Assert(err, check.FitsTypeOf, testCase.err, comment)
}
}
}

View file

@ -174,7 +174,7 @@ func (s *WebSuite) SetUpTest(c *C) {
[]ssh.Signer{signer},
nodeClient,
nodeDataDir,
nil,
"",
utils.NetAddr{},
regular.SetNamespace(defaults.Namespace),
regular.SetShell("/bin/sh"),
@ -221,7 +221,7 @@ func (s *WebSuite) SetUpTest(c *C) {
[]ssh.Signer{signer},
s.proxyClient,
c.MkDir(),
nil,
"",
utils.NetAddr{},
regular.SetProxyMode(revTunServer),
regular.SetSessionServer(s.proxyClient),

View file

@ -376,7 +376,7 @@ func (g *ResourceCommand) getCollection(client auth.ClientI) (c ResourceCollecti
}
return &serverCollection{servers: servers}, nil
case services.KindProxy:
servers, err := client.GetAuthServers()
servers, err := client.GetProxies()
if err != nil {
return nil, trace.Wrap(err)
}

View file

@ -86,7 +86,7 @@ func Run(options Options) (executedCommand string, conf *service.Config) {
"Full path to the PID file. By default no PID file will be created").StringVar(&ccf.PIDFile)
start.Flag("advertise-ip",
"IP to advertise to clients if running behind NAT").
IPVar(&ccf.AdvertiseIP)
StringVar(&ccf.AdvertiseIP)
start.Flag("listen-ip",
fmt.Sprintf("IP address to bind to [%s]", defaults.BindIP)).
Short('l').
@ -159,7 +159,6 @@ func Run(options Options) (executedCommand string, conf *service.Config) {
if err != nil {
utils.FatalError(err)
}
log.Debug("Clean exit.")
return command, conf
}

View file

@ -18,7 +18,6 @@ package common
import (
"io/ioutil"
"net"
"os"
"path/filepath"
"testing"
@ -119,7 +118,7 @@ func (s *MainTestSuite) TestConfigFile(c *check.C) {
c.Assert(log.GetLevel(), check.Equals, log.DebugLevel)
c.Assert(conf.Hostname, check.Equals, "hvostongo.example.org")
c.Assert(conf.Token, check.Equals, "xxxyyy")
c.Assert(conf.AdvertiseIP, check.DeepEquals, net.ParseIP("10.5.5.5"))
c.Assert(conf.AdvertiseIP, check.DeepEquals, "10.5.5.5")
c.Assert(conf.SSH.Labels, check.DeepEquals, map[string]string{"a": "a1", "b": "b1"})
}