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
28 changes: 28 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,31 @@ services:
KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:9092
depends_on:
- kafka

prometheus:
image: prom/prometheus:v2.54.1
container_name: momogo-prometheus
ports:
- "127.0.0.1:9090:9090"
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus-data:/prometheus
extra_hosts:
- "host.docker.internal:host-gateway"

grafana:
image: grafana/grafana:11.1.0
container_name: momogo-grafana
ports:
- "127.0.0.1:3000:3000"
volumes:
- grafana-data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_USER=${GRAFANA_ADMIN_USER:-admin}
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD:?GRAFANA_ADMIN_PASSWORD is required}
depends_on:
- prometheus

volumes:
prometheus-data:
grafana-data:
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import jakarta.servlet.DispatcherType;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import org.springframework.http.HttpMethod;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
Expand All @@ -18,6 +20,7 @@
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
Expand Down Expand Up @@ -59,22 +62,36 @@ public SecurityFilterChain filterChain(
CustomAuthenticationEntryPoint customAuthenticationEntryPoint,
OAuth2UserDetailsService oAuth2UserDetailsService,
OAuth2LoginSuccessHandler oauth2LoginSuccessHandler,
OAuth2LoginFailureHandler oauth2LoginFailureHandler
OAuth2LoginFailureHandler oauth2LoginFailureHandler,
Environment env
) throws Exception {
boolean isDevOrLocal = env.acceptsProfiles(Profiles.of("local", "dev"));

http
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.csrfTokenRequestHandler(new SpaCsrfTokenRequestHandler())
.ignoringRequestMatchers("/api/auth/sign-in")
)
.authorizeHttpRequests(auth -> auth
.httpBasic(Customizer.withDefaults())
Comment thread
SungHuii marked this conversation as resolved.
.authorizeHttpRequests(auth -> {
auth
.dispatcherTypeMatchers(DispatcherType.ASYNC).permitAll()
// 문서 및 소켓 관련
.requestMatchers("/", "/index.html").permitAll()
.requestMatchers("/ws/**").permitAll()
.requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll()
.requestMatchers("/actuator/health", "/actuator/info").permitAll()
.requestMatchers("/actuator/health", "/actuator/info").permitAll();

// 개발/로컬 프로필일 때만 k6 부하 테스트 스크랩용 prometheus 엔드포인트 공개, 운영 시 인증 요구
if (isDevOrLocal) {
auth.requestMatchers("/actuator/prometheus").permitAll();
} else {
auth.requestMatchers("/actuator/prometheus").hasAnyRole("METRICS", "SUPER_ADMIN");
}

auth
.requestMatchers("/actuator/**").hasRole("SUPER_ADMIN")
.requestMatchers("/api/super-admin/**").hasRole("SUPER_ADMIN")

Expand Down Expand Up @@ -105,8 +122,8 @@ public SecurityFilterChain filterChain(
.requestMatchers(HttpMethod.GET, "/uploads/**").permitAll()

.requestMatchers("/api/**").authenticated()
.anyRequest().authenticated()
)
.anyRequest().authenticated();
})
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
Expand Down
17 changes: 17 additions & 0 deletions momogo-api/src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,20 @@ app:

server:
port: 8080

# monitoring
management:
endpoints:
web:
exposure:
include: health, info, prometheus, metrics
prometheus:
metrics:
export:
enabled: true
metrics:
tags:
application: ${spring.application.name:momogo-api}
distribution:
percentiles-histogram:
http.server.requests: true
1 change: 1 addition & 0 deletions momogo-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ dependencies {
api 'org.springframework.boot:spring-boot-starter-data-jpa'
api 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
api 'io.micrometer:micrometer-registry-prometheus'
runtimeOnly 'org.postgresql:postgresql'

// QueryDSL (Spring Boot 3.x / Jakarta)
Expand Down
25 changes: 25 additions & 0 deletions prometheus/prometheus.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
global:
scrape_interval: 5s
evaluation_interval: 5s

scrape_configs:
- job_name: 'momogo-local-api'
metrics_path: '/actuator/prometheus'
scheme: 'http'
scrape_interval: 5s
static_configs:
- targets: ['host.docker.internal:8080']
labels:
env: 'local'

- job_name: 'momogo-prod-api'
metrics_path: '/actuator/prometheus'
scheme: 'http'
scrape_interval: 5s
basic_auth:
username: '${PROMETHEUS_USER:?PROMETHEUS_USER is required}'
password: '${PROMETHEUS_PASS:?PROMETHEUS_PASS is required}'
Comment thread
SungHuii marked this conversation as resolved.
static_configs:
- targets: ['momogo.kro.kr']
Comment thread
coderabbitai[bot] marked this conversation as resolved.
labels:
env: 'production'