Fix an issue kube local proxy requirement is wrong in separate port mode (#27634)

* Fix an issue kube local proxy requirement is wrong in separate port mode

* move kube local proxy requirement check to api/profile
This commit is contained in:
STeve (Xin) Huang 2023-06-12 09:49:09 -04:00 committed by GitHub
parent cb493019bb
commit 66f5b5510c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 79 additions and 21 deletions

View file

@ -142,6 +142,12 @@ func (p *Profile) TLSConfig() (*tls.Config, error) {
}, nil
}
// RequireKubeLocalProxy returns true if this profile indicates a local proxy
// is required for kube access.
func (p *Profile) RequireKubeLocalProxy() bool {
return p.KubeProxyAddr == p.WebProxyAddr && p.TLSRoutingConnUpgradeRequired
}
func certPoolFromProfile(p *Profile) (*x509.CertPool, error) {
// Check if CAS dir exist if not try to load certs from legacy certs.pem file.
if _, err := os.Stat(p.TLSClusterCASDir()); err != nil {

View file

@ -115,3 +115,58 @@ func TestProfilePath(t *testing.T) {
require.Equal(t, "/foo/bar", profile.FullProfilePath("/foo/bar"))
require.Equal(t, filepath.Join(dir, ".tsh"), profile.FullProfilePath(""))
}
func TestRequireKubeLocalProxy(t *testing.T) {
t.Parallel()
tests := []struct {
name string
inputProfile *profile.Profile
checkResult require.BoolAssertionFunc
}{
{
name: "kube not enabled",
inputProfile: &profile.Profile{
WebProxyAddr: "example.com:443",
TLSRoutingEnabled: true,
TLSRoutingConnUpgradeRequired: true,
},
checkResult: require.False,
},
{
name: "ALPN connection upgrade not required",
inputProfile: &profile.Profile{
WebProxyAddr: "example.com:443",
KubeProxyAddr: "example.com:443",
TLSRoutingEnabled: true,
},
checkResult: require.False,
},
{
name: "kube uses separate listener",
inputProfile: &profile.Profile{
WebProxyAddr: "example.com:443",
KubeProxyAddr: "example.com:3026",
TLSRoutingEnabled: false,
TLSRoutingConnUpgradeRequired: true,
},
checkResult: require.False,
},
{
name: "local proxy required",
inputProfile: &profile.Profile{
WebProxyAddr: "example.com:443",
KubeProxyAddr: "example.com:443",
TLSRoutingEnabled: true,
TLSRoutingConnUpgradeRequired: true,
},
checkResult: require.True,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
test.checkResult(t, test.inputProfile.RequireKubeLocalProxy())
})
}
}

View file

@ -674,7 +674,15 @@ func (c *Config) SaveProfile(makeCurrent bool) error {
return nil
}
p := &profile.Profile{
if err := c.ClientStore.SaveProfile(c.Profile(), makeCurrent); err != nil {
return trace.Wrap(err)
}
return nil
}
// Profile converts Config to *profile.Profile.
func (c *Config) Profile() *profile.Profile {
return &profile.Profile{
Username: c.Username,
WebProxyAddr: c.WebProxyAddr,
SSHProxyAddr: c.SSHProxyAddr,
@ -690,11 +698,6 @@ func (c *Config) SaveProfile(makeCurrent bool) error {
LoadAllCAs: c.LoadAllCAs,
PrivateKeyPolicy: c.PrivateKeyPolicy,
}
if err := c.ClientStore.SaveProfile(p, makeCurrent); err != nil {
return trace.Wrap(err)
}
return nil
}
// ParsedProxyHost holds the hostname and Web & SSH proxy addresses

View file

@ -648,7 +648,7 @@ func (c *kubeCredentialsCommand) run(cf *CLIConf) error {
return trace.Wrap(c.issueCert(cf))
}
if err := c.checkLocalProxyRequirement(profile.TLSRoutingConnUpgradeRequired); err != nil {
if err := c.checkLocalProxyRequirement(profile); err != nil {
return trace.Wrap(err)
}
@ -684,7 +684,7 @@ func (c *kubeCredentialsCommand) issueCert(cf *CLIConf) error {
if err != nil {
return trace.Wrap(err)
}
if err := c.checkLocalProxyRequirement(tc.TLSRoutingConnUpgradeRequired); err != nil {
if err := c.checkLocalProxyRequirement(tc.Profile()); err != nil {
return trace.Wrap(err)
}
@ -729,7 +729,7 @@ func (c *kubeCredentialsCommand) issueCert(cf *CLIConf) error {
err = client.RetryWithRelogin(ctx, tc, func() error {
// The requirement may change after a new login so check again just in
// case.
if err := c.checkLocalProxyRequirement(tc.TLSRoutingConnUpgradeRequired); err != nil {
if err := c.checkLocalProxyRequirement(tc.Profile()); err != nil {
return trace.Wrap(err)
}
@ -773,8 +773,8 @@ func isNetworkError(err error) bool {
return errors.As(err, &opErr) || trace.IsConnectionProblem(err)
}
func (c *kubeCredentialsCommand) checkLocalProxyRequirement(connUpgradeRequired bool) error {
if connUpgradeRequired {
func (c *kubeCredentialsCommand) checkLocalProxyRequirement(profile *profile.Profile) error {
if profile.RequireKubeLocalProxy() {
return trace.BadParameter("Cannot connect Kubernetes clients to Teleport Proxy directly. Please use `tsh proxy kube` or `tsh kubectl` instead.")
}
return nil
@ -1183,7 +1183,7 @@ func (c *kubeLoginCommand) run(cf *CLIConf) error {
}
func (c *kubeLoginCommand) printUserMessage(cf *CLIConf, tc *client.TeleportClient) {
if c.localProxyRequired(tc) {
if tc.Profile().RequireKubeLocalProxy() {
c.printLocalProxyUserMessage(cf)
return
}
@ -1213,10 +1213,6 @@ Use the kubeconfig provided by the local proxy, select a context, and try 'kubec
}
}
func (c *kubeLoginCommand) localProxyRequired(tc *client.TeleportClient) bool {
return tc.TLSRoutingConnUpgradeRequired
}
func fetchKubeClusters(ctx context.Context, tc *client.TeleportClient) (teleportCluster string, kubeClusters []types.KubeCluster, err error) {
err = client.RetryWithRelogin(ctx, tc, func() error {
pc, err := tc.ConnectToProxy(ctx)

View file

@ -453,11 +453,11 @@ func makeAndStartKubeLocalProxy(cf *CLIConf, config *clientcmdapi.Config, cluste
}
// shouldUseKubeLocalProxy checks if a local proxy is required for kube
// access.
// access for `tsh kubectl` or `tsh kube exec`.
//
// The local proxy is required when all of these conditions are met:
// - profile is loadable
// - kube access is enabled
// - kube access is enabled, and is accessed through web proxy address
// - ALPN connection upgrade is required (e.g. Proxy behind ALB)
// - not `kubectl config` commands
// - original/default kubeconfig is loadable
@ -470,9 +470,7 @@ func shouldUseKubeLocalProxy(cf *CLIConf, kubectlArgs []string) (*clientcmdapi.C
return nil, nil, false
}
// Only use local proxy when Kube is enabled and ALPN connection upgrade is
// required.
if !profile.TLSRoutingConnUpgradeRequired || profile.KubeProxyAddr == "" {
if !profile.RequireKubeLocalProxy() {
return nil, nil, false
}