인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

똘똘이님의 프로필 이미지

작성한 질문수

Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)

Test

도커 컨테이너로 동작할 때 user-service에서 403 forbidden 오류 관련

작성

·

241

1

유사한 질문이 있어서 도움이 될 수 있을까 찾아 봤지만 해당 github에 접근할 수 없었고(아마 삭제한 듯), chat GPT를 통해서 답을 얻을 수 있을까 질문을 해 봤지만 해결책이 나오지 않아서 대략 1주일 이상을 헤매고 있었습니다.

그런데 강사님이 다른 분의 질문에 답을 주신 것을 보고 user-service의 SecurityConfig.java 파일에서

.requestMatchers("/**").access(
        new WebExpressionAuthorizationManager("hasIpAddress('127.0.0.1') or hasIpAddress('172.18.0.5') or hasIpAddress('192.168.0.172')")) // ip address of my pc
.anyRequest().authenticated()

위의 코드처럼 나의 pc의 ip address를 포함하니 더이상 403 오류가 발생하지 않더군요. 그래서 결국에는 내 pc의 ip address를 포함해야 하는구나라고 생각했습니다. 그런데 동일한 코드를 다른 pc(이 pc에서도 계속해서 403 오류 발생했었음)에서 구동시켰더니 내 pc의 ip address를 변경시키지 않았음에도 403 오류 발생 없이 잘 동작하더군요. 그동안 무엇이 문제였을까요? 물론 github에 올라가 있는 configuration 파일에서도 gateway의 ip adddress를 172.18.0.5로 지정했고, SecurityConfig.java에서도 위의 코드같이 172.18.0.5를 포함했었습니다.

답변 2

0

김수여이님의 프로필 이미지

저는 도커로 배포할때 도커 내부 네트워크 ip 지정 안해주니까 게이트웨이에서 user-service 로 로드 밸런싱이 안되더라구요

아래 코드처럼 내부 아이피도 추가 해주니까 도커에서 정상동작하기 시작했습니다!

이틀만에 해결한거라,, 처음으로 q&n올려봅니다!

@Bean
    protected SecurityFilterChain configure(HttpSecurity http) throws Exception
    {// 권한 관련 메소드
        // Configure AuthenticationManagerBuilder
        AuthenticationManagerBuilder authenticationManagerBuilder =
                http.getSharedObject(AuthenticationManagerBuilder.class);
        authenticationManagerBuilder.userDetailsService(userService).passwordEncoder(bCryptPasswordEncoder);

        AuthenticationManager authenticationManager = authenticationManagerBuilder.build();
        http.csrf( (csrf) -> csrf.disable());

        http.authorizeHttpRequests((authz) -> authz
                                .requestMatchers(new AntPathRequestMatcher("/actuator/**")).permitAll()
                                .requestMatchers(new AntPathRequestMatcher("/actuator/**")).permitAll()
                                .requestMatchers(new AntPathRequestMatcher("/h2-console/**")).permitAll()
                                .requestMatchers(new AntPathRequestMatcher("/users", "POST")).permitAll()
                                .requestMatchers(new AntPathRequestMatcher("/welcome")).permitAll()
                                .requestMatchers(new AntPathRequestMatcher("/health-check")).permitAll()
                                .requestMatchers(new AntPathRequestMatcher("/swagger-ui/**")).permitAll()
                                .requestMatchers(new AntPathRequestMatcher("/swagger-resources/**")).permitAll()
                                .requestMatchers(new AntPathRequestMatcher("/v3/api-docs/**")).permitAll()
//                        .requestMatchers("/**").access(this::hasIpAddress)
//                                .requestMatchers("/**").access(
//                                        new WebExpressionAuthorizationManager(
//                                                "hasIpAddress('127.0.0.1') " +
//                                                "or hasIpAddress('192.168.45.83')"+
//                                                "or hasIpAddress('172.17.0.0/32')")) // host pc ip address
//                                .anyRequest().authenticated()
                // IP 주소 체크와 로그 찍기
                            .requestMatchers("/**").access((authentication, httpServletRequest) -> {
                                    // 클라이언트 IP 주소 가져오기
                                    String clientIp = httpServletRequest.getRequest().getRemoteAddr();
                                    log.info("Request from IP: {}", clientIp);  // 로그 출력

                                    // IP 주소가 허용된 범위 내인지 확인
                                    if (clientIp.equals("127.0.0.1") || clientIp.equals("192.168.45.83") || clientIp.startsWith("172.18.")) {
                                        log.info("Access granted for IP: {}", clientIp);  // 허용된 IP에 대한 로그
                                        return new AuthorizationDecision(true);  // 인증 통과
                                    } else {
                                        log.warn("Access denied for IP: {}", clientIp);  // 허용되지 않은 IP에 대한 로그
                                        return new AuthorizationDecision(false);  // 인증 실패
                                    }
                                })
                                .anyRequest().authenticated()
                )
                .formLogin(Customizer.withDefaults())
                .authenticationManager(authenticationManager);
//                .sessionManagement((session) -> session
//                        .sessionCreationPolicy(SessionCreationPolicy.STATELESS));

        http.addFilter(getAuthenticationFilter(authenticationManager));
        http.headers((headers) -> headers.frameOptions((frameOptions) -> frameOptions.sameOrigin()));

        return http.build();
    }

0

Dowon Lee님의 프로필 이미지
Dowon Lee
지식공유자

안녕하세요, 이도원입니다.

답변이 늦어 죄송합니다.

먼저, WebExpressionAuthorizationManager 에 등록 된 IP Address 가 어떤 주소인지 확인해 보는 게 필요할 것 같습니다. 127.0.0.1은 Loopback이니까 생략하도록 하고, 172.18.0.5 하고 192.168.0.172 2개가 PC1 번의 물리적인 Network(Wireless 등)IP 인지? Docker 컨테이너에 발급 된 IP 인지? Gateway의 IP를 지정했기 때문인지? 등을 확인해 봐야할 것 같습니다. PC2번과 IP 또는 컨테이너의 IP 등의 확인이 필요할 것 같습니다. 만약 같은 공유기에 연결 된 PC가 아니라, 다른 공유기나 다른 장소의 PC라면 말씀하신 것처럼 작동되지는 않을 거라 생각됩니다.

추가 질문사항 있으시면 다시 글 남겨 주세요.

감사합니다.