Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion lib/service/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ func (process *TeleportProcess) firstTimeConnectIdentityRemote(role types.System
id := state.IdentityID{
Role: role,
HostUUID: instanceIdentity.ID.HostUUID,
NodeName: instanceIdentity.ID.NodeName,
NodeName: process.Config.Hostname,
}
additionalPrincipals, dnsNames, err := process.getAdditionalPrincipals(role, id.HostID())
if err != nil {
Expand Down Expand Up @@ -936,6 +936,13 @@ func (process *TeleportProcess) rotate(conn *Connector, localState state.StateV2
return nil, trace.Wrap(err)
}

// Ensure the <hostname>.<clustername> principal is included and repair the
// host certificates if it is not. This is not included in the output of
// process.getAdditionalPrincipals which is usually called while joining
// before the cluster name is known.
additionalPrincipals = append(additionalPrincipals,
process.Config.Hostname+"."+conn.ClusterName())

var assertionID string
var systemRoles []types.SystemRole
var wantsSystemRoleRepair bool
Expand Down
70 changes: 69 additions & 1 deletion lib/service/service_test.go
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for extending the tests to cover this 🚀

Original file line number Diff line number Diff line change
Expand Up @@ -993,8 +993,10 @@ func TestTeleportProcess_reconnectToAuth(t *testing.T) {
// get a certificate with both the Proxy and Node system roles.
func TestInstanceSelfRepair(t *testing.T) {
// Setup: create an auth server with two tokens, one proxy proxies and one for nodes.
const clusterName = "testcluster"
testAuthServer, err := authtest.NewAuthServer(authtest.AuthServerConfig{
Dir: makeTempDir(t),
Dir: makeTempDir(t),
ClusterName: clusterName,
})
require.NoError(t, err)
tlsServer, err := testAuthServer.NewTestTLSServer()
Expand All @@ -1014,11 +1016,13 @@ func TestInstanceSelfRepair(t *testing.T) {

logger := logtest.NewLogger()
dataDir := makeTempDir(t)
const hostName = "testhost"
newStartedProcess := func(token string, sshEnabled bool) *TeleportProcess {
cfg := servicecfg.MakeDefaultConfig()
cfg.SetAuthServerAddress(*utils.MustParseAddr(tlsServer.Listener.Addr().String()))
cfg.Clock = clockwork.NewRealClock()
cfg.DataDir = dataDir
cfg.Hostname = hostName
cfg.Auth.Enabled = false
cfg.Proxy.Enabled = true
cfg.Proxy.DisableWebInterface = true
Expand Down Expand Up @@ -1071,6 +1075,70 @@ func TestInstanceSelfRepair(t *testing.T) {
// Close the process to clean up.
require.NoError(t, process.Close())
require.NoError(t, process.Wait())

nodeConnector, err := process.WaitForConnector(SSHIdentityEvent, logger)
require.NoError(t, err)
nodeID := nodeConnector.clientState.Load().identity
expectSSHPrincipals := expectedSSHPrincipals(nodeID.ID.HostID(), hostName, clusterName)
require.ElementsMatch(t, expectSSHPrincipals, nodeID.Cert.ValidPrincipals)
}

func TestSSHPrincipals(t *testing.T) {
const clusterName = "testcluster"
authServer, err := authtest.NewTestServer(authtest.ServerConfig{
Auth: authtest.AuthServerConfig{
Dir: t.TempDir(),
ClusterName: clusterName,
},
})
require.NoError(t, err)

token, err := types.NewProvisionTokenFromSpec("token", time.Now().Add(time.Minute), types.ProvisionTokenSpecV2{
Roles: []types.SystemRole{types.RoleNode},
})
require.NoError(t, err)
require.NoError(t, authServer.Auth().UpsertToken(t.Context(), token))

logger := logtest.NewLogger()
const hostName = "testhost"
nodeCfg := servicecfg.MakeDefaultConfig()
nodeCfg.SetAuthServerAddress(*utils.MustParseAddr(authServer.TLS.Listener.Addr().String()))
nodeCfg.Clock = clockwork.NewRealClock()
nodeCfg.DataDir = t.TempDir()
nodeCfg.Hostname = hostName
nodeCfg.Auth.Enabled = false
nodeCfg.Proxy.Enabled = false
nodeCfg.SSH.Enabled = true
nodeCfg.SSH.Addr = utils.NetAddr{Addr: "127.0.0.1:0", AddrNetwork: "tcp"}
nodeCfg.SetToken(token.GetName())
nodeCfg.JoinMethod = types.JoinMethodToken
nodeCfg.Logger = logger
nodeProcess, err := NewTeleport(nodeCfg)
require.NoError(t, err)
go nodeProcess.Start()
defer func() {
assert.NoError(t, nodeProcess.Close())
assert.NoError(t, nodeProcess.Wait())
}()

nodeConnector, err := nodeProcess.WaitForConnector(SSHIdentityEvent, logger)
require.NoError(t, err)
nodeID := nodeConnector.clientState.Load().identity
expectSSHPrincipals := expectedSSHPrincipals(nodeID.ID.HostID(), hostName, clusterName)
assert.ElementsMatch(t, expectSSHPrincipals, nodeID.Cert.ValidPrincipals)
}

func expectedSSHPrincipals(hostID, hostName, clusterName string) []string {
return []string{
hostID,
hostID + "." + clusterName,
hostName,
hostName + "." + clusterName,
string(teleport.PrincipalLocalhost),
string(teleport.PrincipalLoopbackV4),
string(teleport.PrincipalLoopbackV6),
}

}

func TestTeleportProcessAuthVersionCheck(t *testing.T) {
Expand Down
Loading