apache / apache/pulsar-client-go
Producer encryption key metadata is never refreshed after first message
- Dominant language
- Go
- Stars
- 745
- Forks
- 389
- Avg merge
- 3d 20h
- Merged PRs (30d)
- 3
Description
## Expected behavior
When `KeyReader.PublicKey()` returns updated metadata for a key name (e.g., after key rotation), subsequent `Encrypt` calls should use the new metadata.
## Actual behavior
`DefaultMessageCrypto.Encrypt` caches the `EncryptionKeyInfo` (including metadata) on the first call for each `keyName` in `encryptedDataKeyMap`. The guard at line 153 (`if _, ok := d.encryptedDataKeyMap.Load(keyName); !ok`) prevents `addPublicKeyCipher` from being called again, so metadata is frozen for the producer's lifetime.
Long-lived producers stamp stale key-id metadata onto every message. After key rotation, consumers request private keys that no longer exist.
## Steps to reproduce
1. Create a `KeyReader` returning `Metadata{"key-id": "uuid-A"}` for key name `"latest"`
2. Call `Encrypt(["latest"], ...)` — metadata has `uuid-A` ✓
3. Update `KeyReader` to return `Metadata{"key-id": "uuid-B"}`
4. Call `Encrypt(["latest"], ...)` again
5. **Expected:** `uuid-B` / **Actual:** still `uuid-A`
Failing test
```go
func TestKeyRotationMetadataNotRefreshed(t *testing.T) {
keyName := "latest"
keyIDs := []string{"uuid-A", "uuid-B"}
keyReader := newRotatingKeyReader(t, keyIDs) // returns keyIDs[callCount % len] on each PublicKey call
msgCrypto, _ := NewDefaultMessageCrypto("test", true, log.DefaultNopLogger())
// First encrypt: captures uuid-A
msg1 := &pb.MessageMetadata{}
msgCrypto.Encrypt([]string{keyName}, keyReader, NewMessageMetadataSupplier(msg1), []byte("m1"))
keyID1 := msg1.EncryptionKeys[0].Metadata // uuid-A ✓
// KeyReader now returns uuid-B, but Encrypt won't call it again
msg2 := &pb.MessageMetadata{}
msgCrypto.Encrypt([]string{keyName}, keyReader, NewMessageMetadataSupplier(msg2), []byte("m2"))
keyID2 := msg2.EncryptionKeys[0].Metadata
// FAILS: keyID2 == "uuid-A" (stale), expected "uuid-B"
assert.Equal(t, "uuid-B", keyID2)
}
```
## System configuration
- pulsar-client-go: v0.19.0, v0.20.0, master
- Go/OS: any
---
I plan to open a PR with a fix. Thanks!
Contributor guide
Research direction
Start by locating DefaultMessageCrypto.Encrypt, encryptedDataKeyMap, and addPublicKeyCipher around the guard described at line 153. Reproduce the supplied TestKeyRotationMetadataNotRefreshed case with the rotating KeyReader, then run the relevant Go tests and verify that the second Encrypt records uuid-B rather than stale uuid-A metadata.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- security
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 65/100