Display license out of compliance warnings (#14114)

This commit is contained in:
Bernard Kim 2022-07-26 19:31:50 -07:00 committed by GitHub
parent c0fcb143e6
commit 26e3df82b5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 896 additions and 686 deletions

File diff suppressed because it is too large Load diff

View file

@ -467,6 +467,8 @@ message PingResponse {
string ProxyPublicAddr = 4 [ (gogoproto.jsontag) = "proxy_public_addr" ];
// IsBoring signals whether or not the server was compiled with BoringCrypto.
bool IsBoring = 5 [ (gogoproto.jsontag) = "is_boring" ];
// LicenseWarnings is a list of license compliance warnings.
repeated string LicenseWarnings = 6 [ (gogoproto.jsontag) = "license_warnings" ];
}
// Features are auth server features.

View file

@ -285,6 +285,8 @@ type PingResponse struct {
MinClientVersion string `json:"min_client_version"`
// ClusterName contains the name of the Teleport cluster.
ClusterName string `json:"cluster_name"`
// LicenseWarnings contains a list of license compliance warning messages
LicenseWarnings []string `json:"license_warnings,omitempty"`
}
// PingErrorResponse contains the error message if the requested connector

2
e

@ -1 +1 @@
Subproject commit 7868ba469330df45a76cae1840b7b961aee315f3
Subproject commit 1362c0bde5bd53566badc9083f24a2d3885e33b0

View file

@ -975,3 +975,6 @@ type NewRemoteProxyCachingAccessPoint func(clt ClientI, cacheName []string) (Rem
// 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"
// LicenseExpiredNotification defines a license expired notification
const LicenseExpiredNotification = "licenseExpired"

View file

@ -154,6 +154,9 @@ func NewServer(cfg *InitConfig, opts ...ServerOption) (*Server, error) {
return nil, trace.Wrap(err)
}
}
if cfg.Enforcer == nil {
cfg.Enforcer = local.NewNoopEnforcer()
}
if cfg.KeyStoreConfig.RSAKeyPairSource == nil {
native.PrecomputeKeys()
cfg.KeyStoreConfig.RSAKeyPairSource = native.GenerateKeyPair
@ -204,6 +207,7 @@ func NewServer(cfg *InitConfig, opts ...ServerOption) (*Server, error) {
Events: cfg.Events,
WindowsDesktops: cfg.WindowsDesktops,
SessionTrackerService: cfg.SessionTrackerService,
Enforcer: cfg.Enforcer,
},
keyStore: keyStore,
getClaimsFun: getClaims,
@ -232,6 +236,7 @@ type Services struct {
services.Databases
services.WindowsDesktops
services.SessionTrackerService
services.Enforcer
types.Events
events.IAuditLog
}
@ -610,6 +615,11 @@ func (a *Server) SetAuditLog(auditLog events.IAuditLog) {
a.IAuditLog = auditLog
}
// SetEnforcer sets the server's enforce service
func (a *Server) SetEnforcer(enforcer services.Enforcer) {
a.Enforcer = enforcer
}
// GetAuthPreference gets AuthPreference from the cache.
func (a *Server) GetAuthPreference(ctx context.Context) (types.AuthPreference, error) {
return a.GetCache().GetAuthPreference(ctx)

View file

@ -57,6 +57,7 @@ import (
"github.com/gravitational/teleport/lib/tlsca"
"github.com/gravitational/teleport/lib/utils"
reporting "github.com/gravitational/reporting/types"
"github.com/gravitational/trace"
"github.com/coreos/go-oidc/jose"
@ -2038,3 +2039,39 @@ func TestCAGeneration(t *testing.T) {
})
}
}
type mockEnforcer struct {
services.Enforcer
notifications []reporting.Notification
}
func (m mockEnforcer) GetLicenseCheckResult(ctx context.Context) (*reporting.Heartbeat, error) {
return &reporting.Heartbeat{
Spec: reporting.HeartbeatSpec{
Notifications: m.notifications,
},
}, nil
}
func TestEnforcerGetLicenseCheckResult(t *testing.T) {
t.Parallel()
ctx := context.Background()
s := newAuthSuite(t)
expected := []reporting.Notification{
{
Type: "test",
Severity: "warning",
Text: "test warning",
HTML: "test warning",
},
}
s.a.SetEnforcer(&mockEnforcer{
notifications: expected,
})
heartbeat, err := s.a.GetLicenseCheckResult(ctx)
require.NoError(t, err)
require.Equal(t, expected, heartbeat.Spec.Notifications)
}

View file

@ -1919,13 +1919,23 @@ func (a *ServerWithRoles) Ping(ctx context.Context) (proto.PingResponse, error)
if err != nil {
return proto.PingResponse{}, trace.Wrap(err)
}
heartbeat, err := a.authServer.GetLicenseCheckResult(ctx)
if err != nil {
return proto.PingResponse{}, trace.Wrap(err)
}
var warnings []string
for _, notification := range heartbeat.Spec.Notifications {
if notification.Type == LicenseExpiredNotification {
warnings = append(warnings, notification.Text)
}
}
return proto.PingResponse{
ClusterName: cn.GetClusterName(),
ServerVersion: teleport.Version,
ServerFeatures: modules.GetModules().Features().ToProto(),
ProxyPublicAddr: a.getProxyPublicAddr(),
IsBoring: modules.GetModules().IsBoringBinary(),
LicenseWarnings: warnings,
}, nil
}

