github.com/gravitational/teleport/api@v0.0.0-20240507183017-3110591cbafc/types/trustedcluster.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/google/go-cmp/cmp"
    25  	"github.com/gravitational/trace"
    26  )
    27  
    28  // TrustedCluster holds information needed for a cluster that can not be directly
    29  // accessed (maybe be behind firewall without any open ports) to join a parent cluster.
    30  type TrustedCluster interface {
    31  	// Resource provides common resource properties
    32  	Resource
    33  	// SetMetadata sets object metadata
    34  	SetMetadata(meta Metadata)
    35  	// GetEnabled returns the state of the TrustedCluster.
    36  	GetEnabled() bool
    37  	// SetEnabled enables (handshake and add ca+reverse tunnel) or disables TrustedCluster.
    38  	SetEnabled(bool)
    39  	// CombinedMapping is used to specify combined mapping from legacy property Roles
    40  	// and new property RoleMap
    41  	CombinedMapping() RoleMap
    42  	// GetRoleMap returns role map property
    43  	GetRoleMap() RoleMap
    44  	// SetRoleMap sets role map
    45  	SetRoleMap(m RoleMap)
    46  	// GetRoles returns the roles for the certificate authority.
    47  	GetRoles() []string
    48  	// SetRoles sets the roles for the certificate authority.
    49  	SetRoles([]string)
    50  	// GetToken returns the authorization and authentication token.
    51  	GetToken() string
    52  	// SetToken sets the authorization and authentication.
    53  	SetToken(string)
    54  	// GetProxyAddress returns the address of the proxy server.
    55  	GetProxyAddress() string
    56  	// SetProxyAddress sets the address of the proxy server.
    57  	SetProxyAddress(string)
    58  	// GetReverseTunnelAddress returns the address of the reverse tunnel.
    59  	GetReverseTunnelAddress() string
    60  	// SetReverseTunnelAddress sets the address of the reverse tunnel.
    61  	SetReverseTunnelAddress(string)
    62  	// CanChangeStateTo checks the TrustedCluster can transform into another.
    63  	CanChangeStateTo(TrustedCluster) error
    64  }
    65  
    66  // NewTrustedCluster is a convenience way to create a TrustedCluster resource.
    67  func NewTrustedCluster(name string, spec TrustedClusterSpecV2) (TrustedCluster, error) {
    68  	c := &TrustedClusterV2{
    69  		Metadata: Metadata{
    70  			Name: name,
    71  		},
    72  		Spec: spec,
    73  	}
    74  	if err := c.CheckAndSetDefaults(); err != nil {
    75  		return nil, trace.Wrap(err)
    76  	}
    77  	return c, nil
    78  }
    79  
    80  // setStaticFields sets static resource header and metadata fields.
    81  func (c *TrustedClusterV2) setStaticFields() {
    82  	c.Kind = KindTrustedCluster
    83  	c.Version = V2
    84  }
    85  
    86  // CheckAndSetDefaults checks validity of all parameters and sets defaults
    87  func (c *TrustedClusterV2) CheckAndSetDefaults() error {
    88  	c.setStaticFields()
    89  	if err := c.Metadata.CheckAndSetDefaults(); err != nil {
    90  		return trace.Wrap(err)
    91  	}
    92  
    93  	// This is to force users to migrate
    94  	if len(c.Spec.Roles) != 0 && len(c.Spec.RoleMap) != 0 {
    95  		return trace.BadParameter("should set either 'roles' or 'role_map', not both")
    96  	}
    97  	// Imply that by default proxy listens on the same port for
    98  	// web and reverse tunnel connections
    99  	if c.Spec.ReverseTunnelAddress == "" {
   100  		c.Spec.ReverseTunnelAddress = c.Spec.ProxyAddress
   101  	}
   102  	return nil
   103  }
   104  
   105  // GetVersion returns resource version
   106  func (c *TrustedClusterV2) GetVersion() string {
   107  	return c.Version
   108  }
   109  
   110  // GetKind returns resource kind
   111  func (c *TrustedClusterV2) GetKind() string {
   112  	return c.Kind
   113  }
   114  
   115  // GetSubKind returns resource sub kind
   116  func (c *TrustedClusterV2) GetSubKind() string {
   117  	return c.SubKind
   118  }
   119  
   120  // SetSubKind sets resource subkind
   121  func (c *TrustedClusterV2) SetSubKind(s string) {
   122  	c.SubKind = s
   123  }
   124  
   125  // GetResourceID returns resource ID
   126  func (c *TrustedClusterV2) GetResourceID() int64 {
   127  	return c.Metadata.ID
   128  }
   129  
   130  // SetResourceID sets resource ID
   131  func (c *TrustedClusterV2) SetResourceID(id int64) {
   132  	c.Metadata.ID = id
   133  }
   134  
   135  // GetRevision returns the revision
   136  func (c *TrustedClusterV2) GetRevision() string {
   137  	return c.Metadata.GetRevision()
   138  }
   139  
   140  // SetRevision sets the revision
   141  func (c *TrustedClusterV2) SetRevision(rev string) {
   142  	c.Metadata.SetRevision(rev)
   143  }
   144  
   145  // CombinedMapping is used to specify combined mapping from legacy property Roles
   146  // and new property RoleMap
   147  func (c *TrustedClusterV2) CombinedMapping() RoleMap {
   148  	if len(c.Spec.Roles) != 0 {
   149  		return []RoleMapping{{Remote: Wildcard, Local: c.Spec.Roles}}
   150  	}
   151  	return c.Spec.RoleMap
   152  }
   153  
   154  // GetRoleMap returns role map property
   155  func (c *TrustedClusterV2) GetRoleMap() RoleMap {
   156  	return c.Spec.RoleMap
   157  }
   158  
   159  // SetRoleMap sets role map
   160  func (c *TrustedClusterV2) SetRoleMap(m RoleMap) {
   161  	c.Spec.RoleMap = m
   162  }
   163  
   164  // GetMetadata returns object metadata
   165  func (c *TrustedClusterV2) GetMetadata() Metadata {
   166  	return c.Metadata
   167  }
   168  
   169  // SetMetadata sets object metadata
   170  func (c *TrustedClusterV2) SetMetadata(meta Metadata) {
   171  	c.Metadata = meta
   172  }
   173  
   174  // SetExpiry sets expiry time for the object
   175  func (c *TrustedClusterV2) SetExpiry(expires time.Time) {
   176  	c.Metadata.SetExpiry(expires)
   177  }
   178  
   179  // Expiry returns object expiry setting
   180  func (c *TrustedClusterV2) Expiry() time.Time {
   181  	return c.Metadata.Expiry()
   182  }
   183  
   184  // GetName returns the name of the TrustedCluster.
   185  func (c *TrustedClusterV2) GetName() string {
   186  	return c.Metadata.Name
   187  }
   188  
   189  // SetName sets the name of the TrustedCluster.
   190  func (c *TrustedClusterV2) SetName(e string) {
   191  	c.Metadata.Name = e
   192  }
   193  
   194  // GetEnabled returns the state of the TrustedCluster.
   195  func (c *TrustedClusterV2) GetEnabled() bool {
   196  	return c.Spec.Enabled
   197  }
   198  
   199  // SetEnabled enables (handshake and add ca+reverse tunnel) or disables TrustedCluster.
   200  func (c *TrustedClusterV2) SetEnabled(e bool) {
   201  	c.Spec.Enabled = e
   202  }
   203  
   204  // GetRoles returns the roles for the certificate authority.
   205  func (c *TrustedClusterV2) GetRoles() []string {
   206  	return c.Spec.Roles
   207  }
   208  
   209  // SetRoles sets the roles for the certificate authority.
   210  func (c *TrustedClusterV2) SetRoles(e []string) {
   211  	c.Spec.Roles = e
   212  }
   213  
   214  // GetToken returns the authorization and authentication token.
   215  func (c *TrustedClusterV2) GetToken() string {
   216  	return c.Spec.Token
   217  }
   218  
   219  // SetToken sets the authorization and authentication.
   220  func (c *TrustedClusterV2) SetToken(e string) {
   221  	c.Spec.Token = e
   222  }
   223  
   224  // GetProxyAddress returns the address of the proxy server.
   225  func (c *TrustedClusterV2) GetProxyAddress() string {
   226  	return c.Spec.ProxyAddress
   227  }
   228  
   229  // SetProxyAddress sets the address of the proxy server.
   230  func (c *TrustedClusterV2) SetProxyAddress(e string) {
   231  	c.Spec.ProxyAddress = e
   232  }
   233  
   234  // GetReverseTunnelAddress returns the address of the reverse tunnel.
   235  func (c *TrustedClusterV2) GetReverseTunnelAddress() string {
   236  	return c.Spec.ReverseTunnelAddress
   237  }
   238  
   239  // SetReverseTunnelAddress sets the address of the reverse tunnel.
   240  func (c *TrustedClusterV2) SetReverseTunnelAddress(e string) {
   241  	c.Spec.ReverseTunnelAddress = e
   242  }
   243  
   244  // CanChangeStateTo checks if the state change is allowed or not. If not, returns
   245  // an error explaining the reason.
   246  func (c *TrustedClusterV2) CanChangeStateTo(t TrustedCluster) error {
   247  	immutableFieldErr := func(name string) error {
   248  		return trace.BadParameter("can not update %s for existing leaf cluster, delete and re-create this leaf cluster with updated %s", name, name)
   249  	}
   250  	if c.GetToken() != t.GetToken() {
   251  		return immutableFieldErr("token")
   252  	}
   253  	if c.GetProxyAddress() != t.GetProxyAddress() {
   254  		return immutableFieldErr("web_proxy_address")
   255  	}
   256  	if c.GetReverseTunnelAddress() != t.GetReverseTunnelAddress() {
   257  		return immutableFieldErr("tunnel_addr")
   258  	}
   259  	if !slices.Equal(c.GetRoles(), t.GetRoles()) {
   260  		return immutableFieldErr("roles")
   261  	}
   262  	roleMapUpdated := !cmp.Equal(c.GetRoleMap(), t.GetRoleMap())
   263  
   264  	if c.GetEnabled() == t.GetEnabled() && !roleMapUpdated {
   265  		if t.GetEnabled() {
   266  			return trace.AlreadyExists("leaf cluster is already enabled, this update would have no effect")
   267  		}
   268  		return trace.AlreadyExists("leaf cluster is already disabled, this update would have no effect")
   269  	}
   270  
   271  	return nil
   272  }
   273  
   274  // String represents a human readable version of trusted cluster settings.
   275  func (c *TrustedClusterV2) String() string {
   276  	return fmt.Sprintf("TrustedCluster(Enabled=%v,Roles=%v,Token=%v,ProxyAddress=%v,ReverseTunnelAddress=%v)",
   277  		c.Spec.Enabled, c.Spec.Roles, c.Spec.Token, c.Spec.ProxyAddress, c.Spec.ReverseTunnelAddress)
   278  }
   279  
   280  // RoleMap is a list of mappings
   281  type RoleMap []RoleMapping
   282  
   283  // SortedTrustedCluster sorts clusters by name
   284  type SortedTrustedCluster []TrustedCluster
   285  
   286  // Len returns the length of a list.
   287  func (s SortedTrustedCluster) Len() int {
   288  	return len(s)
   289  }
   290  
   291  // Less compares items by name.
   292  func (s SortedTrustedCluster) Less(i, j int) bool {
   293  	return s[i].GetName() < s[j].GetName()
   294  }
   295  
   296  // Swap swaps two items in a list.
   297  func (s SortedTrustedCluster) Swap(i, j int) {
   298  	s[i], s[j] = s[j], s[i]
   299  }