RabbitMQ

RabbitMQ - Received ERROR payload=Access refused for user 'guest' 에러 원인 및 해결

비뀨_ 2023. 5. 7. 02:01

문제 상황

AWS EC2에서 8082 포트에서 1:1 채팅을 할 수 있는 모듈을  RabbitMQ와 STOMP를 사용해 구동하려는 중 발생함.

자꾸 guest로 연결을 하려고 한다.

[           main] o.s.a.r.c.CachingConnectionFactory       : Attempting to connect to: {EC2 퍼블릭 IPv4 주소}:5672
[           main] o.s.a.r.c.CachingConnectionFactory       : Created new connection: connectionFactory#2a50b32d:0/SimpleConnection@2d4fb0d8 [delegate=amqp://lastone@{EC2 퍼블릭 IPv4 주소}:5672/, localPort= 35466]
[           main] o.s.m.s.s.StompBrokerRelayMessageHandler : Starting...
[           main] o.s.m.s.s.StompBrokerRelayMessageHandler : Starting "system" session, StompBrokerRelay[ReactorNettyTcpClient[reactor.netty.tcp.TcpClientConnect@60dcf9ec]]
[           main] o.s.m.s.s.StompBrokerRelayMessageHandler : Started.
[           main] com.lastone.chat.ChatServerApplication   : Started ChatServerApplication in 15.154 seconds (JVM running for 16.559)
[ent-scheduler-1] o.s.m.s.s.StompBrokerRelayMessageHandler : Received ERROR {message=[Bad CONNECT], content-type=[text/plain], version=[1.0,1.1,1.2], content-length=[26]} session=_system_ text/plain payload=non-loopback access denied

위의 로그처럼 StompBrokerReplayMessageHandler 에서 오류가 났다.

그래서 RabbitMQ의 로그를 한번 들여다 봤다.

 

기본적으로 ubuntu에서는 /var/log/rabbitmq 경로에 로그가 있다.

 

RabbitMQ의 로그

