* Move the authorizer into its own package.
The Authorizer and associated functions and constants have been moved into
their own package `authz`. This will allow us to more easily create separate
services for gRPC functionality so that we're not pushing as much into the
`lib/auth` package.
Though this PR is large, the only actual code change here is making
`ContextForLocalUser` exported and changing the `permissions_test.go` so that
it doesn't rely on the `lib/auth` package.
* Use context functions.
* Test and linting fixes.
* Add in a temporary alias file to ensure e still compiles.
* Use functions instead of var aliases for performance reasons.
* Adding in godocs, cleaning up tests.
* Fix tests.
* Add a few more aliases.
`auth.Middleware` to make use of them. This allows for less redundancy
per RPC and provides the ability to perform session control when grpc
connections are established.
The `auth.Middleware.withAuthenticatedUser` function was called from all
interceptors of any gRPC server that leveraged `auth.Middleware`. This
was constructing the identity of the client from the TLS certificate
per RPC. Since the identity of a connection cannot change between RPCs
there is no need to construct the identity in an interceptor. Instead,
the new `auth.TransportCredentials` can build the identity once after the
TLS handshake completes. When interceptors or gRPC handlers need to
acquire the identity they can do so using the same
mechanism via `peer.Peer.AuthInfo` and assert on the new `auth.IdentityInfo`
type:
```go
peerInfo, ok := peer.FromContext(ctx)
if !ok {
return
}
connInfo, ok := peerInfo.AuthInfo.(auth.IdentityInfo)
if !ok {
return
}
identity := connInfo.IdentityGetter.GetIdentity()
connState := connInfo.TLSInfo.State
```
The gRPC server that is served on the Proxy ssh port needs to hold the
same invariants as the ssh server available on the same port. This
means that connection limits need to be enforced when new connections
are established. To achieve this the new `auth.TransportCredentials` can
be provided with an `auth.ConnectionEnforcer` and an `auth.Authorizer`
to first build an identity, then ensures that the user is authorized and
finally that the user has not exceeded their connection limits.
Other minor changes include providing the cluster name to the
`auth.Middleware` instead of it looking the value up from the cache every
time an identity is created. Some interceptors were also moved around or
removed to eliminate the chances of having duplicate interceptors end up in
the interceptor chain.
Part of #19812
* Add a new db engine
* Add tests for new engine
* Update tsh db subcommands
* Refactor error message and suggestions for unsupported tsh commands
* Add dynamodb to test plan
* Add AWS external ID to db config and update protos
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
* Enable nolintlint linter
* Fix nolint comments in the api package
* Fix RDP client comment
* Address review comment
Co-authored-by: Alan Parra <alan.parra@goteleport.com>
* Allow unused for nolintlint linter
* Remove redundant casting
* Add comment on why allowed unused is enabled
Co-authored-by: Alan Parra <alan.parra@goteleport.com>
Co-authored-by: Alan Parra <alan.parra@goteleport.com>
* Connection Diagnostics: Postgres Database tester
When adding a new resource using the Web UI we want to allow users to
test connecting to it.
We have two connection testers already:
- for SSH Nodes
- for Kube clusters
This PR adds a third tester: Postgres Database.
Most of the required changes for any Database are already present but
we're focusing on Postgres for now. Other databases will be added as
future PRs.
Testing a Database is similar to the other tests:
- generate certs for the logged in user
- connect to the resource using those certs
When generating the certificate, we inject an ID so that the Database
Service can add Connection Diagnostic traces.
* Make SessionTracker heartbeat loop more robust
`(*SessionTracker).UpdateExpirationLoop` terminated the first time
it got an error attempting to persist the updated expiry to Auth.
A momentary network outage could prevent the `types.SessionTracker`
from being updated again causing it to have the wrong TTL in the
backend. This could result in sessions sticking around longer than
needed or being assumed to have been terminated prior to the session
actually ending.
A `retryutils.Retry` has been added to allow for retrying to update
a `types.SessionTracker` with some backoff. The retry loop will continue
until the session is closed, the update is successful, or the retry
has occurred for longer than the `types.SessionTrackers` last known
expiry.
`apidefaults.SessionTrackerTTL` was also reduced from 1h to 30m to
reduce the amount of time a stale tracker may linger in the backend.
The added robustness to the update loop should alleviate the need for
the lengthy TTL.
Also update the active sessions test to operate based on the presence
of session trackers rather than actually starting a session. This
allows us to test additional session types and is more deterministic.
For app sessions, use the name from the types.Application, since
the value in the cert is only present for CLI sessions.
For database sessions, use the database service name, which maps
to the Teleport database service the user is connecting to, since
the actual "logical" database name is not required.
Closes#17126Closes#17871
* Add Azure auto-discovery configuration fields
* Init databases if azure matchers are in config
* Use AzureMatchers in db service
* Use all azure subscriptions/resource groups if omitted in matcher
* Add azure config tests
* Go mod tidy to update dependencies
* Add azure response error conversion
* Check for azure access denied and give a helpful error message
* Add azure subscriptions api
* Add azure mysql/postgresql api and wrappers
* Test generic db server for azure
* Make server properties its own type
* Convert server types manually instead of via json
* Move server list method selection logic out of api client
* Update azure db server tests
* Fixup merge
* Update comments
* Update more comments and remove junk code
* Move all azure api into lib/cloud/azure
* Update state and version checks
* Convert Azure DB Server into database
* Add mutex to subscription client for caching, just in case
* Test database conversion from azure db server
* Refactor common code
* Add azure matchers to watch config
* Remove unused imports
* Use common max pages in memorydb users
* Add azure clients to cloud clients
* Add azure fetchers to watcher
* Skip fetcher NotFound errors
* Add azure watcher tests
* Fix test comment
* Add wildcard region matching
* Remove redundant import
* Update lib/srv/db/cloud/watchers/azure.go
Co-authored-by: Marek Smoliński <marek@goteleport.com>
* Move db server listing logic into separate func
* Refactor some db conversion code
* Use local var to cache sub IDs
* Rename azure subscription client
* Rename azure subscription client and remove sub ID caching
* Move azure cloud clients into separate embedded interface
* Update watcher test for 'NotFound' handling
* Embed azureClients struct
* Update lib/cloud/azure/db_server_test.go
Co-authored-by: Marek Smoliński <marek@goteleport.com>
* Update lib/cloud/azure/subscriptions_test.go
Co-authored-by: Marek Smoliński <marek@goteleport.com>
* Update lib/cloud/azure/db_server_test.go
Co-authored-by: Marek Smoliński <marek@goteleport.com>
* Update lib/cloud/azure/db_server_test.go
Co-authored-by: Marek Smoliński <marek@goteleport.com>
* Update lib/cloud/azure/db_server_test.go
Co-authored-by: Marek Smoliński <marek@goteleport.com>
* Rename azure subscription client and remove sub ID caching
* Add reference links for azure db ports
* Move indirect dep into group
* Wrap all converted azure response errors
* Remove unreachable panic
* Godoc DBServer
* Remove maxPages arg to azure client funcs
* Gofmt
* Spacing between copyright and package
* import order
* Update lib/srv/db/cloud/watchers/azure.go
Co-authored-by: Marek Smoliński <marek@goteleport.com>
* Fix import order
* Refactor region matching
* Fix usage of azure clients to remove max pages arg
* Query azure subscriptions in fetcher.Get if matching wildcard subscription
* Fix azure matcher construction
* Test azure fetcher discovers new subscriptions
* Remove unused test helper func
* Set azure database resource id metadata
* Log errors when fetching from azure subscription fails
* Use more readable protocol in azure db description
* Get azure mysql engine version from labels
* Update lib/srv/db/cloud/watchers/watcher_test.go
Co-authored-by: Marek Smoliński <marek@goteleport.com>
* Update lib/srv/db/cloud/watchers/watcher_test.go
Co-authored-by: Marek Smoliński <marek@goteleport.com>
Co-authored-by: Marek Smoliński <marek@goteleport.com>
* Add Azure auto-discovery configuration fields
* Init databases if azure matchers are in config
* Use AzureMatchers in db service
* Use all azure subscriptions/resource groups if omitted in matcher
* Add azure config tests
* Update lib/services/matchers.go
Co-authored-by: Krzysztof Skrzętnicki <krzysztof.skrzetnicki@goteleport.com>
* Update lib/config/fileconf.go
Co-authored-by: Marek Smoliński <marek@goteleport.com>
* Update lib/config/fileconf.go
Co-authored-by: Marek Smoliński <marek@goteleport.com>
* Update lib/services/matchers.go
Co-authored-by: Marek Smoliński <marek@goteleport.com>
* Remove superfluous cmp option for diffing azure matcher
* Rename AzureMatchers Tags to ResourceTags
* Deduplicate subscription/resource groups and add tests
* Remove azure matcher config fixup
Co-authored-by: Krzysztof Skrzętnicki <krzysztof.skrzetnicki@goteleport.com>
Co-authored-by: Marek Smoliński <marek@goteleport.com>
* Add an AWS EC2 instance fetcher
* Resolve comments
- Remove leftover VPCID stuff
- Document public functions
- Return a notfound when there are no nodes fetched instead of nil nil
* Resolve comments
* Fix fileconf_test.go
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.
Teleport now will try to extract MySQL server version from initial handshake package instead of sending `8.0.0-Teleport` every time. This string can be overridden by new configuration option `mysql.server_version`. On DB service start Teleport will also try to fetch the current version from MySQL/MariaDB instance. After that the server version will be updated on every successful connection to keep it up to date.
Co-authored-by: STeve (Xin) Huang <xin.huang@goteleport.com>
Co-authored-by: Paul Gottschling <paul.gottschling@goteleport.com>
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>
Allow users to secure GCP Cloud SQL instances by setting "Allow only SSL
connections", which enforces client certificate authentication.
This implementation does not require any configuration changes for Teleport
users. Teleport will detect whether client certificate authentication is
required and handle either case automatically.
Client certificates are ephemeral. They are created for every connection by
calling the GCP Cloud SQL API's GenerateEphemeralCert function. Certificates
are only created when the destination Cloud SQL instance is configured to
require client certificate authentication. The configuration is detected by
requesting instance settings from the GCP Cloud SQL API on every connection
attempt.
A special case was implemented for MySQL. MySQL servers in GCP Cloud SQL do not
trust the ephemeral certificate's CA but GCP Cloud Proxy does. To work around
this issue, the implementation will connect to the MySQL Cloud Proxy port using
a TLS dialer instead of the default MySQL port when client certificate
authentication is required.
The common.CloudClients interface and implementation now return an interface
(GCPSQLAdminClient) from the GetGCPSQLAdminClient function instead of the GCP
client's sqladmin.Service. Returning an interface simplified calling code and
allowed for the client to be mocked for testing.
Existing GCP Cloud SQL tests are configured to not require client certificate
authentication by default. A new test named TestGCPRequireSSL was created to
simulate client certificate authentication for both Postgres and MySQL. This
required some minor changes to the test server code.
A new ConnectWithDialer function was added to the
github.com/gravitational/go-mysql fork. This function is available upstream in
v1.4.0 but other changes upstream resulted in a number of errors and a panic
processing network packets. So instead of upgrading, the dialer function was
copied to the Teleport fork and a custom version was created instead:
v1.1.1-teleport.1.
- If we can an error when we stop proxying a database, include
the name of the database in the error message.
- Don't treat context.Canceled as an error from Wait().
Canceling the context is how we implement graceful shutdown,
so that's expected behavior.
Some integration tests modify global "constants" to speed up test
execution (e.g. shortening polling intervals). This is occasionally
tripping the Go data race detector, so I have added explicit
serialisation to reading and writing these global settings.
These values are only ever changed in a test environment, and there
should be zero contention for them in a non-test environment.