Skip to content

Commit

Permalink
[v14] TAG initial implementation (#34569)
Browse files Browse the repository at this point in the history
* TAG initial implementation

This change introduces the initial Teleport integration with TAG. The implementation introduces:

* new `access_graph` section in `teleport.yaml` file that holds the access graph configuration
* new `access_graph` RBAC kind, that controls who has access to TAG feature
* the new access graph RBAC kind is added to the ACL REST endpoint, so WebUI know if TAG is enabled and the user has access to it.

* Remove `UseAuth` and improve comments in `AccessGraph`

This commit removes the `UseAuth` field from the `AccessGraph` configuration. At the same time, the comments for each field in `AccessGraph` have been made more consistent and descriptive, providing clear declaration of each field's purpose. The comments in `WatchEvents` in `grpcserver.go` have also been updated for clarity.
  • Loading branch information
jakule committed Nov 14, 2023
1 parent 6b21a2a commit ed864a3
Show file tree
Hide file tree
Showing 13 changed files with 108 additions and 8 deletions.
2 changes: 2 additions & 0 deletions api/client/webclient/webclient.go
Expand Up @@ -316,6 +316,8 @@ type ProxySettings struct {
TLSRoutingEnabled bool `json:"tls_routing_enabled"`
// AssistEnabled is true when Teleport Assist is enabled.
AssistEnabled bool `json:"assist_enabled"`
// AccessGraphEnabled is true when Access Graph is enabled.
AccessGraphEnabled bool `json:"access_graph_enabled"`
}

// KubeProxySettings is kubernetes proxy settings
Expand Down
2 changes: 2 additions & 0 deletions api/client/webclient/webconfig.go
Expand Up @@ -77,6 +77,8 @@ type WebConfig struct {
HideInaccessibleFeatures bool `json:"hideInaccessibleFeatures"`
// CustomTheme is a string that represents the name of the custom theme that the WebUI should use.
CustomTheme string `json:"customTheme"`
// AccessGraphEnabled is true when the access graph feature is enabled.
AccessGraphEnabled bool `json:"accessGraphEnabled"`
}

// UIConfig provides config options for the web UI served by the proxy service.
Expand Down
3 changes: 3 additions & 0 deletions api/types/constants.go
Expand Up @@ -436,6 +436,9 @@ const (
// Teleport Assist resources.
KindAssistant = "assistant"

// KindAccessGraph is an access to access graph service.
KindAccessGraph = "access_graph"

// KindIntegration is a connection to a 3rd party system API.
KindIntegration = "integration"

Expand Down
21 changes: 19 additions & 2 deletions lib/auth/grpcserver.go
Expand Up @@ -54,6 +54,7 @@ import (
trustpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/trust/v1"
userloginstatev1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/userloginstate/v1"
userpreferencespb "github.com/gravitational/teleport/api/gen/proto/go/userpreferences/v1"
"github.com/gravitational/teleport/api/internalutils/stream"
"github.com/gravitational/teleport/api/metadata"
"github.com/gravitational/teleport/api/types"
apievents "github.com/gravitational/teleport/api/types/events"
Expand Down Expand Up @@ -377,8 +378,24 @@ func (g *GRPCServer) WatchEvents(watch *authpb.Watch, stream authpb.AuthService_
if err != nil {
return trace.Wrap(err)
}

return trace.Wrap(WatchEvents(watch, stream, auth.User.GetName(), auth))
}

// WatchEvent is a stream interface for sending events.
type WatchEvent interface {
Context() context.Context
Send(*authpb.Event) error
}

type Watcher interface {
NewStream(ctx context.Context, watch types.Watch) (stream.Stream[types.Event], error)
}

// WatchEvents watches for events and streams them to the provided stream.
func WatchEvents(watch *authpb.Watch, stream WatchEvent, componentName string, auth Watcher) error {
servicesWatch := types.Watch{
Name: auth.User.GetName(),
Name: componentName,
Kinds: watch.Kinds,
AllowPartialSuccess: watch.AllowPartialSuccess,
}
Expand Down Expand Up @@ -418,7 +435,7 @@ func (g *GRPCServer) WatchEvents(watch *authpb.Watch, stream authpb.AuthService_
}
}

// defferred cleanup func will inject stream error if needed
// deferred cleanup func will inject stream error if needed
return nil
}

Expand Down
12 changes: 12 additions & 0 deletions lib/config/configuration.go
Expand Up @@ -345,6 +345,18 @@ func ApplyFileConfig(fc *FileConfig, cfg *servicecfg.Config) error {
if fc.WindowsDesktop.Disabled() {
cfg.WindowsDesktop.Enabled = false
}

if fc.AccessGraph.Enabled {
cfg.AccessGraph.Enabled = true
if fc.AccessGraph.Endpoint == "" {
return trace.Errorf("Please, provide access_graph_service.addr configuration variable")
}
cfg.AccessGraph.Addr = fc.AccessGraph.Endpoint
cfg.AccessGraph.CA = fc.AccessGraph.CA
// TODO(tigrato): change this behavior when we drop support for plain text connections
cfg.AccessGraph.Insecure = fc.AccessGraph.Insecure
}

applyString(fc.NodeName, &cfg.Hostname)

// apply "advertise_ip" setting:
Expand Down
15 changes: 15 additions & 0 deletions lib/config/fileconf.go
Expand Up @@ -96,6 +96,9 @@ type FileConfig struct {

// Plugins is the section of the config for configuring the plugin service.
Plugins PluginService `yaml:"plugin_service,omitempty"`

// AccessGraph is the section of the config describing AccessGraph service
AccessGraph AccessGraph `yaml:"access_graph,omitempty"`
}

// ReadFromFile reads Teleport configuration from a file. Currently only YAML
Expand Down Expand Up @@ -815,6 +818,18 @@ type PluginService struct {
Plugins map[string]string `yaml:"plugins,omitempty"`
}

// AccessGraph represents the configuration for the AccessGraph service.
type AccessGraph struct {
// Enabled enables the AccessGraph service.
Enabled bool `yaml:"enabled"`
// Endpoint is the endpoint of the AccessGraph service.
Endpoint string `yaml:"endpoint"`
// CA is the path to the CA certificate for the AccessGraph service.
CA string `yaml:"ca"`
// Insecure is true if the AccessGraph service should not verify the CA.
Insecure bool `yaml:"insecure"`
}

// Opsgenie represents the configuration for the Opsgenie plugin.
type Opsgenie struct {
// APIKeyFile is the path to a file containing an Opsgenie API key.
Expand Down
5 changes: 3 additions & 2 deletions lib/service/proxy_settings.go
Expand Up @@ -73,8 +73,9 @@ func (p *proxySettings) GetProxySettings(ctx context.Context) (*webclient.ProxyS
// where incoming connections are routed to the proper proxy service based on TLS SNI ALPN routing information.
func (p *proxySettings) buildProxySettings(proxyListenerMode types.ProxyListenerMode) *webclient.ProxySettings {
proxySettings := webclient.ProxySettings{
TLSRoutingEnabled: proxyListenerMode == types.ProxyListenerMode_Multiplex,
AssistEnabled: p.cfg.Proxy.AssistAPIKey != "",
TLSRoutingEnabled: proxyListenerMode == types.ProxyListenerMode_Multiplex,
AssistEnabled: p.cfg.Proxy.AssistAPIKey != "",
AccessGraphEnabled: p.cfg.AccessGraph.Enabled,
Kube: webclient.KubeProxySettings{
Enabled: p.cfg.Proxy.Kube.Enabled,
},
Expand Down
18 changes: 14 additions & 4 deletions lib/service/service.go
Expand Up @@ -4027,6 +4027,15 @@ func (process *TeleportProcess) initProxyEndpoint(conn *Connector) error {
traceClt = clt
}

var accessGraphAddr utils.NetAddr
if cfg.AccessGraph.Enabled {
addr, err := utils.ParseAddr(cfg.AccessGraph.Addr)
if err != nil {
return trace.Wrap(err)
}
accessGraphAddr = *addr
}

webConfig := web.Config{
Proxy: tsrv,
AuthServers: cfg.AuthServerAddresses()[0],
Expand Down Expand Up @@ -4056,10 +4065,11 @@ func (process *TeleportProcess) initProxyEndpoint(conn *Connector) error {
ctx, err := controller(ctx, sctx, login, localAddr, remoteAddr)
return ctx, trace.Wrap(err)
}),
PROXYSigner: proxySigner,
OpenAIConfig: cfg.OpenAIConfig,
NodeWatcher: nodeWatcher,
TracerProvider: process.TracingProvider,
PROXYSigner: proxySigner,
OpenAIConfig: cfg.OpenAIConfig,
NodeWatcher: nodeWatcher,
AccessGraphAddr: accessGraphAddr,
TracerProvider: process.TracingProvider,
}
webHandler, err := web.NewHandler(webConfig)
if err != nil {
Expand Down
18 changes: 18 additions & 0 deletions lib/service/servicecfg/config.go
Expand Up @@ -268,6 +268,9 @@ type Config struct {
// Options provide a way to customize behavior of service initialization.
Options []Option

// AccessGraph represents AccessGraph server config
AccessGraph AccessGraphConfig

// token is either the token needed to join the auth server, or a path pointing to a file
// that contains the token
//
Expand Down Expand Up @@ -308,6 +311,21 @@ func WithKubeMultiplexerIgnoreSelfConnectionsOption() KubeMultiplexerIgnoreSelfC
return KubeMultiplexerIgnoreSelfConnectionsOption{}
}

// AccessGraphConfig represents TAG server config
type AccessGraphConfig struct {
// Enabled Access Graph reporting enabled
Enabled bool

// Addr of the Access Graph service addr
Addr string

// CA is the path to the CA certificate file
CA string

// Insecure is true if the connection to the Access Graph service should be insecure
Insecure bool
}

// RoleAndIdentityEvent is a role and its corresponding identity event.
type RoleAndIdentityEvent struct {
// Role is a system role.
Expand Down
1 change: 1 addition & 0 deletions lib/services/presets.go
Expand Up @@ -165,6 +165,7 @@ func NewPresetEditorRole() types.Role {
types.NewRule(types.KindDiscoveryConfig, RW()),
types.NewRule(types.KindSecurityReport, append(RW(), types.VerbUse)),
types.NewRule(types.KindAuditQuery, append(RW(), types.VerbUse)),
types.NewRule(types.KindAccessGraph, RW()),
},
},
},
Expand Down
4 changes: 4 additions & 0 deletions lib/services/role_test.go
Expand Up @@ -7574,6 +7574,10 @@ func (u mockCurrentUser) GetTraits() map[string][]string {
return u.traits
}

func (u mockCurrentUser) GetName() string {
return "mockCurrentUser"
}

func TestNewAccessCheckerForRemoteCluster(t *testing.T) {
user := mockCurrentUser{
roles: []string{"dev", "admin"},
Expand Down
4 changes: 4 additions & 0 deletions lib/services/useracl.go
Expand Up @@ -98,6 +98,8 @@ type UserACL struct {
AuditQuery ResourceAccess `json:"auditQuery"`
// SecurityReport defines access to security reports.
SecurityReport ResourceAccess `json:"securityReport"`
// AccessGraph defines access to access graph.
AccessGraph ResourceAccess `json:"accessGraph"`
}

func hasAccess(roleSet RoleSet, ctx *Context, kind string, verbs ...string) bool {
Expand Down Expand Up @@ -142,6 +144,7 @@ func NewUserACL(user types.User, userRoles RoleSet, features proto.Features, des
desktopAccess := newAccess(userRoles, ctx, types.KindWindowsDesktop)
cnDiagnosticAccess := newAccess(userRoles, ctx, types.KindConnectionDiagnostic)
samlIdpServiceProviderAccess := newAccess(userRoles, ctx, types.KindSAMLIdPServiceProvider)
accessGraphAccess := newAccess(userRoles, ctx, types.KindAccessGraph)

var assistAccess ResourceAccess
if features.Assist {
Expand Down Expand Up @@ -209,5 +212,6 @@ func NewUserACL(user types.User, userRoles RoleSet, features proto.Features, des
AccessList: accessListAccess,
AuditQuery: auditQuery,
SecurityReport: securityReports,
AccessGraph: accessGraphAccess,
}
}
11 changes: 11 additions & 0 deletions lib/web/apiserver.go
Expand Up @@ -278,6 +278,9 @@ type Config struct {
// Eg, v13.4.3
// Optional: uses cloud/stable channel when omitted.
AutomaticUpgradesVersionURL string

// AccessGraphAddr is the address of the Access Graph service GRPC API
AccessGraphAddr utils.NetAddr
}

// SetDefaults ensures proper default values are set if
Expand Down Expand Up @@ -1009,6 +1012,11 @@ func (h *Handler) PublicProxyAddr() string {
return h.cfg.PublicProxyAddr
}

// AccessGraphAddr returns the TAG API address
func (h *Handler) AccessGraphAddr() utils.NetAddr {
return h.cfg.AccessGraphAddr
}

func localSettings(cap types.AuthPreference) (webclient.AuthenticationSettings, error) {
as := webclient.AuthenticationSettings{
Type: constants.Local,
Expand Down Expand Up @@ -1499,6 +1507,7 @@ func (h *Handler) getWebConfig(w http.ResponseWriter, r *http.Request, p httprou
// get tunnel address to display on cloud instances
tunnelPublicAddr := ""
assistEnabled := false // TODO(jakule) remove when plugins are implemented
accessGraphEnabled := false
proxyConfig, err := h.cfg.ProxySettings.GetProxySettings(r.Context())
if err != nil {
h.log.WithError(err).Warn("Cannot retrieve ProxySettings, tunnel address won't be set in Web UI.")
Expand All @@ -1516,6 +1525,7 @@ func (h *Handler) getWebConfig(w http.ResponseWriter, r *http.Request, p httprou
// disable if auth doesn't support assist
assistEnabled = enabled.Enabled
}
accessGraphEnabled = proxyConfig.AccessGraphEnabled
}

// disable joining sessions if proxy session recording is enabled
Expand Down Expand Up @@ -1548,6 +1558,7 @@ func (h *Handler) getWebConfig(w http.ResponseWriter, r *http.Request, p httprou
AutomaticUpgrades: automaticUpgradesEnabled,
AutomaticUpgradesTargetVersion: automaticUpgradesTargetVersion,
AssistEnabled: assistEnabled,
AccessGraphEnabled: accessGraphEnabled,
HideInaccessibleFeatures: clusterFeatures.GetFeatureHiding(),
CustomTheme: clusterFeatures.GetCustomTheme(),
}
Expand Down

0 comments on commit ed864a3

Please sign in to comment.