Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v14] Access Plugins: Support dynamic credential reloading #34079

Merged
merged 9 commits into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions api/client/credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -576,16 +576,19 @@ func (d *DynamicIdentityFileCreds) SSHClientConfig() (*ssh.ClientConfig, error)
return hostKeyCallback(hostname, remote, key)
},
Timeout: defaults.DefaultIOTimeout,
User: userFromSSHCert(d.sshCert),
// We use this because we can't always guarantee that a user will have
// a principal other than this (they may not have access to SSH nodes)
// and the actual user here doesn't matter for auth server API
// authentication. All that matters is that the principal specified here
// is stable across all certificates issued to the user, since this
// value cannot be changed in a following rotation -
// SSHSessionJoinPrincipal is included on all user ssh certs.
//
// This is a bit of a hack - the ideal solution is a refactor of the
// API client in order to support the SSH config being generated at
// time of use, rather than a single SSH config being made dynamic.
// ~ noah
User: "-teleport-internal-join",
}
return cfg, nil
}

func userFromSSHCert(c *ssh.Certificate) string {
// The KeyId is not always a valid principal, so we prefer the first valid
// principal.
if len(c.ValidPrincipals) > 0 {
return c.ValidPrincipals[0]
}
return c.KeyId
}
2 changes: 0 additions & 2 deletions integrations/access/common/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ import (
const (
// minServerVersion is the minimal teleport version the plugin supports.
minServerVersion = "6.1.0-beta.1"
// grpcBackoffMaxDelay is a maximum time gRPC client waits before reconnection attempt.
grpcBackoffMaxDelay = time.Second * 2
// InitTimeout is used to bound execution time of health check and teleport version check.
initTimeout = time.Second * 10
// handlerTimeout is used to bound the execution time of watcher event handler.
Expand Down
34 changes: 1 addition & 33 deletions integrations/access/common/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,9 @@ package common
import (
"context"

"github.com/gravitational/trace"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
grpcbackoff "google.golang.org/grpc/backoff"

"github.com/gravitational/teleport/api/client"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integrations/access/common/teleport"
"github.com/gravitational/teleport/integrations/lib"
"github.com/gravitational/teleport/integrations/lib/credentials"
"github.com/gravitational/teleport/integrations/lib/logger"
)

Expand All @@ -51,32 +44,7 @@ func (c BaseConfig) GetRecipients() RawRecipientsMap {
}

func (c BaseConfig) GetTeleportClient(ctx context.Context) (teleport.Client, error) {
if validCred, err := credentials.CheckIfExpired(c.Teleport.Credentials()); err != nil {
log.Warn(err)
if !validCred {
return nil, trace.BadParameter(
"No valid credentials found, this likely means credentials are expired. In this case, please sign new credentials and increase their TTL if needed.",
)
}
log.Info("At least one non-expired credential has been found, continuing startup")
}

bk := grpcbackoff.DefaultConfig
bk.MaxDelay = grpcBackoffMaxDelay

clt, err := client.New(ctx, client.Config{
Addrs: c.Teleport.GetAddrs(),
Credentials: c.Teleport.Credentials(),
DialOpts: []grpc.DialOption{
grpc.WithConnectParams(grpc.ConnectParams{Backoff: bk, MinConnectTimeout: initTimeout}),
grpc.WithReturnConnectionError(),
},
})
if err != nil {
return nil, trace.Wrap(err)
}

return clt, nil
return c.Teleport.NewClient(ctx)
}

// GetPluginType returns the type of plugin this config is for.
Expand Down
2 changes: 1 addition & 1 deletion integrations/access/discord/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func (c *Config) GetTeleportClient(ctx context.Context) (teleport.Client, error)
if c.Client != nil {
return c.Client, nil
}
return c.BaseConfig.GetTeleportClient(ctx)
return c.BaseConfig.Teleport.NewClient(ctx)
}

// NewBot initializes the new Discord message generator (DiscordBot)
Expand Down
39 changes: 2 additions & 37 deletions integrations/access/jira/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,14 @@ import (

"github.com/gravitational/trace"
"github.com/jonboulle/clockwork"
"google.golang.org/grpc"
grpcbackoff "google.golang.org/grpc/backoff"

"github.com/gravitational/teleport/api/client"
"github.com/gravitational/teleport/api/client/proto"
"github.com/gravitational/teleport/api/types"
apiutils "github.com/gravitational/teleport/api/utils"
"github.com/gravitational/teleport/integrations/access/common"
"github.com/gravitational/teleport/integrations/access/common/teleport"
"github.com/gravitational/teleport/integrations/lib"
"github.com/gravitational/teleport/integrations/lib/backoff"
"github.com/gravitational/teleport/integrations/lib/credentials"
"github.com/gravitational/teleport/integrations/lib/logger"
"github.com/gravitational/teleport/integrations/lib/watcherjob"
)
Expand All @@ -47,8 +43,6 @@ const (
minServerVersion = "6.1.0"
// pluginName is used to tag PluginData and as a Delegator in Audit log.
pluginName = "jira"
// grpcBackoffMaxDelay is a maximum time gRPC client waits before reconnection attempt.
grpcBackoffMaxDelay = time.Second * 2
// initTimeout is used to bound execution time of health check and teleport version check.
initTimeout = time.Second * 10
// handlerTimeout is used to bound the execution time of watcher event handler.
Expand Down Expand Up @@ -169,43 +163,14 @@ func (a *App) run(ctx context.Context) error {
return trace.NewAggregate(httpErr, watcherJob.Err())
}

func (a *App) createTeleportClient(ctx context.Context) error {
log := logger.Get(ctx)

if validCred, err := credentials.CheckIfExpired(a.conf.Teleport.Credentials()); err != nil {
log.Warn(err)
if !validCred {
return trace.BadParameter(
"No valid credentials found, this likely means credentials are expired. In this case, please sign new credentials and increase their TTL if needed.",
)
}
log.Info("At least one non-expired credential has been found, continuing startup")
}

var err error
bk := grpcbackoff.DefaultConfig
bk.MaxDelay = grpcBackoffMaxDelay
if a.teleport, err = client.New(ctx, client.Config{
Addrs: a.conf.Teleport.GetAddrs(),
Credentials: a.conf.Teleport.Credentials(),
DialOpts: []grpc.DialOption{
grpc.WithConnectParams(grpc.ConnectParams{Backoff: bk, MinConnectTimeout: initTimeout}),
grpc.WithReturnConnectionError(),
},
}); err != nil {
return trace.Wrap(err)
}

return nil
}

func (a *App) init(ctx context.Context) error {
ctx, cancel := context.WithTimeout(ctx, initTimeout)
defer cancel()
log := logger.Get(ctx)

var err error
if a.teleport == nil {
if err := a.createTeleportClient(ctx); err != nil {
if a.teleport, err = a.conf.Teleport.NewClient(ctx); err != nil {
return trace.Wrap(err)
}
}
Expand Down
34 changes: 1 addition & 33 deletions integrations/access/opsgenie/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,13 @@ import (

"github.com/gravitational/trace"
"github.com/jonboulle/clockwork"
"google.golang.org/grpc"
grpcbackoff "google.golang.org/grpc/backoff"

tp "github.com/gravitational/teleport"
"github.com/gravitational/teleport/api/client"
"github.com/gravitational/teleport/api/client/proto"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integrations/access/common/teleport"
"github.com/gravitational/teleport/integrations/lib"
"github.com/gravitational/teleport/integrations/lib/backoff"
"github.com/gravitational/teleport/integrations/lib/credentials"
"github.com/gravitational/teleport/integrations/lib/logger"
"github.com/gravitational/teleport/integrations/lib/watcherjob"
)
Expand All @@ -45,8 +41,6 @@ const (
pluginName = "opsgenie"
// minServerVersion is the minimal teleport version the plugin supports.
minServerVersion = "6.1.0"
// grpcBackoffMaxDelay is a maximum time gRPC client waits before reconnection attempt.
grpcBackoffMaxDelay = time.Second * 2
// initTimeout is used to bound execution time of health check and teleport version check.
initTimeout = time.Second * 10
// handlerTimeout is used to bound the execution time of watcher event handler.
Expand All @@ -73,13 +67,8 @@ type App struct {

// NewOpsgenieApp initializes a new teleport-opsgenie app and returns it.
func NewOpsgenieApp(ctx context.Context, conf *Config) (*App, error) {
teleportClient, err := conf.GetTeleportClient(ctx)
if err != nil {
return nil, trace.Wrap(err)
}
opsgenieApp := &App{
PluginName: pluginName,
teleport: teleportClient,
conf: *conf,
}
opsgenieApp.mainJob = lib.NewServiceJob(opsgenieApp.run)
Expand Down Expand Up @@ -147,31 +136,10 @@ func (a *App) run(ctx context.Context) error {
func (a *App) init(ctx context.Context) error {
ctx, cancel := context.WithTimeout(ctx, initTimeout)
defer cancel()
log := logger.Get(ctx)

if validCred, err := credentials.CheckIfExpired(a.conf.Teleport.Credentials()); err != nil {
log.Warnf("Invalid Teleport credentials: %v", err)
if !validCred {
return trace.BadParameter(
"No valid credentials found, this likely means credentials are expired. In this case, please sign new credentials and increase their TTL if needed.",
)
}
log.Info("At least one non-expired credential has been found, continuing startup")
}

var err error

if a.teleport == nil {
bk := grpcbackoff.DefaultConfig
bk.MaxDelay = grpcBackoffMaxDelay
if a.teleport, err = client.New(ctx, client.Config{
Addrs: a.conf.Teleport.GetAddrs(),
Credentials: a.conf.Teleport.Credentials(),
DialOpts: []grpc.DialOption{
grpc.WithConnectParams(grpc.ConnectParams{Backoff: bk, MinConnectTimeout: initTimeout}),
grpc.WithReturnConnectionError(),
},
}); err != nil {
if a.teleport, err = a.conf.Teleport.NewClient(ctx); err != nil {
return trace.Wrap(err)
}
}
Expand Down
27 changes: 1 addition & 26 deletions integrations/access/pagerduty/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,13 @@ import (

"github.com/gravitational/trace"
"github.com/jonboulle/clockwork"
"google.golang.org/grpc"
grpcbackoff "google.golang.org/grpc/backoff"

"github.com/gravitational/teleport/api/client"
"github.com/gravitational/teleport/api/client/proto"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integrations/access/common"
"github.com/gravitational/teleport/integrations/access/common/teleport"
"github.com/gravitational/teleport/integrations/lib"
"github.com/gravitational/teleport/integrations/lib/backoff"
"github.com/gravitational/teleport/integrations/lib/credentials"
"github.com/gravitational/teleport/integrations/lib/logger"
"github.com/gravitational/teleport/integrations/lib/watcherjob"
)
Expand All @@ -45,8 +41,6 @@ const (
minServerVersion = "6.1.0"
// pluginName is used to tag PluginData and as a Delegator in Audit log.
pluginName = "pagerduty"
// grpcBackoffMaxDelay is a maximum time gRPC client waits before reconnection attempt.
grpcBackoffMaxDelay = time.Second * 2
// initTimeout is used to bound execution time of health check and teleport version check.
initTimeout = time.Second * 10
// handlerTimeout is used to bound the execution time of watcher event handler.
Expand Down Expand Up @@ -147,32 +141,13 @@ func (a *App) init(ctx context.Context) error {
defer cancel()
log := logger.Get(ctx)

if validCred, err := credentials.CheckIfExpired(a.conf.Teleport.Credentials()); err != nil {
log.Warn(err)
if !validCred {
return trace.BadParameter(
"No valid credentials found, this likely means credentials are expired. In this case, please sign new credentials and increase their TTL if needed.",
)
}
log.Info("At least one non-expired credential has been found, continuing startup")
}

var (
err error
pong proto.PingResponse
)

if a.teleport == nil {
bk := grpcbackoff.DefaultConfig
bk.MaxDelay = grpcBackoffMaxDelay
if a.teleport, err = client.New(ctx, client.Config{
Addrs: a.conf.Teleport.GetAddrs(),
Credentials: a.conf.Teleport.Credentials(),
DialOpts: []grpc.DialOption{
grpc.WithConnectParams(grpc.ConnectParams{Backoff: bk, MinConnectTimeout: initTimeout}),
grpc.WithReturnConnectionError(),
},
}); err != nil {
if a.teleport, err = a.conf.Teleport.NewClient(ctx); err != nil {
return trace.Wrap(err)
}
}
Expand Down
34 changes: 1 addition & 33 deletions integrations/access/servicenow/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,13 @@ import (
"github.com/gravitational/trace"
"github.com/jonboulle/clockwork"
"golang.org/x/exp/slices"
"google.golang.org/grpc"
grpcbackoff "google.golang.org/grpc/backoff"

tp "github.com/gravitational/teleport"
"github.com/gravitational/teleport/api/client"
"github.com/gravitational/teleport/api/client/proto"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integrations/access/common/teleport"
"github.com/gravitational/teleport/integrations/lib"
"github.com/gravitational/teleport/integrations/lib/backoff"
"github.com/gravitational/teleport/integrations/lib/credentials"
"github.com/gravitational/teleport/integrations/lib/logger"
"github.com/gravitational/teleport/integrations/lib/watcherjob"
)
Expand All @@ -47,8 +43,6 @@ const (
pluginName = "servicenow"
// minServerVersion is the minimal teleport version the plugin supports.
minServerVersion = "13.0.0"
// grpcBackoffMaxDelay is a maximum time GRPC client waits before reconnection attempt.
grpcBackoffMaxDelay = time.Second * 2
// initTimeout is used to bound execution time of health check and teleport version check.
initTimeout = time.Second * 10
// handlerTimeout is used to bound the execution time of watcher event handler.
Expand All @@ -75,13 +69,8 @@ type App struct {

// NewServicenowApp initializes a new teleport-servicenow app and returns it.
func NewServiceNowApp(ctx context.Context, conf *Config) (*App, error) {
teleportClient, err := conf.GetTeleportClient(ctx)
if err != nil {
return nil, trace.Wrap(err)
}
serviceNowApp := &App{
PluginName: pluginName,
teleport: teleportClient,
conf: *conf,
}
serviceNowApp.mainJob = lib.NewServiceJob(serviceNowApp.run)
Expand Down Expand Up @@ -147,31 +136,10 @@ func (a *App) run(ctx context.Context) error {
func (a *App) init(ctx context.Context) error {
ctx, cancel := context.WithTimeout(ctx, initTimeout)
defer cancel()
log := logger.Get(ctx)

if validCred, err := credentials.CheckIfExpired(a.conf.Teleport.Credentials()); err != nil {
log.Warnf("Invalid Teleport credentials: %v", err)
if !validCred {
return trace.BadParameter(
"No valid credentials found, this likely means credentials are expired. In this case, please sign new credentials and increase their TTL if needed.",
)
}
log.Info("At least one non-expired credential has been found, continuing startup")
}

var err error

if a.teleport == nil {
bk := grpcbackoff.DefaultConfig
bk.MaxDelay = grpcBackoffMaxDelay
if a.teleport, err = client.New(ctx, client.Config{
Addrs: a.conf.Teleport.GetAddrs(),
Credentials: a.conf.Teleport.Credentials(),
DialOpts: []grpc.DialOption{
grpc.WithConnectParams(grpc.ConnectParams{Backoff: bk, MinConnectTimeout: initTimeout}),
grpc.WithReturnConnectionError(),
},
}); err != nil {
if a.teleport, err = a.conf.Teleport.NewClient(ctx); err != nil {
return trace.Wrap(err)
}
}
Expand Down
Loading
Loading