* Add mapping between user groups and applications.
Within Okta, user groups can assign permission to many applications and
applications can belong to many user groups. This commit establishes that
mapping so that the Okta service can perform more user friendly access
requests by adding all applications from a user group to the access request
and additionally allowing application access requests to request associated
user groups as well.
* Adjust NewUserGroup to take a spec.
* Simplify Okta assignment statuses.
The Okta assignment statuses have been simplfieid so that there's only a
status on the Okta assignment object itself and the number of states is
reduced.
* Fix tests, remove unused code.
* Add in Duration for update statuses to prevent changing status too soon.
* Make sure LastTransition is UTC.
* Remove actions in favor of targets, make cleanup time non-nullable.
* Add CA, Role, Lock AuthPreference RO persmissions to RoleOkta.
RoleOkta now has read only access for CertAuthority, Role, Lock, and
ClusterAuthPreference objects so that it can utilize an authorizer when
redirecting apps.
* Remove lock from Okta cache, remove tasks*.go.
* 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>
* Allow Okta service reverse tunnel access.
In order to allow the Okta service to be connectable via the reverse
tunnel, the following things were added.
* The cache has permissions to retrieve cluster configuration objects.
While here, I removed access to the App objects, which was not necessary.
* The permissions have been updated to allow for AppServer access and
ClusterNetworkingConfig access.
* The cache has been updated to cache app servers and cluster networking
configuration resources. While here, access to App objects has been
removed.
* The reverse tunnel now recognizes the Okta role.
* Add in ListResources to the Okta access point.
* Remove access to apps and to access requests.
* Add in Semaphore read/write permission.
* Include cache entry for app server. Remove read access for access request.
* Refactor UserGroups local service to use generic service.
The UserGroups local service now uses the generic service. This came about
due to a bug in the pagination logic for the user group listing. This fixes
that issue and simplifies the user group service logic.
* Turn *Svc vars into *Cache vars to make things uniform.
* Add application RW permissions to the Okta role.
Application read/write permissions have been added to the Okta role along with
modifications to the cache and to the OktaAccessPoint to support application
object management.
* Add in app label wildcards.
* Introduce Okta objects into the cache.
The OktaImportRule and the OktaAssignment objects have been added into the
cache. This takes a slightly different take than has been done previously
because the Okta service lives outside of the `auth.ClientI` interface.
However, the additions are pretty straightforward.
* Export NewLocalCache for enterprise.
* Add the Okta services into , fix missing events for the Okta resources.
* Re-add err check for Okta client.
* Add in comment clarifying the usage of access requests in the Okta service cache.
* Add in user groups to Okta cache.
Adds `UpsertCertAuthority` to the `teleport.v1.trust.TrustService`
and deprecates the HTTP api. The `services.Trust` interface was
also updated to include a `context.Context` in both
`CreateCertAuthority` and `UpsertCertAuthority.
To ensure backwards compatibility the `auth.Client` will first
attempt to use the gRPC client and if that fails with a not
implemented error it will fallback to using HTTP.
Part of #6394
Adds `DeleteCertAuthority` to the trust grpc service and deprecates
the legacy HTTP api. Additionally the `DeleteCertAuthority` method
in the `services.Trust` interface now takes a `context.Context` as
the first parameter. In order to plumb the context through from all
the call sites `DeleteRemoteCluster` from `services.Presence` was
also modified to take a `context.Context` as the first parameter.
Adds a new `GetCertAuthorities` unary RPC to
`teleport.v1.trust.TrustService` and deprecates the equivalent
HTTP endpoint. All associated interfaces have been updated to remove
the marshal options as well.
The locks were not being properly upserted to the cache after the collections
refactor. This was due to a typo when writing the `upsert` logic for the locks
collection.
This PR removes the `types.KindKubeService` objects that were
deprecated in Teleport 11.
Teleport 12 removed the double heartbeat and for Teleport 13 we can
safely drop the support of the old hearbeat based on `types.Server`
objects.
Clients older than Teleport 12 connecting to a Teleport 13 server will
fail since they cannot heartbeat using the old mechanism.
The HTTP client created by `auth.NewClient` has an idle timeout of
30s and each instance periodically gets cert authorities in
`TeleportProcess.syncRotationStateCycle`. If there has been no
activity when the ticker expires then the request will result in a
brand new connection to Auth to be established. This can cause a
spikes in open file descriptors on the Proxy when there are a large
number of instances connected via a tunnel.
To prevent periodic dialing when retrieving cert authorities the
endpoint has been migrated to the new Trust gRPC service. For now
only the get endpoint has been migrated but the rest of the CRUD
operations for cert authorities should be migrated from the HTTP
api to the gRPC service as well.
Most of the cache collections had an extremely similar structure. Where
possible, the cache collections have been adjusted to make use of common
functions to minimize the amount of duplication within the cache collections.
All network I/O should be done in the cache collection fetch and
not the appy function returned from fetch. This moves the
`ListResources` request for database services out of the apply
function to be compliant with the collection requirements.
* Add UiConfig option to proxy service config
* Add uiConfig to GRV_CONFIG window object and use in terminal constructor
* Update configuration reference docs
* Remove extra structs and change property to scrollbackLines
* Update web/packages/teleport/src/config.ts
Co-authored-by: Jeff Pihach <hatched@users.noreply.github.com>
* Use a common struct and apply in applyProxyConfig
* Remove webclient dependency for fileconf
* Add missing doc comments
* Set individual properties of cfg.Proxy.UI
* Remove unneeded comment
* Add nolint rule
* Fix nolint
* Add test for UIConfig
* Cleanup tests
* Fix TestUIConfig context
* Allow dynamic config for web ui (#22097)
* Update protofiles
---------
Co-authored-by: Jeff Pihach <hatched@users.noreply.github.com>
* Simplify the cache tests.
Several of the cache tests had a very similar structure. Where possible, these
have been adjusted such that all tests with similar structures use a generic
testing function that executes the same logic on each resource type.
* Re-add t.Parallel() for namespaces.
* Create a generic local backend service.
Many of the local backend services have a very similar pattern in terms of how
objects are retrieved and stored. This PR introduces a generic backend which
implements backend retrieval and storage of objects and migrates the SAML
IdP service provider service to it. More services could easily be migrated
to this generic service implementation.
* Feedback, add in generic tests.
* Tim's feedback, added in a test for updating a resource that doesn't exist.
* Tim's feedback.
* Apply suggestions from code review
Co-authored-by: rosstimothy <39066650+rosstimothy@users.noreply.github.com>
* Edoardo's feedback.
* Added in UpdateAndSwap.
* Edoardo's feedback, Tim's feedback.
* Use a default page size if the page limit is not specified.
* More of Edoardo's feedback.
* Propagate error instead of panic.
---------
Co-authored-by: rosstimothy <39066650+rosstimothy@users.noreply.github.com>
* SAML IdP sessions added to the API and cache.
SAML IdP sessions have now been added to the API and to the cache.
* Update lib/auth/sessions.go
Co-authored-by: rosstimothy <39066650+rosstimothy@users.noreply.github.com>
* Revert changes to types.proto.
* Fix missing session ID, misnamed variable, gRPC update.
---------
Co-authored-by: rosstimothy <39066650+rosstimothy@users.noreply.github.com>
* Extract entity ID when creating SAML service provider.
The entity ID will be parsed from the entity descriptor metadata when the
service provider's entity descriptor is set. The motivation of this PR is to
do the following:
* Extract the entity ID from the entity descriptor during the creation of the
SAML IdP service provider.
* Prevent the creation of service providers in the backend that have an
entity ID that does not match the entity ID represented in the entity
descriptor.
* When reading or listing service providers, prevent the parsing of every
entity descriptor during the listing.
The goal here is to make it performant to look up entity descriptors by their
entity ID without incurring the cost of parsing every single entity descriptor
to determine the entity ID.
* Feedback, eliminating the parsing from the object, pushing parsing verification into the local service.
* Fix up tests, e_imports.
* Fix comment in types.proto.
* Remove dead comment.
* Deduplicate entity ID in update as well.
* Small refactor to move parse out of lock.
* Remove XML parsing from type, fix grpcserver test, fix locking boundaries.
* Tim's and Edoardo's feedback.
* Fix cache test.
* Update lib/services/local/saml_idp_service_provider.go
Co-authored-by: Edoardo Spadolini <edoardo.spadolini@goteleport.com>
* Expanding the comments on the EntityID field.
---------
Co-authored-by: Edoardo Spadolini <edoardo.spadolini@goteleport.com>
* Add SAML IdP service providers to the cache and CLI.
SAML IdP service providers have been added to the cache and are now manageable
via the CLI. Some alterations to role permissions have occurred to ensure that
the system and users can manage these.
* Tiago's feedback.
* Update tool/tctl/common/collection.go
Co-authored-by: rosstimothy <39066650+rosstimothy@users.noreply.github.com>
* Tim's feedback.
* Update lib/cache/collections.go
Co-authored-by: rosstimothy <39066650+rosstimothy@users.noreply.github.com>
---------
Co-authored-by: rosstimothy <39066650+rosstimothy@users.noreply.github.com>
* Loop over the CA type list in collections
Also adds a NewlyAdded method to CertAuthType to indicate the CA types
that have been added in the current major version, so that we can
ignore any related BadParameter error when handling those kinds of CAs
with potentially older versions of Teleport.
* Mention NewlyAdded in the CertAuthType description
* Adding in a new SAML IdP certificate authority.
A new SAML IdP certificate authority has been added. It has been added to
initialization, the cache, and the certificate can be rotated.
* Update lib/services/authority.go
Co-authored-by: Sam Freiberg <sfreiberg@goteleport.com>
* Update api/types/trust.go
Co-authored-by: Edoardo Spadolini <edoardo.spadolini@goteleport.com>
* Only validate private key if it's present.
---------
Co-authored-by: Sam Freiberg <sfreiberg@goteleport.com>
Co-authored-by: Edoardo Spadolini <edoardo.spadolini@goteleport.com>
* WIP adding OpenSSH CA
* fix creating OpenSSH CA for tests
* fix a test name and tctl usage flag
* fix 'tctl status' not displaying openssh CA sometimes
* add OpenSSH CA to TestInit_bootstrap, remove TLS key pair
* add OpenSSH CA to a few more places
* make help text of 'tctl auth rotate' more helpful and accurate
* fix web cert export test
* tbot doesn't need to know about OpenSSH CA
* address feedback
* fix comment formatting
Update the version we should check against: v12 (the current in master)
Update the list of resources to watch for RemoteOldProxy.
The list should be equal to the RemoteProxy as seen in `branch/v11`
As soon as we cut v12, we should update this again in master because
we'll be preparing v13.
When modifying the `types.WatchKind` of `ForRemoteProxy` a series of
steps need to be performed to prevent bricking remote cluster caches.
First, the `cfg.Watches` of `ForOldRemoteProxy` must be replaced
with the current `cfg.Watches` of `ForRemoteProxy`. Next, the
version used by `lib/reversetunnel/srv.go` to determine whether
to use `ForRemoteProxy` or `ForOldRemoteProxy` must be updated
to be the release in which the new resource(s) will exist in.
Once both of these are done, `ForRemoteProxy` may be updated.
Comments are added to `ForRemoteProxy`, `ForOldRemoteProxy`, and
`createRemoteAccessPoint` to help prevent backward incompatible
changes like https://github.com/gravitational/teleport/issues/17211
and https://github.com/gravitational/teleport/issues/19907 from
occurring again in future releases.
This PR includes a new Role resource version that is compatible with V5 spec.
The new resource introduces the `kubernetes_resources` definition that allows operators to limit the Kubernetes resources that each member can access. The `kubernetes_resources` entries must follow the following format: `{"kind":"<kind>", "namespace":"<namespace>","name":"<pod>"}`. Currently, it only supports objects of `kind` `pod`. Valid examples `<namespace>/<name>:
- `*/*`: matches all pods in all namespaces.
- `default/*`: matches all pods in the `default` namespace.
- `*/nginx-*`: matches every pod prefixed with `nginx-` in every namespace.
For older resource versions - V5, V4, V3 - `kubernetes_resources` is automatically populated with `{"kind":"pod","namespace":"*","name":"*"}` to keep compatibility. For the newest version, it's mandatory to define its value otherwise access to pods will be denied.
Part of #18434
n the context of Teleport Discover, we must be able to known if there's any DatabaseService available to proxy a given Database resource.
If there's none available, we will offer a script for the user to run and install a DatabaseService which proxies the desired Database resource.
By DatabaseService, we mean the process that Teleport binary manages when the `teleport.yaml` config has the following section:
```yaml
db_service:
enabled: "yes"
```
To accomplish this we are creating a new resource: DatabaseService.
The UI will fetch all DatabaseServices and check if there's any ResourceMatcher that matches the DatabaseLabels.
Previous PRs created the DatabaseService resource and its CRUD methods.
This PR adds an heartbeat for DatabaseServices similar to what we have for Databases.
There's also a new command to list DatabaseServices using `tctl`:
```
$ tctl get db_service --format text
Name Resource Matchers
------------------------------------ --------------------------------------
a6065ee9-d5ee-4555-8d47-94a78625277b (Labels: <all databases>)
d4e13f2b-0a55-4e0a-b363-bacfb1a11294 (Labels: env=[prod],aws-tag=[xyz abc])
```
Test using Teleport Cloud
```
dinis@lenix ~/p/cloudagents> tctl get db_services
kind: db_service
metadata:
expires: "2022-12-21T18:05:10Z"
id: 1671645310983808522
name: 2a28d394-900c-42ea-a120-eed918e4526b
spec:
resources:
- labels:
aws-tag:
- xyz
- abc
env: prod
version: v1
dinis@lenix ~/p/cloudagents> tctl status
Cluster marcoacme.cloud.gravitational.io
Version 12.0.0-dev
```
Part of #19032
Related #19363#19469
* Improve and unify cache logging
Re-init the cache errors now provide the error via `WithError` instead
of passing the stringify error into the log message. This allows for
the stack trace of the log to show up in the logs to help determine
which resource caused the error.
Logging in the various collection resources was all converted to
follow the same pattern to ensure consistency.
The `Logger` field of the cache was also moved to a named field instead
of being an embedded field.
With the arrival of Teleport 12, we stop supporting v10.x.x clients, and we no longer require the `types.KindKubernetesService` legacy heartbeat.
This change removes the legacy heartbeat from Kubernetes Service but keeps the legacy Auth Server CRUD methods and heartbeat support to maintain compatibility with Teleport 11 Kubernetes Service - Teleport 11 still heartbeats the legacy type.
We postponed the related `DELETES` to Teleport 13.
We were inconsistent throughout the codebase and would sometimes
use the slices package and other times use our own equivalents
in api/.
This removes our versions in favor of the golang.org/x package that
does the same, which has the added benefit of reducing the surface
area of the public API module.
Note: despite existing uses of the slices package, for some reason
it didn't show up in go.mod or go.sum. Fixed that too.
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