Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Kubernetes SNI proxy improvements, implements #2614
Browse files Browse the repository at this point in the history
This commit hex encodes trusted cluster names
in target addresses for kubernetes SNI proxy.

For example, assuming public address of Teleport
Kubernetes proxy is main.example.com, and trusted
cluster is remote.example.com, resulting target
address added to kubeconfig will look like

k72656d6f74652e6578616d706c652e636f6d0a.main.example.com

And Teleport Proxy's DNS Name will include wildcard:

'*.main.example.com' in addition to 'main.example.com'

Note that no dots are in the SNI address thanks to hex encoding.

This will allow administrators to avoid manually updating
list of public_addr sections every time the trusted cluster and use
the wildcard DNS name.

The following addr:

remote.example.com.main.example.com would not have matched
*.main.example.com per DNS wildcard spec.
klizhentas committed Mar 21, 2019
1 parent ea17f9c commit e0b47aa
Showing 11 changed files with 142 additions and 49 deletions.
12 changes: 11 additions & 1 deletion lib/auth/auth.go
Original file line number Diff line number Diff line change
@@ -760,6 +760,9 @@ type GenerateServerKeysRequest struct {
// AdditionalPrincipals is a list of additional principals
// to include in OpenSSH and X509 certificates
AdditionalPrincipals []string `json:"additional_principals"`
// DNSNames is a list of DNS names
// to include in the x509 client certificate
DNSNames []string `json:"dns_names"`
// PublicTLSKey is a PEM encoded public key
// used for TLS setup
PublicTLSKey []byte `json:"public_tls_key"`
@@ -877,11 +880,15 @@ func (s *AuthServer) GenerateServerKeys(req GenerateServerKeysRequest) (*PackedK
if req.Roles.Include(teleport.RoleAuth) || req.Roles.Include(teleport.RoleAdmin) {
certRequest.DNSNames = append(certRequest.DNSNames, "*."+teleport.APIDomain, teleport.APIDomain)
}
// Unlike additional pricinpals, DNS Names is x509 specific
// and is limited to auth servers and proxies
if req.Roles.Include(teleport.RoleAuth) || req.Roles.Include(teleport.RoleAdmin) || req.Roles.Include(teleport.RoleProxy) {
certRequest.DNSNames = append(certRequest.DNSNames, req.DNSNames...)
}
hostTLSCert, err := tlsAuthority.GenerateCertificate(certRequest)
if err != nil {
return nil, trace.Wrap(err)
}

return &PackedKeys{
Key: privateKeyPEM,
Cert: hostSSHCert,
@@ -949,6 +956,8 @@ type RegisterUsingTokenRequest struct {
Token string `json:"token"`
// AdditionalPrincipals is a list of additional principals
AdditionalPrincipals []string `json:"additional_principals"`
// DNSNames is a list of DNS names to include in the x509 client certificate
DNSNames []string `json:"dns_names"`
// PublicTLSKey is a PEM encoded public key
// used for TLS setup
PublicTLSKey []byte `json:"public_tls_key"`
@@ -1011,6 +1020,7 @@ func (s *AuthServer) RegisterUsingToken(req RegisterUsingTokenRequest) (*PackedK
PublicTLSKey: req.PublicTLSKey,
PublicSSHKey: req.PublicSSHKey,
RemoteAddr: req.RemoteAddr,
DNSNames: req.DNSNames,
})
if err != nil {
return nil, trace.Wrap(err)
29 changes: 15 additions & 14 deletions lib/auth/init.go
Original file line number Diff line number Diff line change
@@ -527,12 +527,13 @@ func isFirstStart(authServer *AuthServer, cfg InitConfig) (bool, error) {
}

// GenerateIdentity generates identity for the auth server
func GenerateIdentity(a *AuthServer, id IdentityID, additionalPrincipals []string) (*Identity, error) {
func GenerateIdentity(a *AuthServer, id IdentityID, additionalPrincipals, dnsNames []string) (*Identity, error) {
keys, err := a.GenerateServerKeys(GenerateServerKeysRequest{
HostID: id.HostUUID,
NodeName: id.NodeName,
Roles: teleport.Roles{id.Role},
AdditionalPrincipals: additionalPrincipals,
DNSNames: dnsNames,
})
if err != nil {
return nil, trace.Wrap(err)
@@ -557,18 +558,17 @@ type Identity struct {
KeySigner ssh.Signer
// Cert is a parsed SSH certificate
Cert *ssh.Certificate
// XCert is X509 client certificate
XCert *x509.Certificate
// ClusterName is a name of host's cluster
ClusterName string
}

// String returns user-friendly representation of the identity.
func (i *Identity) String() string {
var out []string
cert, err := tlsca.ParseCertificatePEM(i.TLSCertBytes)
if err != nil {
out = append(out, err.Error())
} else {
out = append(out, fmt.Sprintf("cert(%v issued by %v:%v)", cert.Subject.CommonName, cert.Issuer.CommonName, cert.Issuer.SerialNumber))
if i.XCert != nil {
out = append(out, fmt.Sprintf("cert(%v issued by %v:%v)", i.XCert.Subject.CommonName, i.XCert.Issuer.CommonName, i.XCert.Issuer.SerialNumber))
}
for j := range i.TLSCACertsBytes {
cert, err := tlsca.ParseCertificatePEM(i.TLSCACertsBytes[j])
@@ -598,18 +598,17 @@ func (i *Identity) HasPrincipals(additionalPrincipals []string) bool {
}

// HasDNSNames returns true if TLS certificate has required DNS names
func (i *Identity) HasDNSNames(dnsNames []string) (bool, error) {
cert, err := tlsca.ParseCertificatePEM(i.TLSCertBytes)
if err != nil {
return false, trace.Wrap(err)
func (i *Identity) HasDNSNames(dnsNames []string) bool {
if i.XCert == nil {
return false
}
set := utils.StringsSet(cert.DNSNames)
set := utils.StringsSet(i.XCert.DNSNames)
for _, dnsName := range dnsNames {
if _, ok := set[dnsName]; !ok {
return false, nil
return false
}
}
return true, nil
return true
}

// TLSConfig returns TLS config for mutual TLS authentication
@@ -672,12 +671,13 @@ func ReadIdentityFromKeyPair(keyBytes, sshCertBytes, tlsCertBytes []byte, tlsCAC
}
if len(tlsCertBytes) != 0 {
// just to verify that identity parses properly for future use
_, err := ReadTLSIdentityFromKeyPair(keyBytes, tlsCertBytes, tlsCACertsBytes)
i, err := ReadTLSIdentityFromKeyPair(keyBytes, tlsCertBytes, tlsCACertsBytes)
if err != nil {
return nil, trace.Wrap(err)
}
identity.TLSCertBytes = tlsCertBytes
identity.TLSCACertsBytes = tlsCACertsBytes
identity.XCert = i.XCert
}
return identity, nil
}
@@ -716,6 +716,7 @@ func ReadTLSIdentityFromKeyPair(keyBytes, certBytes []byte, caCertsBytes [][]byt
KeyBytes: keyBytes,
TLSCertBytes: certBytes,
TLSCACertsBytes: caCertsBytes,
XCert: cert,
}
// The passed in ciphersuites don't appear to matter here since the returned
// *tls.Config is never actually used?
13 changes: 10 additions & 3 deletions lib/auth/oidc.go
Original file line number Diff line number Diff line change
@@ -131,7 +131,8 @@ func (a *AuthServer) ValidateOIDCAuthCallback(q url.Values) (*OIDCAuthResponse,
a.EmitAuditEvent(events.UserLoginEvent, events.EventFields{
events.LoginMethod: events.LoginMethodOIDC,
events.AuthAttemptSuccess: false,
events.AuthAttemptErr: err.Error(),
// log the original internal error in audit log
events.AuthAttemptErr: trace.Unwrap(err).Error(),
})
} else {
a.EmitAuditEvent(events.UserLoginEvent, events.EventFields{
@@ -178,8 +179,14 @@ func (a *AuthServer) validateOIDCAuthCallback(q url.Values) (*OIDCAuthResponse,
// extract claims from both the id token and the userinfo endpoint and merge them
claims, err := a.getClaims(oidcClient, connector.GetIssuerURL(), connector.GetScope(), code)
if err != nil {
return nil, trace.OAuth2(
oauth2.ErrorUnsupportedResponseType, "unable to construct claims", q)
return nil, trace.WrapWithMessage(
// preserve the original error message, to avoid leaking
// server errors to the user in the UI, but override
// user message to the high level instruction to check audit log for details
trace.OAuth2(
oauth2.ErrorUnsupportedResponseType, err.Error(), q),
"unable to construct claims, check audit log for details",
)
}

log.Debugf("OIDC claims: %v.", claims)
10 changes: 8 additions & 2 deletions lib/auth/register.go
Original file line number Diff line number Diff line change
@@ -32,19 +32,19 @@ import (
// LocalRegister is used to generate host keys when a node or proxy is running
// within the same process as the Auth Server and as such, does not need to
// use provisioning tokens.
func LocalRegister(id IdentityID, authServer *AuthServer, additionalPrincipals []string, remoteAddr string) (*Identity, error) {
func LocalRegister(id IdentityID, authServer *AuthServer, additionalPrincipals, dnsNames []string, remoteAddr string) (*Identity, error) {
// If local registration is happening and no remote address was passed in
// (which means no advertise IP was set), use localhost.
if remoteAddr == "" {
remoteAddr = defaults.Localhost
}

keys, err := authServer.GenerateServerKeys(GenerateServerKeysRequest{
HostID: id.HostUUID,
NodeName: id.NodeName,
Roles: teleport.Roles{id.Role},
AdditionalPrincipals: additionalPrincipals,
RemoteAddr: remoteAddr,
DNSNames: dnsNames,
})
if err != nil {
return nil, trace.Wrap(err)
@@ -72,6 +72,8 @@ type RegisterParams struct {
Servers []utils.NetAddr
// AdditionalPrincipals is a list of additional principals to dial
AdditionalPrincipals []string
// DNSNames is a list of DNS names to add to x509 certificate
DNSNames []string
// PrivateKey is a PEM encoded private key (not passed to auth servers)
PrivateKey []byte
// PublicTLSKey is a server's public key to sign
@@ -120,6 +122,7 @@ func Register(params RegisterParams) (*Identity, error) {
NodeName: params.ID.NodeName,
Role: params.ID.Role,
AdditionalPrincipals: params.AdditionalPrincipals,
DNSNames: params.DNSNames,
PublicTLSKey: params.PublicTLSKey,
PublicSSHKey: params.PublicSSHKey,
})
@@ -243,6 +246,8 @@ type ReRegisterParams struct {
ID IdentityID
// AdditionalPrincipals is a list of additional principals to dial
AdditionalPrincipals []string
// DNSNames is a list of DNS Names to add to the x509 client certificate
DNSNames []string
// PrivateKey is a PEM encoded private key (not passed to auth servers)
PrivateKey []byte
// PublicTLSKey is a server's public key to sign
@@ -262,6 +267,7 @@ func ReRegister(params ReRegisterParams) (*Identity, error) {
NodeName: params.ID.NodeName,
Roles: teleport.Roles{params.ID.Role},
AdditionalPrincipals: params.AdditionalPrincipals,
DNSNames: params.DNSNames,
PublicTLSKey: params.PublicTLSKey,
PublicSSHKey: params.PublicSSHKey,
})
11 changes: 8 additions & 3 deletions lib/kube/client/kubeclient.go
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ import (

"github.com/gravitational/teleport"
"github.com/gravitational/teleport/lib/client"
kubeutils "github.com/gravitational/teleport/lib/kube/utils"
"github.com/gravitational/teleport/lib/utils"

"github.com/gravitational/trace"
@@ -29,10 +30,15 @@ func UpdateKubeconfig(tc *client.TeleportClient) error {
}

clusterName, proxyPort := tc.KubeProxyHostPort()
var clusterAddr string
if tc.SiteName != "" {
clusterName = fmt.Sprintf("%v.%v", tc.SiteName, clusterName)
// In case of a remote cluster, use SNI subdomain to "point" to a remote cluster name
clusterAddr = fmt.Sprintf("https://%v.%v:%v",
kubeutils.EncodeClusterName(tc.SiteName), clusterName, proxyPort)
clusterName = tc.SiteName
} else {
clusterAddr = fmt.Sprintf("https://%v:%v", clusterName, proxyPort)
}
clusterAddr := fmt.Sprintf("https://%v:%v", clusterName, proxyPort)

creds, err := tc.LocalAgent().GetKey()
if err != nil {
@@ -62,7 +68,6 @@ func UpdateKubeconfig(tc *client.TeleportClient) error {
newContext.Extensions = lastContext.Extensions
}
config.Contexts[clusterName] = newContext

config.CurrentContext = clusterName
return SaveKubeConfig(*config)
}
4 changes: 3 additions & 1 deletion lib/kube/proxy/forwarder.go
Original file line number Diff line number Diff line change
@@ -334,7 +334,8 @@ func (f *Forwarder) setupContext(ctx auth.AuthContext, req *http.Request, isRemo
return nil, trace.Wrap(err)
}
for _, remoteCluster := range f.Tunnel.GetSites() {
if strings.HasPrefix(req.Host, remoteCluster.GetName()+".") {
encodedName := kubeutils.EncodeClusterName(remoteCluster.GetName())
if strings.HasPrefix(req.Host, remoteCluster.GetName()+".") || strings.HasPrefix(req.Host, encodedName+".") {
f.Debugf("Going to proxy to cluster: %v based on matching host prefix %v.", remoteCluster.GetName(), req.Host)
targetCluster = remoteCluster
isRemoteCluster = remoteCluster.GetName() != f.ClusterName
@@ -771,6 +772,7 @@ func (f *Forwarder) newClusterSession(ctx authContext) (*clusterSession, error)
return sess, nil
}

// DialFunc is a network dialer function that returns a network connection
type DialFunc func(string, string) (net.Conn, error)

func (f *Forwarder) newTransport(dial DialFunc, tlsConfig *tls.Config) *http.Transport {
27 changes: 27 additions & 0 deletions lib/kube/utils/utils.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package utils

import (
"encoding/hex"

"github.com/gravitational/trace"

"k8s.io/client-go/kubernetes"
@@ -42,3 +44,28 @@ func GetKubeConfig(configPath string) (*rest.Config, error) {
}
return rest.InClusterConfig()
}

// EncodeClusterName encodes cluster name for SNI matching
//
// For example:
//
// * Main cluster is main.example.com
// * Remote cluster is remote.example.com
//
// After 'tsh login' the URL of the Kubernetes endpoint of 'remote.example.com'
// when accessed 'via main.example.com' looks like this:
//
// 'k72656d6f74652e6578616d706c652e636f6d0a.main.example.com'
//
// For this to work, users have to add this address in public_addr section of kubernetes service
// to include 'main.example.com' in X509 '*.main.example.com' domain name
//
// where part '72656d6f74652e6578616d706c652e636f6d0a' is a hex encoded remote.example.com
//
// It is hex encoded to allow wildcard matching to work. In DNS wildcard match
// include only one '.'
//
func EncodeClusterName(clusterName string) string {
// k is to avoid first letter to be a number
return "k" + hex.EncodeToString([]byte(clusterName))
}
36 changes: 18 additions & 18 deletions lib/service/connect.go
Original file line number Diff line number Diff line change
@@ -65,11 +65,7 @@ func (process *TeleportProcess) connect(role teleport.Role) (conn *Connector, er
// this is a migration clutch, used to re-register
// in case if identity of the auth server does not have the wildcard cert
if role == teleport.RoleAdmin || role == teleport.RoleAuth {
hasNames, err := identity.HasDNSNames([]string{"*." + teleport.APIDomain})
if err != nil {
return nil, trace.Wrap(err)
}
if !hasNames {
if !identity.HasDNSNames([]string{"*." + teleport.APIDomain}) {
process.Debugf("Detected Auth server certificate without wildcard principals: %v, regenerating.", identity.Cert.ValidPrincipals)
return process.firstTimeConnect(role)
}
@@ -255,9 +251,9 @@ func (process *TeleportProcess) getCertAuthority(conn *Connector, id services.Ce
// reRegister receives new identity credentials for proxy, node and auth.
// In case if auth servers, the role is 'TeleportAdmin' and instead of using
// TLS client this method uses the local auth server.
func (process *TeleportProcess) reRegister(conn *Connector, additionalPrincipals []string) (*auth.Identity, error) {
func (process *TeleportProcess) reRegister(conn *Connector, additionalPrincipals, dnsNames []string) (*auth.Identity, error) {
if conn.ClientIdentity.ID.Role == teleport.RoleAdmin || conn.ClientIdentity.ID.Role == teleport.RoleAuth {
return auth.GenerateIdentity(process.localAuth, conn.ClientIdentity.ID, additionalPrincipals)
return auth.GenerateIdentity(process.localAuth, conn.ClientIdentity.ID, additionalPrincipals, dnsNames)
}
const reason = "re-register"
keyPair, err := process.generateKeyPair(conn.ClientIdentity.ID.Role, reason)
@@ -271,6 +267,7 @@ func (process *TeleportProcess) reRegister(conn *Connector, additionalPrincipals
PrivateKey: keyPair.PrivateKey,
PublicTLSKey: keyPair.PublicTLSKey,
PublicSSHKey: keyPair.PublicSSHKey,
DNSNames: dnsNames,
})
if err != nil {
return nil, trace.Wrap(err)
@@ -285,7 +282,7 @@ func (process *TeleportProcess) firstTimeConnect(role teleport.Role) (*Connector
HostUUID: process.Config.HostUUID,
NodeName: process.Config.Hostname,
}
additionalPrincipals, err := process.getAdditionalPrincipals(role)
additionalPrincipals, dnsNames, err := process.getAdditionalPrincipals(role)
if err != nil {
return nil, trace.Wrap(err)
}
@@ -294,7 +291,7 @@ func (process *TeleportProcess) firstTimeConnect(role teleport.Role) (*Connector
// Auth service is on the same host, no need to go though the invitation
// procedure.
process.Debugf("This server has local Auth server started, using it to add role to the cluster.")
identity, err = auth.LocalRegister(id, process.getLocalAuth(), additionalPrincipals, process.Config.AdvertiseIP)
identity, err = auth.LocalRegister(id, process.getLocalAuth(), additionalPrincipals, dnsNames, process.Config.AdvertiseIP)
if err != nil {
return nil, trace.Wrap(err)
}
@@ -315,6 +312,7 @@ func (process *TeleportProcess) firstTimeConnect(role teleport.Role) (*Connector
ID: id,
Servers: process.Config.AuthServers,
AdditionalPrincipals: additionalPrincipals,
DNSNames: dnsNames,
PrivateKey: keyPair.PrivateKey,
PublicTLSKey: keyPair.PublicTLSKey,
PublicSSHKey: keyPair.PublicSSHKey,
@@ -558,19 +556,21 @@ func (process *TeleportProcess) rotate(conn *Connector, localState auth.StateV2,
id := conn.ClientIdentity.ID
local := localState.Spec.Rotation

additionalPrincipals, err := process.getAdditionalPrincipals(id.Role)
additionalPrincipals, dnsNames, err := process.getAdditionalPrincipals(id.Role)
if err != nil {
return nil, trace.Wrap(err)
}

additionalPrincipals = utils.ReplaceInSlice(
additionalPrincipals,
defaults.AnyAddress,
defaults.Localhost,
)

principalsChanged := len(additionalPrincipals) != 0 && !conn.ServerIdentity.HasPrincipals(additionalPrincipals)
principalsOrDNSNamesChanged := (len(additionalPrincipals) != 0 && !conn.ServerIdentity.HasPrincipals(additionalPrincipals)) ||
(len(dnsNames) != 0 && !conn.ServerIdentity.HasDNSNames(dnsNames))

if local.Matches(remote) && !principalsChanged {
if local.Matches(remote) && !principalsOrDNSNamesChanged {
// nothing to do, local state and rotation state are in sync
return &rotationStatus{}, nil
}
@@ -599,9 +599,9 @@ 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 principalsChanged {
process.Infof("Service %v has updated principals to %q, going to request new principals and update.", id.Role, additionalPrincipals)
identity, err := process.reRegister(conn, additionalPrincipals)
if principalsOrDNSNamesChanged {
process.Infof("Service %v has updated principals to %q, DNS Names to %q, going to request new principals and update.", id.Role, additionalPrincipals)
identity, err := process.reRegister(conn, additionalPrincipals, dnsNames)
if err != nil {
return nil, trace.Wrap(err)
}
@@ -618,7 +618,7 @@ func (process *TeleportProcess) rotate(conn *Connector, localState auth.StateV2,
if local.Phase != services.RotationPhaseRollback && local.CurrentID != remote.CurrentID {
return nil, trace.CompareFailed(outOfSync, id.Role, remote, local, id.Role)
}
identity, err := process.reRegister(conn, additionalPrincipals)
identity, err := process.reRegister(conn, additionalPrincipals, dnsNames)
if err != nil {
return nil, trace.Wrap(err)
}
@@ -654,7 +654,7 @@ func (process *TeleportProcess) rotate(conn *Connector, localState auth.StateV2,
if local.Phase != services.RotationPhaseInit && local.CurrentID != remote.CurrentID {
return nil, trace.CompareFailed(outOfSync, id.Role, remote, local, id.Role)
}
identity, err := process.reRegister(conn, additionalPrincipals)
identity, err := process.reRegister(conn, additionalPrincipals, dnsNames)
if err != nil {
return nil, trace.Wrap(err)
}
@@ -686,7 +686,7 @@ func (process *TeleportProcess) rotate(conn *Connector, localState auth.StateV2,
// because it will be widely used to recover cluster state to
// the previously valid state, client will re-register to receive
// credentials signed by the "old" CA.
identity, err := process.reRegister(conn, additionalPrincipals)
identity, err := process.reRegister(conn, additionalPrincipals, dnsNames)
if err != nil {
return nil, trace.Wrap(err)
}
27 changes: 20 additions & 7 deletions lib/service/service.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2015-2018 Gravitational, Inc.
Copyright 2015-2019 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -313,11 +313,11 @@ func (process *TeleportProcess) GetIdentity(role teleport.Role) (i *auth.Identit
// for admin identity use local auth server
// because admin identity is requested by auth server
// itself
principals, err := process.getAdditionalPrincipals(role)
principals, dnsNames, err := process.getAdditionalPrincipals(role)
if err != nil {
return nil, trace.Wrap(err)
}
i, err = auth.GenerateIdentity(process.localAuth, id, principals)
i, err = auth.GenerateIdentity(process.localAuth, id, principals, dnsNames)
} else {
// try to locate static identity provided in the file
i, err = process.findStaticIdentity(id)
@@ -1505,8 +1505,9 @@ func (process *TeleportProcess) initDiagnosticService() error {

// getAdditionalPrincipals returns a list of additional principals to add
// to role's service certificates.
func (process *TeleportProcess) getAdditionalPrincipals(role teleport.Role) ([]string, error) {
func (process *TeleportProcess) getAdditionalPrincipals(role teleport.Role) ([]string, []string, error) {
var principals []string
var dnsNames []string
if process.Config.Hostname != "" {
principals = append(principals, process.Config.Hostname)
}
@@ -1516,6 +1517,18 @@ func (process *TeleportProcess) getAdditionalPrincipals(role teleport.Role) ([]s
addrs = append(process.Config.Proxy.PublicAddrs, utils.NetAddr{Addr: reversetunnel.RemoteKubeProxy})
addrs = append(addrs, process.Config.Proxy.SSHPublicAddrs...)
addrs = append(addrs, process.Config.Proxy.Kube.PublicAddrs...)
// Automatically add wildcards for every proxy public address for k8s SNI routing
if process.Config.Proxy.Kube.Enabled {
for _, publicAddr := range utils.JoinAddrSlices(process.Config.Proxy.PublicAddrs, process.Config.Proxy.Kube.PublicAddrs) {
host, err := utils.Host(publicAddr.Addr)
if err != nil {
return nil, nil, trace.Wrap(err)
}
if ip := net.ParseIP(host); ip == nil {
dnsNames = append(dnsNames, "*."+host)
}
}
}
case teleport.RoleAuth, teleport.RoleAdmin:
addrs = process.Config.Auth.PublicAddrs
case teleport.RoleNode:
@@ -1526,7 +1539,7 @@ func (process *TeleportProcess) getAdditionalPrincipals(role teleport.Role) ([]s
if process.Config.AdvertiseIP != "" {
advertiseIP, err := utils.ParseAddr(process.Config.AdvertiseIP)
if err != nil {
return nil, trace.Wrap(err)
return nil, nil, trace.Wrap(err)
}
addrs = append(addrs, *advertiseIP)
} else {
@@ -1536,11 +1549,11 @@ func (process *TeleportProcess) getAdditionalPrincipals(role teleport.Role) ([]s
for _, addr := range addrs {
host, err := utils.Host(addr.Addr)
if err != nil {
return nil, trace.Wrap(err)
return nil, nil, trace.Wrap(err)
}
principals = append(principals, host)
}
return principals, nil
return principals, dnsNames, nil
}

// initProxy gets called if teleport runs with 'proxy' role enabled.
11 changes: 11 additions & 0 deletions lib/utils/addr.go
Original file line number Diff line number Diff line change
@@ -172,6 +172,17 @@ func FromAddr(a net.Addr) NetAddr {
return NetAddr{AddrNetwork: a.Network(), Addr: a.String()}
}

// JoinAddrSlices joins two addr slices and returns a resulting slice
func JoinAddrSlices(a []NetAddr, b []NetAddr) []NetAddr {
if len(a)+len(b) == 0 {
return nil
}
out := make([]NetAddr, 0, len(a)+len(b))
out = append(out, a...)
out = append(out, b...)
return out
}

// ParseHostPortAddr takes strings like "host:port" and returns
// *NetAddr or an error
//
11 changes: 11 additions & 0 deletions lib/utils/copy.go
Original file line number Diff line number Diff line change
@@ -38,6 +38,17 @@ func CopyByteSlices(in [][]byte) [][]byte {
return out
}

// JoinStringSlices joins two string slices and returns a resulting slice
func JoinStringSlices(a []string, b []string) []string {
if len(a)+len(b) == 0 {
return nil
}
out := make([]string, 0, len(a)+len(b))
out = append(out, a...)
out = append(out, b...)
return out
}

// CopyStrings makes a deep copy of the passed in string slice and returns
// the copy.
func CopyStrings(in []string) []string {

0 comments on commit e0b47aa

Please sign in to comment.