Files
teleport/lib/auth/api.go
T
Andrew Lytvynov b16ad647b4 Kubernetes request routing and cluster registration (#4670)
This change has several parts: cluster registration, cache updates,
routing and a new tctl flag.

> cluster registration

Cluster registration means adding `KubernetesClusters` to `ServerSpec`
for servers with `KindKubeService`.

`kubernetes_service` instances will parse their kubeconfig or local
`kube_cluster_name` and add them to their `ServerSpec` sent to the auth
server. They are effectively declaring that "I can serve k8s requests
for k8s cluster X".

> cache updates

This is just cache plumbing for `kubernetes_service` presence, so that
other teleport processes can fetch all of kube services. It was missed
in the previous PR implementing CRUD for `kubernetes_service`.

> routing

Now the fun part - routing logic. This logic lives in
`/lib/kube/proxy/forwarder.go` and is shared by both `proxy_service`
(with kubernetes integration enabled) and `kubernetes_service`.

The target k8s cluster name is passed in the client cert, along with k8s
users/groups information.

`kubernetes_service` only serves requests for its direct k8s cluster
(from `Forwarder.creds`) and doesn't route requests to other teleport
instances.

`proxy_service` can serve requests:
- directly to a k8s cluster (the way it works pre-5.0)
- to a leaf teleport cluster (also same as pre-5.0, based on
  `RouteToCluster` field in the client cert)
- to a `kubernetes_service` (directly or over a tunnel)

The last two modes require the proxy to generate an ephemeral client TLS
cert to do an outbound mTLS connection.

> tctl flag

A flag `--kube-cluster-name` for `tctl auth sign --format=kubernetes`
which allows generating client certs for non-default k8s cluster name
(as long as it's registered in a cluster).
I used this for testing, but it could be used for automation too.
2020-11-09 19:40:02 +00:00

288 lines
11 KiB
Go

/*
Copyright 2015-2020 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 auth
import (
"context"
"io"
"github.com/gravitational/teleport/lib/events"
"github.com/gravitational/teleport/lib/services"
"github.com/gravitational/teleport/lib/session"
"github.com/gravitational/trace"
)
// Announcer specifies interface responsible for announcing presence
type Announcer interface {
// UpsertNode registers node presence, permanently if ttl is 0 or
// for the specified duration with second resolution if it's >= 1 second
UpsertNode(s services.Server) (*services.KeepAlive, error)
// UpsertProxy registers proxy presence, permanently if ttl is 0 or
// for the specified duration with second resolution if it's >= 1 second
UpsertProxy(s services.Server) error
// UpsertAuthServer registers auth server presence, permanently if ttl is 0 or
// for the specified duration with second resolution if it's >= 1 second
UpsertAuthServer(s services.Server) error
// UpsertKubeService registers kubernetes presence, permanently if ttl is 0
// or for the specified duration with second resolution if it's >= 1 second
UpsertKubeService(context.Context, services.Server) error
// NewKeepAliver returns a new instance of keep aliver
NewKeepAliver(ctx context.Context) (services.KeepAliver, error)
// UpsertAppServer adds an application server.
UpsertAppServer(context.Context, services.Server) (*services.KeepAlive, error)
}
// ReadAccessPoint is an API interface implemented by a certificate authority (CA)
type ReadAccessPoint interface {
// Closer closes all the resources
io.Closer
// NewWatcher returns a new event watcher.
NewWatcher(ctx context.Context, watch services.Watch) (services.Watcher, error)
// GetReverseTunnels returns a list of reverse tunnels
GetReverseTunnels(opts ...services.MarshalOption) ([]services.ReverseTunnel, error)
// GetClusterName returns cluster name
GetClusterName(opts ...services.MarshalOption) (services.ClusterName, error)
// GetClusterConfig returns cluster level configuration.
GetClusterConfig(opts ...services.MarshalOption) (services.ClusterConfig, error)
// GetNamespaces returns a list of namespaces
GetNamespaces() ([]services.Namespace, error)
// GetNamespace returns namespace by name
GetNamespace(name string) (*services.Namespace, error)
// GetNodes returns a list of registered servers for this cluster.
GetNodes(namespace string, opts ...services.MarshalOption) ([]services.Server, error)
// GetProxies returns a list of proxy servers registered in the cluster
GetProxies() ([]services.Server, error)
// GetAuthServers returns a list of auth servers registered in the cluster
GetAuthServers() ([]services.Server, error)
// GetCertAuthority returns cert authority by id
GetCertAuthority(id services.CertAuthID, loadKeys bool, opts ...services.MarshalOption) (services.CertAuthority, error)
// GetCertAuthorities returns a list of cert authorities
GetCertAuthorities(caType services.CertAuthType, loadKeys bool, opts ...services.MarshalOption) ([]services.CertAuthority, error)
// GetUser returns a services.User for this cluster.
GetUser(name string, withSecrets bool) (services.User, error)
// GetUsers returns a list of local users registered with this domain
GetUsers(withSecrets bool) ([]services.User, error)
// GetRole returns role by name
GetRole(name string) (services.Role, error)
// GetRoles returns a list of roles
GetRoles() ([]services.Role, error)
// GetAllTunnelConnections returns all tunnel connections
GetAllTunnelConnections(opts ...services.MarshalOption) ([]services.TunnelConnection, error)
// GetTunnelConnections returns tunnel connections for a given cluster
GetTunnelConnections(clusterName string, opts ...services.MarshalOption) ([]services.TunnelConnection, error)
// GetAppServers gets all application servers.
GetAppServers(ctx context.Context, namespace string, opts ...services.MarshalOption) ([]services.Server, error)
// GetAppSession gets an application web session.
GetAppSession(context.Context, services.GetAppSessionRequest) (services.WebSession, error)
// GetRemoteClusters returns a list of remote clusters
GetRemoteClusters(opts ...services.MarshalOption) ([]services.RemoteCluster, error)
// GetRemoteCluster returns a remote cluster by name
GetRemoteCluster(clusterName string) (services.RemoteCluster, error)
// GetKubeServices returns a list of kubernetes services registered in the cluster
GetKubeServices(context.Context) ([]services.Server, error)
}
// AccessPoint is an API interface implemented by a certificate authority (CA)
type AccessPoint interface {
// ReadAccessPoint provides methods to read data
ReadAccessPoint
// Announcer adds methods used to announce presence
Announcer
// Streamer creates and manages audit streams
events.Streamer
// Semaphores provides semaphore operations
services.Semaphores
// UpsertTunnelConnection upserts tunnel connection
UpsertTunnelConnection(conn services.TunnelConnection) error
// DeleteTunnelConnection deletes tunnel connection
DeleteTunnelConnection(clusterName, connName string) error
}
// AccessCache is a subset of the interface working on the certificate authorities
type AccessCache interface {
// GetCertAuthority returns cert authority by id
GetCertAuthority(id services.CertAuthID, loadKeys bool, opts ...services.MarshalOption) (services.CertAuthority, error)
// GetCertAuthorities returns a list of cert authorities
GetCertAuthorities(caType services.CertAuthType, loadKeys bool, opts ...services.MarshalOption) ([]services.CertAuthority, error)
// GetClusterConfig returns cluster level configuration.
GetClusterConfig(opts ...services.MarshalOption) (services.ClusterConfig, error)
// GetClusterName gets the name of the cluster from the backend.
GetClusterName(opts ...services.MarshalOption) (services.ClusterName, error)
}
// Cache is a subset of the auth interface hanlding
// access to the discovery API and static tokens
type Cache interface {
ReadAccessPoint
// GetStaticTokens gets the list of static tokens used to provision nodes.
GetStaticTokens() (services.StaticTokens, error)
// GetTokens returns all active (non-expired) provisioning tokens
GetTokens(opts ...services.MarshalOption) ([]services.ProvisionToken, error)
// GetToken finds and returns token by ID
GetToken(token string) (services.ProvisionToken, error)
// NewWatcher returns a new event watcher
NewWatcher(ctx context.Context, watch services.Watch) (services.Watcher, error)
}
// NewWrapper returns new access point wrapper
func NewWrapper(base AccessPoint, cache ReadAccessPoint) AccessPoint {
return &Wrapper{
NoCache: base,
ReadAccessPoint: cache,
}
}
// Wrapper wraps access point and auth cache in one client
// so that reads of cached values can be intercepted.
type Wrapper struct {
ReadAccessPoint
NoCache AccessPoint
}
// ResumeAuditStream resumes existing audit stream
func (w *Wrapper) ResumeAuditStream(ctx context.Context, sid session.ID, uploadID string) (events.Stream, error) {
return w.NoCache.ResumeAuditStream(ctx, sid, uploadID)
}
// CreateAuditStream creates new audit stream
func (w *Wrapper) CreateAuditStream(ctx context.Context, sid session.ID) (events.Stream, error) {
return w.NoCache.CreateAuditStream(ctx, sid)
}
// Close closes all associated resources
func (w *Wrapper) Close() error {
err := w.NoCache.Close()
err2 := w.ReadAccessPoint.Close()
return trace.NewAggregate(err, err2)
}
// UpsertNode is part of auth.AccessPoint implementation
func (w *Wrapper) UpsertNode(s services.Server) (*services.KeepAlive, error) {
return w.NoCache.UpsertNode(s)
}
// UpsertAuthServer is part of auth.AccessPoint implementation
func (w *Wrapper) UpsertAuthServer(s services.Server) error {
return w.NoCache.UpsertAuthServer(s)
}
// NewKeepAliver returns a new instance of keep aliver
func (w *Wrapper) NewKeepAliver(ctx context.Context) (services.KeepAliver, error) {
return w.NoCache.NewKeepAliver(ctx)
}
// UpsertProxy is part of auth.AccessPoint implementation
func (w *Wrapper) UpsertProxy(s services.Server) error {
return w.NoCache.UpsertProxy(s)
}
// UpsertTunnelConnection is a part of auth.AccessPoint implementation
func (w *Wrapper) UpsertTunnelConnection(conn services.TunnelConnection) error {
return w.NoCache.UpsertTunnelConnection(conn)
}
// DeleteTunnelConnection is a part of auth.AccessPoint implementation
func (w *Wrapper) DeleteTunnelConnection(clusterName, connName string) error {
return w.NoCache.DeleteTunnelConnection(clusterName, connName)
}
// AcquireSemaphore acquires lease with requested resources from semaphore
func (w *Wrapper) AcquireSemaphore(ctx context.Context, params services.AcquireSemaphoreRequest) (*services.SemaphoreLease, error) {
return w.NoCache.AcquireSemaphore(ctx, params)
}
// KeepAliveSemaphoreLease updates semaphore lease
func (w *Wrapper) KeepAliveSemaphoreLease(ctx context.Context, lease services.SemaphoreLease) error {
return w.NoCache.KeepAliveSemaphoreLease(ctx, lease)
}
// CancelSemaphoreLease cancels semaphore lease early
func (w *Wrapper) CancelSemaphoreLease(ctx context.Context, lease services.SemaphoreLease) error {
return w.NoCache.CancelSemaphoreLease(ctx, lease)
}
// GetSemaphores returns a list of semaphores matching supplied filter.
func (w *Wrapper) GetSemaphores(ctx context.Context, filter services.SemaphoreFilter) ([]services.Semaphore, error) {
return w.NoCache.GetSemaphores(ctx, filter)
}
// DeleteSemaphore deletes a semaphore matching supplied filter.
func (w *Wrapper) DeleteSemaphore(ctx context.Context, filter services.SemaphoreFilter) error {
return w.NoCache.DeleteSemaphore(ctx, filter)
}
// UpsertKubeService is part of auth.AccessPoint implementation
func (w *Wrapper) UpsertKubeService(ctx context.Context, s services.Server) error {
return w.NoCache.UpsertKubeService(ctx, s)
}
// UpsertAppServer adds an application server.
func (w *Wrapper) UpsertAppServer(ctx context.Context, server services.Server) (*services.KeepAlive, error) {
return w.NoCache.UpsertAppServer(ctx, server)
}
// NewCachingAcessPoint returns new caching access point using
// access point policy
type NewCachingAccessPoint func(clt ClientI, cacheName []string) (AccessPoint, error)
// NoCache is a no cache used for access point
func NoCache(clt ClientI, cacheName []string) (AccessPoint, error) {
return clt, nil
}
// notImplementedMessage is the message to return for endpoints that are not
// implemented. This is due to how service interfaces are used with Teleport.
const notImplementedMessage = "not implemented: can only be called by auth locally"