spring-cloud-consul icon indicating copy to clipboard operation
spring-cloud-consul copied to clipboard

Ttl Heartbeats don't send acl token if configured

Open chriswhite199 opened this issue 5 years ago • 2 comments

If heartbeat is enabled paired with acl tokens, then the heartbeat task does not configure the token to use when communicating with the consul server

spring.cloud.consul.discovery:
  acl-token: ${uuid}
  heartbeat.enabled: true

ConsulHeartbeatTask has this method call to agentCheckPass:

@Override
public void run() {
	TtlScheduler.this.client.agentCheckPass(this.checkId);
	if (log.isDebugEnabled()) {
		log.debug("Sending consul heartbeat for: " + this.checkId);
	}
}

Which without a token, you'll see the following stack trace:

com.ecwid.consul.v1.OperationException: OperationException(statusCode=403, statusMessage='Forbidden', statusContent='Permission denied')
        at com.ecwid.consul.v1.agent.AgentConsulClient.agentCheckPass(AgentConsulClient.java:211) ~[consul-api-1.4.1.jar:na]
        at com.ecwid.consul.v1.agent.AgentConsulClient.agentCheckPass(AgentConsulClient.java:198) ~[consul-api-1.4.1.jar:na]
        at com.ecwid.consul.v1.agent.AgentConsulClient.agentCheckPass(AgentConsulClient.java:193) ~[consul-api-1.4.1.jar:na]
        at com.ecwid.consul.v1.ConsulClient.agentCheckPass(ConsulClient.java:259) ~[consul-api-1.4.1.jar:na]
        at org.springframework.cloud.consul.discovery.TtlScheduler$ConsulHeartbeatTask.run(TtlScheduler.java:95) ~[spring-cloud-consul-discovery-2.1.1.RELEASE.jar:2.1.1.RELEASE]

Which can be overridden to pass a token too (can be null too):

@Override
public void run() {
	TtlScheduler.this.client.agentCheckPass(this.checkId, this.aclToken);
	if (log.isDebugEnabled()) {
		log.debug("Sending consul heartbeat for: " + this.checkId);
	}
}

So any reason why i can't submit a simple PR to fix this (Ie am i missing something?)

chriswhite199 avatar May 16 '19 17:05 chriswhite199

PRs welcome

spencergibb avatar May 16 '19 17:05 spencergibb

An AOP based approach to patch while a PR is worked on:

import com.ecwid.consul.v1.ConsulClient;
import com.ecwid.consul.v1.Response;
import javax.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.consul.ConditionalOnConsulEnabled;
import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties;
import org.springframework.context.annotation.Configuration;

/**
 * AOP fix to ensure the ACL token is sent when performing agent checks
 *
 * <p>https://github.com/spring-cloud/spring-cloud-consul/issues/559
 */
@Aspect
@Configuration
@RequiredArgsConstructor
@ConditionalOnConsulEnabled
@ConditionalOnProperty("spring.cloud.consul.discovery.acl-token")
@Slf4j
public class ConsulClientAspect {
    private final ConsulDiscoveryProperties consulDiscoveryProperties;

    @PostConstruct
    public void init() {
        log.warn("Hooking ConsulClient.agentCheckPass(String) calls to enforce acl token passing");
    }

    /**
     * Trap calls made to {@link ConsulClient#agentCheckPass(String)} and call the overridden method variant with ACL
     * token
     */
    @SneakyThrows
    @Around("execution (* com.ecwid.consul.v1.ConsulClient.agentCheckPass(String))")
    public Response<Void> trapAgentCheckPass(final ProceedingJoinPoint joinPoint) {
        final String checkId = (String) joinPoint.getArgs()[0];
        final ConsulClient client = (ConsulClient) joinPoint.getThis();

        return client.agentCheckPass(checkId, null, this.consulDiscoveryProperties.getAclToken());
    }
}

chriswhite199 avatar May 16 '19 18:05 chriswhite199