mirror of
https://github.com/tailscale/tailscale.git
synced 2026-11-06 01:23:10 -05:00
ipn/store/kubestore: omit ARI replaces for unstamped shared certs (#22053)
A retained legacy cert may have been issued by a different account even when no pre-adoption local key is available. Require a matching fingerprint before claiming a shared-account renewal replaces it. Fixes #22041 Signed-off-by: Jaron Kramer <info@jkramertech.com>
This commit is contained in:
1 parent
1334899864
commit
6c6dd62b60
2 files changed
+36
-8
No files matched your search
@@ -284,9 +284,11 @@ func (s *Store) ShouldUseARIReplacesForRenewal(domain string) (bool, error) {
|
||||
}
|
||||
certFP := sec.Data[keyACMEAcctFP]
|
||||
if len(certFP) == 0 {
|
||||
// Legacy cert, no fingerprint stamp. Assume misaligned only if
|
||||
// we adopted a foreign shared key.
|
||||
if len(s.preAdoptedLocalKey) > 0 {
|
||||
// A legacy cert has no record of its issuing account. With a
|
||||
// shared account, the current key may have been created or adopted
|
||||
// after this cert was issued, even without a prior local key.
|
||||
// Omit replaces until a renewal stamps the issuing fingerprint.
|
||||
if s.acmeAccountsSecretName != "" || len(s.preAdoptedLocalKey) > 0 {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
|
||||
@@ -1107,6 +1107,7 @@ func TestShouldUseARIReplacesForRenewal(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
certShareMode string
|
||||
sharedSecret string
|
||||
acmeInMemory []byte // per-pod ACME key present in memory
|
||||
preAdopted []byte // sha256 of pre-adoption local key (foreign-key path)
|
||||
certSecret map[string][]byte
|
||||
@@ -1173,6 +1174,30 @@ func TestShouldUseARIReplacesForRenewal(t *testing.T) {
|
||||
certSecret: map[string][]byte{}, // no fingerprint field
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "legacy_cert_with_shared_account_returns_false",
|
||||
certShareMode: "rw",
|
||||
sharedSecret: "tailscale-acme-accounts",
|
||||
acmeInMemory: acmeKey,
|
||||
certSecret: map[string][]byte{},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "shared_account_fingerprint_matches",
|
||||
certShareMode: "rw",
|
||||
sharedSecret: "tailscale-acme-accounts",
|
||||
acmeInMemory: acmeKey,
|
||||
certSecret: map[string][]byte{keyACMEAcctFP: curFP},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "shared_account_fingerprint_differs",
|
||||
certShareMode: "rw",
|
||||
sharedSecret: "tailscale-acme-accounts",
|
||||
acmeInMemory: acmeKey,
|
||||
certSecret: map[string][]byte{keyACMEAcctFP: otherFP},
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
@@ -1186,11 +1211,12 @@ func TestShouldUseARIReplacesForRenewal(t *testing.T) {
|
||||
},
|
||||
}
|
||||
s := &Store{
|
||||
client: client,
|
||||
certShareMode: tt.certShareMode,
|
||||
memory: mem.Store{},
|
||||
preAdoptedLocalKey: tt.preAdopted,
|
||||
logf: t.Logf,
|
||||
client: client,
|
||||
certShareMode: tt.certShareMode,
|
||||
acmeAccountsSecretName: tt.sharedSecret,
|
||||
memory: mem.Store{},
|
||||
preAdoptedLocalKey: tt.preAdopted,
|
||||
logf: t.Logf,
|
||||
}
|
||||
if len(tt.acmeInMemory) > 0 {
|
||||
s.memory.WriteState(ipn.StateKey(acmeAccountStateKey), tt.acmeInMemory)
|
||||
|
||||
Reference in new issue
Block a user