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

     1  /*
     2  Copyright 2021 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  	"strings"
    21  
    22  	"github.com/gravitational/trace"
    23  )
    24  
    25  // SystemRole identifies the role of an SSH connection. Unlike "user roles"
    26  // introduced as part of RBAC in Teleport 1.4+ these are built-in roles used
    27  // for different Teleport components when connecting to each other.
    28  type SystemRole string
    29  
    30  // SystemRoles is a TeleportRole list
    31  type SystemRoles []SystemRole
    32  
    33  const (
    34  	// RoleAuth is for teleport auth server (authority, authentication and authorization)
    35  	RoleAuth SystemRole = "Auth"
    36  	// RoleNode is a role for SSH node in the cluster
    37  	RoleNode SystemRole = "Node"
    38  	// RoleProxy is a role for SSH proxy in the cluster
    39  	RoleProxy SystemRole = "Proxy"
    40  	// RoleAdmin is admin role
    41  	RoleAdmin SystemRole = "Admin"
    42  	// RoleProvisionToken is a role for nodes authenticated using provisioning tokens
    43  	RoleProvisionToken SystemRole = "ProvisionToken"
    44  	// RoleTrustedCluster is a role needed for tokens used to add trusted clusters.
    45  	RoleTrustedCluster SystemRole = "Trusted_cluster"
    46  	// RoleSignup is for first time signing up users
    47  	RoleSignup SystemRole = "Signup"
    48  	// RoleNop is used for actions that are already using external authz mechanisms
    49  	// e.g. tokens or passwords
    50  	RoleNop SystemRole = "Nop"
    51  	// RoleRemoteProxy is a role for remote SSH proxy in the cluster
    52  	RoleRemoteProxy SystemRole = "RemoteProxy"
    53  	// RoleKube is a role for a kubernetes service.
    54  	RoleKube SystemRole = "Kube"
    55  	// RoleApp is a role for a app proxy in the cluster.
    56  	RoleApp SystemRole = "App"
    57  	// RoleDatabase is a role for a database proxy in the cluster.
    58  	RoleDatabase SystemRole = "Db"
    59  	// RoleWindowsDesktop is a role for a Windows desktop service.
    60  	RoleWindowsDesktop SystemRole = "WindowsDesktop"
    61  	// RoleBot is a role for a bot.
    62  	RoleBot SystemRole = "Bot"
    63  	// RoleInstance is a role implicitly held by teleport servers (i.e. any teleport
    64  	// auth token which grants a server role such as proxy/node/etc also implicitly
    65  	// grants the instance role, and any valid cert that proves that the caller holds
    66  	// a server role also implies that the caller holds the instance role). This role
    67  	// doesn't grant meaningful privileges on its own, but is a useful placeholder in
    68  	// contexts such as multi-role certs where there is no particular system role that
    69  	// is "primary".
    70  	RoleInstance SystemRole = "Instance"
    71  	// RoleDiscovery is a role for discovery nodes in the cluster
    72  	RoleDiscovery SystemRole = "Discovery"
    73  	// RoleOkta is a role for Okta nodes in the cluster
    74  	RoleOkta SystemRole = "Okta"
    75  	// RoleMDM is the role for MDM services in the cluster.
    76  	// An MDM service, like Jamf Service, has the powers to manage the cluster's
    77  	// device inventory.
    78  	// Device Trust requires Teleport Enteprise.
    79  	RoleMDM SystemRole = "MDM"
    80  
    81  	// RoleAccessGraphPlugin is a role for Access Graph plugins to access
    82  	// Teleport's internal API and access graph.
    83  	RoleAccessGraphPlugin SystemRole = "AccessGraphPlugin"
    84  )
    85  
    86  // roleMappings maps a set of allowed lowercase system role names
    87  // to the proper system role
    88  var roleMappings = map[string]SystemRole{
    89  	"auth":              RoleAuth,
    90  	"node":              RoleNode,
    91  	"proxy":             RoleProxy,
    92  	"admin":             RoleAdmin,
    93  	"provisiontoken":    RoleProvisionToken,
    94  	"trusted_cluster":   RoleTrustedCluster,
    95  	"trustedcluster":    RoleTrustedCluster,
    96  	"signup":            RoleSignup,
    97  	"nop":               RoleNop,
    98  	"remoteproxy":       RoleRemoteProxy,
    99  	"remote_proxy":      RoleRemoteProxy,
   100  	"kube":              RoleKube,
   101  	"app":               RoleApp,
   102  	"db":                RoleDatabase,
   103  	"windowsdesktop":    RoleWindowsDesktop,
   104  	"windows_desktop":   RoleWindowsDesktop,
   105  	"bot":               RoleBot,
   106  	"instance":          RoleInstance,
   107  	"discovery":         RoleDiscovery,
   108  	"okta":              RoleOkta,
   109  	"mdm":               RoleMDM,
   110  	"accessgraphplugin": RoleAccessGraphPlugin,
   111  }
   112  
   113  func normalizedSystemRole(s string) SystemRole {
   114  	if role, ok := roleMappings[strings.ToLower(strings.TrimSpace(s))]; ok {
   115  		return role
   116  	}
   117  	return SystemRole(s)
   118  }
   119  
   120  func normalizedSystemRoles(s []string) []SystemRole {
   121  	roles := make([]SystemRole, 0, len(s))
   122  	for _, role := range s {
   123  		roles = append(roles, normalizedSystemRole(role))
   124  	}
   125  	return roles
   126  }
   127  
   128  // localServiceMappings is the subset of role mappings which happen to be true
   129  // teleport services (e.g. db, kube, etc), excluding those which represent remote
   130  // services (i.e. remoteproxy).
   131  var localServiceMappings = map[SystemRole]struct{}{
   132  	RoleAuth:              {},
   133  	RoleNode:              {},
   134  	RoleProxy:             {},
   135  	RoleKube:              {},
   136  	RoleApp:               {},
   137  	RoleDatabase:          {},
   138  	RoleWindowsDesktop:    {},
   139  	RoleDiscovery:         {},
   140  	RoleOkta:              {},
   141  	RoleMDM:               {},
   142  	RoleAccessGraphPlugin: {},
   143  }
   144  
   145  // controlPlaneMapping is the subset of local services which are definitively control plane
   146  // elements.
   147  var controlPlaneMapping = map[SystemRole]struct{}{
   148  	RoleAuth:  {},
   149  	RoleProxy: {},
   150  }
   151  
   152  // LocalServiceMappings returns the subset of role mappings which happen
   153  // to be true Teleport services (e.g. db, kube, proxy, etc), excluding
   154  // those which represent remote service (i.e. remoteproxy).
   155  func LocalServiceMappings() SystemRoles {
   156  	var sr SystemRoles
   157  	for k := range localServiceMappings {
   158  		sr = append(sr, k)
   159  	}
   160  	return sr
   161  }
   162  
   163  // NewTeleportRoles return a list of teleport roles from slice of strings
   164  func NewTeleportRoles(in []string) (SystemRoles, error) {
   165  	roles := SystemRoles(normalizedSystemRoles(in))
   166  	return roles, roles.Check()
   167  }
   168  
   169  // ParseTeleportRoles takes a comma-separated list of roles and returns a slice
   170  // of teleport roles, or an error if parsing failed
   171  func ParseTeleportRoles(str string) (SystemRoles, error) {
   172  	var roles SystemRoles
   173  	for _, s := range strings.Split(str, ",") {
   174  		if r := normalizedSystemRole(s); r.Check() == nil {
   175  			roles = append(roles, r)
   176  			continue
   177  		}
   178  		return nil, trace.BadParameter("invalid role %q", s)
   179  	}
   180  	if len(roles) == 0 {
   181  		return nil, trace.BadParameter("no valid roles in $%q", str)
   182  	}
   183  
   184  	return roles, roles.Check()
   185  }
   186  
   187  // Include returns 'true' if a given list of teleport roles includes a given role
   188  func (roles SystemRoles) Include(role SystemRole) bool {
   189  	for _, r := range roles {
   190  		if r == role {
   191  			return true
   192  		}
   193  	}
   194  	return false
   195  }
   196  
   197  // IncludeAny returns 'true' if a given list of teleport roles includes any of
   198  // the given candidate roles.
   199  func (roles SystemRoles) IncludeAny(candidates ...SystemRole) bool {
   200  	for _, r := range candidates {
   201  		if roles.Include(r) {
   202  			return true
   203  		}
   204  	}
   205  	return false
   206  }
   207  
   208  // StringSlice returns teleport roles as string slice
   209  func (roles SystemRoles) StringSlice() []string {
   210  	s := make([]string, 0)
   211  	for _, r := range roles {
   212  		s = append(s, r.String())
   213  	}
   214  	return s
   215  }
   216  
   217  // asSet returns teleport roles as set (map).
   218  func (roles SystemRoles) asSet() map[SystemRole]struct{} {
   219  	s := make(map[SystemRole]struct{}, len(roles))
   220  	for _, r := range roles {
   221  		s[r] = struct{}{}
   222  	}
   223  	return s
   224  }
   225  
   226  // Equals compares two sets of teleport roles
   227  func (roles SystemRoles) Equals(other SystemRoles) bool {
   228  	rs, os := roles.asSet(), other.asSet()
   229  	if len(rs) != len(os) {
   230  		return false
   231  	}
   232  	for r := range rs {
   233  		if _, ok := os[r]; !ok {
   234  			return false
   235  		}
   236  	}
   237  	return true
   238  }
   239  
   240  // Check returns an error if the teleport role set is incorrect (contains unknown roles)
   241  func (roles SystemRoles) Check() error {
   242  	seen := make(map[SystemRole]struct{})
   243  	for _, role := range roles {
   244  		if err := role.Check(); err != nil {
   245  			return trace.Wrap(err)
   246  		}
   247  		if _, ok := seen[role]; ok {
   248  			return trace.BadParameter("duplicate role %q", role)
   249  		}
   250  		seen[role] = struct{}{}
   251  	}
   252  	return nil
   253  }
   254  
   255  // String returns comma separated string with teleport roles
   256  func (roles SystemRoles) String() string {
   257  	return strings.Join(roles.StringSlice(), ",")
   258  }
   259  
   260  // Set sets the value of the teleport role from string, used to integrate with CLI tools
   261  func (r *SystemRole) Set(v string) error {
   262  	if len(v) > 0 {
   263  		v = strings.ToUpper(v[:1]) + v[1:]
   264  	}
   265  	val := SystemRole(v)
   266  	if err := val.Check(); err != nil {
   267  		return trace.Wrap(err)
   268  	}
   269  	*r = val
   270  	return nil
   271  }
   272  
   273  // String returns the system role string representation. Returned values must
   274  // match (case-insensitive) the role mappings; otherwise, the validation check
   275  // will fail.
   276  func (r *SystemRole) String() string {
   277  	switch *r {
   278  	case RoleTrustedCluster:
   279  		return "trusted_cluster"
   280  	default:
   281  		return string(*r)
   282  	}
   283  }
   284  
   285  // Check checks if this a a valid teleport role value, returns nil
   286  // if it's ok, false otherwise
   287  // Check checks if this a a valid teleport role value, returns nil
   288  // if it's ok, false otherwise
   289  func (r *SystemRole) Check() error {
   290  	sr, ok := roleMappings[strings.ToLower(string(*r))]
   291  	if ok && string(*r) == string(sr) {
   292  		return nil
   293  	}
   294  
   295  	return trace.BadParameter("role %v is not registered", *r)
   296  }
   297  
   298  // IsLocalService checks if the given system role is a teleport service (e.g. auth),
   299  // as opposed to some non-service role (e.g. admin). Excludes remote services such
   300  // as remoteproxy.
   301  func (r *SystemRole) IsLocalService() bool {
   302  	_, ok := localServiceMappings[*r]
   303  	return ok
   304  }
   305  
   306  // IsControlPlane checks if the given system role is a control plane element (i.e. auth/proxy).
   307  func (r *SystemRole) IsControlPlane() bool {
   308  	_, ok := controlPlaneMapping[*r]
   309  	return ok
   310  }