Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,17 @@ dependencies {

// Swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.6.0'

// monoitoring
implementation("org.springframework.boot:spring-boot-starter-actuator")
runtimeOnly("io.micrometer:micrometer-registry-prometheus")
}

tasks.named('test') {
useJUnitPlatform()
}

tasks.withType(Checkstyle){
tasks.withType(Checkstyle) {
reports {
xml.required = true
html.required = true
Expand All @@ -91,7 +95,7 @@ tasks.withType(Checkstyle){

checkstyle {
configFile = file("checkstyle/config/rules.xml")
configProperties = ["suppressionFile" : "checkstyle/config/suppressions.xml"]
configProperties = ["suppressionFile": "checkstyle/config/suppressions.xml"]
maxWarnings = 0
}

Expand Down
68 changes: 68 additions & 0 deletions docker-compose-db.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
version: '3.8'
services:
redis:
image: redis:alpine
container_name: rabbit-redis
hostname: redis
ports:
- "6379:6379"
networks:
- rabbit-db

mysql_master:
container_name: rabbit-mysql-master
image: mysql:8.0
environment:
MYSQL_DATABASE: rabbit
MYSQL_ROOT_HOST: '%'
MYSQL_ROOT_PASSWORD: 1234
ports:
- "3306:3306"
volumes:
- ./mysql/master-data-source.cnf:/etc/mysql/conf.d/my.cnf
- ./mysql/init-master.sql:/docker-entrypoint-initdb.d/01-init-master.sql
networks:
- rabbit-db
healthcheck:
test: [ "CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p1234" ]
timeout: 20s
retries: 10

mysql_replica:
container_name: rabbit-mysql-replica
image: mysql:8.0
environment:
MYSQL_DATABASE: rabbit
MYSQL_ROOT_HOST: '%'
MYSQL_ROOT_PASSWORD: 1234
ports:
- "3307:3306"
volumes:
- ./mysql/replica-data-source.cnf:/etc/mysql/conf.d/my.cnf
networks:
- rabbit-db
depends_on:
mysql_master:
condition: service_healthy
healthcheck:
test: [ "CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p1234" ]
timeout: 20s
retries: 10

mysql_replication_setup:
image: mysql:8.0
container_name: mysql_replication_setup
volumes:
- ./mysql/setup-replication.sh:/setup-replication.sh
command: [ "/bin/bash", "/setup-replication.sh" ]
networks:
- rabbit-db
depends_on:
mysql_master:
condition: service_healthy
mysql_replica:
condition: service_healthy
restart: "no"

networks:
rabbit-db:
30 changes: 30 additions & 0 deletions docker-compose-monitoring.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
version: '3.8'
services:
prometheus:
build: ./monitoring/prometheus
container_name: rabbit-prometheus
ports:
- 9090:9090
environment:
ACTUATOR_METRICS_PATH: ${ACTUATOR_METRICS_PATH:-/actuator/prometheus}
ACTUATOR_USERNAME: ${ACTUATOR_USERNAME:-rabbit}
ACTUATOR_PASSWORD: ${ACTUATOR_PASSWORD:-rabbit1234}
restart: always
networks:
- rabbit-monitoring

grafana:
image: grafana/grafana
container_name: rabbit-grafana
ports:
- 3000:3000
volumes:
- ./monitoring/grafana/volume:/var/lib/grafana
restart: always
networks:
- rabbit-monitoring
depends_on:
- prometheus

networks:
rabbit-monitoring:
74 changes: 5 additions & 69 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: '3.8'
services:
rabbitmq:
image: rabbitmq:3-management
container_name: rabbitmq
container_name: rabbit-rabbitmq
ports:
- "5672:5672"
- "15672:15672"
Expand All @@ -13,83 +13,19 @@ services:
RABBITMQ_DEFAULT_USER: guest
RABBITMQ_DEFAULT_PASS: guest
networks:
- my_network

redis:
image: redis:alpine
container_name: redis
hostname: redis
ports:
- "6379:6379"
networks:
- my_network

mysql_master:
container_name: rabbit-mysql-master
image: mysql:8.0
environment:
MYSQL_DATABASE: rabbit
MYSQL_ROOT_HOST: '%'
MYSQL_ROOT_PASSWORD: 1234
ports:
- "3306:3306"
volumes:
- ./mysql/master-data-source.cnf:/etc/mysql/conf.d/my.cnf
- ./mysql/init-master.sql:/docker-entrypoint-initdb.d/01-init-master.sql
networks:
- my_network
healthcheck:
test: [ "CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p1234" ]
timeout: 20s
retries: 10

mysql_replica:
container_name: rabbit-mysql-replica
image: mysql:8.0
environment:
MYSQL_DATABASE: rabbit
MYSQL_ROOT_HOST: '%'
MYSQL_ROOT_PASSWORD: 1234
ports:
- "3307:3306"
volumes:
- ./mysql/replica-data-source.cnf:/etc/mysql/conf.d/my.cnf
networks:
- my_network
depends_on:
mysql_master:
condition: service_healthy
healthcheck:
test: [ "CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p1234" ]
timeout: 20s
retries: 10

mysql_replication_setup:
image: mysql:8.0
container_name: mysql_replication_setup
volumes:
- ./mysql/setup-replication.sh:/setup-replication.sh
command: [ "/bin/bash", "/setup-replication.sh" ]
networks:
- my_network
depends_on:
mysql_master:
condition: service_healthy
mysql_replica:
condition: service_healthy
restart: "no"
- rabbit-default

nginx:
image: nginx:latest
container_name: nginx
container_name: rabbit-nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/config/nginx.conf:/etc/nginx/conf.d/default.conf
- ./nginx/ssl:/etc/nginx/ssl
networks:
- my_network
- rabbit-default

networks:
my_network:
rabbit-default:
19 changes: 19 additions & 0 deletions monitoring/prometheus/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
FROM alpine:latest

# 2025.08.30 ๊ธฐ์ค€ ์ตœ์‹  LTS ๋ฒ„์ „
ENV PROMETHEUS_VERSION=3.5.0

# Prometheus ์„ค์น˜
RUN wget https://github.com/prometheus/prometheus/releases/download/v${PROMETHEUS_VERSION}/prometheus-${PROMETHEUS_VERSION}.linux-amd64.tar.gz \
&& tar xvf prometheus-${PROMETHEUS_VERSION}.linux-amd64.tar.gz \
&& mv prometheus-${PROMETHEUS_VERSION}.linux-amd64/prometheus /bin/prometheus \
&& mv prometheus-${PROMETHEUS_VERSION}.linux-amd64/promtool /bin/promtool \
&& rm -rf prometheus-${PROMETHEUS_VERSION}.linux-amd64*

# envsubst ์„ค์น˜
RUN apk add --no-cache gettext

# ์„ค์ • ํŒŒ์ผ ๋ณต์‚ฌ
COPY config/prometheus-env.yml /etc/prometheus/prometheus-env.yml

ENTRYPOINT ["/bin/sh", "-c", "envsubst < /etc/prometheus/prometheus-env.yml > /etc/prometheus/prometheus.yml && exec prometheus --web.enable-lifecycle --enable-feature=expand-external-labels --config.file=/etc/prometheus/prometheus.yml"]
15 changes: 15 additions & 0 deletions monitoring/prometheus/config/prometheus-env.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
global:
scrape_interval: 15s # scrap target์˜ ๊ธฐ๋ณธ interval์„ 15์ดˆ๋กœ ๋ณ€๊ฒฝ / default = 1m
scrape_timeout: 15s # scrap request ๊ฐ€ timeout wait/ default = 10s

external_labels:
monitor: 'rabbit-prometheus' # ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ถ™์—ฌ์ค„ ๋ผ๋ฒจ

scrape_configs:
- job_name: prometheus
metrics_path: ${ACTUATOR_METRICS_PATH}
static_configs:
- targets: [ 'host.docker.internal:8080' ]
basic_auth:
username: ${ACTUATOR_USERNAME}
password: ${ACTUATOR_PASSWORD}
54 changes: 51 additions & 3 deletions src/main/java/com/rabbitmqprac/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,27 @@
import com.rabbitmqprac.infra.security.filter.JwtAuthenticationFilter;
import com.rabbitmqprac.infra.security.filter.JwtExceptionFilter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.security.ConditionalOnDefaultWebSecurity;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
Expand All @@ -27,6 +35,7 @@

import java.util.List;

@Slf4j
@Configuration
@EnableWebSecurity
@ConditionalOnDefaultWebSecurity
Expand All @@ -37,16 +46,55 @@ public class SecurityConfig {
private final CorsConfigurationSource corsConfigurationSource;
private final AccessDeniedHandler accessDeniedHandler;
private final AuthenticationEntryPoint authenticationEntryPoint;
private final PasswordEncoder bCryptPasswordEncoder;

@Value("${management.actuator.username}")
private String actuatorUsername;
@Value("${management.actuator.password}")
private String actuatorPassword;
@Value("${management.actuator.role}")
private String actuatorRole;
@Value("${management.endpoints.web.exposure.base-path}")
private String metricsPath;

@Bean(name = "actuatorUserDetailsService")
public UserDetailsService actuatorUserDetailsService() {
String encodedPassword = bCryptPasswordEncoder.encode(actuatorPassword);
UserDetails actuatorUser = User.builder()
.username(actuatorUsername)
.password(encodedPassword)
.roles(actuatorRole)
.build();
return new InMemoryUserDetailsManager(actuatorUser);
}

@Bean
@Order(1)
public SecurityFilterChain actuatorFilterChain(
HttpSecurity http,
@Qualifier("actuatorUserDetailsService") UserDetailsService actuatorUserDetailsService
) throws Exception {
http
.securityMatcher(metricsPath)
.authorizeHttpRequests(auth -> auth
.anyRequest().hasRole(actuatorRole)
)
.userDetailsService(actuatorUserDetailsService)
.httpBasic(Customizer.withDefaults())
.csrf(csrf -> csrf.disable());
return http.build();
}

@Bean
@Order(SecurityProperties.BASIC_AUTH_ORDER)
public SecurityFilterChain filterChainDev(HttpSecurity http) throws Exception {
@Order(2)
public SecurityFilterChain jwtFilterChain(HttpSecurity http) throws Exception {
return defaultSecurity(http)
.cors((cors) -> cors.configurationSource(corsConfigurationSource()))
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(jwtExceptionFilter, JwtAuthenticationFilter.class)
.authorizeHttpRequests(
auth -> defaultAuthorizeHttpRequests(auth)
.requestMatchers(metricsPath).permitAll()
.requestMatchers(WebSecurityUrls.SWAGGER_ENDPOINTS).permitAll()
.anyRequest().authenticated()
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
package com.rabbitmqprac.domain.context.auth.service;

import com.rabbitmqprac.infra.security.authentication.SecurityUserDetails;
import com.rabbitmqprac.domain.context.user.service.UserService;
import com.rabbitmqprac.domain.persistence.user.entity.User;
import com.rabbitmqprac.infra.security.authentication.SecurityUserDetails;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Primary;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

@Service
@Primary
@RequiredArgsConstructor
public class UserDetailServiceImpl implements UserDetailsService {
private final UserService userService;
Expand Down
Loading
Loading