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
2 changes: 2 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ jobs:
echo "JWT_SECRET=${{ secrets.JWT_SECRET }}" >> .env
echo "MAIL_USERNAME=${{ secrets.MAIL_USERNAME }}" >> .env
echo "MAIL_PASSWORD=${{ secrets.MAIL_PASSWORD }}" >> .env
echo "SBA_ADMIN_NAME=${{ secrets.SBA_ADMIN_NAME }}" >> .env
echo "SBA_ADMIN_PASSWORD=${{ secrets.SBA_ADMIN_PASSWORD }}" >> .env

# 필요하다면 풀 사이즈 변수도 추가
# echo "DB_POOL_MAX=30" >> .env
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ protected void doFilterInternal(@NotNull HttpServletRequest request,
@Override
protected boolean shouldNotFilter(HttpServletRequest request) {
String path = request.getRequestURI();

boolean isAdminZone = Arrays.stream(SecurityConstants.ADMIN_URLS)
.anyMatch(pattern -> pathMatcher.match(pattern, path));

if (isAdminZone) {
return true;
}

boolean excluded = Arrays.stream(SecurityConstants.WHITELIST_URLS)
.anyMatch(pattern -> pathMatcher.match(pattern, path));

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package org.sejongisc.backend.common.config.security;

import de.codecentric.boot.admin.server.config.AdminServerProperties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class AdminSecurityConfig {

private final AdminServerProperties adminServerProperties;
private final PasswordEncoder passwordEncoder;

@Value("${spring.security.user.name}")
private String adminUsername;

@Value("${spring.security.user.password}")
private String adminPassword;

public AdminSecurityConfig(AdminServerProperties adminServerProperties, PasswordEncoder passwordEncoder) {
this.adminServerProperties = adminServerProperties;
this.passwordEncoder = passwordEncoder;
}

@Bean
@Order(1) // 1순위로 체크: /admin 및 /actuator 경로는 이 설정이 우선 적용됨
public SecurityFilterChain adminSecurityFilterChain(HttpSecurity http) throws Exception {
String adminContextPath = adminServerProperties.getContextPath();

// 관리자 계정 설정
UserDetails adminUser = User.withUsername(adminUsername)
.password(passwordEncoder.encode(adminPassword))
.roles("ADMIN")
.build();

InMemoryUserDetailsManager userDetailsService = new InMemoryUserDetailsManager(adminUser);

// 관리자 전용 인증 프로바이더 설정
DaoAuthenticationProvider adminAuthenticationProvider = new DaoAuthenticationProvider();
adminAuthenticationProvider.setUserDetailsService(userDetailsService);
adminAuthenticationProvider.setPasswordEncoder(passwordEncoder);

http
.securityMatcher(SecurityConstants.ADMIN_URLS)
.authenticationProvider(adminAuthenticationProvider)
.csrf(csrf -> csrf.ignoringRequestMatchers(
adminContextPath + "/instances",
adminContextPath + "/instances/**",
"/actuator/**"
))
.authorizeHttpRequests(auth -> auth
// 무인증 허용 리스트
.requestMatchers(SecurityConstants.ADMIN_PUBLIC_URLS).permitAll()

// SBA 클라이언트 등록 엔드포인트 보호
.requestMatchers(adminContextPath + "/instances", adminContextPath + "/instances/**").authenticated()

// 나머지는 관리자 인증 필수
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage(adminContextPath + "/login")
.defaultSuccessUrl(adminContextPath + "/", true)
)
.httpBasic(Customizer.withDefaults());

return http.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ public RoleHierarchy roleHierarchy() {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.securityMatcher(request -> {
String requestUri = request.getRequestURI();
boolean isAdminRequest = requestUri.startsWith("/admin");
boolean isActuatorRequest = requestUri.startsWith("/actuator");
return !isAdminRequest && !isActuatorRequest;
})
.cors(Customizer.withDefaults())
.csrf(AbstractHttpConfigurer::disable)
.formLogin(AbstractHttpConfigurer::disable)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ public class SecurityConstants {
"/api/auth/reissue",
"/api/user/password/reset/**",
"/api/email/**",
"/actuator/**",
"/v3/api-docs/**",
"/swagger-ui/**",
"/swagger-ui.html",
Expand Down Expand Up @@ -37,4 +36,17 @@ public class SecurityConstants {
//"/api/attendance/**"

};

public static final String[] ADMIN_URLS = {
"/admin/**", "/actuator/**"
};

public static final String[] ADMIN_PUBLIC_URLS = {
"/admin/assets/**",
"/admin/login",
"/favicon.ico",
"/admin/favicon.ico",
"/actuator/health",
"/actuator/info"
};
}
24 changes: 23 additions & 1 deletion backend/src/main/resources/application-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,26 @@ spring:
auth: true
starttls:
enable: true
required: true
required: true

security:
user:
name: ${SBA_ADMIN_NAME}
password: ${SBA_ADMIN_PASSWORD}

boot:
admin:
context-path: /admin
client:
url: "http://localhost:8080/admin"
username: ${SBA_ADMIN_NAME}
password: ${SBA_ADMIN_PASSWORD}

instance:
name: sisc-backend
service-base-url: "http://localhost:8080"
management-base-url: "http://localhost:8080"
metadata:
user:
name: ${SBA_ADMIN_NAME}
password: ${SBA_ADMIN_PASSWORD}
26 changes: 25 additions & 1 deletion backend/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,28 @@ spring:
dialect: org.hibernate.dialect.PostgreSQLDialect
show_sql: false
format_sql: false # 가로로 너무 길어지는 게 싫다면 이것도 false
use_sql_comments: false # 부가 설명 제거
use_sql_comments: false # 부가 설명 제거

boot:
admin:
context-path: /admin
notify:
mail:
enabled: false

management:
endpoints:
web:
base-path: /actuator
exposure:
include: "health,info,metrics,logfile,httpexchanges,threaddump"
endpoint:
health:
show-details: when_authorized
health:
mail:
enabled: false

logging:
file:
name: ./logs/application.log