github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/caas/specs/rbac.go (about)

     1  // Copyright 2019 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package specs
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/juju/collections/set"
    10  	"github.com/juju/errors"
    11  )
    12  
    13  // PolicyRule defines a rule policy for a role or cluster role.
    14  type PolicyRule struct {
    15  	Verbs           []string `json:"verbs" yaml:"verbs"`
    16  	APIGroups       []string `json:"apiGroups,omitempty" yaml:"apiGroups,omitempty"`
    17  	Resources       []string `json:"resources,omitempty" yaml:"resources,omitempty"`
    18  	ResourceNames   []string `json:"resourceNames,omitempty" yaml:"resourceNames,omitempty"`
    19  	NonResourceURLs []string `json:"nonResourceURLs,omitempty" yaml:"nonResourceURLs,omitempty"`
    20  }
    21  
    22  // ServiceAccountSpecV2 defines spec for referencing or creating RBAC resource for the application for version 2.
    23  type ServiceAccountSpecV2 struct {
    24  	AutomountServiceAccountToken *bool        `json:"automountServiceAccountToken,omitempty" yaml:"automountServiceAccountToken,omitempty"`
    25  	Global                       bool         `json:"global,omitempty" yaml:"global,omitempty"`
    26  	Rules                        []PolicyRule `json:"rules,omitempty" yaml:"rules,omitempty"`
    27  }
    28  
    29  // Validate returns an error if the spec is not valid.
    30  func (sa ServiceAccountSpecV2) Validate() error {
    31  	if len(sa.Rules) == 0 {
    32  		return errors.NewNotValid(nil, "rules is required")
    33  	}
    34  	return nil
    35  }
    36  
    37  // ToLatest converts ServiceAccountSpecV2 to the latest version.
    38  func (sa ServiceAccountSpecV2) ToLatest() *PrimeServiceAccountSpecV3 {
    39  	return &PrimeServiceAccountSpecV3{
    40  		ServiceAccountSpecV3: ServiceAccountSpecV3{
    41  			AutomountServiceAccountToken: sa.AutomountServiceAccountToken,
    42  			Roles: []Role{
    43  				{
    44  					Global: sa.Global,
    45  					Rules:  sa.Rules,
    46  				},
    47  			},
    48  		},
    49  	}
    50  }
    51  
    52  // Role defines role spec for version 3.
    53  type Role struct {
    54  	Name   string       `json:"name" yaml:"name"`
    55  	Global bool         `json:"global,omitempty" yaml:"global,omitempty"`
    56  	Rules  []PolicyRule `json:"rules,omitempty" yaml:"rules,omitempty"`
    57  }
    58  
    59  // Validate returns an error if the spec is not valid.
    60  func (r Role) Validate() error {
    61  	if len(r.Rules) == 0 {
    62  		return errors.NewNotValid(nil, "rules is required")
    63  	}
    64  	return nil
    65  }
    66  
    67  // ServiceAccountSpecV3 defines spec for creating RBAC resource for the application for version 3.
    68  type ServiceAccountSpecV3 struct {
    69  	AutomountServiceAccountToken *bool `json:"automountServiceAccountToken,omitempty" yaml:"automountServiceAccountToken,omitempty"`
    70  
    71  	Roles []Role `json:"roles" yaml:"roles"`
    72  }
    73  
    74  // Validate returns an error if the spec is not valid.
    75  func (sa ServiceAccountSpecV3) Validate() error {
    76  	if len(sa.Roles) == 0 {
    77  		return errors.NewNotValid(nil, "roles is required")
    78  	}
    79  	for _, r := range sa.Roles {
    80  		if err := r.Validate(); err != nil {
    81  			return errors.Trace(err)
    82  		}
    83  	}
    84  	roleNames := set.NewStrings()
    85  	for _, r := range sa.Roles {
    86  		if err := r.Validate(); err != nil {
    87  			return errors.Trace(err)
    88  		}
    89  		if r.Name == "" {
    90  			continue
    91  		}
    92  		if roleNames.Contains(r.Name) {
    93  			return errors.NotValidf("duplicated role name %q", r.Name)
    94  		}
    95  		roleNames.Add(r.Name)
    96  	}
    97  	if roleNames.Size() == 0 || len(sa.Roles) == roleNames.Size() {
    98  		// All good.
    99  		return nil
   100  	}
   101  	return errors.NewNotValid(nil, "either all or none of the roles should have a name set")
   102  }
   103  
   104  // PrimeServiceAccountSpecV3 defines spec for creating the prime RBAC resources for version 3.
   105  type PrimeServiceAccountSpecV3 struct {
   106  	name                 string
   107  	ServiceAccountSpecV3 `json:",inline" yaml:",inline"`
   108  }
   109  
   110  // GetName returns the service accout name.
   111  func (psa PrimeServiceAccountSpecV3) GetName() string {
   112  	return psa.name
   113  }
   114  
   115  // SetName sets the service accout name.
   116  func (psa *PrimeServiceAccountSpecV3) SetName(name string) {
   117  	psa.name = name
   118  }
   119  
   120  // Validate returns an error if the spec is not valid.
   121  func (psa PrimeServiceAccountSpecV3) Validate() error {
   122  	err := psa.ServiceAccountSpecV3.Validate()
   123  	msg := "invalid primary service account"
   124  	if psa.name != "" {
   125  		msg = fmt.Sprintf("%s %q", msg, psa.name)
   126  	}
   127  	return errors.Annotatef(err, msg)
   128  }