Skip to content

Commit

Permalink
Fix Lease revocation on SecretLeaseContainer destroy.
Browse files Browse the repository at this point in the history
Closes gh-844
  • Loading branch information
mp911de committed Dec 27, 2023
1 parent 47028c9 commit 0bc5513
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
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;
Expand Down Expand Up @@ -410,6 +411,9 @@ else if (isRotatingGenericSecret(requestedSecret, secrets)) {
else if (renewalScheduler.isLeaseRotateOnly(lease, requestedSecret)) {
scheduleLeaseRotation(requestedSecret, lease, renewalScheduler);
}
else if (lease.hasLeaseId()) {
renewalScheduler.associateLease(lease);
}

callback.accept(secrets, lease);
}
Expand Down Expand Up @@ -502,11 +506,16 @@ public void destroy() throws Exception {
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();

Expand Down Expand Up @@ -844,12 +853,19 @@ protected void doRevokeLease(RequestedSecret requestedSecret, Lease lease) {
*/
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<>();

Expand Down Expand Up @@ -884,8 +900,8 @@ void scheduleRenewal(RequestedSecret requestedSecret, RenewLease renewLease, Lea
}
}

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);
Expand All @@ -898,7 +914,7 @@ public void run() {

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;
}
Expand All @@ -918,7 +934,7 @@ public void run() {
// 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);
Expand All @@ -932,6 +948,10 @@ public void run() {
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);
Expand All @@ -951,7 +971,8 @@ private void cancelSchedule(Lease lease) {
*/
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) {
Expand Down Expand Up @@ -984,7 +1005,12 @@ private boolean isLeaseRenewable(@Nullable Lease lease, RequestedSecret requeste

@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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,27 @@ void shouldNotRevokeSecretsWithoutLease() throws Exception {
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() {

Expand Down

0 comments on commit 0bc5513

Please sign in to comment.