connection <0.688.0> ({EC2 퍼블릭IPv4주소}:35466 -> XXX.XX.XX.XXX:5672 - connectionFactory#2a50b32d:0): user 'lastone' authenticated and granted access to vhost '/'
accepting STOMP connection <0.708.0> ({EC2 퍼블릭IPv4주소}:49016 -> XXX.XX.XX.XXX:61613)
AMQP 0-9-1 client call timeout was 70000 ms, is updated to a safe effective value of 130000 ms
STOMP login failed for user 'guest': this user's access is restricted to localhost
STOMP error frame sent:
Message: "Bad CONNECT"
Detail: "non-loopback access denied"
Server private detail: none
closing STOMP connection <0.708.0> ({EC2 퍼블릭IPv4주소}:49016 -> XXX.XX.XX.XXX:61613)
closing AMQP connection <0.688.0> ({EC2 퍼블릭IPv4주소}:35466 -> XXX.XX.XX.XXX:5672 - connectionFactory#2a50b32d:0, vhost: '/', user: 'lastone')

 

application-prod.yml

yml 파일은 rabbitmq 부분만 보여줘도 되기 때문에 해당 부분만 적었다.

spring:
  rabbitmq:
    host: {EC2 퍼블릭IPv4 주소}
    port: 5672
    username: lastone
    password: 비밀번호
    virtual-host: /

설정하지 않으면 username과 password는 guest, guest가 된다. 

 

STOMP 설정

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.messaging.simp.config.StompBrokerRelayRegistration;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@Configuration
@EnableWebSocketMessageBroker
@Slf4j
public class StompConfig implements WebSocketMessageBrokerConfigurer {
    @Value("${lastOne.front.url}")
    private String frontEndURL;
    @Value("${spring.rabbitmq.host}")
    private String host;
    @Value("${lastOne.rabbitmq.username}")
    private String clientUsername;
    @Value("${lastOne.rabbitmq.password}")
    private String clientPassword;
    @Value("${spring.rabbitmq.port}")
    private int port;
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/chat/stomp")
                .setAllowedOrigins("*")
                .withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.setPathMatcher(new AntPathMatcher("."));
        StompBrokerRelayRegistration relayRegistration = registry.enableStompBrokerRelay("/topic")
                .setRelayHost(host)
                .setRelayPort(61613)
                .setClientLogin(clientUsername)
                .setClientPasscode(clientPassword);
                
        relayRegistration.setSystemHeartbeatSendInterval(20000);
        relayRegistration.setSystemHeartbeatReceiveInterval(20000);
    }

}

 

 

그래서 왜 guest로 연결할까라고 했는데, 되게 멍청한 곳에서 실수를 했다.

 

연결 설정을 등록하는 클래스인 StompBrokerRelayRegistration는 기본적인 설정이 들어있다.

 

위에서 나는 ClientLogin만 설정하고 SystemLogin을 설정하지 않았기 때문에, 

기본인 guest로 연결을 진행한 것이다.

 

STOMP 설정에서 configureMessageBroker 메서드에 아래의 시스템에 연결하는 코드를 변경하자

StompBrokerRelayRegistration relayRegistration = registry.enableStompBrokerRelay("/topic")
        .setRelayHost(host)
        .setRelayPort(61613)
        .setClientLogin(clientUsername)
        .setClientPasscode(clientPassword)
        .setSystemLogin(systemUsername)
        .setSystemPasscode(systemPassword);

 

!물론 RabbitMQ의 Management에서 systemUsername에 해당하는 유저를 만들어야한다.!

기본적으로 rabbitmq-management 플러그인을 설치하는 법은 구글에 많으니까 그걸 보면 되고

위의 이미지에서 빨간박스로 추가하거나, EC2에 putty로 접속해서 

sudo rabbitmqctl add_user [추가할 사용자 이름] [사용자 비밀번호]

명령어로 해당 유저를 생성하고 필요한 태그, 권한을 설정해주면 된다. 

 

 

설정 후 EC2에서 Application을 띄웠을 때 로그

[           main] o.s.a.r.c.CachingConnectionFactory       : Attempting to connect to: {EC2 퍼블릭 IPv4 주소}:5672
[           main] o.s.a.r.c.CachingConnectionFactory       : Created new connection: connectionFactory#2ce03e86:0/SimpleConnection@365cef67 [delegate=amqp://lastone@{EC2 퍼블릭 IPv4 주소}:5672/, localPort= 41180]
[           main] o.s.m.s.s.StompBrokerRelayMessageHandler : Starting...
[           main] o.s.m.s.s.StompBrokerRelayMessageHandler : Starting "system" session, StompBrokerRelay[ReactorNettyTcpClient[reactor.netty.tcp.TcpClientConnect@7c2b6acb]]
[           main] o.s.m.s.s.StompBrokerRelayMessageHandler : Started.
[           main] com.lastone.chat.ChatServerApplication   : Started ChatServerApplication in 14.404 seconds (JVM running for 15.444)
[ent-scheduler-1] o.s.m.s.s.StompBrokerRelayMessageHandler : "System" session connected.
[ent-scheduler-1] o.s.m.s.s.StompBrokerRelayMessageHandler : BrokerAvailabilityEvent[available=true, StompBrokerRelay[ReactorNettyTcpClient[reactor.netty.tcp.TcpClientConnect@7c2b6acb]]]
[nio-8082-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
[nio-8082-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
[nio-8082-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 3 ms
[MessageBroker-1] o.s.w.s.c.WebSocketMessageBrokerStats    : WebSocketSession[0 current WS(0)-HttpStream(0)-HttpPoll(0), 0 total, 0 closed abnormally (0 connect failure, 0 send limit, 0 transport error)], stompSubProtocol[processed CONNECT(0)-CONNECTED(0)-DISCONNECT(0)], stompBrokerRelay[1 sessions, ReactorNettyTcpClient[reactor.netty.tcp.TcpClientConnect@7c2b6acb] (available), processed CONNECT(1)-CONNECTED(1)-DISCONNECT(0)], inboundChannel[pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0], outboundChannel[pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0], sockJsScheduler[pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 0]

연결이 잘 됐다.

 

후기

해결책은 너무 간단해서 어이없을 정도지만, 일단 됐으니깐…

사실 RabbitMQ 도입을 포기할까 싶었다.

위의 이미지는 Notion에 정리한 시도다. 엄청 삽질을 많이 했다. 

 

일주일 넘게 일 끝나고서 3-4시간씩 보고, 주말에도 반나절 이상씩 EC2에 설치된 RabbitMQ의 로그를 분석하기도 하고, 챗 GPT에 계속 돌려 물어보고, 공식문서를 살펴보기도 했기 때문이다.

물론 공식문서를 제대로 이해를 못 했기 때문에 그동안 해결 못 했겠지만…

근데 진짜 해뜨기 전이 가장 어둡다고, 원활하게 끝내기 위해서는 ‘RabbitMQ 도입을 포기해야 할 것 같다’고 팀원들에게 말하고 오늘까지만 해보자라는 마음으로 찾다가 된 거라 좀 장난 아니게 좋았다.

사실 이번 프로젝트 하면서 기한이 있는 작업에서 모르는 기술에 대한 기반지식 없이 무작정 배우려 쫓는 건 지양해야 할 것 같다.

물감들로 색 배합하는 법도 모르면서 엄청 멋있는 그림들을 만들려는 느낌?

Message Queue는 지금은 RabbitMQ를 썼고, 큰 규모에서 Apache Kafka 등 많은 활용도를 가졌기 때문에 계속적으로 공부를 할 예정이다. 다음 사이드 프로젝트는 Message Queue를 사용하기 때문에 그전까지 기반 지식들을 쌓아야 놓아야겠다. 그 뒤에 지금 프로젝트도 적용시킬 수 있었으면 좋겠다.