View file

@ -4163,6 +4163,7 @@ func NewGRPCServer(cfg GRPCServerConfig) (*GRPCServer, error) {
grpc.Creds(&httplib.TLSCreds{
Config: cfg.TLS,
}),
grpc.ChainUnaryInterceptor(otelgrpc.UnaryServerInterceptor(), cfg.UnaryInterceptor),
grpc.ChainStreamInterceptor(otelgrpc.StreamServerInterceptor(), cfg.StreamInterceptor),
grpc.KeepaliveParams(

View file

@ -170,6 +170,9 @@ type InitConfig struct {
WindowsDesktops services.WindowsDesktops
SessionTrackerService services.SessionTrackerService
// Enforcer is used to enforce Teleport Enterprise license compliance.
Enforcer services.Enforcer
}
// Init instantiates and configures an instance of AuthServer

29
lib/services/enforcer.go Normal file
View file

@ -0,0 +1,29 @@
/*
Copyright 2022 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 services
import (
"context"
"github.com/gravitational/reporting/types"
)
// Enforcer defines interface for fetching license status.
type Enforcer interface {
// GetLicenseCheckResult returns the license status in a heartbeat.
GetLicenseCheckResult(ctx context.Context) (*types.Heartbeat, error)
}

View file

@ -0,0 +1,36 @@
/*
Copyright 2022 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 local
import (
"context"
"github.com/gravitational/reporting/types"
)
// NoopEnforcer is a no-op enforcer.
type NoopEnforcer struct{}
// NewNoopEnforcer returns a new no-op enforcer.
func NewNoopEnforcer() *NoopEnforcer {
return &NoopEnforcer{}
}
// GetLicenseCheckResult returns the default heartbeat.
func (r *NoopEnforcer) GetLicenseCheckResult(ctx context.Context) (*types.Heartbeat, error) {
return types.NewHeartbeat(), nil
}

View file

@ -841,12 +841,18 @@ func (h *Handler) ping(w http.ResponseWriter, r *http.Request, p httprouter.Para
return nil, trace.Wrap(err)
}
pr, err := h.cfg.ProxyClient.Ping(r.Context())
if err != nil {
return nil, trace.Wrap(err)
}
return webclient.PingResponse{
Auth: authSettings,
Proxy: *proxyConfig,
ServerVersion: teleport.Version,
MinClientVersion: teleport.MinClientVersion,
ClusterName: h.auth.clusterName,
LicenseWarnings: pr.LicenseWarnings,
}, nil
}

View file

@ -1458,7 +1458,20 @@ func onLogin(cf *CLIConf) error {
cf.Proxy = webProxyHost
// Print status to show information of the logged in user.
return trace.Wrap(onStatus(cf))
if err := onStatus(cf); err != nil {
return trace.Wrap(err)
}
// Display any license compliance warnings
resp, err := tc.Ping(cf.Context)
if err != nil {
return trace.Wrap(err)
}
for _, warning := range resp.LicenseWarnings {
fmt.Fprintf(os.Stderr, "%s\n\n", warning)
}
return nil
}
// setupNoninteractiveClient sets up existing client to use