Files
teleport/lib/utils/proxyconn.go
T
ef8da1724e Security fixes 03/23 (#23864)
* Prevent tunneling if the os login doesn't exist

A user.Lookup was added to srv.RunForward to prevent dialing
and forwarding any data if the os login is not found. The check
alone only terminates the direct-tcpip ssh channel and not the
underlying ssh connection.

In order for the parent process to determine if the ssh connection
should be terminated it needs to know why the child exited. That was
not possible by looking at the exit code and any data written to
standard error of the child process was forwarded to standard error
on the parent; which was used to simply log the error and move on.
To pass more detailed errors to the parent, the child process spawned
by srv.RunForward now json marshals the trace.Error to standard
error which is then decoded by the parent process. If the parent
detects the error was due to a missing user it terminates the ssh
connection.

tsh ssh -N was also modified to terminate if the command context
of tsh OR the ssh connection to the node is closes. Prior, it
only terminated if the user cancelled the process by blocking on
ctx.Done(). While this was necessary to end session if the os
login does not exit, it also forces tsh to exit if the node
goes offline.

Note: This does not include any propagation of error messages to the user,
so there won't be any indication from tsh about why the connection was closed.
The session also will not be terminated until the first attempt to forward data and
NOT when the session is created due to the way -N is implemented.

Fixes #217

* Prevent unauthorized access to kube clusters by upserting kube_servers

This PR changes the behavior of the kubernetes_service when validating access
to kubernetes clusters. Previously, the kubernetes_service would use the first
kubernetes cluster it found in the Auth server backend to validate access. This was
problematic because if the first kubernetes cluster was upserted with a
the same name as a kubernetes cluster the user was trying to access but
with different labels, the user would be able to access the cluster even
though they shouldn't be able to.

This PR changes the behavior of the kubernetes_service to use the
in memory kubernetes cluster representation used for heartbeats
instead of relying on the information received from the auth server. This would
block the user from accessing the cluster if the cluster was upserted
with a different set of labels since the kubernetes_service would not
have the updated labels in memory and would deny access.

Fixes #469

---------

Co-authored-by: Tim Ross <tim.ross@goteleport.com>
Co-authored-by: Tiago Silva <tiago.silva@goteleport.com>
2023-03-31 21:55:13 +00:00

95 lines
2.4 KiB
Go

/*
Copyright 2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package utils
import (
"context"
"io"
"github.com/gravitational/trace"
)
// CombinedReadWriteCloser wraps an [io.ReadCloser] and an [io.WriteCloser] to
// implement [io.ReadWriteCloser]. Reads are performed on the [io.ReadCloser] and
// writes are performed on the [io.WriteCloser]. Closing will return the
// aggregated errors of both.
type CombinedReadWriteCloser struct {
r io.ReadCloser
w io.WriteCloser
}
func (o CombinedReadWriteCloser) Read(p []byte) (int, error) {
return o.r.Read(p)
}
func (o CombinedReadWriteCloser) Write(p []byte) (int, error) {
return o.w.Write(p)
}
func (o CombinedReadWriteCloser) Close() error {
return trace.NewAggregate(o.r.Close(), o.w.Close())
}
// CombineReadWriteCloser creates a CombinedReadWriteCloser from the provided
// [io.ReadCloser] and [io.WriteCloser] that implements [io.ReadWriteCloser]
func CombineReadWriteCloser(r io.ReadCloser, w io.WriteCloser) CombinedReadWriteCloser {
return CombinedReadWriteCloser{
r: r,
w: w,
}
}
// ProxyConn launches a double-copy loop that proxies traffic between the
// provided client and server connections.
//
// Exits when one or both copies stop, or when the context is canceled, and
// closes both connections.
func ProxyConn(ctx context.Context, client, server io.ReadWriteCloser) error {
errCh := make(chan error, 2)
defer server.Close()
defer client.Close()
go func() {
defer server.Close()
defer client.Close()
_, err := io.Copy(server, client)
errCh <- err
}()
go func() {
defer server.Close()
defer client.Close()
_, err := io.Copy(client, server)
errCh <- err
}()
var errors []error
for i := 0; i < 2; i++ {
select {
case err := <-errCh:
if err != nil && !IsOKNetworkError(err) {
errors = append(errors, err)
}
case <-ctx.Done():
return ctx.Err()
}
}
return trace.NewAggregate(errors...)
}