github.com/gravitational/teleport/api@v0.0.0-20240507183017-3110591cbafc/types/authority.go (about)

     1  /*
     2  Copyright 2020 Gravitational, Inc.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package types
    18  
    19  import (
    20  	"fmt"
    21  	"slices"
    22  	"time"
    23  
    24  	"github.com/gravitational/trace"
    25  
    26  	"github.com/gravitational/teleport/api/constants"
    27  	"github.com/gravitational/teleport/api/utils"
    28  )
    29  
    30  // CertAuthority is a host or user certificate authority that can check and if
    31  // it has private key stored as well, sign it too.
    32  type CertAuthority interface {
    33  	// ResourceWithSecrets sets common resource properties
    34  	ResourceWithSecrets
    35  	// SetMetadata sets CA metadata
    36  	SetMetadata(meta Metadata)
    37  	// GetID returns certificate authority ID -
    38  	// combined type and name
    39  	GetID() CertAuthID
    40  	// GetType returns user or host certificate authority
    41  	GetType() CertAuthType
    42  	// GetClusterName returns cluster name this cert authority
    43  	// is associated with
    44  	GetClusterName() string
    45  
    46  	GetActiveKeys() CAKeySet
    47  	SetActiveKeys(CAKeySet) error
    48  	GetAdditionalTrustedKeys() CAKeySet
    49  	SetAdditionalTrustedKeys(CAKeySet) error
    50  
    51  	GetTrustedSSHKeyPairs() []*SSHKeyPair
    52  	GetTrustedTLSKeyPairs() []*TLSKeyPair
    53  	GetTrustedJWTKeyPairs() []*JWTKeyPair
    54  
    55  	// CombinedMapping is used to specify combined mapping from legacy property Roles
    56  	// and new property RoleMap
    57  	CombinedMapping() RoleMap
    58  	// GetRoleMap returns role map property
    59  	GetRoleMap() RoleMap
    60  	// SetRoleMap sets role map
    61  	SetRoleMap(m RoleMap)
    62  	// GetRoles returns a list of roles assumed by users signed by this CA
    63  	GetRoles() []string
    64  	// SetRoles sets assigned roles for this certificate authority
    65  	SetRoles(roles []string)
    66  	// AddRole adds a role to ca role list
    67  	AddRole(name string)
    68  	// String returns human readable version of the CertAuthority
    69  	String() string
    70  	// GetRotation returns rotation state.
    71  	GetRotation() Rotation
    72  	// SetRotation sets rotation state.
    73  	SetRotation(Rotation)
    74  	// AllKeyTypes returns the set of all different key types in the CA.
    75  	AllKeyTypes() []string
    76  	// Clone returns a copy of the cert authority object.
    77  	Clone() CertAuthority
    78  }
    79  
    80  // NewCertAuthority returns new cert authority
    81  func NewCertAuthority(spec CertAuthoritySpecV2) (CertAuthority, error) {
    82  	ca := &CertAuthorityV2{Spec: spec}
    83  	if err := ca.CheckAndSetDefaults(); err != nil {
    84  		return nil, trace.Wrap(err)
    85  	}
    86  	return ca, nil
    87  }
    88  
    89  // GetVersion returns resource version
    90  func (ca *CertAuthorityV2) GetVersion() string {
    91  	return ca.Version
    92  }
    93  
    94  // GetKind returns resource kind
    95  func (ca *CertAuthorityV2) GetKind() string {
    96  	return ca.Kind
    97  }
    98  
    99  // GetSubKind returns resource sub kind
   100  func (ca *CertAuthorityV2) GetSubKind() string {
   101  	return ca.SubKind
   102  }
   103  
   104  // SetSubKind sets resource subkind
   105  func (ca *CertAuthorityV2) SetSubKind(s string) {
   106  	ca.SubKind = s
   107  }
   108  
   109  // Clone returns a copy of the cert authority object.
   110  func (ca *CertAuthorityV2) Clone() CertAuthority {
   111  	return utils.CloneProtoMsg(ca)
   112  }
   113  
   114  // GetRotation returns rotation state.
   115  func (ca *CertAuthorityV2) GetRotation() Rotation {
   116  	if ca.Spec.Rotation == nil {
   117  		return Rotation{}
   118  	}
   119  	return *ca.Spec.Rotation
   120  }
   121  
   122  // SetRotation sets rotation state.
   123  func (ca *CertAuthorityV2) SetRotation(r Rotation) {
   124  	ca.Spec.Rotation = &r
   125  }
   126  
   127  // SetMetadata sets object metadata
   128  func (ca *CertAuthorityV2) SetMetadata(meta Metadata) {
   129  	ca.Metadata = meta
   130  }
   131  
   132  // GetMetadata returns object metadata
   133  func (ca *CertAuthorityV2) GetMetadata() Metadata {
   134  	return ca.Metadata
   135  }
   136  
   137  // SetExpiry sets expiry time for the object
   138  func (ca *CertAuthorityV2) SetExpiry(expires time.Time) {
   139  	ca.Metadata.SetExpiry(expires)
   140  }
   141  
   142  // Expiry returns object expiry setting
   143  func (ca *CertAuthorityV2) Expiry() time.Time {
   144  	return ca.Metadata.Expiry()
   145  }
   146  
   147  // GetResourceID returns resource ID
   148  func (ca *CertAuthorityV2) GetResourceID() int64 {
   149  	return ca.Metadata.ID
   150  }
   151  
   152  // SetResourceID sets resource ID
   153  func (ca *CertAuthorityV2) SetResourceID(id int64) {
   154  	ca.Metadata.ID = id
   155  }
   156  
   157  // GetRevision returns the revision
   158  func (ca *CertAuthorityV2) GetRevision() string {
   159  	return ca.Metadata.GetRevision()
   160  }
   161  
   162  // SetRevision sets the revision
   163  func (ca *CertAuthorityV2) SetRevision(rev string) {
   164  	ca.Metadata.SetRevision(rev)
   165  }
   166  
   167  // WithoutSecrets returns an instance of resource without secrets.
   168  func (ca *CertAuthorityV2) WithoutSecrets() Resource {
   169  	ca2 := ca.Clone().(*CertAuthorityV2)
   170  	RemoveCASecrets(ca2)
   171  	return ca2
   172  }
   173  
   174  // RemoveCASecrets removes private (SSH, TLS, and JWT) keys from certificate
   175  // authority.
   176  func RemoveCASecrets(ca CertAuthority) {
   177  	cav2, ok := ca.(*CertAuthorityV2)
   178  	if !ok {
   179  		return
   180  	}
   181  	cav2.Spec.ActiveKeys = cav2.Spec.ActiveKeys.WithoutSecrets()
   182  	cav2.Spec.AdditionalTrustedKeys = cav2.Spec.AdditionalTrustedKeys.WithoutSecrets()
   183  }
   184  
   185  // String returns human readable version of the CertAuthorityV2.
   186  func (ca *CertAuthorityV2) String() string {
   187  	return fmt.Sprintf("CA(name=%v, type=%v)", ca.GetClusterName(), ca.GetType())
   188  }
   189  
   190  // AddRole adds a role to ca role list
   191  func (ca *CertAuthorityV2) AddRole(name string) {
   192  	for _, r := range ca.Spec.Roles {
   193  		if r == name {
   194  			return
   195  		}
   196  	}
   197  	ca.Spec.Roles = append(ca.Spec.Roles, name)
   198  }
   199  
   200  // GetID returns certificate authority ID -
   201  // combined type and name
   202  func (ca *CertAuthorityV2) GetID() CertAuthID {
   203  	return CertAuthID{Type: ca.Spec.Type, DomainName: ca.Metadata.Name}
   204  }
   205  
   206  // SetName sets cert authority name
   207  func (ca *CertAuthorityV2) SetName(name string) {
   208  	ca.Metadata.SetName(name)
   209  }
   210  
   211  // GetName returns cert authority name
   212  func (ca *CertAuthorityV2) GetName() string {
   213  	return ca.Metadata.Name
   214  }
   215  
   216  // GetType returns user or host certificate authority
   217  func (ca *CertAuthorityV2) GetType() CertAuthType {
   218  	return ca.Spec.Type
   219  }
   220  
   221  // GetClusterName returns cluster name this cert authority
   222  // is associated with.
   223  func (ca *CertAuthorityV2) GetClusterName() string {
   224  	return ca.Spec.ClusterName
   225  }
   226  
   227  // GetRoles returns a list of roles assumed by users signed by this CA
   228  func (ca *CertAuthorityV2) GetRoles() []string {
   229  	return ca.Spec.Roles
   230  }
   231  
   232  // SetRoles sets assigned roles for this certificate authority
   233  func (ca *CertAuthorityV2) SetRoles(roles []string) {
   234  	ca.Spec.Roles = roles
   235  }
   236  
   237  // CombinedMapping is used to specify combined mapping from legacy property Roles
   238  // and new property RoleMap
   239  func (ca *CertAuthorityV2) CombinedMapping() RoleMap {
   240  	if len(ca.Spec.Roles) != 0 {
   241  		return RoleMap([]RoleMapping{{Remote: Wildcard, Local: ca.Spec.Roles}})
   242  	}
   243  	return RoleMap(ca.Spec.RoleMap)
   244  }
   245  
   246  // GetRoleMap returns role map property
   247  func (ca *CertAuthorityV2) GetRoleMap() RoleMap {
   248  	return RoleMap(ca.Spec.RoleMap)
   249  }
   250  
   251  // SetRoleMap sets role map
   252  func (ca *CertAuthorityV2) SetRoleMap(m RoleMap) {
   253  	ca.Spec.RoleMap = []RoleMapping(m)
   254  }
   255  
   256  // ID returns id (consisting of domain name and type) that
   257  // identifies the authority this key belongs to
   258  func (ca *CertAuthorityV2) ID() *CertAuthID {
   259  	return &CertAuthID{DomainName: ca.Spec.ClusterName, Type: ca.Spec.Type}
   260  }
   261  
   262  func (ca *CertAuthorityV2) GetActiveKeys() CAKeySet {
   263  	return ca.Spec.ActiveKeys
   264  }
   265  
   266  func (ca *CertAuthorityV2) SetActiveKeys(ks CAKeySet) error {
   267  	if err := ks.CheckAndSetDefaults(); err != nil {
   268  		return trace.Wrap(err)
   269  	}
   270  	ca.Spec.ActiveKeys = ks
   271  	return nil
   272  }
   273  
   274  func (ca *CertAuthorityV2) GetAdditionalTrustedKeys() CAKeySet {
   275  	return ca.Spec.AdditionalTrustedKeys
   276  }
   277  
   278  func (ca *CertAuthorityV2) SetAdditionalTrustedKeys(ks CAKeySet) error {
   279  	if err := ks.CheckAndSetDefaults(); err != nil {
   280  		return trace.Wrap(err)
   281  	}
   282  	ca.Spec.AdditionalTrustedKeys = ks
   283  	return nil
   284  }
   285  
   286  func (ca *CertAuthorityV2) GetTrustedSSHKeyPairs() []*SSHKeyPair {
   287  	var kps []*SSHKeyPair
   288  	for _, k := range ca.GetActiveKeys().SSH {
   289  		kps = append(kps, k.Clone())
   290  	}
   291  	for _, k := range ca.GetAdditionalTrustedKeys().SSH {
   292  		kps = append(kps, k.Clone())
   293  	}
   294  	return kps
   295  }
   296  
   297  func (ca *CertAuthorityV2) GetTrustedTLSKeyPairs() []*TLSKeyPair {
   298  	var kps []*TLSKeyPair
   299  	for _, k := range ca.GetActiveKeys().TLS {
   300  		kps = append(kps, k.Clone())
   301  	}
   302  	for _, k := range ca.GetAdditionalTrustedKeys().TLS {
   303  		kps = append(kps, k.Clone())
   304  	}
   305  	return kps
   306  }
   307  
   308  func (ca *CertAuthorityV2) GetTrustedJWTKeyPairs() []*JWTKeyPair {
   309  	var kps []*JWTKeyPair
   310  	for _, k := range ca.GetActiveKeys().JWT {
   311  		kps = append(kps, k.Clone())
   312  	}
   313  	for _, k := range ca.GetAdditionalTrustedKeys().JWT {
   314  		kps = append(kps, k.Clone())
   315  	}
   316  	return kps
   317  }
   318  
   319  // setStaticFields sets static resource header and metadata fields.
   320  func (ca *CertAuthorityV2) setStaticFields() {
   321  	ca.Kind = KindCertAuthority
   322  	ca.Version = V2
   323  	// ca.Metadata.Name and ca.Spec.ClusterName should always be equal.
   324  	if ca.Metadata.Name == "" {
   325  		ca.Metadata.Name = ca.Spec.ClusterName
   326  	} else {
   327  		ca.Spec.ClusterName = ca.Metadata.Name
   328  	}
   329  }
   330  
   331  // CheckAndSetDefaults checks and set default values for any missing fields.
   332  func (ca *CertAuthorityV2) CheckAndSetDefaults() error {
   333  	ca.setStaticFields()
   334  	if err := ca.Metadata.CheckAndSetDefaults(); err != nil {
   335  		return trace.Wrap(err)
   336  	}
   337  
   338  	if ca.SubKind == "" {
   339  		ca.SubKind = string(ca.Spec.Type)
   340  	}
   341  
   342  	if err := ca.ID().Check(); err != nil {
   343  		return trace.Wrap(err)
   344  	}
   345  
   346  	if err := ca.Spec.ActiveKeys.CheckAndSetDefaults(); err != nil {
   347  		return trace.Wrap(err)
   348  	}
   349  	if err := ca.Spec.AdditionalTrustedKeys.CheckAndSetDefaults(); err != nil {
   350  		return trace.Wrap(err)
   351  	}
   352  	if err := ca.Spec.Rotation.CheckAndSetDefaults(); err != nil {
   353  		return trace.Wrap(err)
   354  	}
   355  
   356  	if err := ca.GetType().Check(); err != nil {
   357  		return trace.Wrap(err)
   358  	}
   359  
   360  	return nil
   361  }
   362  
   363  // AllKeyTypes returns the set of all different key types in the CA.
   364  func (ca *CertAuthorityV2) AllKeyTypes() []string {
   365  	keyTypes := make(map[PrivateKeyType]struct{})
   366  	for _, keySet := range []CAKeySet{ca.Spec.ActiveKeys, ca.Spec.AdditionalTrustedKeys} {
   367  		for _, keyPair := range keySet.SSH {
   368  			keyTypes[keyPair.PrivateKeyType] = struct{}{}
   369  		}
   370  		for _, keyPair := range keySet.TLS {
   371  			keyTypes[keyPair.KeyType] = struct{}{}
   372  		}
   373  		for _, keyPair := range keySet.JWT {
   374  			keyTypes[keyPair.PrivateKeyType] = struct{}{}
   375  		}
   376  	}
   377  	var strs []string
   378  	for k := range keyTypes {
   379  		strs = append(strs, k.String())
   380  	}
   381  	return strs
   382  }
   383  
   384  const (
   385  	// RotationStateStandby is initial status of the rotation -
   386  	// nothing is being rotated.
   387  	RotationStateStandby = "standby"
   388  	// RotationStateInProgress - that rotation is in progress.
   389  	RotationStateInProgress = "in_progress"
   390  	// RotationPhaseStandby is the initial phase of the rotation
   391  	// it means no operations have started.
   392  	RotationPhaseStandby = "standby"
   393  	// RotationPhaseInit = is a phase of the rotation
   394  	// when new certificate authority is issued, but not used
   395  	// It is necessary for remote trusted clusters to fetch the
   396  	// new certificate authority, otherwise the new clients
   397  	// will reject it
   398  	RotationPhaseInit = "init"
   399  	// RotationPhaseUpdateClients is a phase of the rotation
   400  	// when client credentials will have to be updated and reloaded
   401  	// but servers will use and respond with old credentials
   402  	// because clients have no idea about new credentials at first.
   403  	RotationPhaseUpdateClients = "update_clients"
   404  	// RotationPhaseUpdateServers is a phase of the rotation
   405  	// when servers will have to reload and should start serving
   406  	// TLS and SSH certificates signed by new CA.
   407  	RotationPhaseUpdateServers = "update_servers"
   408  	// RotationPhaseRollback means that rotation is rolling
   409  	// back to the old certificate authority.
   410  	RotationPhaseRollback = "rollback"
   411  	// RotationModeManual is a manual rotation mode when all phases
   412  	// are set by the operator.
   413  	RotationModeManual = "manual"
   414  	// RotationModeAuto is set to go through all phases by the schedule.
   415  	RotationModeAuto = "auto"
   416  )
   417  
   418  // RotatePhases lists all supported rotation phases
   419  var RotatePhases = []string{
   420  	RotationPhaseInit,
   421  	RotationPhaseStandby,
   422  	RotationPhaseUpdateClients,
   423  	RotationPhaseUpdateServers,
   424  	RotationPhaseRollback,
   425  }
   426  
   427  // Matches returns true if this state rotation matches
   428  // external rotation state, phase and rotation ID should match,
   429  // notice that matches does not behave like Equals because it does not require
   430  // all fields to be the same.
   431  func (r *Rotation) Matches(rotation Rotation) bool {
   432  	return r.CurrentID == rotation.CurrentID && r.State == rotation.State && r.Phase == rotation.Phase
   433  }
   434  
   435  // IsZero checks if this is the zero value of Rotation. Works on nil and non-nil rotation
   436  // values.
   437  func (r *Rotation) IsZero() bool {
   438  	if r == nil {
   439  		return true
   440  	}
   441  
   442  	return r.Matches(Rotation{})
   443  }
   444  
   445  // LastRotatedDescription returns human friendly description.
   446  func (r *Rotation) LastRotatedDescription() string {
   447  	if r.LastRotated.IsZero() {
   448  		return "never updated"
   449  	}
   450  	return fmt.Sprintf("last rotated %v", r.LastRotated.Format(constants.HumanDateFormatSeconds))
   451  }
   452  
   453  // PhaseDescription returns human friendly description of a current rotation phase.
   454  func (r *Rotation) PhaseDescription() string {
   455  	switch r.Phase {
   456  	case RotationPhaseInit:
   457  		return "initialized"
   458  	case RotationPhaseStandby, "":
   459  		return "on standby"
   460  	case RotationPhaseUpdateClients:
   461  		return "rotating clients"
   462  	case RotationPhaseUpdateServers:
   463  		return "rotating servers"
   464  	case RotationPhaseRollback:
   465  		return "rolling back"
   466  	default:
   467  		return fmt.Sprintf("unknown phase: %q", r.Phase)
   468  	}
   469  }
   470  
   471  // String returns user friendly information about certificate authority.
   472  func (r *Rotation) String() string {
   473  	switch r.State {
   474  	case "", RotationStateStandby:
   475  		if r.LastRotated.IsZero() {
   476  			return "never updated"
   477  		}
   478  		return fmt.Sprintf("rotated %v", r.LastRotated.Format(constants.HumanDateFormatSeconds))
   479  	case RotationStateInProgress:
   480  		return fmt.Sprintf("%v (mode: %v, started: %v, ending: %v)",
   481  			r.PhaseDescription(),
   482  			r.Mode,
   483  			r.Started.Format(constants.HumanDateFormatSeconds),
   484  			r.Started.Add(r.GracePeriod.Duration()).Format(constants.HumanDateFormatSeconds),
   485  		)
   486  	default:
   487  		return "unknown"
   488  	}
   489  }
   490  
   491  // CheckAndSetDefaults checks and sets default rotation parameters.
   492  func (r *Rotation) CheckAndSetDefaults() error {
   493  	if r == nil {
   494  		return nil
   495  	}
   496  	switch r.Phase {
   497  	case "", RotationPhaseInit, RotationPhaseStandby, RotationPhaseRollback, RotationPhaseUpdateClients, RotationPhaseUpdateServers:
   498  	default:
   499  		return trace.BadParameter("unsupported phase: %q", r.Phase)
   500  	}
   501  	switch r.Mode {
   502  	case "", RotationModeAuto, RotationModeManual:
   503  	default:
   504  		return trace.BadParameter("unsupported mode: %q", r.Mode)
   505  	}
   506  	switch r.State {
   507  	case "":
   508  		r.State = RotationStateStandby
   509  	case RotationStateStandby:
   510  	case RotationStateInProgress:
   511  		if r.CurrentID == "" {
   512  			return trace.BadParameter("set 'current_id' parameter for in progress rotation")
   513  		}
   514  		if r.Started.IsZero() {
   515  			return trace.BadParameter("set 'started' parameter for in progress rotation")
   516  		}
   517  	default:
   518  		return trace.BadParameter(
   519  			"unsupported rotation 'state': %q, supported states are: %q, %q",
   520  			r.State, RotationStateStandby, RotationStateInProgress)
   521  	}
   522  	return nil
   523  }
   524  
   525  // GenerateSchedule generates schedule based on the time period, using
   526  // even time periods between rotation phases.
   527  func GenerateSchedule(now time.Time, gracePeriod time.Duration) (*RotationSchedule, error) {
   528  	if gracePeriod <= 0 {
   529  		return nil, trace.BadParameter("invalid grace period %q, provide value > 0", gracePeriod)
   530  	}
   531  	return &RotationSchedule{
   532  		UpdateClients: now.UTC().Add(gracePeriod / 3),
   533  		UpdateServers: now.UTC().Add((gracePeriod * 2) / 3),
   534  		Standby:       now.UTC().Add(gracePeriod),
   535  	}, nil
   536  }
   537  
   538  // CheckAndSetDefaults checks and sets default values of the rotation schedule.
   539  func (s *RotationSchedule) CheckAndSetDefaults(now time.Time) error {
   540  	if s.UpdateServers.IsZero() {
   541  		return trace.BadParameter("phase %q has no time switch scheduled", RotationPhaseUpdateServers)
   542  	}
   543  	if s.Standby.IsZero() {
   544  		return trace.BadParameter("phase %q has no time switch scheduled", RotationPhaseStandby)
   545  	}
   546  	if s.Standby.Before(s.UpdateServers) {
   547  		return trace.BadParameter("phase %q can not be scheduled before %q", RotationPhaseStandby, RotationPhaseUpdateServers)
   548  	}
   549  	if s.UpdateServers.Before(now) {
   550  		return trace.BadParameter("phase %q can not be scheduled in the past", RotationPhaseUpdateServers)
   551  	}
   552  	if s.Standby.Before(now) {
   553  		return trace.BadParameter("phase %q can not be scheduled in the past", RotationPhaseStandby)
   554  	}
   555  	return nil
   556  }
   557  
   558  // CertRoles defines certificate roles
   559  type CertRoles struct {
   560  	// Version is current version of the roles
   561  	Version string `json:"version"`
   562  	// Roles is a list of roles
   563  	Roles []string `json:"roles"`
   564  }
   565  
   566  // Clone returns a deep copy of TLSKeyPair that can be mutated without
   567  // modifying the original.
   568  func (k *TLSKeyPair) Clone() *TLSKeyPair {
   569  	return &TLSKeyPair{
   570  		KeyType: k.KeyType,
   571  		Key:     slices.Clone(k.Key),
   572  		Cert:    slices.Clone(k.Cert),
   573  	}
   574  }
   575  
   576  // Clone returns a deep copy of JWTKeyPair that can be mutated without
   577  // modifying the original.
   578  func (k *JWTKeyPair) Clone() *JWTKeyPair {
   579  	return &JWTKeyPair{
   580  		PrivateKeyType: k.PrivateKeyType,
   581  		PrivateKey:     slices.Clone(k.PrivateKey),
   582  		PublicKey:      slices.Clone(k.PublicKey),
   583  	}
   584  }
   585  
   586  // Clone returns a deep copy of SSHKeyPair that can be mutated without
   587  // modifying the original.
   588  func (k *SSHKeyPair) Clone() *SSHKeyPair {
   589  	return &SSHKeyPair{
   590  		PrivateKeyType: k.PrivateKeyType,
   591  		PrivateKey:     slices.Clone(k.PrivateKey),
   592  		PublicKey:      slices.Clone(k.PublicKey),
   593  	}
   594  }
   595  
   596  // Clone returns a deep copy of CAKeySet that can be mutated without modifying
   597  // the original.
   598  func (ks CAKeySet) Clone() CAKeySet {
   599  	var out CAKeySet
   600  	if len(ks.TLS) > 0 {
   601  		out.TLS = make([]*TLSKeyPair, 0, len(ks.TLS))
   602  		for _, k := range ks.TLS {
   603  			out.TLS = append(out.TLS, k.Clone())
   604  		}
   605  	}
   606  	if len(ks.JWT) > 0 {
   607  		out.JWT = make([]*JWTKeyPair, 0, len(ks.JWT))
   608  		for _, k := range ks.JWT {
   609  			out.JWT = append(out.JWT, k.Clone())
   610  		}
   611  	}
   612  	if len(ks.SSH) > 0 {
   613  		out.SSH = make([]*SSHKeyPair, 0, len(ks.SSH))
   614  		for _, k := range ks.SSH {
   615  			out.SSH = append(out.SSH, k.Clone())
   616  		}
   617  	}
   618  	return out
   619  }
   620  
   621  // WithoutSecrets returns a deep copy of CAKeySet with all secret fields
   622  // (private keys) removed.
   623  func (ks CAKeySet) WithoutSecrets() CAKeySet {
   624  	ks = ks.Clone()
   625  	for _, k := range ks.SSH {
   626  		k.PrivateKey = nil
   627  	}
   628  	for _, k := range ks.TLS {
   629  		k.Key = nil
   630  	}
   631  	for _, k := range ks.JWT {
   632  		k.PrivateKey = nil
   633  	}
   634  	return ks
   635  }
   636  
   637  // CheckAndSetDefaults validates CAKeySet and sets defaults on any empty fields
   638  // as needed.
   639  func (ks CAKeySet) CheckAndSetDefaults() error {
   640  	for _, kp := range ks.SSH {
   641  		if err := kp.CheckAndSetDefaults(); err != nil {
   642  			return trace.Wrap(err)
   643  		}
   644  	}
   645  	for _, kp := range ks.TLS {
   646  		if err := kp.CheckAndSetDefaults(); err != nil {
   647  			return trace.Wrap(err)
   648  		}
   649  	}
   650  	for _, kp := range ks.JWT {
   651  		if err := kp.CheckAndSetDefaults(); err != nil {
   652  			return trace.Wrap(err)
   653  		}
   654  	}
   655  	return nil
   656  }
   657  
   658  // Empty returns true if the CAKeySet holds no keys
   659  func (ks *CAKeySet) Empty() bool {
   660  	return len(ks.SSH) == 0 && len(ks.TLS) == 0 && len(ks.JWT) == 0
   661  }
   662  
   663  // CheckAndSetDefaults validates SSHKeyPair and sets defaults on any empty
   664  // fields as needed.
   665  func (k *SSHKeyPair) CheckAndSetDefaults() error {
   666  	if len(k.PublicKey) == 0 {
   667  		return trace.BadParameter("SSH key pair missing public key")
   668  	}
   669  	return nil
   670  }
   671  
   672  // CheckAndSetDefaults validates TLSKeyPair and sets defaults on any empty
   673  // fields as needed.
   674  func (k *TLSKeyPair) CheckAndSetDefaults() error {
   675  	if len(k.Cert) == 0 {
   676  		return trace.BadParameter("TLS key pair missing certificate")
   677  	}
   678  	return nil
   679  }
   680  
   681  // CheckAndSetDefaults validates JWTKeyPair and sets defaults on any empty
   682  // fields as needed.
   683  func (k *JWTKeyPair) CheckAndSetDefaults() error {
   684  	if len(k.PublicKey) == 0 {
   685  		return trace.BadParameter("JWT key pair missing public key")
   686  	}
   687  	return nil
   688  }
   689  
   690  type CertAuthorityFilter map[CertAuthType]string
   691  
   692  func (f CertAuthorityFilter) IsEmpty() bool {
   693  	return len(f) == 0
   694  }
   695  
   696  // Match checks if a given CA matches this filter.
   697  func (f CertAuthorityFilter) Match(ca CertAuthority) bool {
   698  	if len(f) == 0 {
   699  		return true
   700  	}
   701  
   702  	return f[ca.GetType()] == Wildcard || f[ca.GetType()] == ca.GetClusterName()
   703  }
   704  
   705  // IntoMap makes this filter into a map for use as the Filter in a WatchKind.
   706  func (f CertAuthorityFilter) IntoMap() map[string]string {
   707  	if len(f) == 0 {
   708  		return nil
   709  	}
   710  
   711  	m := make(map[string]string, len(f))
   712  	for caType, name := range f {
   713  		m[string(caType)] = name
   714  	}
   715  	return m
   716  }
   717  
   718  // FromMap converts the provided map into this filter.
   719  func (f *CertAuthorityFilter) FromMap(m map[string]string) {
   720  	if len(m) == 0 {
   721  		*f = nil
   722  		return
   723  	}
   724  
   725  	*f = make(CertAuthorityFilter, len(m))
   726  	// there's not a lot of value in rejecting unknown values from the filter
   727  	for key, val := range m {
   728  		(*f)[CertAuthType(key)] = val
   729  	}
   730  }
   731  
   732  // Contains checks if the CA filter contains another CA filter as a subset.
   733  // Unlike other filters, a CA filter's scope becomes more broad as map keys
   734  // are added to it.
   735  // Therefore, to check if kind's filter contains the subset's filter,
   736  // we should check that the subset's keys are all present in kind and as
   737  // narrow or narrower.
   738  // A special case is when kind's filter is either empty or specifies all
   739  // authorities, in which case it is as broad as possible and subset's filter
   740  // is always contained within it.
   741  func (f CertAuthorityFilter) Contains(other CertAuthorityFilter) bool {
   742  	if len(f) == 0 {
   743  		// f has no filter, which is as broad as possible.
   744  		return true
   745  	}
   746  
   747  	if len(other) == 0 {
   748  		// f has a filter, but other does not.
   749  		// treat this as "contained" if f's filter is for all authorities.
   750  		for _, caType := range CertAuthTypes {
   751  			clusterName, ok := f[caType]
   752  			if !ok || clusterName != Wildcard {
   753  				return false
   754  			}
   755  		}
   756  		return true
   757  	}
   758  
   759  	for k, v := range other {
   760  		v2, ok := f[k]
   761  		if !ok || (v2 != Wildcard && v2 != v) {
   762  			return false
   763  		}
   764  	}
   765  	return true
   766  }