✅ 결론: 보안 수준과 요구사항에 따라 다르지만, 보통 게이트웨이와 백엔드에 적용!
MSA(Microservices Architecture)에서 보안(Security)을 적용하는 방식은 각 계층의 역할에 따라 달라집니다.
일반적으로 보안 적용이 필요한 곳은 API Gateway와 백엔드 서비스입니다.
- API Gateway: 인증(Authentication) 및 인가(Authorization) 처리
- 백엔드 서비스: 개별 서비스 보안 관리
- 프론트엔드: 주로 OAuth 토큰 관리, 로그인 UI 제공
- Eureka: 보통 보안 적용하지 않음
📌 MSA 구조별 Security 적용 방식
| 계층 | 보안 적응 필요 여부 | 보안 역할 |
| 프론트엔드 (React, Vue 등) | ❌ 선택적 | 로그인 UI, JWT 저장 (쿠키/로컬스토리지) |
| API Gateway (Spring Cloud Gateway) | ✅ 필수! | 인증(Authentication) 및 인가(Authorization), 토큰 검증 |
| Eureka Server | ❌ 보통 적용 안 함 | 서비스 디스커버리 역할만 수행 |
| 백엔드 서비스 (User, Order, Payment 등) | ✅ 필수! | 개별 서비스 보안, 역할(Role) 기반 접근 제어 |
📌 1️⃣ API Gateway에서 Security 적용 (필수!)
✅ API Gateway에서 인증(Auth) 적용하는 이유
- API Gateway는 모든 요청이 처음 들어오는 지점이므로 보안 관문 역할을 수행해야 함
- 로그인된 사용자만 특정 API에 접근하도록 제한
- JWT(Token) 검증을 통해 유효한 요청만 백엔드로 전달
- 비인가 요청을 차단하여 백엔드 부하를 줄임
✅ 적용 방식
- Spring Security + JWT 기반 인증 적용
- Gateway에서 JWT를 검증하고, 검증된 요청만 백엔드로 전달
- OAuth2 / Keycloak 같은 인증 서버 연동
- API Gateway에서 OAuth2 토큰을 검증하여 보안 강화
- Role 기반 접근 제어
- ROLE_ADMIN만 특정 API 접근 가능하도록 설정
📌 예제 코드 (API Gateway - Spring Security & JWT)
@Bean
public SecurityWebFilterChain securityFilterChain(ServerHttpSecurity http) {
return http
.csrf(ServerHttpSecurity.CsrfSpec::disable)
.authorizeExchange(exchange -> exchange
.pathMatchers("/api/public/**").permitAll() // 공개 API는 인증 없이 접근 가능
.pathMatchers("/api/admin/**").hasRole("ADMIN") // ADMIN 권한 필요
.anyExchange().authenticated() // 그 외 모든 요청은 인증 필요
)
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults())) // JWT 검증
.build();
}
✅ 모든 요청이 Gateway를 통과하면서 보안 검사를 수행!
✅ 백엔드 서비스는 Gateway에서 검증된 요청만 받기 때문에 추가적인 인증 부담이 줄어듦.
📌 2️⃣ 백엔드 서비스에서 Security 적용 (필수!)
✅ 백엔드 서비스에서 보안 적용 이유
- API Gateway가 인증을 수행하더라도, 각 서비스는 개별적인 보안이 필요함
- 사용자마다 접근할 수 있는 리소스가 다를 수 있음
- ROLE_USER, ROLE_ADMIN 같은 역할(Role) 기반 접근 제어 필요
📌 적용 방식
- JWT 기반 보안 적용
- API Gateway에서 JWT를 검증하지만, 백엔드 서비스에서도 추가 검증 가능
- Method-Level Security (@PreAuthorize)
- 특정 API를 호출할 수 있는 사용자 권한(Role) 지정
📌 예제 코드 (백엔드 - Spring Security)
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.requestMatchers("/api/user/**").hasRole("USER")
.anyRequest().authenticated()
)
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); // JWT 검증 추가
return http.build();
}
}
✅ 백엔드 서비스에서 추가적인 역할(Role) 기반 보안 적용 가능!
📌 3️⃣ 프론트엔드에서 Security 적용 (선택)
✅ 프론트엔드에서 해야 할 보안 작업
- 로그인 UI 제공 (React, Vue, Angular)
- JWT 토큰을 안전하게 저장 (httpOnly 쿠키 또는 sessionStorage)
- API Gateway에 인증된 요청 보내기 (Authorization: Bearer {JWT})
📌 예제 코드 (React에서 로그인 후 JWT 저장)
axios.post("http://localhost:8080/api/login", { username, password })
.then(response => {
localStorage.setItem("token", response.data.token); // JWT 저장
});
✅ JWT를 브라우저 저장소에 안전하게 저장하고, API 요청 시 Authorization 헤더에 포함
📌 4️⃣ Eureka Server에서 Security 적용 (필요 없음)
❌ Eureka에 보안 적용할 필요가 없는 이유
- Eureka는 서비스 간 디스커버리 역할만 수행
- 보안 적용하면 각 마이크로서비스가 Eureka에 등록할 때 인증해야 하므로 관리 복잡성 증가
- 내부 네트워크에서만 사용된다면 보안 적용 필요 없음!
✅ Eureka에 Security 적용이 필요한 경우
- 공개된 네트워크에서 Eureka를 운영하는 경우
- 마이크로서비스 간의 Eureka 인증이 필요한 경우 (Basic Auth 적용 가능)
📌 예제 코드 (Eureka에 Basic Auth 적용)
# Eureka Security 설정 (application.properties)
spring.security.user.name=eureka
spring.security.user.password=secret
✅ 각 서비스는 eureka:secret 인증을 통해 Eureka에 등록 가능!
📌 결론 (Security 적용해야 하는 곳)
| 계층 | Security 적용 여부 | 적용 이유 |
| 프론트엔드 (React, Vue) | ⭕ (선택) | JWT 저장, 로그인 UI 제공 |
| API Gateway | ✅ (필수) | 인증 및 인가 처리 (JWT 검증) |
| Eureka Server | ❌ (필요 없음) | 내부 네트워크에서 사용 (외부에 노출될 경우 보안 적용 가능) |
| 백엔드 서비스 | ✅ (필수) | API별 권한 관리 (Role 기반 접근 제어) |
✅ API Gateway에서 인증 및 토큰 검증을 수행!
✅ 백엔드 서비스에서 추가적인 보안 및 권한 관리!
✅ 프론트엔드는 JWT 관리만 하면 됨!
❌ Eureka는 보통 보안 적용하지 않음!
'Spring > 10. rest-api' 카테고리의 다른 글
| 일반적인 MVC 와 @FeignClient에서 @RequestBody / @PathVariable의 사용법 (0) | 2025.03.18 |
|---|---|
| @JsonCreator 사용 (0) | 2025.03.18 |
| Eureka에 프론트엔드 등록 여부 – 꼭 등록해야 할까? (0) | 2025.03.18 |
| MSA 환경에서 프런트 엔드를 위한 서버구조 (0) | 2025.03.18 |
| Controller 와 FeignClient에서의 @PathVariable 역할 (0) | 2025.03.17 |