Files
teleport/lib/reversetunnel/agent_dialer_test.go
T
rosstimothy 7541d6d7d0 Introduce logtest package (#56741)
Moves all test related logger initialization and creation to the
logtest package to reduce testing symbols in production code. The
existing helpers in lib/utils have been left in place until the
enterprise references can be converted.

Updates #51023.
2025-07-15 18:11:10 +00:00

128 lines
3.7 KiB
Go

/*
* Teleport
* Copyright (C) 2023 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package reversetunnel
import (
"context"
"testing"
"github.com/gravitational/trace"
"github.com/stretchr/testify/require"
"golang.org/x/crypto/ssh"
"github.com/gravitational/teleport/api/types"
apisshutils "github.com/gravitational/teleport/api/utils/sshutils"
"github.com/gravitational/teleport/lib/auth/authclient"
"github.com/gravitational/teleport/lib/cryptosuites"
"github.com/gravitational/teleport/lib/sshutils"
"github.com/gravitational/teleport/lib/utils"
"github.com/gravitational/teleport/lib/utils/log/logtest"
)
// TestAgentCertChecker validates that reverse tunnel agents properly validate
// SSH host certificates.
func TestAgentCertChecker(t *testing.T) {
handler := sshutils.NewChanHandlerFunc(func(_ context.Context, ccx *sshutils.ConnectionContext, nch ssh.NewChannel) {
ch, _, err := nch.Accept()
require.NoError(t, err)
require.NoError(t, ch.Close())
})
ca, err := apisshutils.MakeTestSSHCA()
require.NoError(t, err)
tests := []struct {
name string
signerFunc func(ssh.Signer) (ssh.Signer, error)
requireErr require.ErrorAssertionFunc
}{
{
"Ensure valid host certificate is accepted.",
apisshutils.MakeRealHostCert,
require.NoError,
},
{
"Ensure invalid host certificate is rejected.",
apisshutils.MakeSpoofedHostCert,
require.Error,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
cert, err := tc.signerFunc(ca)
require.NoError(t, err)
sshServer, err := sshutils.NewServer(
"test",
utils.NetAddr{AddrNetwork: "tcp", Addr: "localhost:0"},
handler,
sshutils.StaticHostSigners(cert),
sshutils.AuthMethods{NoClient: true},
sshutils.SetInsecureSkipHostValidation(),
)
require.NoError(t, err)
t.Cleanup(func() { require.NoError(t, sshServer.Close()) })
require.NoError(t, sshServer.Start())
priv, err := cryptosuites.GenerateKeyWithAlgorithm(cryptosuites.Ed25519)
require.NoError(t, err)
signer, err := ssh.NewSignerFromKey(priv)
require.NoError(t, err)
dialer := agentDialer{
client: &fakeClient{caKey: ca.PublicKey()},
authMethods: []ssh.AuthMethod{ssh.PublicKeys(signer)},
logger: logtest.NewLogger(),
}
_, err = dialer.DialContext(context.Background(), *utils.MustParseAddr(sshServer.Addr()))
tc.requireErr(t, err)
})
}
}
type fakeClient struct {
authclient.AccessCache
caKey ssh.PublicKey
}
func (fc *fakeClient) GetCertAuthorities(ctx context.Context, caType types.CertAuthType, loadKeys bool) ([]types.CertAuthority, error) {
ca, err := types.NewCertAuthority(types.CertAuthoritySpecV2{
Type: types.HostCA,
ClusterName: "example.com",
ActiveKeys: types.CAKeySet{
SSH: []*types.SSHKeyPair{
{
PublicKey: ssh.MarshalAuthorizedKey(fc.caKey),
},
},
},
})
if err != nil {
return nil, trace.Wrap(err)
}
return []types.CertAuthority{ca}, nil
}
func (fc *fakeClient) GetClusterNetworkingConfig(ctx context.Context) (types.ClusterNetworkingConfig, error) {
return types.NewClusterNetworkingConfigFromConfigFile(types.ClusterNetworkingConfigSpecV2{})
}