mirror of
https://github.com/gravitational/teleport
synced 2024-10-19 08:43:58 +00:00
Turn AuditConfig into a standalone resource (#6997)
This commit is contained in:
parent
feebcd97c0
commit
3d22eaac0e
|
@ -1438,3 +1438,27 @@ func (c *Client) ResetAuthPreference(ctx context.Context) error {
|
|||
_, err := c.grpc.ResetAuthPreference(ctx, &empty.Empty{})
|
||||
return trail.FromGRPC(err)
|
||||
}
|
||||
|
||||
// GetClusterAuditConfig gets cluster audit configuration.
|
||||
func (c *Client) GetClusterAuditConfig(ctx context.Context) (types.ClusterAuditConfig, error) {
|
||||
resp, err := c.grpc.GetClusterAuditConfig(ctx, &empty.Empty{}, c.callOpts...)
|
||||
if err != nil {
|
||||
return nil, trail.FromGRPC(err)
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// SetClusterAuditConfig sets cluster audit configuration.
|
||||
func (c *Client) SetClusterAuditConfig(ctx context.Context, auditConfig types.ClusterAuditConfig) error {
|
||||
auditConfigV2, ok := auditConfig.(*types.ClusterAuditConfigV2)
|
||||
if !ok {
|
||||
return trace.BadParameter("invalid type %T", auditConfig)
|
||||
}
|
||||
_, err := c.grpc.SetClusterAuditConfig(ctx, auditConfigV2, c.callOpts...)
|
||||
return trail.FromGRPC(err)
|
||||
}
|
||||
|
||||
// DeleteClusterAuditConfig not implemented: can only be called locally.
|
||||
func (c *Client) DeleteClusterAuditConfig(ctx context.Context) error {
|
||||
return trace.NotImplemented(notImplementedMessage)
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -84,6 +84,9 @@ message Event {
|
|||
// AuthPreference is cluster auth preference.
|
||||
types.AuthPreferenceV2 AuthPreference = 22
|
||||
[ (gogoproto.jsontag) = "auth_preference,omitempty" ];
|
||||
// ClusterAuditConfig is a resource for cluster audit configuration.
|
||||
types.ClusterAuditConfigV2 ClusterAuditConfig = 23
|
||||
[ (gogoproto.jsontag) = "cluster_audit_config,omitempty" ];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1099,6 +1102,11 @@ service AuthService {
|
|||
// DeleteToken deletes an existing token in a backend described by the given request.
|
||||
rpc DeleteToken(types.ResourceRequest) returns (google.protobuf.Empty);
|
||||
|
||||
// GetClusterAuditConfig gets cluster audit configuration.
|
||||
rpc GetClusterAuditConfig(google.protobuf.Empty) returns (types.ClusterAuditConfigV2);
|
||||
// SetClusterAuditConfig sets cluster audit configuration.
|
||||
rpc SetClusterAuditConfig(types.ClusterAuditConfigV2) returns (google.protobuf.Empty);
|
||||
|
||||
// GetClusterNetworkingConfig gets cluster networking configuration.
|
||||
rpc GetClusterNetworkingConfig(google.protobuf.Empty) returns (types.ClusterNetworkingConfigV2);
|
||||
// SetClusterNetworkingConfig sets cluster networking configuration.
|
||||
|
|
|
@ -166,6 +166,9 @@ func eventFromGRPC(in proto.Event) (*types.Event, error) {
|
|||
} else if r := in.GetDatabaseServer(); r != nil {
|
||||
out.Resource = r
|
||||
return &out, nil
|
||||
} else if r := in.GetClusterAuditConfig(); r != nil {
|
||||
out.Resource = r
|
||||
return &out, nil
|
||||
} else if r := in.GetClusterNetworkingConfig(); r != nil {
|
||||
out.Resource = r
|
||||
return &out, nil
|
||||
|
|
261
api/types/audit.go
Normal file
261
api/types/audit.go
Normal file
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
Copyright 2021 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 types
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gravitational/teleport/api/defaults"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
)
|
||||
|
||||
// ClusterAuditConfig defines cluster-wide audit log configuration. This is
|
||||
// a configuration resource, never create more than one instance of it.
|
||||
type ClusterAuditConfig interface {
|
||||
Resource
|
||||
|
||||
// Type gets the audit backend type.
|
||||
Type() string
|
||||
// SetType sets the audit backend type.
|
||||
SetType(string)
|
||||
|
||||
// Region gets a cloud provider region.
|
||||
Region() string
|
||||
// SetRegion sets a cloud provider region.
|
||||
SetRegion(string)
|
||||
|
||||
// ShouldUploadSessions returns whether audit config
|
||||
// instructs server to upload sessions.
|
||||
ShouldUploadSessions() bool
|
||||
|
||||
// AuditSessionsURI gets the audit sessions URI.
|
||||
AuditSessionsURI() string
|
||||
// SetAuditSessionsURI sets the audit sessions URI.
|
||||
SetAuditSessionsURI(string)
|
||||
|
||||
// AuditEventsURIs gets the audit events URIs.
|
||||
AuditEventsURIs() []string
|
||||
// SetAuditEventsURIs sets the audit events URIs.
|
||||
SetAuditEventsURIs([]string)
|
||||
|
||||
// EnableContinuousBackups is used to enable (or disable) PITR (Point-In-Time Recovery).
|
||||
EnableContinuousBackups() bool
|
||||
// EnableAutoScaling is used to enable (or disable) auto scaling policy.
|
||||
EnableAutoScaling() bool
|
||||
// ReadMaxCapacity is the maximum provisioned read capacity.
|
||||
ReadMaxCapacity() int64
|
||||
// ReadMinCapacity is the minimum provisioned read capacity.
|
||||
ReadMinCapacity() int64
|
||||
// ReadTargetValue is the ratio of consumed read to provisioned capacity.
|
||||
ReadTargetValue() float64
|
||||
// WriteMaxCapacity is the maximum provisioned write capacity.
|
||||
WriteMaxCapacity() int64
|
||||
// WriteMinCapacity is the minimum provisioned write capacity.
|
||||
WriteMinCapacity() int64
|
||||
// WriteTargetValue is the ratio of consumed write to provisioned capacity.
|
||||
WriteTargetValue() float64
|
||||
}
|
||||
|
||||
// NewClusterAuditConfig is a convenience method to to create ClusterAuditConfigV2.
|
||||
func NewClusterAuditConfig(spec ClusterAuditConfigSpecV2) (ClusterAuditConfig, error) {
|
||||
auditConfig := &ClusterAuditConfigV2{
|
||||
Kind: KindClusterAuditConfig,
|
||||
Version: V2,
|
||||
Metadata: Metadata{
|
||||
Name: MetaNameClusterAuditConfig,
|
||||
Namespace: defaults.Namespace,
|
||||
},
|
||||
Spec: spec,
|
||||
}
|
||||
|
||||
if err := auditConfig.CheckAndSetDefaults(); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return auditConfig, nil
|
||||
}
|
||||
|
||||
// DefaultClusterAuditConfig returns the default audit log configuration.
|
||||
func DefaultClusterAuditConfig() ClusterAuditConfig {
|
||||
config, _ := NewClusterAuditConfig(ClusterAuditConfigSpecV2{})
|
||||
return config
|
||||
}
|
||||
|
||||
// GetVersion returns resource version.
|
||||
func (c *ClusterAuditConfigV2) GetVersion() string {
|
||||
return c.Version
|
||||
}
|
||||
|
||||
// GetName returns the name of the resource.
|
||||
func (c *ClusterAuditConfigV2) GetName() string {
|
||||
return c.Metadata.Name
|
||||
}
|
||||
|
||||
// SetName sets the name of the resource.
|
||||
func (c *ClusterAuditConfigV2) SetName(e string) {
|
||||
c.Metadata.Name = e
|
||||
}
|
||||
|
||||
// SetExpiry sets expiry time for the object.
|
||||
func (c *ClusterAuditConfigV2) SetExpiry(expires time.Time) {
|
||||
c.Metadata.SetExpiry(expires)
|
||||
}
|
||||
|
||||
// Expiry returns object expiry setting.
|
||||
func (c *ClusterAuditConfigV2) Expiry() time.Time {
|
||||
return c.Metadata.Expiry()
|
||||
}
|
||||
|
||||
// SetTTL sets Expires header using the provided clock.
|
||||
// Use SetExpiry instead.
|
||||
// DELETE IN 7.0.0
|
||||
func (c *ClusterAuditConfigV2) SetTTL(clock Clock, ttl time.Duration) {
|
||||
c.Metadata.SetTTL(clock, ttl)
|
||||
}
|
||||
|
||||
// GetMetadata returns object metadata.
|
||||
func (c *ClusterAuditConfigV2) GetMetadata() Metadata {
|
||||
return c.Metadata
|
||||
}
|
||||
|
||||
// GetResourceID returns resource ID.
|
||||
func (c *ClusterAuditConfigV2) GetResourceID() int64 {
|
||||
return c.Metadata.ID
|
||||
}
|
||||
|
||||
// SetResourceID sets resource ID.
|
||||
func (c *ClusterAuditConfigV2) SetResourceID(id int64) {
|
||||
c.Metadata.ID = id
|
||||
}
|
||||
|
||||
// GetKind returns resource kind.
|
||||
func (c *ClusterAuditConfigV2) GetKind() string {
|
||||
return c.Kind
|
||||
}
|
||||
|
||||
// GetSubKind returns resource subkind.
|
||||
func (c *ClusterAuditConfigV2) GetSubKind() string {
|
||||
return c.SubKind
|
||||
}
|
||||
|
||||
// SetSubKind sets resource subkind.
|
||||
func (c *ClusterAuditConfigV2) SetSubKind(sk string) {
|
||||
c.SubKind = sk
|
||||
}
|
||||
|
||||
// Type gets the audit backend type.
|
||||
func (c *ClusterAuditConfigV2) Type() string {
|
||||
return c.Spec.Type
|
||||
}
|
||||
|
||||
// SetType sets the audit backend type.
|
||||
func (c *ClusterAuditConfigV2) SetType(backendType string) {
|
||||
c.Spec.Type = backendType
|
||||
}
|
||||
|
||||
// Region gets a cloud provider region.
|
||||
func (c *ClusterAuditConfigV2) Region() string {
|
||||
return c.Spec.Region
|
||||
}
|
||||
|
||||
// SetRegion sets a cloud provider region.
|
||||
func (c *ClusterAuditConfigV2) SetRegion(region string) {
|
||||
c.Spec.Region = region
|
||||
}
|
||||
|
||||
// ShouldUploadSessions returns whether audit config
|
||||
// instructs server to upload sessions.
|
||||
func (c *ClusterAuditConfigV2) ShouldUploadSessions() bool {
|
||||
return c.Spec.AuditSessionsURI != ""
|
||||
}
|
||||
|
||||
// AuditSessionsURI gets the audit sessions URI.
|
||||
func (c *ClusterAuditConfigV2) AuditSessionsURI() string {
|
||||
return c.Spec.AuditSessionsURI
|
||||
}
|
||||
|
||||
// SetAuditSessionsURI sets the audit sessions URI.
|
||||
func (c *ClusterAuditConfigV2) SetAuditSessionsURI(uri string) {
|
||||
c.Spec.AuditSessionsURI = uri
|
||||
}
|
||||
|
||||
// AuditEventsURIs gets the audit events URIs.
|
||||
func (c *ClusterAuditConfigV2) AuditEventsURIs() []string {
|
||||
return c.Spec.AuditEventsURI
|
||||
}
|
||||
|
||||
// SetAuditEventsURIs sets the audit events URIs.
|
||||
func (c *ClusterAuditConfigV2) SetAuditEventsURIs(uris []string) {
|
||||
c.Spec.AuditEventsURI = uris
|
||||
}
|
||||
|
||||
// EnableContinuousBackups is used to enable (or disable) PITR (Point-In-Time Recovery).
|
||||
func (c *ClusterAuditConfigV2) EnableContinuousBackups() bool {
|
||||
return c.Spec.EnableContinuousBackups
|
||||
}
|
||||
|
||||
// EnableAutoScaling is used to enable (or disable) auto scaling policy.
|
||||
func (c *ClusterAuditConfigV2) EnableAutoScaling() bool {
|
||||
return c.Spec.EnableAutoScaling
|
||||
}
|
||||
|
||||
// ReadMaxCapacity is the maximum provisioned read capacity.
|
||||
func (c *ClusterAuditConfigV2) ReadMaxCapacity() int64 {
|
||||
return c.Spec.ReadMaxCapacity
|
||||
}
|
||||
|
||||
// ReadMinCapacity is the minimum provisioned read capacity.
|
||||
func (c *ClusterAuditConfigV2) ReadMinCapacity() int64 {
|
||||
return c.Spec.ReadMinCapacity
|
||||
}
|
||||
|
||||
// ReadTargetValue is the ratio of consumed read to provisioned capacity.
|
||||
func (c *ClusterAuditConfigV2) ReadTargetValue() float64 {
|
||||
return c.Spec.ReadTargetValue
|
||||
}
|
||||
|
||||
// WriteMaxCapacity is the maximum provisioned write capacity.
|
||||
func (c *ClusterAuditConfigV2) WriteMaxCapacity() int64 {
|
||||
return c.Spec.WriteMaxCapacity
|
||||
}
|
||||
|
||||
// WriteMinCapacity is the minimum provisioned write capacity.
|
||||
func (c *ClusterAuditConfigV2) WriteMinCapacity() int64 {
|
||||
return c.Spec.WriteMinCapacity
|
||||
}
|
||||
|
||||
// WriteTargetValue is the ratio of consumed write to provisioned capacity.
|
||||
func (c *ClusterAuditConfigV2) WriteTargetValue() float64 {
|
||||
return c.Spec.WriteTargetValue
|
||||
}
|
||||
|
||||
// setStaticFields sets static resource header and metadata fields.
|
||||
func (c *ClusterAuditConfigV2) setStaticFields() {
|
||||
c.Kind = KindClusterAuditConfig
|
||||
c.Version = V2
|
||||
c.Metadata.Name = MetaNameClusterAuditConfig
|
||||
}
|
||||
|
||||
// CheckAndSetDefaults verifies the constraints for ClusterAuditConfig.
|
||||
func (c *ClusterAuditConfigV2) CheckAndSetDefaults() error {
|
||||
c.setStaticFields()
|
||||
if err := c.Metadata.CheckAndSetDefaults(); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -37,11 +37,13 @@ type ClusterConfig interface {
|
|||
// SetClusterID sets the cluster ID
|
||||
SetClusterID(string)
|
||||
|
||||
// GetAuditConfig returns audit settings
|
||||
GetAuditConfig() AuditConfig
|
||||
// HasAuditConfig returns true if audit configuration is set.
|
||||
// DELETE IN 8.0.0
|
||||
HasAuditConfig() bool
|
||||
|
||||
// SetAuditConfig sets audit config
|
||||
SetAuditConfig(AuditConfig)
|
||||
// SetAuditConfig sets audit configuration.
|
||||
// DELETE IN 8.0.0
|
||||
SetAuditConfig(ClusterAuditConfig) error
|
||||
|
||||
// HasNetworkingFields returns true if embedded networking configuration is set.
|
||||
// DELETE IN 8.0.0
|
||||
|
@ -166,16 +168,6 @@ func (c *ClusterConfigV3) SetClusterID(id string) {
|
|||
c.Spec.ClusterID = id
|
||||
}
|
||||
|
||||
// GetAuditConfig returns audit settings
|
||||
func (c *ClusterConfigV3) GetAuditConfig() AuditConfig {
|
||||
return c.Spec.Audit
|
||||
}
|
||||
|
||||
// SetAuditConfig sets audit config
|
||||
func (c *ClusterConfigV3) SetAuditConfig(cfg AuditConfig) {
|
||||
c.Spec.Audit = cfg
|
||||
}
|
||||
|
||||
// CheckAndSetDefaults checks validity of all parameters and sets defaults.
|
||||
func (c *ClusterConfigV3) CheckAndSetDefaults() error {
|
||||
// make sure we have defaults for all metadata fields
|
||||
|
@ -189,6 +181,23 @@ func (c *ClusterConfigV3) CheckAndSetDefaults() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// HasAuditConfig returns true if audit configuration is set.
|
||||
// DELETE IN 8.0.0
|
||||
func (c *ClusterConfigV3) HasAuditConfig() bool {
|
||||
return c.Spec.Audit != nil
|
||||
}
|
||||
|
||||
// SetAuditConfig sets audit configuration.
|
||||
// DELETE IN 8.0.0
|
||||
func (c *ClusterConfigV3) SetAuditConfig(auditConfig ClusterAuditConfig) error {
|
||||
auditConfigV2, ok := auditConfig.(*ClusterAuditConfigV2)
|
||||
if !ok {
|
||||
return trace.BadParameter("unexpected type %T", auditConfig)
|
||||
}
|
||||
c.Spec.Audit = &auditConfigV2.Spec
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasNetworkingFields returns true if embedded networking configuration is set.
|
||||
// DELETE IN 8.0.0
|
||||
func (c *ClusterConfigV3) HasNetworkingFields() bool {
|
||||
|
@ -251,9 +260,10 @@ func (c *ClusterConfigV3) SetAuthFields(authPref AuthPreference) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ClearLegacyFields clears embedded legacy fields.
|
||||
// ClearLegacyFields clears legacy fields.
|
||||
// DELETE IN 8.0.0
|
||||
func (c *ClusterConfigV3) ClearLegacyFields() {
|
||||
c.Spec.Audit = nil
|
||||
c.Spec.ClusterNetworkingConfigSpecV2 = nil
|
||||
c.Spec.LegacySessionRecordingConfigSpec = nil
|
||||
c.Spec.LegacyClusterConfigAuthFields = nil
|
||||
|
|
|
@ -155,6 +155,13 @@ const (
|
|||
// MetaNameClusterConfig is the exact name of the cluster config singleton resource.
|
||||
MetaNameClusterConfig = "cluster-config"
|
||||
|
||||
// KindClusterAuditConfig is the resource that holds cluster audit configuration.
|
||||
KindClusterAuditConfig = "cluster_audit_config"
|
||||
|
||||
// MetaNameClusterAuditConfig is the exact name of the singleton resource holding
|
||||
// cluster audit configuration.
|
||||
MetaNameClusterAuditConfig = "cluster-audit-config"
|
||||
|
||||
// KindClusterNetworkingConfig is the resource that holds cluster networking configuration.
|
||||
KindClusterNetworkingConfig = "cluster_networking_config"
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ func DefaultClusterNetworkingConfig() ClusterNetworkingConfig {
|
|||
// newClusterNetworkingConfigWithLabels is a convenience method to create
|
||||
// ClusterNetworkingConfigV2 with a specific map of labels.
|
||||
func newClusterNetworkingConfigWithLabels(spec ClusterNetworkingConfigSpecV2, labels map[string]string) (ClusterNetworkingConfig, error) {
|
||||
netConfig := ClusterNetworkingConfigV2{
|
||||
netConfig := &ClusterNetworkingConfigV2{
|
||||
Kind: KindClusterNetworkingConfig,
|
||||
Version: V2,
|
||||
Metadata: Metadata{
|
||||
|
@ -91,7 +91,7 @@ func newClusterNetworkingConfigWithLabels(spec ClusterNetworkingConfigSpecV2, la
|
|||
if err := netConfig.CheckAndSetDefaults(); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return &netConfig, nil
|
||||
return netConfig, nil
|
||||
}
|
||||
|
||||
// GetVersion returns resource version.
|
||||
|
|
|
@ -42,10 +42,6 @@ type SessionRecordingConfig interface {
|
|||
|
||||
// SetProxyChecksHostKeys sets if the proxy will check host keys.
|
||||
SetProxyChecksHostKeys(bool)
|
||||
|
||||
// CheckAndSetDefaults sets and default values and then
|
||||
// verifies the constraints for SessionRecordingConfig.
|
||||
CheckAndSetDefaults() error
|
||||
}
|
||||
|
||||
// NewSessionRecordingConfigFromConfigFile is a convenience method to create
|
||||
|
@ -67,7 +63,7 @@ func DefaultSessionRecordingConfig() SessionRecordingConfig {
|
|||
// newSessionRecordingConfigWithLabels is a convenience method to create
|
||||
// SessionRecordingConfigV2 with a specific map of labels.
|
||||
func newSessionRecordingConfigWithLabels(spec SessionRecordingConfigSpecV2, labels map[string]string) (SessionRecordingConfig, error) {
|
||||
recConfig := SessionRecordingConfigV2{
|
||||
recConfig := &SessionRecordingConfigV2{
|
||||
Kind: KindSessionRecordingConfig,
|
||||
Version: V2,
|
||||
Metadata: Metadata{
|
||||
|
@ -81,7 +77,7 @@ func newSessionRecordingConfigWithLabels(spec SessionRecordingConfigSpecV2, labe
|
|||
if err := recConfig.CheckAndSetDefaults(); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return &recConfig, nil
|
||||
return recConfig, nil
|
||||
}
|
||||
|
||||
// GetVersion returns resource version.
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -518,7 +518,8 @@ message ClusterConfigSpecV3 {
|
|||
string ClusterID = 2 [ (gogoproto.jsontag) = "cluster_id" ];
|
||||
|
||||
// Audit is a section with audit config
|
||||
AuditConfig Audit = 4 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "audit" ];
|
||||
ClusterAuditConfigSpecV2 Audit = 4
|
||||
[ (gogoproto.nullable) = true, (gogoproto.jsontag) = "audit,omitempty" ];
|
||||
|
||||
// DELETE IN 8.0.0
|
||||
ClusterNetworkingConfigSpecV2 NetworkingConfig = 11
|
||||
|
@ -533,8 +534,27 @@ message ClusterConfigSpecV3 {
|
|||
[ (gogoproto.nullable) = true, (gogoproto.jsontag) = "", (gogoproto.embed) = true ];
|
||||
}
|
||||
|
||||
// AuditConfig represents audit log settings in the cluster
|
||||
message AuditConfig {
|
||||
// ClusterAuditConfigV2 represents audit log settings in the cluster.
|
||||
message ClusterAuditConfigV2 {
|
||||
// Kind is a resource kind
|
||||
string Kind = 1 [ (gogoproto.jsontag) = "kind" ];
|
||||
// SubKind is an optional resource sub kind, used in some resources
|
||||
string SubKind = 2 [ (gogoproto.jsontag) = "sub_kind,omitempty" ];
|
||||
// Version is a resource version
|
||||
string Version = 3 [ (gogoproto.jsontag) = "version" ];
|
||||
// Metadata is resource metadata
|
||||
Metadata Metadata = 4 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "metadata" ];
|
||||
// Spec is a ClusterAuditConfig specification
|
||||
ClusterAuditConfigSpecV2 Spec = 5
|
||||
[ (gogoproto.nullable) = false, (gogoproto.jsontag) = "spec" ];
|
||||
}
|
||||
|
||||
// ClusterAuditConfigSpecV2 is the actual data we care about
|
||||
// for ClusterAuditConfig.
|
||||
message ClusterAuditConfigSpecV2 {
|
||||
reserved 5;
|
||||
reserved "audit_table_name";
|
||||
|
||||
// Type is audit backend type
|
||||
string Type = 1 [ (gogoproto.jsontag) = "type,omitempty" ];
|
||||
// Region is a region setting for audit sessions used by cloud providers
|
||||
|
@ -548,14 +568,9 @@ message AuditConfig {
|
|||
(gogoproto.jsontag) = "audit_events_uri,omitempty",
|
||||
(gogoproto.customtype) = "github.com/gravitational/teleport/api/types/wrappers.Strings"
|
||||
];
|
||||
// AuditTableName is a DB table name used for audits
|
||||
// Deprecated in favor of AuditEventsURI
|
||||
// DELETE IN (3.1.0)
|
||||
string AuditTableName = 5 [ (gogoproto.jsontag) = "audit_table_name,omitempty" ];
|
||||
|
||||
// EnableContinuousBackups is used to enable (or disable) PITR (Point-In-Time Recovery).
|
||||
bool EnableContinuousBackups = 6 [ (gogoproto.jsontag) = "continuous_backups,omitempty" ];
|
||||
|
||||
// EnableAutoScaling is used to enable (or disable) auto scaling policy.
|
||||
bool EnableAutoScaling = 7 [ (gogoproto.jsontag) = "auto_scaling,omitempty" ];
|
||||
// ReadMaxCapacity is the maximum provisioned read capacity.
|
||||
|
@ -695,7 +710,7 @@ message AuthPreferenceSpecV2 {
|
|||
BoolValue DisconnectExpiredCert = 6 [
|
||||
(gogoproto.nullable) = true,
|
||||
(gogoproto.jsontag) = "disconnect_expired_cert,omitempty",
|
||||
(gogoproto.casttype) = "BoolOption"
|
||||
(gogoproto.customtype) = "BoolOption"
|
||||
];
|
||||
|
||||
// AllowLocalAuth is true if local authentication is enabled.
|
||||
|
|
|
@ -256,8 +256,8 @@ func testAuditOn(t *testing.T, suite *integrationTestSuite) {
|
|||
for _, tt := range tests {
|
||||
t.Run(tt.comment, func(t *testing.T) {
|
||||
makeConfig := func() (*testing.T, []string, []*InstanceSecrets, *service.Config) {
|
||||
clusterConfig, err := types.NewClusterConfig(types.ClusterConfigSpecV3{
|
||||
Audit: types.AuditConfig{AuditSessionsURI: tt.auditSessionsURI},
|
||||
auditConfig, err := types.NewClusterAuditConfig(types.ClusterAuditConfigSpecV2{
|
||||
AuditSessionsURI: tt.auditSessionsURI,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
|
@ -268,7 +268,7 @@ func testAuditOn(t *testing.T, suite *integrationTestSuite) {
|
|||
|
||||
tconf := suite.defaultServiceConfig()
|
||||
tconf.Auth.Enabled = true
|
||||
tconf.Auth.ClusterConfig = clusterConfig
|
||||
tconf.Auth.AuditConfig = auditConfig
|
||||
tconf.Auth.SessionRecordingConfig = recConfig
|
||||
tconf.Proxy.Enabled = true
|
||||
tconf.Proxy.DisableWebService = true
|
||||
|
|
|
@ -74,6 +74,9 @@ type ReadAccessPoint interface {
|
|||
// GetClusterConfig returns cluster level configuration.
|
||||
GetClusterConfig(opts ...services.MarshalOption) (types.ClusterConfig, error)
|
||||
|
||||
// GetClusterAuditConfig returns cluster audit configuration.
|
||||
GetClusterAuditConfig(ctx context.Context, opts ...services.MarshalOption) (types.ClusterAuditConfig, error)
|
||||
|
||||
// GetClusterNetworkingConfig returns cluster networking configuration.
|
||||
GetClusterNetworkingConfig(ctx context.Context, opts ...services.MarshalOption) (types.ClusterNetworkingConfig, error)
|
||||
|
||||
|
@ -180,6 +183,9 @@ type AccessCache interface {
|
|||
// GetClusterConfig returns cluster level configuration.
|
||||
GetClusterConfig(opts ...services.MarshalOption) (types.ClusterConfig, error)
|
||||
|
||||
// GetClusterAuditConfig returns cluster audit configuration.
|
||||
GetClusterAuditConfig(ctx context.Context, opts ...services.MarshalOption) (types.ClusterAuditConfig, error)
|
||||
|
||||
// GetClusterNetworkingConfig returns cluster networking configuration.
|
||||
GetClusterNetworkingConfig(ctx context.Context, opts ...services.MarshalOption) (types.ClusterNetworkingConfig, error)
|
||||
|
||||
|
|
|
@ -379,11 +379,31 @@ func (a *Server) SetAuditLog(auditLog events.IAuditLog) {
|
|||
a.IAuditLog = auditLog
|
||||
}
|
||||
|
||||
// GetAuthPreference gets AuthPreference from the backend.
|
||||
func (a *Server) GetAuthPreference() (types.AuthPreference, error) {
|
||||
return a.GetCache().GetAuthPreference()
|
||||
}
|
||||
|
||||
// GetClusterConfig gets ClusterConfig from the backend.
|
||||
func (a *Server) GetClusterConfig(opts ...services.MarshalOption) (types.ClusterConfig, error) {
|
||||
return a.GetCache().GetClusterConfig(opts...)
|
||||
}
|
||||
|
||||
// GetClusterAuditConfig gets ClusterAuditConfig from the backend.
|
||||
func (a *Server) GetClusterAuditConfig(ctx context.Context, opts ...services.MarshalOption) (types.ClusterAuditConfig, error) {
|
||||
return a.GetCache().GetClusterAuditConfig(ctx, opts...)
|
||||
}
|
||||
|
||||
// GetClusterNetworkingConfig gets ClusterNetworkingConfig from the backend.
|
||||
func (a *Server) GetClusterNetworkingConfig(ctx context.Context, opts ...services.MarshalOption) (types.ClusterNetworkingConfig, error) {
|
||||
return a.GetCache().GetClusterNetworkingConfig(ctx, opts...)
|
||||
}
|
||||
|
||||
// GetSessionRecordingConfig gets SessionRecordingConfig from the backend.
|
||||
func (a *Server) GetSessionRecordingConfig(ctx context.Context, opts ...services.MarshalOption) (types.SessionRecordingConfig, error) {
|
||||
return a.GetCache().GetSessionRecordingConfig(ctx, opts...)
|
||||
}
|
||||
|
||||
// GetClusterName returns the domain name that identifies this authority server.
|
||||
// Also known as "cluster name"
|
||||
func (a *Server) GetClusterName(opts ...services.MarshalOption) (types.ClusterName, error) {
|
||||
|
|
|
@ -77,9 +77,11 @@ type AuthSuite struct {
|
|||
var _ = Suite(&AuthSuite{})
|
||||
|
||||
func (s *AuthSuite) SetUpTest(c *C) {
|
||||
ctx := context.Background()
|
||||
|
||||
var err error
|
||||
s.dataDir = c.MkDir()
|
||||
s.bk, err = lite.NewWithConfig(context.TODO(), lite.Config{Path: s.dataDir})
|
||||
s.bk, err = lite.NewWithConfig(ctx, lite.Config{Path: s.dataDir})
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
clusterName, err := types.NewClusterName(types.ClusterNameSpecV2{
|
||||
|
@ -116,10 +118,13 @@ func (s *AuthSuite) SetUpTest(c *C) {
|
|||
err = s.a.SetAuthPreference(authPreference)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
err = s.a.SetClusterNetworkingConfig(context.TODO(), types.DefaultClusterNetworkingConfig())
|
||||
err = s.a.SetClusterAuditConfig(ctx, types.DefaultClusterAuditConfig())
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
err = s.a.SetSessionRecordingConfig(context.TODO(), types.DefaultSessionRecordingConfig())
|
||||
err = s.a.SetClusterNetworkingConfig(ctx, types.DefaultClusterNetworkingConfig())
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
err = s.a.SetSessionRecordingConfig(ctx, types.DefaultSessionRecordingConfig())
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
err = s.a.SetClusterConfig(services.DefaultClusterConfig())
|
||||
|
|
|
@ -2260,6 +2260,30 @@ func (a *ServerWithRoles) DeleteAuthPreference(context.Context) error {
|
|||
return trace.NotImplemented(notImplementedMessage)
|
||||
}
|
||||
|
||||
// GetClusterAuditConfig gets cluster audit configuration.
|
||||
func (a *ServerWithRoles) GetClusterAuditConfig(ctx context.Context, opts ...services.MarshalOption) (types.ClusterAuditConfig, error) {
|
||||
if err := a.action(apidefaults.Namespace, types.KindClusterAuditConfig, types.VerbRead); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return a.authServer.GetClusterAuditConfig(ctx, opts...)
|
||||
}
|
||||
|
||||
// SetClusterAuditConfig sets cluster audit configuration.
|
||||
func (a *ServerWithRoles) SetClusterAuditConfig(ctx context.Context, auditConfig types.ClusterAuditConfig) error {
|
||||
if err := a.action(apidefaults.Namespace, types.KindClusterAuditConfig, types.VerbCreate); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
if err := a.action(apidefaults.Namespace, types.KindClusterAuditConfig, types.VerbUpdate); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
return a.authServer.SetClusterAuditConfig(ctx, auditConfig)
|
||||
}
|
||||
|
||||
// DeleteClusterAuditConfig not implemented: can only be called locally.
|
||||
func (a *ServerWithRoles) DeleteClusterAuditConfig(ctx context.Context) error {
|
||||
return trace.NotImplemented(notImplementedMessage)
|
||||
}
|
||||
|
||||
// GetClusterNetworkingConfig gets cluster networking configuration.
|
||||
func (a *ServerWithRoles) GetClusterNetworkingConfig(ctx context.Context, opts ...services.MarshalOption) (types.ClusterNetworkingConfig, error) {
|
||||
if err := a.action(apidefaults.Namespace, types.KindClusterNetworkingConfig, types.VerbRead); err != nil {
|
||||
|
|
|
@ -1644,6 +1644,11 @@ func (c *Client) DeleteAuthPreference(context.Context) error {
|
|||
return trace.NotImplemented(notImplementedMessage)
|
||||
}
|
||||
|
||||
// GetClusterAuditConfig gets cluster audit configuration.
|
||||
func (c *Client) GetClusterAuditConfig(ctx context.Context, opts ...services.MarshalOption) (types.ClusterAuditConfig, error) {
|
||||
return c.APIClient.GetClusterAuditConfig(ctx)
|
||||
}
|
||||
|
||||
// GetClusterNetworkingConfig gets cluster networking configuration.
|
||||
func (c *Client) GetClusterNetworkingConfig(ctx context.Context, opts ...services.MarshalOption) (types.ClusterNetworkingConfig, error) {
|
||||
return c.APIClient.GetClusterNetworkingConfig(ctx)
|
||||
|
|
|
@ -399,6 +399,10 @@ func eventToGRPC(ctx context.Context, in types.Event) (*proto.Event, error) {
|
|||
out.Resource = &proto.Event_DatabaseServer{
|
||||
DatabaseServer: r,
|
||||
}
|
||||
case *types.ClusterAuditConfigV2:
|
||||
out.Resource = &proto.Event_ClusterAuditConfig{
|
||||
ClusterAuditConfig: r,
|
||||
}
|
||||
case *types.ClusterNetworkingConfigV2:
|
||||
out.Resource = &proto.Event_ClusterNetworkingConfig{
|
||||
ClusterNetworkingConfig: r,
|
||||
|
@ -2483,6 +2487,35 @@ func (g *GRPCServer) DeleteAllNodes(ctx context.Context, req *types.ResourcesInN
|
|||
return &empty.Empty{}, nil
|
||||
}
|
||||
|
||||
// GetClusterAuditConfig gets cluster audit configuration.
|
||||
func (g *GRPCServer) GetClusterAuditConfig(ctx context.Context, _ *empty.Empty) (*types.ClusterAuditConfigV2, error) {
|
||||
auth, err := g.authenticate(ctx)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
auditConfig, err := auth.ServerWithRoles.GetClusterAuditConfig(ctx)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
auditConfigV2, ok := auditConfig.(*types.ClusterAuditConfigV2)
|
||||
if !ok {
|
||||
return nil, trace.BadParameter("unexpected type %T", auditConfig)
|
||||
}
|
||||
return auditConfigV2, nil
|
||||
}
|
||||
|
||||
// SetClusterAuditConfig sets cluster audit configuration.
|
||||
func (g *GRPCServer) SetClusterAuditConfig(ctx context.Context, auditConfig *types.ClusterAuditConfigV2) (*empty.Empty, error) {
|
||||
auth, err := g.authenticate(ctx)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
if err = auth.ServerWithRoles.SetClusterAuditConfig(ctx, auditConfig); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return &empty.Empty{}, nil
|
||||
}
|
||||
|
||||
// GetClusterNetworkingConfig gets cluster networking configuration.
|
||||
func (g *GRPCServer) GetClusterNetworkingConfig(ctx context.Context, _ *empty.Empty) (*types.ClusterNetworkingConfigV2, error) {
|
||||
auth, err := g.authenticate(ctx)
|
||||
|
|
|
@ -235,6 +235,11 @@ func NewTestAuthServer(cfg TestAuthServerConfig) (*TestAuthServer, error) {
|
|||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
err = srv.AuthServer.SetClusterAuditConfig(ctx, types.DefaultClusterAuditConfig())
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
err = srv.AuthServer.SetClusterNetworkingConfig(ctx, types.DefaultClusterNetworkingConfig())
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
|
|
|
@ -139,6 +139,9 @@ type InitConfig struct {
|
|||
// ClusterConfig holds cluster level configuration.
|
||||
ClusterConfig types.ClusterConfig
|
||||
|
||||
// ClusterAuditConfig holds cluster audit configuration.
|
||||
ClusterAuditConfig types.ClusterAuditConfig
|
||||
|
||||
// ClusterNetworkingConfig holds cluster networking configuration.
|
||||
ClusterNetworkingConfig types.ClusterNetworkingConfig
|
||||
|
||||
|
@ -241,6 +244,11 @@ func Init(cfg InitConfig, opts ...ServerOption) (*Server, error) {
|
|||
log.Infof("Created reverse tunnel: %v.", tunnel)
|
||||
}
|
||||
|
||||
err = asrv.SetClusterAuditConfig(ctx, cfg.ClusterAuditConfig)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
err = initSetClusterNetworkingConfig(ctx, asrv, cfg.ClusterNetworkingConfig)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
|
|
|
@ -847,6 +847,7 @@ func setupConfig(t *testing.T) InitConfig {
|
|||
Backend: bk,
|
||||
Authority: testauthority.New(),
|
||||
ClusterConfig: services.DefaultClusterConfig(),
|
||||
ClusterAuditConfig: types.DefaultClusterAuditConfig(),
|
||||
ClusterNetworkingConfig: types.DefaultClusterNetworkingConfig(),
|
||||
SessionRecordingConfig: types.DefaultSessionRecordingConfig(),
|
||||
ClusterName: clusterName,
|
||||
|
|
|
@ -262,6 +262,7 @@ func (a *authorizer) authorizeRemoteBuiltinRole(r RemoteBuiltinRole) (*Context,
|
|||
types.NewRule(types.KindReverseTunnel, services.RO()),
|
||||
types.NewRule(types.KindTunnelConnection, services.RO()),
|
||||
types.NewRule(types.KindClusterConfig, services.RO()),
|
||||
types.NewRule(types.KindClusterAuditConfig, services.RO()),
|
||||
types.NewRule(types.KindClusterNetworkingConfig, services.RO()),
|
||||
types.NewRule(types.KindSessionRecordingConfig, services.RO()),
|
||||
types.NewRule(types.KindKubeService, services.RO()),
|
||||
|
@ -330,6 +331,7 @@ func GetCheckerForBuiltinRole(clusterName string, recConfig types.SessionRecordi
|
|||
types.NewRule(types.KindReverseTunnel, services.RW()),
|
||||
types.NewRule(types.KindTunnelConnection, services.RO()),
|
||||
types.NewRule(types.KindClusterConfig, services.RO()),
|
||||
types.NewRule(types.KindClusterAuditConfig, services.RO()),
|
||||
types.NewRule(types.KindClusterNetworkingConfig, services.RO()),
|
||||
types.NewRule(types.KindSessionRecordingConfig, services.RO()),
|
||||
types.NewRule(types.KindClusterAuthPreference, services.RO()),
|
||||
|
@ -354,6 +356,7 @@ func GetCheckerForBuiltinRole(clusterName string, recConfig types.SessionRecordi
|
|||
types.NewRule(types.KindReverseTunnel, services.RW()),
|
||||
types.NewRule(types.KindTunnelConnection, services.RO()),
|
||||
types.NewRule(types.KindClusterConfig, services.RO()),
|
||||
types.NewRule(types.KindClusterAuditConfig, services.RO()),
|
||||
types.NewRule(types.KindClusterNetworkingConfig, services.RO()),
|
||||
types.NewRule(types.KindSessionRecordingConfig, services.RO()),
|
||||
types.NewRule(types.KindClusterAuthPreference, services.RO()),
|
||||
|
@ -381,6 +384,7 @@ func GetCheckerForBuiltinRole(clusterName string, recConfig types.SessionRecordi
|
|||
types.NewRule(types.KindReverseTunnel, services.RW()),
|
||||
types.NewRule(types.KindTunnelConnection, services.RO()),
|
||||
types.NewRule(types.KindClusterConfig, services.RO()),
|
||||
types.NewRule(types.KindClusterAuditConfig, services.RO()),
|
||||
types.NewRule(types.KindClusterNetworkingConfig, services.RO()),
|
||||
types.NewRule(types.KindSessionRecordingConfig, services.RO()),
|
||||
types.NewRule(types.KindClusterAuthPreference, services.RO()),
|
||||
|
@ -418,6 +422,7 @@ func GetCheckerForBuiltinRole(clusterName string, recConfig types.SessionRecordi
|
|||
types.NewRule(types.KindRole, services.RO()),
|
||||
types.NewRule(types.KindClusterAuthPreference, services.RO()),
|
||||
types.NewRule(types.KindClusterConfig, services.RO()),
|
||||
types.NewRule(types.KindClusterAuditConfig, services.RO()),
|
||||
types.NewRule(types.KindClusterNetworkingConfig, services.RO()),
|
||||
types.NewRule(types.KindSessionRecordingConfig, services.RO()),
|
||||
types.NewRule(types.KindClusterName, services.RO()),
|
||||
|
@ -478,6 +483,7 @@ func GetCheckerForBuiltinRole(clusterName string, recConfig types.SessionRecordi
|
|||
types.NewRule(types.KindRole, services.RO()),
|
||||
types.NewRule(types.KindClusterAuthPreference, services.RO()),
|
||||
types.NewRule(types.KindClusterConfig, services.RO()),
|
||||
types.NewRule(types.KindClusterAuditConfig, services.RO()),
|
||||
types.NewRule(types.KindClusterNetworkingConfig, services.RO()),
|
||||
types.NewRule(types.KindSessionRecordingConfig, services.RO()),
|
||||
types.NewRule(types.KindClusterName, services.RO()),
|
||||
|
@ -559,6 +565,7 @@ func GetCheckerForBuiltinRole(clusterName string, recConfig types.SessionRecordi
|
|||
types.NewRule(types.KindEvent, services.RW()),
|
||||
types.NewRule(types.KindCertAuthority, services.ReadNoSecrets()),
|
||||
types.NewRule(types.KindClusterConfig, services.RO()),
|
||||
types.NewRule(types.KindClusterAuditConfig, services.RO()),
|
||||
types.NewRule(types.KindClusterNetworkingConfig, services.RO()),
|
||||
types.NewRule(types.KindSessionRecordingConfig, services.RO()),
|
||||
types.NewRule(types.KindClusterAuthPreference, services.RO()),
|
||||
|
|
|
@ -3034,7 +3034,7 @@ func (s *TLSSuite) TestEvents(c *check.C) {
|
|||
suite.Events(c)
|
||||
}
|
||||
|
||||
// TestEventsClusterConifg test cluster configuration
|
||||
// TestEventsClusterConfig test cluster configuration
|
||||
func (s *TLSSuite) TestEventsClusterConfig(c *check.C) {
|
||||
clt, err := s.server.NewClient(TestBuiltin(types.RoleAdmin))
|
||||
c.Assert(err, check.IsNil)
|
||||
|
@ -3120,17 +3120,15 @@ func (s *TLSSuite) TestEventsClusterConfig(c *check.C) {
|
|||
},
|
||||
})
|
||||
|
||||
// update cluster config
|
||||
clusterConfig, err := types.NewClusterConfig(types.ClusterConfigSpecV3{
|
||||
Audit: types.AuditConfig{
|
||||
AuditEventsURI: []string{"dynamodb://audit_table_name", "file:///home/log"},
|
||||
},
|
||||
// update audit config
|
||||
auditConfig, err := types.NewClusterAuditConfig(types.ClusterAuditConfigSpecV2{
|
||||
AuditEventsURI: []string{"dynamodb://audit_table_name", "file:///home/log"},
|
||||
})
|
||||
c.Assert(err, check.IsNil)
|
||||
err = s.server.Auth().SetClusterConfig(clusterConfig)
|
||||
err = s.server.Auth().SetClusterAuditConfig(ctx, auditConfig)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
clusterConfig, err = s.server.Auth().GetClusterConfig()
|
||||
clusterConfig, err := s.server.Auth().GetClusterConfig()
|
||||
c.Assert(err, check.IsNil)
|
||||
suite.ExpectResource(c, w, 3*time.Second, clusterConfig)
|
||||
|
||||
|
|
|
@ -108,6 +108,7 @@ func newTestAuthServer(ctx context.Context, t *testing.T, name ...string) *Serve
|
|||
a, err := NewServer(authConfig)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { a.Close() })
|
||||
require.NoError(t, a.SetClusterAuditConfig(ctx, types.DefaultClusterAuditConfig()))
|
||||
require.NoError(t, a.SetClusterNetworkingConfig(ctx, types.DefaultClusterNetworkingConfig()))
|
||||
require.NoError(t, a.SetSessionRecordingConfig(ctx, types.DefaultSessionRecordingConfig()))
|
||||
require.NoError(t, a.SetAuthPreference(types.DefaultAuthPreference()))
|
||||
|
|
|
@ -189,7 +189,7 @@ type Config struct {
|
|||
Type string `yaml:"type,omitempty"`
|
||||
|
||||
// Params is a generic key/value property bag which allows arbitrary
|
||||
// falues to be passed to backend
|
||||
// values to be passed to backend
|
||||
Params Params `yaml:",inline"`
|
||||
}
|
||||
|
||||
|
|
18
lib/cache/cache.go
vendored
18
lib/cache/cache.go
vendored
|
@ -47,6 +47,7 @@ func ForAuth(cfg Config) Config {
|
|||
{Kind: types.KindCertAuthority, LoadSecrets: true},
|
||||
{Kind: types.KindClusterName},
|
||||
{Kind: types.KindClusterConfig},
|
||||
{Kind: types.KindClusterAuditConfig},
|
||||
{Kind: types.KindClusterNetworkingConfig},
|
||||
{Kind: types.KindClusterAuthPreference},
|
||||
{Kind: types.KindSessionRecordingConfig},
|
||||
|
@ -80,6 +81,7 @@ func ForProxy(cfg Config) Config {
|
|||
{Kind: types.KindCertAuthority, LoadSecrets: false},
|
||||
{Kind: types.KindClusterName},
|
||||
{Kind: types.KindClusterConfig},
|
||||
{Kind: types.KindClusterAuditConfig},
|
||||
{Kind: types.KindClusterNetworkingConfig},
|
||||
{Kind: types.KindClusterAuthPreference},
|
||||
{Kind: types.KindSessionRecordingConfig},
|
||||
|
@ -110,6 +112,7 @@ func ForRemoteProxy(cfg Config) Config {
|
|||
{Kind: types.KindCertAuthority, LoadSecrets: false},
|
||||
{Kind: types.KindClusterName},
|
||||
{Kind: types.KindClusterConfig},
|
||||
{Kind: types.KindClusterAuditConfig},
|
||||
{Kind: types.KindClusterNetworkingConfig},
|
||||
{Kind: types.KindClusterAuthPreference},
|
||||
{Kind: types.KindSessionRecordingConfig},
|
||||
|
@ -139,6 +142,7 @@ func ForOldRemoteProxy(cfg Config) Config {
|
|||
{Kind: types.KindCertAuthority, LoadSecrets: false},
|
||||
{Kind: types.KindClusterName},
|
||||
{Kind: types.KindClusterConfig},
|
||||
{Kind: types.KindClusterAuditConfig},
|
||||
{Kind: types.KindClusterNetworkingConfig},
|
||||
{Kind: types.KindClusterAuthPreference},
|
||||
{Kind: types.KindSessionRecordingConfig},
|
||||
|
@ -165,6 +169,7 @@ func ForNode(cfg Config) Config {
|
|||
{Kind: types.KindCertAuthority, LoadSecrets: false},
|
||||
{Kind: types.KindClusterName},
|
||||
{Kind: types.KindClusterConfig},
|
||||
{Kind: types.KindClusterAuditConfig},
|
||||
{Kind: types.KindClusterNetworkingConfig},
|
||||
{Kind: types.KindClusterAuthPreference},
|
||||
{Kind: types.KindSessionRecordingConfig},
|
||||
|
@ -186,6 +191,7 @@ func ForKubernetes(cfg Config) Config {
|
|||
{Kind: types.KindCertAuthority, LoadSecrets: false},
|
||||
{Kind: types.KindClusterName},
|
||||
{Kind: types.KindClusterConfig},
|
||||
{Kind: types.KindClusterAuditConfig},
|
||||
{Kind: types.KindClusterNetworkingConfig},
|
||||
{Kind: types.KindClusterAuthPreference},
|
||||
{Kind: types.KindSessionRecordingConfig},
|
||||
|
@ -205,6 +211,7 @@ func ForApps(cfg Config) Config {
|
|||
{Kind: types.KindCertAuthority, LoadSecrets: false},
|
||||
{Kind: types.KindClusterName},
|
||||
{Kind: types.KindClusterConfig},
|
||||
{Kind: types.KindClusterAuditConfig},
|
||||
{Kind: types.KindClusterNetworkingConfig},
|
||||
{Kind: types.KindClusterAuthPreference},
|
||||
{Kind: types.KindSessionRecordingConfig},
|
||||
|
@ -225,6 +232,7 @@ func ForDatabases(cfg Config) Config {
|
|||
{Kind: types.KindCertAuthority, LoadSecrets: false},
|
||||
{Kind: types.KindClusterName},
|
||||
{Kind: types.KindClusterConfig},
|
||||
{Kind: types.KindClusterAuditConfig},
|
||||
{Kind: types.KindClusterNetworkingConfig},
|
||||
{Kind: types.KindClusterAuthPreference},
|
||||
{Kind: types.KindSessionRecordingConfig},
|
||||
|
@ -1040,6 +1048,16 @@ func (c *Cache) GetClusterConfig(opts ...services.MarshalOption) (types.ClusterC
|
|||
return rg.clusterConfig.GetClusterConfig(opts...)
|
||||
}
|
||||
|
||||
// GetClusterAuditConfig gets ClusterAuditConfig from the backend.
|
||||
func (c *Cache) GetClusterAuditConfig(ctx context.Context, opts ...services.MarshalOption) (types.ClusterAuditConfig, error) {
|
||||
rg, err := c.read()
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
defer rg.Release()
|
||||
return rg.clusterConfig.GetClusterAuditConfig(ctx, opts...)
|
||||
}
|
||||
|
||||
// GetClusterNetworkingConfig gets ClusterNetworkingConfig from the backend.
|
||||
func (c *Cache) GetClusterNetworkingConfig(ctx context.Context, opts ...services.MarshalOption) (types.ClusterNetworkingConfig, error) {
|
||||
rg, err := c.read()
|
||||
|
|
28
lib/cache/cache_test.go
vendored
28
lib/cache/cache_test.go
vendored
|
@ -842,11 +842,12 @@ func (s *CacheSuite) TestTokens(c *check.C) {
|
|||
|
||||
// TestClusterConfig tests cluster configuration
|
||||
func (s *CacheSuite) TestClusterConfig(c *check.C) {
|
||||
ctx := context.Background()
|
||||
p := s.newPackForAuth(c)
|
||||
defer p.Close()
|
||||
|
||||
// DELETE IN 8.0.0
|
||||
err := p.clusterConfigS.SetClusterNetworkingConfig(context.TODO(), types.DefaultClusterNetworkingConfig())
|
||||
err := p.clusterConfigS.SetClusterNetworkingConfig(ctx, types.DefaultClusterNetworkingConfig())
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
select {
|
||||
|
@ -867,8 +868,7 @@ func (s *CacheSuite) TestClusterConfig(c *check.C) {
|
|||
c.Fatalf("timeout waiting for event")
|
||||
}
|
||||
|
||||
// DELETE IN 8.0.0
|
||||
err = p.clusterConfigS.SetSessionRecordingConfig(context.TODO(), types.DefaultSessionRecordingConfig())
|
||||
err = p.clusterConfigS.SetSessionRecordingConfig(ctx, types.DefaultSessionRecordingConfig())
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
select {
|
||||
|
@ -878,17 +878,25 @@ func (s *CacheSuite) TestClusterConfig(c *check.C) {
|
|||
c.Fatalf("timeout waiting for event")
|
||||
}
|
||||
|
||||
// update cluster config
|
||||
clusterConfig, err := types.NewClusterConfig(types.ClusterConfigSpecV3{
|
||||
Audit: types.AuditConfig{
|
||||
AuditEventsURI: []string{"dynamodb://audit_table_name", "file:///home/log"},
|
||||
},
|
||||
// DELETE IN 8.0.0
|
||||
auditConfig, err := types.NewClusterAuditConfig(types.ClusterAuditConfigSpecV2{
|
||||
AuditEventsURI: []string{"dynamodb://audit_table_name", "file:///home/log"},
|
||||
})
|
||||
c.Assert(err, check.IsNil)
|
||||
err = p.clusterConfigS.SetClusterConfig(clusterConfig)
|
||||
err = p.clusterConfigS.SetClusterAuditConfig(ctx, auditConfig)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
clusterConfig, err = p.clusterConfigS.GetClusterConfig()
|
||||
select {
|
||||
case event := <-p.eventsC:
|
||||
c.Assert(event.Type, check.Equals, EventProcessed)
|
||||
case <-time.After(time.Second):
|
||||
c.Fatalf("timeout waiting for event")
|
||||
}
|
||||
|
||||
err = p.clusterConfigS.SetClusterConfig(services.DefaultClusterConfig())
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
clusterConfig, err := p.clusterConfigS.GetClusterConfig()
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
select {
|
||||
|
|
75
lib/cache/collections.go
vendored
75
lib/cache/collections.go
vendored
|
@ -73,6 +73,11 @@ func setupCollections(c *Cache, watches []types.WatchKind) (map[resourceKind]col
|
|||
return nil, trace.BadParameter("missing parameter ClusterConfig")
|
||||
}
|
||||
collections[resourceKind] = &clusterConfig{watch: watch, Cache: c}
|
||||
case types.KindClusterAuditConfig:
|
||||
if c.ClusterConfig == nil {
|
||||
return nil, trace.BadParameter("missing parameter ClusterConfig")
|
||||
}
|
||||
collections[resourceKind] = &clusterAuditConfig{watch: watch, Cache: c}
|
||||
case types.KindClusterNetworkingConfig:
|
||||
if c.ClusterConfig == nil {
|
||||
return nil, trace.BadParameter("missing parameter ClusterConfig")
|
||||
|
@ -1761,6 +1766,76 @@ func (c *authPreference) watchKind() types.WatchKind {
|
|||
return c.watch
|
||||
}
|
||||
|
||||
type clusterAuditConfig struct {
|
||||
*Cache
|
||||
watch types.WatchKind
|
||||
}
|
||||
|
||||
func (c *clusterAuditConfig) erase(ctx context.Context) error {
|
||||
if err := c.clusterConfigCache.DeleteClusterAuditConfig(ctx); err != nil {
|
||||
if !trace.IsNotFound(err) {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *clusterAuditConfig) fetch(ctx context.Context) (apply func(ctx context.Context) error, err error) {
|
||||
var noConfig bool
|
||||
resource, err := c.ClusterConfig.GetClusterAuditConfig(ctx)
|
||||
if err != nil {
|
||||
if !trace.IsNotFound(err) {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
noConfig = true
|
||||
}
|
||||
return func(ctx context.Context) error {
|
||||
// either zero or one instance exists, so we either erase or
|
||||
// update, but not both.
|
||||
if noConfig {
|
||||
if err := c.erase(ctx); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
c.setTTL(resource)
|
||||
if err := c.clusterConfigCache.SetClusterAuditConfig(ctx, resource); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *clusterAuditConfig) processEvent(ctx context.Context, event types.Event) error {
|
||||
switch event.Type {
|
||||
case types.OpDelete:
|
||||
err := c.clusterConfigCache.DeleteClusterAuditConfig(ctx)
|
||||
if err != nil {
|
||||
if !trace.IsNotFound(err) {
|
||||
c.Warningf("Failed to delete resource %v.", err)
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
}
|
||||
case types.OpPut:
|
||||
resource, ok := event.Resource.(types.ClusterAuditConfig)
|
||||
if !ok {
|
||||
return trace.BadParameter("unexpected type %T", event.Resource)
|
||||
}
|
||||
c.setTTL(resource)
|
||||
if err := c.clusterConfigCache.SetClusterAuditConfig(ctx, resource); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
default:
|
||||
c.Warningf("Skipping unsupported event type %v.", event.Type)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *clusterAuditConfig) watchKind() types.WatchKind {
|
||||
return c.watch
|
||||
}
|
||||
|
||||
type clusterNetworkingConfig struct {
|
||||
*Cache
|
||||
watch types.WatchKind
|
||||
|
|
|
@ -502,16 +502,13 @@ func applyAuthConfig(fc *FileConfig, cfg *service.Config) error {
|
|||
log.Warnf(warningMessage)
|
||||
}
|
||||
|
||||
auditConfig, err := services.AuditConfigFromObject(fc.Storage.Params)
|
||||
// Set cluster audit configuration from file configuration.
|
||||
auditConfigSpec, err := services.ClusterAuditConfigSpecFromObject(fc.Storage.Params)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
auditConfig.Type = fc.Storage.Type
|
||||
|
||||
// Set cluster-wide configuration from file configuration.
|
||||
cfg.Auth.ClusterConfig, err = types.NewClusterConfig(types.ClusterConfigSpecV3{
|
||||
Audit: *auditConfig,
|
||||
})
|
||||
auditConfigSpec.Type = fc.Storage.Type
|
||||
cfg.Auth.AuditConfig, err = types.NewClusterAuditConfig(*auditConfigSpec)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
|
|
@ -495,6 +495,9 @@ type AuthConfig struct {
|
|||
// ClusterConfig stores cluster level configuration.
|
||||
ClusterConfig types.ClusterConfig
|
||||
|
||||
// AuditConfig stores cluster audit configuration.
|
||||
AuditConfig types.ClusterAuditConfig
|
||||
|
||||
// NetworkingConfig stores cluster networking configuration.
|
||||
NetworkingConfig types.ClusterNetworkingConfig
|
||||
|
||||
|
@ -854,6 +857,7 @@ func ApplyDefaults(cfg *Config) {
|
|||
cfg.Auth.StorageConfig.Params = backend.Params{defaults.BackendPath: filepath.Join(cfg.DataDir, defaults.BackendDir)}
|
||||
cfg.Auth.StaticTokens = services.DefaultStaticTokens()
|
||||
cfg.Auth.ClusterConfig = services.DefaultClusterConfig()
|
||||
cfg.Auth.AuditConfig = types.DefaultClusterAuditConfig()
|
||||
cfg.Auth.NetworkingConfig = types.DefaultClusterNetworkingConfig()
|
||||
cfg.Auth.SessionRecordingConfig = types.DefaultSessionRecordingConfig()
|
||||
cfg.Auth.Preference = types.DefaultAuthPreference()
|
||||
|
|
|
@ -867,8 +867,8 @@ func adminCreds() (*int, *int, error) {
|
|||
// initUploadHandler initializes upload handler based on the config settings,
|
||||
// currently the only upload handler supported is S3
|
||||
// the call can return trace.NotFound if no upload handler is setup
|
||||
func initUploadHandler(auditConfig types.AuditConfig, dataDir string) (events.MultipartHandler, error) {
|
||||
if auditConfig.AuditSessionsURI == "" {
|
||||
func initUploadHandler(auditConfig types.ClusterAuditConfig, dataDir string) (events.MultipartHandler, error) {
|
||||
if !auditConfig.ShouldUploadSessions() {
|
||||
recordsDir := filepath.Join(dataDir, events.RecordsDir)
|
||||
if err := os.MkdirAll(recordsDir, teleport.SharedDirMode); err != nil {
|
||||
return nil, trace.ConvertSystemError(err)
|
||||
|
@ -888,7 +888,7 @@ func initUploadHandler(auditConfig types.AuditConfig, dataDir string) (events.Mu
|
|||
}
|
||||
return wrapper, nil
|
||||
}
|
||||
uri, err := utils.ParseSessionsURI(auditConfig.AuditSessionsURI)
|
||||
uri, err := utils.ParseSessionsURI(auditConfig.AuditSessionsURI())
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
@ -906,7 +906,7 @@ func initUploadHandler(auditConfig types.AuditConfig, dataDir string) (events.Mu
|
|||
return handler, nil
|
||||
case teleport.SchemeS3:
|
||||
config := s3sessions.Config{}
|
||||
if err := config.SetFromURL(uri, auditConfig.Region); err != nil {
|
||||
if err := config.SetFromURL(uri, auditConfig.Region()); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
handler, err := s3sessions.NewHandler(config)
|
||||
|
@ -934,22 +934,10 @@ func initUploadHandler(auditConfig types.AuditConfig, dataDir string) (events.Mu
|
|||
|
||||
// initExternalLog initializes external storage, if the storage is not
|
||||
// setup, returns (nil, nil).
|
||||
func initExternalLog(ctx context.Context, auditConfig types.AuditConfig, log logrus.FieldLogger, backend backend.Backend) (events.IAuditLog, error) {
|
||||
//
|
||||
// DELETE IN: 5.0
|
||||
// We could probably just remove AuditTableName now (its been deprecated for a while), but
|
||||
// its probably more polite to delete it on a major release transition.
|
||||
//
|
||||
if auditConfig.AuditTableName != "" {
|
||||
log.Warningf("Please note that 'audit_table_name' is deprecated and will be removed in several releases. Use audit_events_uri: '%v://%v' instead.", dynamo.GetName(), auditConfig.AuditTableName)
|
||||
if len(auditConfig.AuditEventsURI) != 0 {
|
||||
return nil, trace.BadParameter("Detected configuration specifying 'audit_table_name' and 'audit_events_uri' at the same time. Please migrate your config to use 'audit_events_uri' only.")
|
||||
}
|
||||
auditConfig.AuditEventsURI = []string{fmt.Sprintf("%v://%v", dynamo.GetName(), auditConfig.AuditTableName)}
|
||||
}
|
||||
func initExternalLog(ctx context.Context, auditConfig types.ClusterAuditConfig, log logrus.FieldLogger, backend backend.Backend) (events.IAuditLog, error) {
|
||||
var hasNonFileLog bool
|
||||
var loggers []events.IAuditLog
|
||||
for _, eventsURI := range auditConfig.AuditEventsURI {
|
||||
for _, eventsURI := range auditConfig.AuditEventsURIs() {
|
||||
uri, err := utils.ParseSessionsURI(eventsURI)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
|
@ -971,15 +959,15 @@ func initExternalLog(ctx context.Context, auditConfig types.AuditConfig, log log
|
|||
hasNonFileLog = true
|
||||
cfg := dynamoevents.Config{
|
||||
Tablename: uri.Host,
|
||||
Region: auditConfig.Region,
|
||||
EnableContinuousBackups: auditConfig.EnableContinuousBackups,
|
||||
EnableAutoScaling: auditConfig.EnableAutoScaling,
|
||||
ReadMinCapacity: auditConfig.ReadMinCapacity,
|
||||
ReadMaxCapacity: auditConfig.ReadMaxCapacity,
|
||||
ReadTargetValue: auditConfig.ReadTargetValue,
|
||||
WriteMinCapacity: auditConfig.WriteMinCapacity,
|
||||
WriteMaxCapacity: auditConfig.WriteMaxCapacity,
|
||||
WriteTargetValue: auditConfig.WriteTargetValue,
|
||||
Region: auditConfig.Region(),
|
||||
EnableContinuousBackups: auditConfig.EnableContinuousBackups(),
|
||||
EnableAutoScaling: auditConfig.EnableAutoScaling(),
|
||||
ReadMinCapacity: auditConfig.ReadMinCapacity(),
|
||||
ReadMaxCapacity: auditConfig.ReadMaxCapacity(),
|
||||
ReadTargetValue: auditConfig.ReadTargetValue(),
|
||||
WriteMinCapacity: auditConfig.WriteMinCapacity(),
|
||||
WriteMaxCapacity: auditConfig.WriteMaxCapacity(),
|
||||
WriteTargetValue: auditConfig.WriteTargetValue(),
|
||||
}
|
||||
err = cfg.SetFromURL(uri)
|
||||
if err != nil {
|
||||
|
@ -1022,7 +1010,7 @@ func initExternalLog(ctx context.Context, auditConfig types.AuditConfig, log log
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
if !services.ShouldUploadSessions(auditConfig) && hasNonFileLog {
|
||||
if !auditConfig.ShouldUploadSessions() && hasNonFileLog {
|
||||
// if audit events are being exported, session recordings should
|
||||
// be exported as well.
|
||||
return nil, trace.BadParameter("please specify audit_sessions_uri when using external audit backends")
|
||||
|
@ -1075,7 +1063,7 @@ func (process *TeleportProcess) initAuthService() error {
|
|||
process.log.Warn(warningMessage)
|
||||
}
|
||||
|
||||
auditConfig := cfg.Auth.ClusterConfig.GetAuditConfig()
|
||||
auditConfig := cfg.Auth.AuditConfig
|
||||
uploadHandler, err = initUploadHandler(
|
||||
auditConfig, filepath.Join(cfg.DataDir, teleport.LogsDir))
|
||||
if err != nil {
|
||||
|
@ -1164,6 +1152,7 @@ func (process *TeleportProcess) initAuthService() error {
|
|||
Authority: cfg.Keygen,
|
||||
ClusterConfiguration: cfg.ClusterConfiguration,
|
||||
ClusterConfig: cfg.Auth.ClusterConfig,
|
||||
ClusterAuditConfig: cfg.Auth.AuditConfig,
|
||||
ClusterNetworkingConfig: cfg.Auth.NetworkingConfig,
|
||||
SessionRecordingConfig: cfg.Auth.SessionRecordingConfig,
|
||||
ClusterName: cfg.Auth.ClusterName,
|
||||
|
|
|
@ -276,9 +276,11 @@ func (s *ServiceTestSuite) TestInitExternalLog(c *check.C) {
|
|||
|
||||
cmt := check.Commentf("tt[%v]: %+v", i, tt)
|
||||
|
||||
loggers, err := initExternalLog(context.Background(), types.AuditConfig{
|
||||
auditConfig, err := types.NewClusterAuditConfig(types.ClusterAuditConfigSpecV2{
|
||||
AuditEventsURI: tt.events,
|
||||
}, t.Log, backend)
|
||||
})
|
||||
c.Assert(err, check.IsNil, cmt)
|
||||
loggers, err := initExternalLog(context.Background(), auditConfig, t.Log, backend)
|
||||
|
||||
if tt.isErr {
|
||||
c.Assert(err, check.NotNil, cmt)
|
||||
|
|
90
lib/services/audit.go
Normal file
90
lib/services/audit.go
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
Copyright 2021 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 (
|
||||
"github.com/gravitational/teleport/api/types"
|
||||
"github.com/gravitational/teleport/lib/utils"
|
||||
"github.com/gravitational/trace"
|
||||
)
|
||||
|
||||
// ClusterAuditConfigSpecFromObject returns audit config spec from object.
|
||||
func ClusterAuditConfigSpecFromObject(in interface{}) (*types.ClusterAuditConfigSpecV2, error) {
|
||||
var cfg types.ClusterAuditConfigSpecV2
|
||||
if in == nil {
|
||||
return &cfg, nil
|
||||
}
|
||||
if err := utils.ObjectToStruct(in, &cfg); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
// UnmarshalClusterAuditConfig unmarshals the ClusterAuditConfig resource from JSON.
|
||||
func UnmarshalClusterAuditConfig(bytes []byte, opts ...MarshalOption) (types.ClusterAuditConfig, error) {
|
||||
var auditConfig types.ClusterAuditConfigV2
|
||||
|
||||
if len(bytes) == 0 {
|
||||
return nil, trace.BadParameter("missing resource data")
|
||||
}
|
||||
|
||||
cfg, err := CollectOptions(opts)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
if err := utils.FastUnmarshal(bytes, &auditConfig); err != nil {
|
||||
return nil, trace.BadParameter(err.Error())
|
||||
}
|
||||
if err := auditConfig.CheckAndSetDefaults(); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
if cfg.ID != 0 {
|
||||
auditConfig.SetResourceID(cfg.ID)
|
||||
}
|
||||
if !cfg.Expires.IsZero() {
|
||||
auditConfig.SetExpiry(cfg.Expires)
|
||||
}
|
||||
return &auditConfig, nil
|
||||
}
|
||||
|
||||
// MarshalClusterAuditConfig marshals the ClusterAuditConfig resource to JSON.
|
||||
func MarshalClusterAuditConfig(auditConfig types.ClusterAuditConfig, opts ...MarshalOption) ([]byte, error) {
|
||||
if err := auditConfig.CheckAndSetDefaults(); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
cfg, err := CollectOptions(opts)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
switch auditConfig := auditConfig.(type) {
|
||||
case *types.ClusterAuditConfigV2:
|
||||
if !cfg.PreserveResourceID {
|
||||
// avoid modifying the original object
|
||||
// to prevent unexpected data races
|
||||
copy := *auditConfig
|
||||
copy.SetResourceID(0)
|
||||
auditConfig = ©
|
||||
}
|
||||
return utils.FastMarshal(auditConfig)
|
||||
default:
|
||||
return nil, trace.BadParameter("unrecognized cluster audit config version %T", auditConfig)
|
||||
}
|
||||
}
|
|
@ -113,11 +113,6 @@ func UnmarshalAuthPreference(bytes []byte, opts ...MarshalOption) (types.AuthPre
|
|||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
err = authPreference.CheckAndSetDefaults()
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
if cfg.ID != 0 {
|
||||
authPreference.SetResourceID(cfg.ID)
|
||||
}
|
||||
|
|
|
@ -38,24 +38,6 @@ func DefaultClusterConfig() types.ClusterConfig {
|
|||
}
|
||||
}
|
||||
|
||||
// AuditConfigFromObject returns audit config from interface object
|
||||
func AuditConfigFromObject(in interface{}) (*types.AuditConfig, error) {
|
||||
var cfg types.AuditConfig
|
||||
if in == nil {
|
||||
return &cfg, nil
|
||||
}
|
||||
if err := utils.ObjectToStruct(in, &cfg); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
// ShouldUploadSessions returns whether audit config
|
||||
// instructs server to upload sessions
|
||||
func ShouldUploadSessions(a types.AuditConfig) bool {
|
||||
return a.AuditSessionsURI != ""
|
||||
}
|
||||
|
||||
// UnmarshalClusterConfig unmarshals the ClusterConfig resource from JSON.
|
||||
func UnmarshalClusterConfig(bytes []byte, opts ...MarshalOption) (types.ClusterConfig, error) {
|
||||
var clusterConfig types.ClusterConfigV3
|
||||
|
|
|
@ -64,6 +64,13 @@ type ClusterConfiguration interface {
|
|||
// DeleteClusterConfig deletes cluster config resource
|
||||
DeleteClusterConfig() error
|
||||
|
||||
// GetClusterAuditConfig gets ClusterAuditConfig from the backend.
|
||||
GetClusterAuditConfig(context.Context, ...MarshalOption) (types.ClusterAuditConfig, error)
|
||||
// SetClusterAuditConfig sets ClusterAuditConfig from the backend.
|
||||
SetClusterAuditConfig(context.Context, types.ClusterAuditConfig) error
|
||||
// DeleteClusterAuditConfig deletes ClusterAuditConfig from the backend.
|
||||
DeleteClusterAuditConfig(ctx context.Context) error
|
||||
|
||||
// GetClusterNetworkingConfig gets ClusterNetworkingConfig from the backend.
|
||||
GetClusterNetworkingConfig(context.Context, ...MarshalOption) (types.ClusterNetworkingConfig, error)
|
||||
// SetClusterNetworkingConfig sets ClusterNetworkingConfig from the backend.
|
||||
|
|
|
@ -233,6 +233,17 @@ func (s *ClusterConfigurationService) GetClusterConfig(opts ...services.MarshalO
|
|||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
// To ensure backward compatibility, extend the fetched ClusterConfig
|
||||
// resource with the values that are now stored in ClusterAuditConfig.
|
||||
// DELETE IN 8.0.0
|
||||
auditConfig, err := s.GetClusterAuditConfig(context.TODO())
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
if err := clusterConfig.SetAuditConfig(auditConfig); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
// To ensure backward compatibility, extend the fetched ClusterConfig
|
||||
// resource with the values that are now stored in ClusterNetworkingConfig.
|
||||
// DELETE IN 8.0.0
|
||||
|
@ -283,6 +294,9 @@ func (s *ClusterConfigurationService) DeleteClusterConfig() error {
|
|||
|
||||
// SetClusterConfig sets services.ClusterConfig on the backend.
|
||||
func (s *ClusterConfigurationService) SetClusterConfig(c types.ClusterConfig) error {
|
||||
if c.HasAuditConfig() {
|
||||
return trace.BadParameter("cluster config has legacy audit config, call SetClusterAuditConfig to set these fields")
|
||||
}
|
||||
if c.HasNetworkingFields() {
|
||||
return trace.BadParameter("cluster config has legacy networking fields, call SetClusterNetworkingConfig to set these fields")
|
||||
}
|
||||
|
@ -312,6 +326,50 @@ func (s *ClusterConfigurationService) SetClusterConfig(c types.ClusterConfig) er
|
|||
return nil
|
||||
}
|
||||
|
||||
// GetClusterAuditConfig gets cluster audit config from the backend.
|
||||
func (s *ClusterConfigurationService) GetClusterAuditConfig(ctx context.Context, opts ...services.MarshalOption) (types.ClusterAuditConfig, error) {
|
||||
item, err := s.Get(ctx, backend.Key(clusterConfigPrefix, auditPrefix))
|
||||
if err != nil {
|
||||
if trace.IsNotFound(err) {
|
||||
return nil, trace.NotFound("cluster audit config not found")
|
||||
}
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return services.UnmarshalClusterAuditConfig(item.Value, append(opts, services.WithResourceID(item.ID), services.WithExpires(item.Expires))...)
|
||||
}
|
||||
|
||||
// SetClusterAuditConfig sets the cluster audit config on the backend.
|
||||
func (s *ClusterConfigurationService) SetClusterAuditConfig(ctx context.Context, auditConfig types.ClusterAuditConfig) error {
|
||||
value, err := services.MarshalClusterAuditConfig(auditConfig)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
item := backend.Item{
|
||||
Key: backend.Key(clusterConfigPrefix, auditPrefix),
|
||||
Value: value,
|
||||
ID: auditConfig.GetResourceID(),
|
||||
}
|
||||
|
||||
_, err = s.Put(ctx, item)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteClusterAuditConfig deletes ClusterAuditConfig from the backend.
|
||||
func (s *ClusterConfigurationService) DeleteClusterAuditConfig(ctx context.Context) error {
|
||||
err := s.Delete(ctx, backend.Key(clusterConfigPrefix, auditPrefix))
|
||||
if err != nil {
|
||||
if trace.IsNotFound(err) {
|
||||
return trace.NotFound("cluster audit config not found")
|
||||
}
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetClusterNetworkingConfig gets cluster networking config from the backend.
|
||||
func (s *ClusterConfigurationService) GetClusterNetworkingConfig(ctx context.Context, opts ...services.MarshalOption) (types.ClusterNetworkingConfig, error) {
|
||||
item, err := s.Get(ctx, backend.Key(clusterConfigPrefix, networkingPrefix))
|
||||
|
@ -418,6 +476,7 @@ const (
|
|||
authPrefix = "authentication"
|
||||
preferencePrefix = "preference"
|
||||
generalPrefix = "general"
|
||||
auditPrefix = "audit"
|
||||
networkingPrefix = "networking"
|
||||
sessionRecordingPrefix = "session_recording"
|
||||
)
|
||||
|
|
|
@ -114,96 +114,87 @@ func (s *ClusterConfigurationSuite) TestSessionRecording(c *check.C) {
|
|||
}
|
||||
|
||||
func (s *ClusterConfigurationSuite) TestAuditConfig(c *check.C) {
|
||||
// default is to record at the node
|
||||
clusterConfig, err := types.NewClusterConfig(types.ClusterConfigSpecV3{})
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
cfg := clusterConfig.GetAuditConfig()
|
||||
c.Assert(cfg, check.DeepEquals, types.AuditConfig{})
|
||||
|
||||
// update sessions to be recorded at the proxy and check again
|
||||
in := types.AuditConfig{
|
||||
Region: "us-west-1",
|
||||
Type: "dynamodb",
|
||||
AuditSessionsURI: "file:///home/log",
|
||||
AuditTableName: "audit_table_name",
|
||||
AuditEventsURI: []string{"dynamodb://audit_table_name", "file:///home/log"},
|
||||
}
|
||||
clusterConfig.SetAuditConfig(in)
|
||||
out := clusterConfig.GetAuditConfig()
|
||||
fixtures.DeepCompare(c, out, in)
|
||||
|
||||
config := `
|
||||
testCases := []struct {
|
||||
spec types.ClusterAuditConfigSpecV2
|
||||
config string
|
||||
}{
|
||||
{
|
||||
spec: types.ClusterAuditConfigSpecV2{
|
||||
Region: "us-west-1",
|
||||
Type: "dynamodb",
|
||||
AuditSessionsURI: "file:///home/log",
|
||||
AuditEventsURI: []string{"dynamodb://audit_table_name", "file:///home/log"},
|
||||
},
|
||||
config: `
|
||||
region: 'us-west-1'
|
||||
type: 'dynamodb'
|
||||
audit_sessions_uri: file:///home/log
|
||||
audit_table_name: audit_table_name
|
||||
audit_events_uri: ['dynamodb://audit_table_name', 'file:///home/log']
|
||||
`
|
||||
var data map[string]interface{}
|
||||
err = yaml.Unmarshal([]byte(config), &data)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
out2, err := services.AuditConfigFromObject(data)
|
||||
c.Assert(err, check.IsNil)
|
||||
fixtures.DeepCompare(c, *out2, in)
|
||||
|
||||
config = `
|
||||
`,
|
||||
},
|
||||
{
|
||||
spec: types.ClusterAuditConfigSpecV2{
|
||||
Region: "us-west-1",
|
||||
Type: "dir",
|
||||
AuditSessionsURI: "file:///home/log",
|
||||
AuditEventsURI: []string{"dynamodb://audit_table_name"},
|
||||
},
|
||||
config: `
|
||||
region: 'us-west-1'
|
||||
type: 'dir'
|
||||
audit_sessions_uri: file:///home/log
|
||||
audit_events_uri: 'dynamodb://audit_table_name'
|
||||
`
|
||||
data = nil
|
||||
err = yaml.Unmarshal([]byte(config), &data)
|
||||
c.Assert(err, check.IsNil)
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
out2, err = services.AuditConfigFromObject(data)
|
||||
c.Assert(err, check.IsNil)
|
||||
fixtures.DeepCompare(c, *out2, types.AuditConfig{
|
||||
for _, tc := range testCases {
|
||||
in, err := types.NewClusterAuditConfig(tc.spec)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
var data map[string]interface{}
|
||||
err = yaml.Unmarshal([]byte(tc.config), &data)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
configSpec, err := services.ClusterAuditConfigSpecFromObject(data)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
out, err := types.NewClusterAuditConfig(*configSpec)
|
||||
c.Assert(err, check.IsNil)
|
||||
fixtures.DeepCompare(c, out, in)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ClusterConfigurationSuite) TestAuditConfigMarshal(c *check.C) {
|
||||
// single audit_events uri value
|
||||
auditConfig, err := types.NewClusterAuditConfig(types.ClusterAuditConfigSpecV2{
|
||||
Region: "us-west-1",
|
||||
Type: "dir",
|
||||
Type: "dynamodb",
|
||||
AuditSessionsURI: "file:///home/log",
|
||||
AuditEventsURI: []string{"dynamodb://audit_table_name"},
|
||||
})
|
||||
}
|
||||
|
||||
func (s *ClusterConfigurationSuite) TestClusterConfigMarshal(c *check.C) {
|
||||
// signle audit_events uri value
|
||||
clusterConfig, err := types.NewClusterConfig(types.ClusterConfigSpecV3{
|
||||
Audit: types.AuditConfig{
|
||||
Region: "us-west-1",
|
||||
Type: "dynamodb",
|
||||
AuditSessionsURI: "file:///home/log",
|
||||
AuditTableName: "audit_table_name",
|
||||
AuditEventsURI: []string{"dynamodb://audit_table_name"},
|
||||
},
|
||||
})
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
data, err := services.MarshalClusterConfig(clusterConfig)
|
||||
data, err := services.MarshalClusterAuditConfig(auditConfig)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
out, err := services.UnmarshalClusterConfig(data)
|
||||
out, err := services.UnmarshalClusterAuditConfig(data)
|
||||
c.Assert(err, check.IsNil)
|
||||
fixtures.DeepCompare(c, clusterConfig, out)
|
||||
fixtures.DeepCompare(c, auditConfig, out)
|
||||
|
||||
// multiple events uri values
|
||||
clusterConfig, err = types.NewClusterConfig(types.ClusterConfigSpecV3{
|
||||
Audit: types.AuditConfig{
|
||||
Region: "us-west-1",
|
||||
Type: "dynamodb",
|
||||
AuditSessionsURI: "file:///home/log",
|
||||
AuditTableName: "audit_table_name",
|
||||
AuditEventsURI: []string{"dynamodb://audit_table_name", "file:///home/test/log"},
|
||||
},
|
||||
auditConfig, err = types.NewClusterAuditConfig(types.ClusterAuditConfigSpecV2{
|
||||
Region: "us-west-1",
|
||||
Type: "dynamodb",
|
||||
AuditSessionsURI: "file:///home/log",
|
||||
AuditEventsURI: []string{"dynamodb://audit_table_name", "file:///home/test/log"},
|
||||
})
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
data, err = services.MarshalClusterConfig(clusterConfig)
|
||||
data, err = services.MarshalClusterAuditConfig(auditConfig)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
out, err = services.UnmarshalClusterConfig(data)
|
||||
out, err = services.UnmarshalClusterAuditConfig(data)
|
||||
c.Assert(err, check.IsNil)
|
||||
fixtures.DeepCompare(c, clusterConfig, out)
|
||||
fixtures.DeepCompare(c, auditConfig, out)
|
||||
}
|
||||
|
|
|
@ -68,6 +68,8 @@ func (e *EventsService) NewWatcher(ctx context.Context, watch types.Watch) (type
|
|||
parser = newStaticTokensParser()
|
||||
case types.KindClusterConfig:
|
||||
parser = newClusterConfigParser(e.getClusterConfig)
|
||||
case types.KindClusterAuditConfig:
|
||||
parser = newClusterAuditConfigParser()
|
||||
case types.KindClusterNetworkingConfig:
|
||||
parser = newClusterNetworkingConfigParser()
|
||||
case types.KindClusterAuthPreference:
|
||||
|
@ -364,6 +366,7 @@ func (p *staticTokensParser) parse(event backend.Event) (types.Resource, error)
|
|||
func newClusterConfigParser(getClusterConfig getClusterConfigFunc) *clusterConfigParser {
|
||||
prefixes := [][]byte{
|
||||
backend.Key(clusterConfigPrefix, generalPrefix),
|
||||
backend.Key(clusterConfigPrefix, auditPrefix),
|
||||
backend.Key(clusterConfigPrefix, networkingPrefix),
|
||||
backend.Key(clusterConfigPrefix, sessionRecordingPrefix),
|
||||
backend.Key(authPrefix, preferencePrefix, generalPrefix),
|
||||
|
@ -406,6 +409,40 @@ func (p *clusterConfigParser) parse(event backend.Event) (types.Resource, error)
|
|||
}
|
||||
}
|
||||
|
||||
func newClusterAuditConfigParser() *clusterAuditConfigParser {
|
||||
return &clusterAuditConfigParser{
|
||||
baseParser: newBaseParser(backend.Key(clusterConfigPrefix, auditPrefix)),
|
||||
}
|
||||
}
|
||||
|
||||
type clusterAuditConfigParser struct {
|
||||
baseParser
|
||||
}
|
||||
|
||||
func (p *clusterAuditConfigParser) parse(event backend.Event) (types.Resource, error) {
|
||||
switch event.Type {
|
||||
case types.OpDelete:
|
||||
h, err := resourceHeader(event, types.KindClusterAuditConfig, types.V2, 0)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
h.SetName(types.MetaNameClusterAuditConfig)
|
||||
return h, nil
|
||||
case types.OpPut:
|
||||
clusterAuditConfig, err := services.UnmarshalClusterAuditConfig(
|
||||
event.Item.Value,
|
||||
services.WithResourceID(event.Item.ID),
|
||||
services.WithExpires(event.Item.Expires),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return clusterAuditConfig, nil
|
||||
default:
|
||||
return nil, trace.BadParameter("event %v is not supported", event.Type)
|
||||
}
|
||||
}
|
||||
|
||||
func newClusterNetworkingConfigParser() *clusterNetworkingConfigParser {
|
||||
return &clusterNetworkingConfigParser{
|
||||
baseParser: newBaseParser(backend.Key(clusterConfigPrefix, networkingPrefix)),
|
||||
|
|
|
@ -1141,6 +1141,16 @@ func CollectOptions(opts ...Option) Options {
|
|||
|
||||
// ClusterConfig tests cluster configuration
|
||||
func (s *ServicesTestSuite) ClusterConfig(c *check.C, opts ...Option) {
|
||||
auditConfig, err := types.NewClusterAuditConfig(types.ClusterAuditConfigSpecV2{
|
||||
Region: "us-west-1",
|
||||
Type: "dynamodb",
|
||||
AuditSessionsURI: "file:///home/log",
|
||||
AuditEventsURI: []string{"dynamodb://audit_table_name", "file:///home/log"},
|
||||
})
|
||||
c.Assert(err, check.IsNil)
|
||||
err = s.ConfigS.SetClusterAuditConfig(context.TODO(), auditConfig)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
// DELETE IN 8.0.0
|
||||
netConfig, err := types.NewClusterNetworkingConfigFromConfigFile(types.ClusterNetworkingConfigSpecV2{
|
||||
ClientIdleTimeout: types.NewDuration(17 * time.Second),
|
||||
|
@ -1167,13 +1177,6 @@ func (s *ServicesTestSuite) ClusterConfig(c *check.C, opts ...Option) {
|
|||
|
||||
config, err := types.NewClusterConfig(types.ClusterConfigSpecV3{
|
||||
ClusterID: "27",
|
||||
Audit: types.AuditConfig{
|
||||
Region: "us-west-1",
|
||||
Type: "dynamodb",
|
||||
AuditSessionsURI: "file:///home/log",
|
||||
AuditTableName: "audit_table_name",
|
||||
AuditEventsURI: []string{"dynamodb://audit_table_name", "file:///home/log"},
|
||||
},
|
||||
})
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
|
@ -1183,6 +1186,7 @@ func (s *ServicesTestSuite) ClusterConfig(c *check.C, opts ...Option) {
|
|||
gotConfig, err := s.ConfigS.GetClusterConfig()
|
||||
c.Assert(err, check.IsNil)
|
||||
config.SetResourceID(gotConfig.GetResourceID())
|
||||
config.SetAuditConfig(auditConfig)
|
||||
config.SetNetworkingFields(netConfig)
|
||||
config.SetSessionRecordingFields(recConfig)
|
||||
config.SetAuthFields(authPref)
|
||||
|
@ -1764,7 +1768,11 @@ func (s *ServicesTestSuite) EventsClusterConfig(c *check.C) {
|
|||
},
|
||||
crud: func(context.Context) types.Resource {
|
||||
// DELETE IN 8.0.0
|
||||
err := s.ConfigS.SetClusterNetworkingConfig(context.TODO(), types.DefaultClusterNetworkingConfig())
|
||||
err := s.ConfigS.SetClusterAuditConfig(context.TODO(), types.DefaultClusterAuditConfig())
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
// DELETE IN 8.0.0
|
||||
err = s.ConfigS.SetClusterNetworkingConfig(context.TODO(), types.DefaultClusterNetworkingConfig())
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
// DELETE IN 8.0.0
|
||||
|
@ -1823,6 +1831,31 @@ func (s *ServicesTestSuite) EventsClusterConfig(c *check.C) {
|
|||
return out
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Cluster audit configuration",
|
||||
kind: types.WatchKind{
|
||||
Kind: types.KindClusterAuditConfig,
|
||||
},
|
||||
crud: func(ctx context.Context) types.Resource {
|
||||
auditConfig, err := types.NewClusterAuditConfig(types.ClusterAuditConfigSpecV2{
|
||||
Region: "us-west-1",
|
||||
Type: "dynamodb",
|
||||
AuditSessionsURI: "file:///home/log",
|
||||
AuditEventsURI: []string{"dynamodb://audit_table_name", "file:///home/test/log"},
|
||||
})
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
err = s.ConfigS.SetClusterAuditConfig(ctx, auditConfig)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
out, err := s.ConfigS.GetClusterAuditConfig(ctx)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
err = s.ConfigS.DeleteClusterAuditConfig(ctx)
|
||||
c.Assert(err, check.IsNil)
|
||||
return out
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Cluster networking configuration",
|
||||
kind: types.WatchKind{
|
||||
|
|
Loading…
Reference in a new issue