When a node doesn't have an active tunnel, the error should say so
clearly. This is reflected in 2 places:
- proxy error log
- tsh user output
Also, use trace.UserMessage instead of utils.UserMessageFromError.
utils.UserMessageFromError will return a full stack trace when calling
process (proxy) is in debug mode. The user shouldn't see this.
Also, rename advertiseIP to advertiseAddr to better represent what it
contains. It can have a custom port, not just IP.
Refactoring the rest of the codebase to use "advertiseAddr" instead of
"advertiseIP" (and *utils.NetAddr instead of string) is too noisy and
low value for this commit.
Caught by `ineffassign` linter.
Note the change in lib/srv/regular/sshserver.go - looks like we
advertised the custom listening port (`aport`), if it differed from
regular listening port (`port`).
Proxy advertises its preferred web/ssh/kube addresses via the `Ping`
endpoint. `tsh` hits this endpoint on login and caches addresses on disk
(in profile, along with credentials).
For all subsequent commands, `tsh` loads the cached information from
disk.
When using an identity file, `tsh` skips loading the profile (and it can
be missing entirely). In this case, we need to `Ping` the proxy
explicitly to fetch the correct public addresses for a proxy.
Fixes#3513
Without setting `ClientAddr` in `TeleportClient`, the proxy will log
itself (`localhost`, the web service) as the remote address of SCP
client.
Plumb the remote address of the original HTTP request to log the actual
user IP (the machine running browser with web interface open).
Fixes#2958
This serves two purposes:
1. on upload, the receiver (node) will exit with error and generate an
SCP error audit event.
2. on download, the receiver (tsh) will print a meaningful message from
the sender (node)
Fixes#2861
This code is not caught by linters because it's exported and they assume
there's some external users.
Since teleport is relatively self-contained, we can tell for sure
whether something is called or not.
There seem to be some test stubs in `lib/auth` that can generate TLS
key/cert but without supporting k8s users/groups.
Rewrite cert generation in `kube_integration_test.go` to use the same
logic as `auth.Server.ProcessKubeCSR`.
Auth server has to trust the proxy with all k8s CSR fields. Usage is the
only field it can enforce, to somewhat limit the blast radius of
compromising this cert flow.
When a proxy forwards a k8s request to another proxy in a trusted leaf
cluster, it dynamically generates a new client key/cert to impersonate
the user. This key/cert is presented to the leaf proxy as if a user was
directly making a request to it.
Auth server, when processing the CSR, would load user identity from the
backend. If this user had temporary role grants via workflow API, they
would not be loaded from the backend.
This means that if a user accesses k8s through:
```
kubectl -> root proxy -> leaf proxy -> k8s
```
the second hop would drop their temporary role grants.
To fix this, preserve full user identity from the original client cert
presented to root proxy, as encoded in CSR Subject. The auth server
implicitly trusts the CSR Subject that the proxy presents.
This also requires fixing the Subject encoding on the proxy side, which
was inconsistent with how auth server does it.
One downside here is: a compromised proxy can mint k8s client certs for
known users with arbitrary roles.
* Add UpdateUser rpc to proto
* Differentiate between create and update in github,oidc,saml
* Edit updated_by event field to be more generic (used with contexts to capture user modifying records)
* Update security issue by removing secrets from user when update/upsert/create (forrest)
* Update createUser in resource_command and require force for updates
The existing kubeCreds already has tls.Config.
Add a new wrapTransport method to it, which handles added bearer tokens
or basic auth to the request before it goes out.
Use this wrapTransport to inject tokens for both SPDY connections and
catch-all forwarder requests.
Also simplify a few unrelated parts:
- don't manually call serverName verification in SPDY dialer
- have requestCertificate return a finished tls.Config instead of an
intermediate type
By importing the magic `k8s.io/client-go/plugin/pkg/client/auth`
package, we compile-in support for auth plugins: gcp, azure, oidc,
openstack.
Without this, users can't provide a kubeconfig using those authn
methods to a proxy.
With gocheck, tests only run if you call `check.TestingT(t)` from a
dummy `func Test(t *testing.T)`.
Added the missing dummy function call in: `lib/services/suite`,
`lib/shell`. The `lib/shell` tests also turned out to be broken.
If you call the dummy wrapper twice, all tests will run twice.
This was happening in `lib/events/s3sessions` and `lib/services/local`.
There are two new ways you can generate a kubeconfig:
- `tctl auth sign --user=foo --format=kubernetes --out=kubeconfig` for
admins
- `tsh login --format=kubernetes -o kubeconfig` for users
This allows admins to generate long-lived kubeconfigs for e.g. CI
systems.
A tricky part is getting the kubernetes endpoint for a proxy in `tctl`.
It does its best to guess the address, but falls back to asking user to
pass `--proxy` flag.
It looks like right now, the proxy info available via the auth server's
API doesn't have kubernetes public_addr for proxies.
Fixes#2825
When building binaries locally, they get linked against a local version
of libc. This makes the resulting binary change based on which machine
it was built on.
By always building in docker, we use the libc version from the build
container, so at least it's predictable.
Ensure main Makefile dependencies are correctly spelled-out so that
`make image` doesn't use stale local binaries. Binaries should always
get rebuilt, with docker.
Fixed findings:
```
lib/auth/clt.go:294:12: SA1019: grpc.WithDialer is deprecated: use WithContextDialer instead. Will be supported throughout 1.x. (staticcheck)
dialer := grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {ion error: desc = "transport: Erro
^
lib/auth/clt.go:1462:5: SA1019: grpc.Code is deprecated: use status.Code instead. (staticcheck)site-A Type:proxy Addr:{Addr:local
if grpc.Code(err) != codes.Unimplemented {
^
lib/auth/clt.go:1500:5: SA1019: grpc.Code is deprecated: use status.Code instead. (staticcheck)rsetunnel/agentpool.go:312
if grpc.Code(err) != codes.Unimplemented {
^
lib/auth/saml.go:294:33: SA5011: possible nil pointer dereference (staticcheck)
events.EventUser: re.auth.Username,
^
lib/auth/auth_test.go:119:2: SA4006: this value of `ws` is never used (staticcheck)ats. stats:map[connected:1 connect
ws, err := s.a.AuthenticateWebUser(AuthenticateUserRequest{
^
lib/auth/auth_test.go:160:2: SA4006: this value of `ws` is never used (staticcheck)ver.go:425
ws, err := s.a.AuthenticateWebUser(AuthenticateUserRequest{
^
lib/auth/auth_test.go:243:2: SA4006: this value of `roles` is never used (staticcheck)es that discovery protocol recover
roles, err = s.a.ValidateToken(tok)
^
lib/auth/password_test.go:228:2: SA4006: this value of `err` is never used (staticcheck)necting -> connected. leaseID:5 ta
token, err := s.a.CreateResetPasswordToken(context.TODO(), CreateResetPasswordTokenRequest{7.0.0.1:46150. reversetunnel/srv.g
^
lib/auth/tls_test.go:109:2: SA4006: this value of `err` is never used (staticcheck)ry(c *check.C) {
err = s.server.AuthServer.Trust(remoteServer, nil)
^
lib/auth/tls_test.go:195:2: SA4006: this value of `err` is never used (staticcheck)meout=10000&_sync=OFF, poll stream
err = s.server.AuthServer.Trust(remoteServer, nil)
^
lib/auth/tls_test.go:360:2: SA4006: this value of `newProxy` is never used (staticcheck) be received and the connection ad
newProxy, err := s.server.NewClient(TestBuiltin(teleport.RoleProxy))o/src/github.com/gravitational/tel
^
lib/auth/tls_test.go:388:2: SA4006: this value of `err` is never used (staticcheck)o/src/github.com/gravitational/tel
err = s.server.Auth().autoRotateCertAuthorities()
^
lib/auth/tls_test.go:1074:2: SA4006: this value of `err` is never used (staticcheck)uest, we will recover session id a
err = os.MkdirAll(filepath.Join(uploadDir, "upload", "sessions", defaults.Namespace), 0755)reversetunnel/agent.go:458
^
lib/auth/tls_test.go:1263:2: SA4006: this value of `err` is never used (staticcheck)quests channel. leaseID:5 target:l
err = clt.UpsertPassword(user, pass)
^
lib/auth/tls_test.go:1691:2: SA4006: this value of `err` is never used (staticcheck)
userCerts, err = adminClient.GenerateUserCerts(context.TODO(), proto.UserCertsRequest{et:localhost:20088 reversetunnel/t
^
lib/auth/auth_with_roles.go:860:32: SA1029: should not use built-in type string as key for value; define your own type to avoid collisions (staticcheck)
return context.WithValue(ctx, events.AccessRequestUpdateBy, user)ts is received, if it's been longe
^
lib/auth/auth_with_roles.go:876:32: SA1029: should not use built-in type string as key for value; define your own type to avoid collisions (staticcheck)
return context.WithValue(ctx, events.AccessRequestDelegator, delegator)ime = f.process.Clock.Now()
^
lib/auth/middleware.go:316:69: SA1029: should not use built-in type string as key for value; define your own type to avoid collisions (staticcheck)
requestWithContext := r.WithContext(context.WithValue(baseContext, ContextUser, user))rocess.Infof("Teleport has recover
^ion to @remote-auth-server [] in r
lib/auth/apiserver.go:285:42: SA1029: should not use built-in type string as key for value; define your own type to avoid collisions (staticcheck)
ctx := context.WithValue(r.Context(), contextParams, p)et:localhost:20088 reversetunnel/t
^
```
Original finding list:
```
tool/tctl/common/node_command.go:163:3: SA1006: printf-style function with dynamic format string and no further arguments should use print-style function instead (staticcheck)
fmt.Printf(string(out))
^
tool/tctl/common/status_command.go:110:2: SA1006: printf-style function with dynamic format string and no further arguments should use print-style function instead (staticcheck)
fmt.Printf(view())
^
tool/tctl/common/status_command.go:126:3: SA1006: printf-style function with dynamic format string and no further arguments should use print-style function instead (staticcheck)
fmt.Printf(view())
^
tool/tctl/common/token_command.go:201:3: SA1006: printf-style function with dynamic format string and no further arguments should use print-style function instead (staticcheck)
fmt.Printf(tokensView())
^
tool/tctl/common/token_command.go:207:3: SA1006: printf-style function with dynamic format string and no further arguments should use print-style function instead (staticcheck)
fmt.Printf(string(data))
^
tool/tctl/common/user_command.go:248:2: SA1006: printf-style function with dynamic format string and no further arguments should use print-style function instead (staticcheck)
fmt.Printf(string(out))
^
tool/tctl/common/user_command.go:294:3: SA1006: printf-style function with dynamic format string and no further arguments should use print-style function instead (staticcheck)
fmt.Printf(string(out))
^
integration/helpers.go:200:2: SA4006: this value of `err` is never used (staticcheck)
cryptoPubKey, err := sshutils.CryptoPublicKey(cfg.Pub)
^
integration/helpers.go:399:3: SA4006: this value of `roles` is never used (staticcheck)
roles = append(roles, role)
^
integration/helpers.go:597:4: SA4006: this value of `roles` is never used (staticcheck)
roles = append(roles, role)
^
integration/helpers.go:599:4: SA4006: this value of `roles` is never used (staticcheck)
roles = user.Roles
^
integration/integration_test.go:1625:2: SA4006: this value of `err` is never used (staticcheck)
adminsRole, err := services.NewRole(mainAdmins, services.RoleSpecV3{
^
integration/integration_test.go:2185:2: SA4006: this value of `output` is never used (staticcheck)
output, err = runCommand(main, []string{"echo", "hello world"}, cfg, 1)
^
integration/integration_test.go:2340:2: SA4006: this value of `output` is never used (staticcheck)
output, err = runCommand(main, []string{"echo", "hello world"}, cfgProxy, 1)
^
integration/kube_integration_test.go:154:2: SA4006: this value of `err` is never used (staticcheck)
role, err := services.NewRole("kubemaster", services.RoleSpecV3{
^
integration/kube_integration_test.go:321:2: SA4006: this value of `err` is never used (staticcheck)
role, err := services.NewRole("kubemaster", services.RoleSpecV3{
^
integration/kube_integration_test.go:366:2: SA4006: this value of `err` is never used (staticcheck)
role, err := services.NewRole("kubemaster", services.RoleSpecV3{
^
integration/kube_integration_test.go:386:2: SA4006: this value of `err` is never used (staticcheck)
pods, err := s.CoreV1().Pods(kubeSystemNamespace).List(metav1.ListOptions{
^
integration/kube_integration_test.go:465:2: SA4006: this value of `err` is never used (staticcheck)
mainRole, err := services.NewRole("main-kube", services.RoleSpecV3{
^
integration/kube_integration_test.go:579:2: SA4006: this value of `err` is never used (staticcheck)
pods, err := proxyClient.CoreV1().Pods(kubeSystemNamespace).List(metav1.ListOptions{
^
integration/kube_integration_test.go:727:2: SA4006: this value of `err` is never used (staticcheck)
mainRole, err := services.NewRole("main-kube", services.RoleSpecV3{
^
integration/kube_integration_test.go:840:2: SA4006: this value of `err` is never used (staticcheck)
pods, err := proxyClient.CoreV1().Pods(kubeSystemNamespace).List(metav1.ListOptions{
^
integration/kube_integration_test.go:1008:2: SA4006: this value of `err` is never used (staticcheck)
role, err := services.NewRole("kubemaster", services.RoleSpecV3{
^
tool/teleport/common/teleport_test.go:83:2: SA4006: this value of `cmd` is never used (staticcheck)
cmd, conf := Run(Options{
^
tool/teleport/common/teleport_test.go:91:2: SA4006: this value of `cmd` is never used (staticcheck)
cmd, conf = Run(Options{
^
tool/tsh/tsh.go:170:2: SA4006: this value of `cmdLine` is never used (staticcheck)
cmdLine := []string{}
^
integration/helpers.go:399:11: SA4010: this result of append is never used, except maybe in other appends (staticcheck)
roles = append(roles, role)
^
integration/helpers.go:597:12: SA4010: this result of append is never used, except maybe in other appends (staticcheck)
roles = append(roles, role)
^
integration/integration_test.go:1092:7: SA4000: identical expressions on the left and right side of the '&&' operator (staticcheck)
for len(b.Tunnel.GetSites()) < 2 && len(b.Tunnel.GetSites()) < 2 {
^
integration/integration_test.go:1426:6: SA4000: identical expressions on the left and right side of the '&&' operator (staticcheck)
for len(main.Tunnel.GetSites()) < 2 && len(main.Tunnel.GetSites()) < 2 {
^
integration/integration_test.go:1691:6: SA4000: identical expressions on the left and right side of the '&&' operator (staticcheck)
for len(main.Tunnel.GetSites()) < 2 && len(main.Tunnel.GetSites()) < 2 {
^
integration/integration_test.go:1895:6: SA4000: identical expressions on the left and right side of the '&&' operator (staticcheck)
for len(main.Tunnel.GetSites()) < 2 && len(main.Tunnel.GetSites()) < 2 {
^
integration/kube_integration_test.go:548:6: SA4000: identical expressions on the left and right side of the '&&' operator (staticcheck)
for len(main.Tunnel.GetSites()) < 2 && len(main.Tunnel.GetSites()) < 2 {
^
integration/kube_integration_test.go:814:6: SA4000: identical expressions on the left and right side of the '&&' operator (staticcheck)
for len(main.Tunnel.GetSites()) < 2 && len(main.Tunnel.GetSites()) < 2 {
^
```