auth: redact auth method client secret (#25328)

OIDC client secrets that users provide in auth method configuration are,
well, secret, so we should hide them from API calls and event streams.
This commit is contained in:
Daniel Bennett
2025-03-10 12:12:02 -04:00
committed by GitHub
parent 4a1b050eb8
commit dc482bf905
5 changed files with 39 additions and 1 deletions

3
.changelog/25328.txt Normal file
View File

@@ -0,0 +1,3 @@
```release-note:security
auth: Redact OIDC client secret from API responses and event stream ([CVE-2025-1296](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2025-1296))
```

View File

@@ -2084,7 +2084,7 @@ func (a *ACL) GetAuthMethod(
// We didn't encounter an error looking up the index; set the auth
// method on the reply and exit successfully.
reply.AuthMethod = out
reply.AuthMethod = out.Sanitize()
return nil
},
})

View File

@@ -110,6 +110,7 @@ func eventFromChange(change memdb.Change) (structs.Event, bool) {
if !ok {
return structs.Event{}, false
}
before = before.Sanitize()
return structs.Event{
Topic: structs.TopicACLAuthMethod,
Key: before.Name,
@@ -283,6 +284,7 @@ func eventFromChange(change memdb.Change) (structs.Event, bool) {
if !ok {
return structs.Event{}, false
}
after = after.Sanitize()
return structs.Event{
Topic: structs.TopicACLAuthMethod,
Key: after.Name,

View File

@@ -978,6 +978,21 @@ func (a *ACLAuthMethod) Validate(minTTL, maxTTL time.Duration) error {
return mErr.ErrorOrNil()
}
// Sanitize returns a copy of the ACLAuthMethod with any secrets redacted
func (a *ACLAuthMethod) Sanitize() *ACLAuthMethod {
if a == nil || a.Config == nil {
return a
}
// copy to ensure we do not mutate a pointer pulled directly out of state.
clean := a.Copy()
// clean nested structs here, so it's obvious what all is being cleaned
// in one spot, rather than follow a stack of sanitization calls.
if clean.Config.OIDCClientSecret != "" {
clean.Config.OIDCClientSecret = "redacted"
}
return clean
}
// TokenLocalityIsGlobal returns whether the auth method creates global ACL
// tokens or not.
func (a *ACLAuthMethod) TokenLocalityIsGlobal() bool {

View File

@@ -1263,6 +1263,24 @@ func TestACLAuthMethod_Validate(t *testing.T) {
}
}
// Sanitize method should redact sensitive values
func TestACLAuthMethod_Sanitize(t *testing.T) {
// these just shouldn't nil panic
am := &ACLAuthMethod{}
am.Sanitize()
am.Config = &ACLAuthMethodConfig{}
am.Sanitize()
t.Run("client secret", func(t *testing.T) {
am := am.Copy()
am.Config.OIDCClientSecret = "very private secret"
dirty := am.Config.OIDCClientSecret
clean := am.Sanitize().Config.OIDCClientSecret
must.Eq(t, "very private secret", dirty)
must.Eq(t, "redacted", clean)
})
}
func TestACLAuthMethod_Merge(t *testing.T) {
ci.Parallel(t)