Fix Lease revocation on SecretLeaseContainer destroy.

Closes gh-844
This commit is contained in:
Mark Paluch
2023-12-27 16:13:55 +01:00
parent 47028c933f
commit 0bc5513016
2 changed files with 54 additions and 7 deletions

View File

@@ -32,6 +32,7 @@ import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.function.BiConsumer;
import org.apache.commons.logging.Log;
@@ -410,6 +411,9 @@ public class SecretLeaseContainer extends SecretLeaseEventPublisher
else if (renewalScheduler.isLeaseRotateOnly(lease, requestedSecret)) {
scheduleLeaseRotation(requestedSecret, lease, renewalScheduler);
}
else if (lease.hasLeaseId()) {
renewalScheduler.associateLease(lease);
}
callback.accept(secrets, lease);
}
@@ -502,11 +506,16 @@ public class SecretLeaseContainer extends SecretLeaseEventPublisher
for (Entry<RequestedSecret, LeaseRenewalScheduler> entry : this.renewals.entrySet()) {
Lease lease = entry.getValue().getLease();
Lease previousLease = entry.getValue().getPreviousLease();
entry.getValue().disableScheduleRenewal();
if (lease != null && lease.hasLeaseId()) {
doRevokeLease(entry.getKey(), lease);
}
if (previousLease != null && previousLease.hasLeaseId()) {
doRevokeLease(entry.getKey(), previousLease);
}
}
this.renewals.clear();
@@ -844,12 +853,19 @@ public class SecretLeaseContainer extends SecretLeaseEventPublisher
*/
static class LeaseRenewalScheduler {
private static final AtomicReferenceFieldUpdater<LeaseRenewalScheduler, Lease> CURRENT_UPDATER = AtomicReferenceFieldUpdater
.newUpdater(LeaseRenewalScheduler.class, Lease.class, "currentLeaseRef");
@SuppressWarnings("FieldMayBeFinal") // allow setting via reflection.
private static Log logger = LogFactory.getLog(LeaseRenewalScheduler.class);
private final TaskScheduler taskScheduler;
final AtomicReference<Lease> currentLeaseRef = new AtomicReference<>();
@Nullable
volatile Lease currentLeaseRef;
@Nullable
volatile Lease previousLeaseRef;
final Map<Lease, ScheduledFuture<?>> schedules = new ConcurrentHashMap<>();
@@ -884,8 +900,8 @@ public class SecretLeaseContainer extends SecretLeaseEventPublisher
}
}
Lease currentLease = this.currentLeaseRef.get();
this.currentLeaseRef.set(lease);
Lease currentLease = CURRENT_UPDATER.get(this);
CURRENT_UPDATER.set(this, lease);
if (currentLease != null) {
cancelSchedule(currentLease);
@@ -898,7 +914,7 @@ public class SecretLeaseContainer extends SecretLeaseEventPublisher
LeaseRenewalScheduler.this.schedules.remove(lease);
if (LeaseRenewalScheduler.this.currentLeaseRef.get() != lease) {
if (CURRENT_UPDATER.get(LeaseRenewalScheduler.this) != lease) {
logger.debug("Current lease has changed. Skipping renewal");
return;
}
@@ -918,7 +934,7 @@ public class SecretLeaseContainer extends SecretLeaseEventPublisher
// Renew lease may call scheduleRenewal(…) with a different lease
// Id to alter set up its own renewal schedule. If it's the old
// lease, then renewLease() outcome controls the current LeaseId.
LeaseRenewalScheduler.this.currentLeaseRef.compareAndSet(lease, renewLease.renewLease(lease));
CURRENT_UPDATER.compareAndSet(LeaseRenewalScheduler.this, lease, renewLease.renewLease(lease));
}
catch (Exception e) {
logger.error(String.format("Cannot renew lease %s", lease.getLeaseId()), e);
@@ -932,6 +948,10 @@ public class SecretLeaseContainer extends SecretLeaseEventPublisher
this.schedules.put(lease, scheduledFuture);
}
void associateLease(Lease lease) {
CURRENT_UPDATER.set(this, lease);
}
private void cancelSchedule(Lease lease) {
ScheduledFuture<?> scheduledFuture = this.schedules.get(lease);
@@ -951,7 +971,8 @@ public class SecretLeaseContainer extends SecretLeaseEventPublisher
*/
void disableScheduleRenewal() {
this.currentLeaseRef.set(null);
// capture the previous lease to revoke it
this.previousLeaseRef = CURRENT_UPDATER.getAndSet(this, null);
Set<Lease> leases = new HashSet<>(this.schedules.keySet());
for (Lease lease : leases) {
@@ -984,7 +1005,12 @@ public class SecretLeaseContainer extends SecretLeaseEventPublisher
@Nullable
public Lease getLease() {
return this.currentLeaseRef.get();
return CURRENT_UPDATER.get(this);
}
@Nullable
public Lease getPreviousLease() {
return this.previousLeaseRef;
}
private boolean isLeaseRotateOnly(Lease lease, RequestedSecret requestedSecret) {

View File

@@ -630,6 +630,27 @@ class SecretLeaseContainerUnitTests {
verify(this.leaseListenerAdapter, never()).onLeaseEvent(any(AfterSecretLeaseRevocationEvent.class));
}
@Test
void shouldRevokeSecretsOnDestroy() throws Exception {
VaultResponse secrets = new VaultResponse();
secrets.setData(Collections.singletonMap("key", (Object) "value"));
secrets.setLeaseId("1234");
secrets.setLeaseDuration(1000);
when(this.vaultOperations.read(this.requestedSecret.getPath())).thenReturn(secrets);
this.secretLeaseContainer.addRequestedSecret(this.requestedSecret);
this.secretLeaseContainer.start();
this.secretLeaseContainer.stop();
this.secretLeaseContainer.destroy();
verify(this.leaseListenerAdapter).onLeaseEvent(any(SecretLeaseCreatedEvent.class));
verify(this.leaseListenerAdapter).onLeaseEvent(any(BeforeSecretLeaseRevocationEvent.class));
verify(this.leaseListenerAdapter).onLeaseEvent(any(AfterSecretLeaseRevocationEvent.class));
}
@Test
void shouldRequestRotatingGenericSecrets() {