github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/core/secrets/secret.go (about) 1 // Copyright 2021 Canonical Ltd. 2 // Licensed under the LGPLv3, see LICENCE file for details. 3 4 package secrets 5 6 import ( 7 "fmt" 8 "net/url" 9 "regexp" 10 "strings" 11 "time" 12 13 "github.com/juju/errors" 14 "github.com/rs/xid" 15 ) 16 17 // SecretConfig is used when creating a secret. 18 type SecretConfig struct { 19 RotatePolicy *RotatePolicy 20 NextRotateTime *time.Time 21 ExpireTime *time.Time 22 Description *string 23 Label *string 24 Params map[string]interface{} 25 } 26 27 // Validate returns an error if params are invalid. 28 func (c *SecretConfig) Validate() error { 29 if c.RotatePolicy != nil && !c.RotatePolicy.IsValid() { 30 return errors.NotValidf("secret rotate policy %q", c.RotatePolicy) 31 } 32 if c.RotatePolicy.WillRotate() && c.NextRotateTime == nil { 33 return errors.New("cannot specify a secret rotate policy without a next rotate time") 34 } 35 if !c.RotatePolicy.WillRotate() && c.NextRotateTime != nil { 36 return errors.New("cannot specify a secret rotate time without a rotate policy") 37 } 38 return nil 39 } 40 41 // URI represents a reference to a secret. 42 type URI struct { 43 SourceUUID string 44 ID string 45 } 46 47 const ( 48 idSnippet = `[0-9a-z]{20}` 49 uuidSnippet = `[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}` 50 51 // SecretScheme is the URL prefix for a secret. 52 SecretScheme = "secret" 53 ) 54 55 var validUUID = regexp.MustCompile(uuidSnippet) 56 57 var secretURIParse = regexp.MustCompile(`^` + 58 fmt.Sprintf(`((?P<source>%s)/)?(?P<id>%s)`, uuidSnippet, idSnippet) + 59 `$`) 60 61 // ParseURI parses the specified string into a URI. 62 func ParseURI(str string) (*URI, error) { 63 u, err := url.Parse(str) 64 if err != nil { 65 return nil, errors.Trace(err) 66 } 67 if u.Scheme == "" { 68 u.Scheme = SecretScheme 69 } else if u.Scheme != SecretScheme { 70 return nil, errors.NotValidf("secret URI scheme %q", u.Scheme) 71 } 72 if u.Host != "" && !validUUID.MatchString(u.Host) { 73 return nil, errors.NotValidf("host controller UUID %q", u.Host) 74 } 75 76 idStr := strings.TrimLeft(u.Path, "/") 77 if idStr == "" { 78 idStr = u.Opaque 79 } 80 valid := secretURIParse.MatchString(idStr) 81 if !valid { 82 return nil, errors.NotValidf("secret URI %q", str) 83 } 84 sourceUUID := secretURIParse.ReplaceAllString(idStr, "$source") 85 if sourceUUID == "" { 86 sourceUUID = u.Host 87 } 88 idPart := secretURIParse.ReplaceAllString(idStr, "$id") 89 id, err := xid.FromString(idPart) 90 if err != nil { 91 return nil, errors.NotValidf("secret URI %q", str) 92 } 93 result := &URI{ 94 SourceUUID: sourceUUID, 95 ID: id.String(), 96 } 97 return result, nil 98 } 99 100 // NewURI returns a new secret URI. 101 func NewURI() *URI { 102 return &URI{ 103 ID: xid.New().String(), 104 } 105 } 106 107 // WithSource returns a secret URI with the source. 108 func (u *URI) WithSource(uuid string) *URI { 109 u.SourceUUID = uuid 110 return u 111 } 112 113 // IsLocal returns true if this URI is local 114 // to the specified uuid. 115 func (u *URI) IsLocal(sourceUUID string) bool { 116 return u.SourceUUID == "" || u.SourceUUID == sourceUUID 117 } 118 119 // Name generates the secret name. 120 func (u URI) Name(revision int) string { 121 return fmt.Sprintf("%s-%d", u.ID, revision) 122 } 123 124 // String prints the URI as a string. 125 func (u *URI) String() string { 126 if u == nil { 127 return "" 128 } 129 var fullPath []string 130 fullPath = append(fullPath, u.ID) 131 str := strings.Join(fullPath, "/") 132 if u.SourceUUID == "" { 133 urlValue := url.URL{ 134 Scheme: SecretScheme, 135 Opaque: str, 136 } 137 return urlValue.String() 138 } 139 urlValue := url.URL{ 140 Scheme: SecretScheme, 141 Host: u.SourceUUID, 142 Path: str, 143 } 144 return urlValue.String() 145 } 146 147 // SecretMetadata holds metadata about a secret. 148 type SecretMetadata struct { 149 // Read only after creation. 150 URI *URI 151 152 // Version starts at 1 and is incremented 153 // whenever an incompatible change is made. 154 Version int 155 156 // These can be updated after creation. 157 Description string 158 Label string 159 RotatePolicy RotatePolicy 160 161 // Set by service on creation/update. 162 163 // OwnerTag is the entity which created the secret. 164 OwnerTag string 165 166 CreateTime time.Time 167 UpdateTime time.Time 168 169 // These are denormalised here for ease of access. 170 171 // LatestRevision is the most recent secret revision. 172 LatestRevision int 173 // LatestExpireTime is the expire time of the most recent revision. 174 LatestExpireTime *time.Time 175 // NextRotateTime is when the secret should be rotated. 176 NextRotateTime *time.Time 177 178 // AutoPrune is true if the secret revisions should be pruned when it's not been used. 179 AutoPrune bool 180 181 // Access is a list of access information for this secret. 182 Access []AccessInfo 183 } 184 185 // AccessInfo holds info about a secret access information. 186 type AccessInfo struct { 187 Target string 188 Scope string 189 Role SecretRole 190 } 191 192 // SecretRevisionMetadata holds metadata about a secret revision. 193 type SecretRevisionMetadata struct { 194 Revision int 195 ValueRef *ValueRef 196 BackendName *string 197 CreateTime time.Time 198 UpdateTime time.Time 199 ExpireTime *time.Time 200 } 201 202 // SecretOwnerMetadata holds a secret metadata and any backend references of revisions. 203 type SecretOwnerMetadata struct { 204 Metadata SecretMetadata 205 Revisions []int 206 } 207 208 // SecretMetadataForDrain holds a secret metadata and any backend references of revisions for drain. 209 type SecretMetadataForDrain struct { 210 Metadata SecretMetadata 211 Revisions []SecretRevisionMetadata 212 } 213 214 // SecretConsumerMetadata holds metadata about a secret 215 // for a consumer of the secret. 216 type SecretConsumerMetadata struct { 217 // Label is used when notifying the consumer 218 // about changes to the secret. 219 Label string 220 // CurrentRevision is current revision the 221 // consumer wants to read. 222 CurrentRevision int 223 // LatestRevision is the latest secret revision. 224 LatestRevision int 225 } 226 227 // SecretRevisionInfo holds info used to read a secret vale. 228 type SecretRevisionInfo struct { 229 Revision int 230 Label string 231 } 232 233 // Filter is used when querying secrets. 234 type Filter struct { 235 URI *URI 236 Label *string 237 Revision *int 238 OwnerTag *string 239 }