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 }