Skip to content

Commit

Permalink
Check cloud feature before setting billing access for web (#6537)
Browse files Browse the repository at this point in the history
* Init web handler with auth server feature flags on proxy init
* Retrieve auth server features by calling Ping when connecting 
  to auth svc which contains the server feature flags in the response
  • Loading branch information
kimlisa committed May 5, 2021
1 parent 155dd98 commit c57d3f9
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 34 deletions.
4 changes: 3 additions & 1 deletion lib/service/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,10 @@ func (process *TeleportProcess) reconnectToAuthService(role teleport.Role) (*Con
// if connected and client is present, make sure the connector's
// client works, by using call that should succeed at all times
if connector.Client != nil {
_, err = connector.Client.GetNamespace(defaults.Namespace)
pingResponse, err := connector.Client.Ping(process.ExitContext())
if err == nil {
process.setClusterFeatures(pingResponse.GetServerFeatures())
process.log.Infof("%v: features loaded from auth server: %+v", role, pingResponse.GetServerFeatures())
return connector, nil
}
process.log.Debugf("Connected client %v failed to execute test call: %v. Node or proxy credentials are out of sync.", role, err)
Expand Down
52 changes: 37 additions & 15 deletions lib/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import (
"github.com/gravitational/trace"

"github.com/gravitational/teleport"
"github.com/gravitational/teleport/api/client/proto"
"github.com/gravitational/teleport/api/client/webclient"
"github.com/gravitational/teleport/lib/auth"
"github.com/gravitational/teleport/lib/auth/native"
Expand Down Expand Up @@ -293,6 +294,9 @@ type TeleportProcess struct {
// appDependCh is used by application service in single process mode to block
// until auth and reverse tunnel servers are ready.
appDependCh chan Event

// clusterFeatures contain flags for supported and unsupported features.
clusterFeatures proto.Features
}

type keyPairKey struct {
Expand Down Expand Up @@ -355,6 +359,22 @@ func (process *TeleportProcess) addConnector(connector *Connector) {
process.connectors[connector.ClientIdentity.ID.Role] = connector
}

func (process *TeleportProcess) setClusterFeatures(features *proto.Features) {
process.Lock()
defer process.Unlock()

if features != nil {
process.clusterFeatures = *features
}
}

func (process *TeleportProcess) getClusterFeatures() proto.Features {
process.Lock()
defer process.Unlock()

return process.clusterFeatures
}

// GetIdentity returns the process identity (credentials to the auth server) for a given
// teleport Role. A teleport process can have any combination of 3 roles: auth, node, proxy
// and they have their own identities
Expand Down Expand Up @@ -2526,23 +2546,25 @@ func (process *TeleportProcess) initProxyEndpoint(conn *Connector) error {
return trace.Wrap(err)
}
}

webHandler, err = web.NewHandler(
web.Config{
Proxy: tsrv,
AuthServers: cfg.AuthServers[0],
DomainName: cfg.Hostname,
ProxyClient: conn.Client,
ProxySSHAddr: proxySSHAddr,
ProxyWebAddr: cfg.Proxy.WebAddr,
ProxySettings: proxySettings,
CipherSuites: cfg.CipherSuites,
FIPS: cfg.FIPS,
AccessPoint: accessPoint,
Emitter: streamEmitter,
PluginRegistry: process.PluginRegistry,
HostUUID: process.Config.HostUUID,
Context: process.ExitContext(),
StaticFS: fs,
Proxy: tsrv,
AuthServers: cfg.AuthServers[0],
DomainName: cfg.Hostname,
ProxyClient: conn.Client,
ProxySSHAddr: proxySSHAddr,
ProxyWebAddr: cfg.Proxy.WebAddr,
ProxySettings: proxySettings,
CipherSuites: cfg.CipherSuites,
FIPS: cfg.FIPS,
AccessPoint: accessPoint,
Emitter: streamEmitter,
PluginRegistry: process.PluginRegistry,
HostUUID: process.Config.HostUUID,
Context: process.ExitContext(),
StaticFS: fs,
ClusterFeatures: process.getClusterFeatures(),
})
if err != nil {
return trace.Wrap(err)
Expand Down
16 changes: 12 additions & 4 deletions lib/web/apiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
"time"

"github.com/gravitational/teleport"
"github.com/gravitational/teleport/api/client/proto"
"github.com/gravitational/teleport/api/client/webclient"
"github.com/gravitational/teleport/api/constants"
"github.com/gravitational/teleport/api/types"
Expand Down Expand Up @@ -84,6 +85,9 @@ type Handler struct {
// sshPort specifies the SSH proxy port extracted
// from configuration
sshPort string

// clusterFeatures contain flags for supported and unsupported features.
clusterFeatures proto.Features
}

// HandlerOption is a functional argument - an option that can be passed
Expand Down Expand Up @@ -157,6 +161,9 @@ type Config struct {
// in the cache before getting purged after it has expired.
// Defaults to cachedSessionLingeringThreshold if unspecified.
cachedSessionLingeringThreshold *time.Duration

// ClusterFeatures contains flags for supported/unsupported features.
ClusterFeatures proto.Features
}

type RewritingHandler struct {
Expand Down Expand Up @@ -197,9 +204,10 @@ func (h *RewritingHandler) Close() error {
func NewHandler(cfg Config, opts ...HandlerOption) (*RewritingHandler, error) {
const apiPrefix = "/" + teleport.WebAPIVersion
h := &Handler{
cfg: cfg,
log: newPackageLogger(),
clock: clockwork.NewRealClock(),
cfg: cfg,
log: newPackageLogger(),
clock: clockwork.NewRealClock(),
clusterFeatures: cfg.ClusterFeatures,
}

for _, o := range opts {
Expand Down Expand Up @@ -507,7 +515,7 @@ func (h *Handler) getUserContext(w http.ResponseWriter, r *http.Request, p httpr
return nil, trace.Wrap(err)
}

userContext, err := ui.NewUserContext(user, roleset)
userContext, err := ui.NewUserContext(user, roleset, h.clusterFeatures)
if err != nil {
return nil, trace.Wrap(err)
}
Expand Down
29 changes: 17 additions & 12 deletions lib/web/ui/usercontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package ui

import (
"github.com/gravitational/teleport/api/client/proto"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/defaults"
"github.com/gravitational/teleport/lib/services"
Expand Down Expand Up @@ -171,21 +172,25 @@ func getAccessStrategy(roleset services.RoleSet) accessStrategy {
}

// NewUserContext returns user context
func NewUserContext(user types.User, userRoles services.RoleSet) (*UserContext, error) {
func NewUserContext(user services.User, userRoles services.RoleSet, features proto.Features) (*UserContext, error) {
ctx := &services.Context{User: user}
sessionAccess := newAccess(userRoles, ctx, types.KindSession)
roleAccess := newAccess(userRoles, ctx, types.KindRole)
authConnectors := newAccess(userRoles, ctx, types.KindAuthConnector)
trustedClusterAccess := newAccess(userRoles, ctx, types.KindTrustedCluster)
eventAccess := newAccess(userRoles, ctx, types.KindEvent)
userAccess := newAccess(userRoles, ctx, types.KindUser)
tokenAccess := newAccess(userRoles, ctx, types.KindToken)
nodeAccess := newAccess(userRoles, ctx, types.KindNode)
appServerAccess := newAccess(userRoles, ctx, types.KindAppServer)
sessionAccess := newAccess(userRoles, ctx, services.KindSession)
roleAccess := newAccess(userRoles, ctx, services.KindRole)
authConnectors := newAccess(userRoles, ctx, services.KindAuthConnector)
trustedClusterAccess := newAccess(userRoles, ctx, services.KindTrustedCluster)
eventAccess := newAccess(userRoles, ctx, services.KindEvent)
userAccess := newAccess(userRoles, ctx, services.KindUser)
tokenAccess := newAccess(userRoles, ctx, services.KindToken)
nodeAccess := newAccess(userRoles, ctx, services.KindNode)
appServerAccess := newAccess(userRoles, ctx, services.KindAppServer)
dbServerAccess := newAccess(userRoles, ctx, types.KindDatabaseServer)
kubeServerAccess := newAccess(userRoles, ctx, types.KindKubeService)
requestAccess := newAccess(userRoles, ctx, types.KindAccessRequest)
billingAccess := newAccess(userRoles, ctx, types.KindBilling)
requestAccess := newAccess(userRoles, ctx, services.KindAccessRequest)

var billingAccess access
if features.Cloud {
billingAccess = newAccess(userRoles, ctx, services.KindBilling)
}

logins := getLogins(userRoles)
accessStrategy := getAccessStrategy(userRoles)
Expand Down
14 changes: 12 additions & 2 deletions lib/web/ui/usercontext_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package ui
import (
"testing"

"github.com/gravitational/teleport/api/client/proto"
"github.com/gravitational/teleport/lib/defaults"
"github.com/gravitational/teleport/lib/services"
"gopkg.in/check.v1"
Expand Down Expand Up @@ -46,6 +47,10 @@ func (s *UserContextSuite) TestNewUserContext(c *check.C) {
Resources: []string{services.KindTrustedCluster},
Verbs: services.RW(),
},
{
Resources: []string{services.KindBilling},
Verbs: services.RO(),
},
})

// set some logins
Expand All @@ -54,7 +59,7 @@ func (s *UserContextSuite) TestNewUserContext(c *check.C) {
role2.SetLogins(services.Allow, []string{"d"})

roleSet := []services.Role{role1, role2}
userContext, err := NewUserContext(user, roleSet)
userContext, err := NewUserContext(user, roleSet, proto.Features{})
c.Assert(err, check.IsNil)

allowed := access{true, true, true, true, true}
Expand All @@ -79,13 +84,18 @@ func (s *UserContextSuite) TestNewUserContext(c *check.C) {
Type: services.RequestStrategyOptional,
Prompt: "",
})
c.Assert(userContext.ACL.Billing, check.DeepEquals, denied)

// test local auth type
c.Assert(userContext.AuthType, check.Equals, authLocal)

// test sso auth type
user.Spec.GithubIdentities = []services.ExternalIdentity{{ConnectorID: "foo", Username: "bar"}}
userContext, err = NewUserContext(user, roleSet)
userContext, err = NewUserContext(user, roleSet, proto.Features{})
c.Assert(err, check.IsNil)
c.Assert(userContext.AuthType, check.Equals, authSSO)

userContext, err = NewUserContext(user, roleSet, proto.Features{Cloud: true})
c.Assert(err, check.IsNil)
c.Assert(userContext.ACL.Billing, check.DeepEquals, access{true, true, false, false, false})
}

0 comments on commit c57d3f9

Please sign in to comment.