Commit Graph
41 Commits
Author SHA1 Message Date
rosstimothy a8568adb82 Make the NodeWatcher more robust (#22877)
Prior to the NodeWatcher being successfully initialized, or when
it became stale any calls to `GetNodes` would return no data or
stale data. This behavior results in the problems described in
#22672.

The NodeWatcher will now fallback to pulling data from the cache
in the event that it has no data or stale data when callers attempt
to retrieve nodes. This should reduce the time that it takes the
a new Proxy or a Proxy with intermittent connectivity issues to
Auth be able to route to nodes.

The impact of this change should be noticeable in tests that
create a Proxy and several Nodes and then immediately try to
open a session on the Nodes.

Closes #22672
2023-03-10 18:34:17 +00:00
Forrest aaee695927 node hb and watcher scalability improvements (#21490)
* node hb and watcher scalability improvements

* ensure that node has ample time to hb

* fix degraded state

* hbv2 test cov
2023-03-03 17:39:00 +00:00
Alan Parra 8c84d0a766 Add device lock support (#21667)
* Add Device to LocketTarget proto

* Refactor LockTarget.Match

* Test lib/srv.ComputeLockTargets

* Test lib/services.LockTargetsFromTLSIdentity

* Test device lock during cert issuance

* Add device lock targets where applicable

* Add --device to `tctl lock`

* Fix godocs (unrelated)

* Review: Drop redundant comments
2023-02-13 14:46:11 +00:00
Jakub Nyckowski 7b3f01470e Initialize fanout before creating watcher (#19800) 2023-01-04 02:27:39 +00:00
Michael Wilson 6fa75978e4 Add an access request watcher. (#19626)
An accesss request watcher has been added to support access requests that
will require downstream reconciliation based on access request approval. This
will be useful for requests that trigger external APIs in other Teleport
services once they've been approved. This will be useful for the upcoming
Okta integration work.
2023-01-03 14:23:54 +00:00
rosstimothy f49c99a315 Deflake TestProxyWatcher (#18312)
Changes the ProxyWatcher to only emit an empty proxy list if the
watcher has already been initialized. This prevents an empty
set of proxies from being emitted after the creation of the watcher,
but allows an empty list to be emitted if the proxies become zero
during the life of the watcher.

Closes #18311
2022-11-10 21:51:50 +00:00
rosstimothy 514bfc7ac6 Ensure invalid tunnel agent connections get closed (#17899)
* Ensure invalid tunnel agent connections get closed

Connections from reverse tunnel agents were being marked
as invalid by the proxy under certain conditions but would
ultimately never be closed. This could lead to scenarios where
the agent thought things were fine but the proxy considered
that agent unhealthy and unroutable.

Pruning of invalid connections used to occur when a proxy
tried to retrieve a connection for that tunnel. This also
further muddied the point in time at which the proxy could
close a connection as it never explicitly stopped tracking
the connection and closed it at the same time.

To remedy this, connections are explicitly closed by the proxy
and removed from the mapping to stop tracking immediately. In order
to prevent a connection that is servicing an active connection
from being closed the proxy now tracks which connections have
sessions. Closing does not occur when there are any active
sessions to prevent them from being force terminated.

When the proxy receives a heartbeat from an agent it now restores
the connection to a valid state. In the event that too many heart
beats have been missed for an agent, the proxy will now terminate
the connection, again only if it is not serving any sessions.

Fixes #15911
2022-11-04 18:05:13 +00:00
Jakub Nyckowski 0ee91f6c37 Enable GCI linter (#17894) 2022-10-28 20:20:28 +00:00
Tiago Silva 249a4c5595 Adds Azure AKS auto-discovery (#16633)
This PR presents a watcher for automatic  `kube_cluster` discovery for Azure AKS clusters. Given a user with access to the Azure cloud, the auto-discovery service will scan the cloud and register all clusters available in AKS .

Once the discovery service creates a `kube_cluster` in Auth Server, the Kubernetes Service will start serving it. The credentials used to access the cluster depend on the different AKS clusters configurations:

# Authentication 
## Local Accounts

If the AKS cluster auth is based on local accounts created during the provisioning phase of the cluster, the agent will use the [`aks:ListClusterUserCredentials`](https://learn.microsoft.com/en-us/rest/api/aks/managed-clusters/list-cluster-user-credentials?tabs=HTTP) endpoint. 

This endpoint returns a `kubeconfig` fully populated with user credentials that Teleport can use to access the cluster.

## AZ Active Directory

When AZ active directory integration is enabled, Azure allows login with AD users. Azure forces the login to happen with dynamic short-lived user tokens. These tokens are generated by calling `credentials.GetToken` with a fixed Scope: `6dae42f8-4368-4678-94ff-3960e28e3630` and with the cluster's `tenant_id`. The token contains the user details as well as `group_ids` to match with authorization rules.

```go
// getAzureToken generates an authentication token for clusters with AD enabled.
func (a *aKSClient) getAzureToken(ctx context.Context, tentantID string, clientCfg *rest.Config) (time.Time, error) {
	const (
		azureManagedClusterScope = "6dae42f8-4368-4678-94ff-3960e28e3630"
	)
	cred, err := a.azIdentity(&azidentity.DefaultAzureCredentialOptions{
		TenantID: tentantID,
	})
	if err != nil {
		return time.Time{}, trace.Wrap(ConvertResponseError(err))
	}

	cliAccessToken, err := cred.GetToken(ctx, policy.TokenRequestOptions{
		// azureManagedClusterScope is a fixed scope that identifies azure AKS managed clusters.
		Scopes: []string{azureManagedClusterScope},
	},
	)
	if err != nil {
		return time.Time{}, trace.Wrap(ConvertResponseError(err))
	}
	// reset the old exec provider credentials
	clientCfg.ExecProvider = nil
	clientCfg.BearerToken = cliAccessToken.Token

	return cliAccessToken.ExpiresOn, nil
}
```

# Authorization

## Local Accounts
The [`aks:ListClusterUserCredentials`](https://learn.microsoft.com/en-us/rest/api/aks/managed-clusters/list-cluster-user-credentials?tabs=HTTP) endpoint returns credentials with enough permissions for Teleport to enroll the cluster.

## AZ AD 

### Azure RBAC

When Azure RBAC mode is enabled, the cluster authorization is based on rules specified in the Azure Identity permissions. 

The AZ group associated with the AZ identity the Teleport Process is running has to define the following permissions:

```json
{
    "Name": "AKS Teleport Discovery Permissions",
    "Description": "Required permissions for Teleport auto-discovery.",
    "Actions": [],
    "NotActions": [],
    "DataActions": [
      "Microsoft.ContainerService/managedClusters/pods/read",
      "Microsoft.ContainerService/managedClusters/users/impersonate/action",
      "Microsoft.ContainerService/managedClusters/groups/impersonate/action",
      "Microsoft.ContainerService/managedClusters/serviceaccounts/impersonate/action",
      "Microsoft.ContainerService/managedClusters/authorization.k8s.io/selfsubjectaccessreviews/write",
      "Microsoft.ContainerService/managedClusters/authorization.k8s.io/selfsubjectrulesreviews/write",
    ],
    "NotDataActions": [],
    "assignableScopes": [
        "/subscriptions/{subscription_id}"
    ]
}
```

If correctly specified, the Azure authentication service automatically grants access to any cluster within  `subscription_id` 
 without any other definition. On the other hand, if it's incorrectly configured, an error is triggered but Teleport cannot gain access to the cluster.


### Kubernetes RBAC

If AZ RBAC integration is disabled, the authorization to the cluster is processed by Kubernetes RBAC. This is done by matching the Az Identity principals (`group_ids`) with `Role`, `ClusterRole` objects that live in the AKS cluster.  This mode requires that the `ClusterRole` and `ClusterRoleBinding` must exist and must be well configured for each cluster to enroll.

```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: teleport-role
rules:
- apiGroups:
  - ""
  resources:
  - users
  - groups
  - serviceaccounts
  verbs:
  - impersonate
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
- apiGroups:
  - "authorization.k8s.io"
  resources:
  - selfsubjectaccessreviews
  - selfsubjectrulesreviews
  verbs:
  - create
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: teleport-role-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: teleport-role
subjects:
- kind: Group
  name: {group_name}
  apiGroup: rbac.authorization.k8s.io
```

#### `ClusterRole` and `ClusterRoleBinding` configured

If cluster operators or previous Teleport run has configured access to the cluster, no further action is required since Teleport already has access to the cluster.

#### Cluster `aks:ListClusterAdminCredentials` returns valid credentials

If the Teleport process has access to [`aks:ListClusterAdminCredentials`](https://learn.microsoft.com/en-us/rest/api/aks/managed-clusters/list-cluster-admin-credentials?tabs=HTTP) and the endpoint returns valid cluster admin credentials, Teleport will automatically create the  `ClusterRole` and `ClusterRoleBinding` objects in the cluster configured to the `group_id` that is listed in the access token. In order to extract the `group_id` from the token, Teleport parses the JWT claims and extracts the first element.

If the object creation was successful, Teleport can access it, otherwise, it will use the `aks:BeginRunCommand` method to try to configure access to itself.

#### Cluster `aks:BeginRunCommand` returns valid credentials

When we reach this mode, Teleport tries to run a `kubectl` command against the cluster to configure the `ClusterRole` and `ClusterRoleBinding`. `aks:BeginRunCommand` allows any user with access to that endpoint to run arbitrary commands in the cluster (commands cannot be validated). Teleport will use it as the last resource to configure the access to itself.

If the command failed, Teleport cannot grant access to the cluster and an error is returned.

# UX

Currently, to discover AKS  resources created and to have them dynamically served by the `kubernetes_service`one can define the following configuration.

```yaml
discovery_service:
   enabled: true
  azure:
  - subscriptions: ["*"]
    types: ["aks"]
    regions: ["*"]
    tags:
      '*': '*'

kubernetes_service:
   enabled: true

   resources:
       labels:
           '*': '*'
```

# Future work
- Support AWS dynamic authentication

Part of #16135, #13376  
Related to  #12048, #16276, #16281
2022-10-11 21:37:50 +00:00
Brian Joerger 4c0a6ff5b1 tsh PIV login integration (#15335)
* Add Yubikey PrivateKey implementation for use by Teleport clients.

  - Add yubikey login logic, reusing previously stored private keys.

  - Fix identity file decoding with PIV keys, which sign ecdsa certificates.

  - Add libpcsclite-dev pre-req for building on linux.

  - Remove unnecessary keys.Signer interface and move its functionality to keys.PrivateKey.

  - Move retry and jitter utils to new api/utils/retryutils package.
2022-09-23 19:44:10 +00:00
Tiago Silva 45c065acee Adds kube_cluster watcher for kubernetes service (#16281)
This PR presents a watcher for dynamic `kube_cluster` resources. The cluster credentials can be set using a `kubeconfig` whose payload is defined in `KubernertesClusterV3.Spec.Kubeconfig`. These credentials are used to connect to the Kubernetes API server and if invalid, the cluster is not served and returns an error.

Currently, `kube_cluster` resources created via the API with a kubeconfig payload can be dynamically served by the `kubernetes_service` by enabling dynamic resources.

```yaml
kubernetes_service:
   enabled: true

   resources:
       labels:
           '*': '*'
```

# Future work
- The discovery service will have to create these resources. 
- Support Azure and AWS dynamic authentication

Part of #16135, #13376  
Related to  #12048, #16276
2022-09-23 17:07:13 +00:00
Alex McGrath e2fab63ba9 Introduce discovery_service and automatically run an SSM Document on discovered EC2 nodes (#14094)
* Add initial version of installer

* Resolve comments

- Use aws waiters when checking commands
- Use SSMRunRequest rather than passing instances
- General comments

* Resolve comments, (rebase) pass scriptname parameter

This resolves comments regarding running on multiple ec2 instances at
once by adding state to the instances cache to check if the instance
is known about and how far into installation it is

* Revert cache

* Dont cache on non discovery nodes

* Resolve some comments

* Move discovery out to its own serviec

* Add a `discovery_service` section

* Fix messed up conflict merge

* Make starting a standalone discovery agent work

* Resolve comments

* Resolve comments

- use a regular events.Emitter
- resolve a thousand typos :)

* Resolve comments

* resolve comments, fix a bad merge

* Fail when a non ec2 matcher type is configured

* fix lint-go

* Resolve comments

* Resolve comments, add initial test (currently broken)

* Fix log string so only 1 pair of [] are used

* Chunk instances for sending commands

* add 'isInitialized' to watchers

* Add test for chunked discovery, log output

* lints

* explicetly set matcher.Tags to "*":"*" if its unset
2022-09-21 12:23:06 +00:00
rosstimothy dea633f16a Remove refetching from resourceWatcher (#14262)
The resourceWatcher is meant to be a long lived way for a component
to receive events about a particular resource from an upstream cache.
However, there was a refetching mechanism that would cause a healthy
and subscribed watcher to be closed, the resourceWatcher to fetch all
the resource types it is watching from the upstream cache and to create a
new watcher **every 10 minutes**. This causes unneeded load on
the upstream cache and also eats up network bandwidth.

This removes the refetching behavior entirely to ensure watchers
aren't unnecessarily closed. The change should be transparent to
users of the resourceWatcher, but should noticeably reduce both
the number of init events being emitted through out a cluster
and the number of cache reads.

Fixes #14234
2022-07-11 14:26:24 +00:00
David BosleeandVitor Enes bb235e15cf Add missing tunnel metric support when proxy peering is enabled (#14022)
Co-authored-by: Vitor Enes <vitor.duarte@goteleport.com>
2022-07-07 15:07:46 +00:00
STeve (Xin) Huang 86d9e30765 Fix an issue DB rotation event get send to older remote cluster (#13857) 2022-06-30 21:16:12 +00:00
David Boslee 32695a2f05 Add proxy peering support (#12359)
This adds proxy peering support. A configurable setting that allows for agents 
to connect to a subset of proxies and be reachable through any proxy in the
cluster. This is achieved by creating grpc connections between each proxy
server. Client connections can then be passed between proxies to the desired
agent.
2022-06-02 17:08:24 +00:00
Andrew Burke a8ed7bd1fd Automatically import EC2 tags (#12593)
This change allows Teleport to automatically import EC2 tags when running in an EC2 instance.
2022-05-31 23:19:16 +00:00
STeve (Xin) Huang c36f2941ce Deflake TestLockWatcherStale (#12977) 2022-05-27 14:41:30 +00:00
rosstimothy 1ac0957d0e Improve CertAuthorityWatcher (#10403)
* Improve CertAuthorityWatcher

CertAuthorityWatcher and its usage are refactored to allow for
all the following:
 - eliminate retransmission of the same CAs
 - reduce memory usage by having one local watcher per proxy
 - adds the ability to filter only the CAs that are desired
 - reduce the time required to send the first CAs

watchCertAuthorities now compares all CAs it receives from the
watcher with the previous CA of the same type and only sends to
the remote site if they are not identical. This is to reduce
unnecessary network traffic which can be problematic for a
root cluster with a larger number of leafs.

The CertAuthorityWatcher is refactored to leverage a fanout
to emit events to any number of watchers, each subscription
can be for a subset of the configured CA types. The proxy
now has only one CertAuthorityWatcher that is passed around
similarly to the LockWatcher. This reduces the memory usage
for proxies, which prior to this has one local CAWatcher per
remote site.

updateCertAuthorities no longer waits on the utils.Retry it
is provided with before starting to watch CAs. By doing this
the proxy no longer has to wait ~8 minutes before it even
starts to watch CAs.
2022-05-17 19:06:41 +00:00
Jakub Nyckowski 402acb85f6 Do not sync Database CA if leaf 9.0 (#12040)
Database CA should not be synced when adding trusted cluster with leaf not in version lower than 10.0.
2022-05-04 20:14:04 +00:00
rosstimothy fa12352214 Stop loading the enitre node set into memory per tsh ssh connection (#12014)
* Prevent proxy from loading entire node set into memory more than once

When establishing a new session to a node, the proxy would load the 
entire node set into memory in an attempt to find the matching host. For
smaller clusters this may not be that problematic. But on larger clusters,
loading >40k nodes into memory from the cache can be quite expensive.
This problem is compounded by the fact that it happened**per** session,
which could potentially cause the proxy to consume all available memory 
and be OOM killed.

A new `NodeWatcher` is introduced which will maintain an in memory list
of all nodes per process. The watcher leverages the existing resource 
watcher system and stores all nodes as types.Server, to eliminate the
cost incurred by unmarshalling the nodes from the cache. The `NodeWatcher`
provides a way to retrieve a filtered list of nodes in order to reduce the number 
of copies made to only the matches.
2022-05-02 15:59:56 -04:00
Jakub Nyckowski 53814a2d60 Migrate trusted remote cluster Database CA (#11878)
Database CA has been added in Teleport 10.0. When migrating from 9.0 local Host CA is copied to keep backward compatibility. Because only local CA is copied trusted cluster fails to connect as described in attached issue, as leaf doesn't have a copy of remote Database CA.
Now remote Host CA will be copied in the same way as we did for local Database CA.
2022-04-25 13:54:15 +00:00
Jakub NyckowskiandMarek Smoliński 1aa38f4bc5 Create Database CA (#9593)
Introduce Database Certificate Authority. New CA is used by Database Access to sign database certificates making them independent from Host CA. 

Co-authored-by: Marek Smoliński <marek@goteleport.com>
2022-04-05 19:44:46 +00:00
rosstimothy 550d23d15d Fix goroutine and memory leak in watchCertAuthorities (#10871)
* Fix goroutine and memory leak in watchCertAuthorities

The CA Watcher was blocking both on writing to a channel when the watcher
was closed and on HTTP calls that had no request timeout or context passed
to cause cancellation.

All resourceWatcher implementations that had a bug which may cause them to block
on writing to a channel forever were fixed by selecting on the write and ctx.Done.

Adding context.Context to all Get/Put/Post/Delete methods on the auth HTTPClient to
force callers to propagate context. Prior all calls used context.TODO which
prevents requests from being properly cancelled.

Add context propagation to RotateCertAuthority, RotateExternalCertAuthority,
GetCertAuthority, GetCertAuthorities. This is needed to get the correct ctx
from the CertAtuhorityWatcher all the way down to the HTTPClient that makes
the call.

Closes #10648
2022-03-10 11:05:39 -05:00
rosstimothy 8932ed4e03 Replace cluster periodics with watchers (#9609)
* Replace cluster periodics with watchers
Remove periodically sending locks and certificate authorities to leaf clusters. Instead
we can rely on the watcher system to only deliver resources to leaf clusters when changes
occur.

Fixes #8817
2022-01-19 16:53:45 -05:00
rosstimothy dbc039c39d Fix Flaky Retry Tests (#9516)
Fix flaky unit tests
Addresses issues causing failures in TestCache_Backoff, TestTeleportProcess_reconnectToAuth
and TestResourceWatcher_Backoff. By utilizing FakeClock.BlockUntil tests ensure that the clock
will not be advanced until retry.After has been called. Move retry duration channels to config in order to allow them to be buffered by tests.
2022-01-05 12:33:58 -05:00
rosstimothy ab857001de Add jitter and backoff to prevent thundering herd on auth (#9133)
Move cache and resourceWatcher watchers from a 10s retry to a jittered backoff retry up to ~1min. Replace the
reconnectToAuthService interval with a retry to add jitter and backoff there as well for when a node restarts due to
changes introduced in #8102.

Fixes #6889.
2021-12-16 11:41:08 -05:00
Forrest Marshall 2e5ea8fb98 improve lock tests 2021-12-09 13:01:35 -08:00
Forrest Marshall cf7d221b64 improve graceful restart behavior 2021-09-21 11:56:39 -07:00
Roman Tkachenko 13e6c52ccc Add app resource watcher/reconciler (#8228) 2021-09-20 09:27:14 -07:00
Andrej Tokarčík fb5f5fdd2e Avoid watching for new Locks with empty LockTarget (#8253) 2021-09-15 07:53:25 -07:00
Andrej Tokarčík 2be3cc8695 Make TestLockWatcherStale more robust (#8134) 2021-09-03 08:20:38 -07:00
Roman Tkachenko 3410bc8594 Dynamically register/unregister database resources (#7957) 2021-09-01 15:27:02 -07:00
Andrej Tokarčík 9cf940ba1b Make srv.TestMonitorStaleLocks more robust (#7877) 2021-08-13 17:23:45 +02:00
Andrej Tokarčík 9f410881f8 Handle stale lock views with strict/best-effort modes (#7798) 2021-08-10 16:56:56 +02:00
Andrej Tokarčík 7d9067da24 Replicate locks to remote clusters (#7737) 2021-08-09 11:59:10 -07:00
Brian Joerger 9b8b9d6d0c rollback - Upgrade api version. (#7751) 2021-07-30 15:34:19 -07:00
Brian Joerger c040aca4c1 Upgrade api version. (#7609) 2021-07-28 13:51:21 -07:00
Andrej Tokarčík 7d878fff24 Enforce locks in auth.Authorize (#7625) 2021-07-28 18:54:21 +02:00
Andrej Tokarčík d5ca862280 Apply locks to connections tracked by srv.Monitor (#7506) 2021-07-23 14:11:50 +02:00
Andrej Tokarčík 3f041daa69 Generalize ProxyWatcher to monitor other resources (#7489) 2021-07-09 14:49:14 +02:00