본문 바로가기

Dev/기타

[gRPC] 인증/인가

''' 다음 링크를 번역한 내용입니다. https://yidongnan.github.io/grpc-spring-boot-starter/en/server/security.html '''

 

Enable Transport Layer Security

 스프링의 구성 메커니즘을 사용하여 전송 수준 보안을 구성할 수 있습니다. 보안과 관련이 없는 구성 옵션은 구성 페이지를 참조하십시오. TLS를 처리하는 역방향 프록시 뒤에 있는 경우 TLS를 설정할 필요가 없습니다. 보안에 대해 잘 모르면 보안 전문가와 상의하세요. 설정에 보안 문제가 있는지 확인하는 것을 잊지 마세요.

참고: 자세한 내용은 공식 문서를 참조하십시오!

 

Prerequisites

1) 클래스 경로에 호환되는 SSL/TLS 구현

grpc-netty-shaded 이것을 포함한다.

- grpc-netty의 경우 netty-tcnative-boringsl-static에 종속성을 추가하십시오

(grpc-java의 netty 보안 섹션에 있는 표에 나열된 것과 동일한 (호환 가능한) 버전을 사용하십시오).

2) 개인 키가 있는 인증서

 

Generating Self Signed Certificates

 인증서(예: 내부 테스트 서버용)가 없는 경우 'openssl'을 사용하여 인증서를 생성할 수 있습니다. :

openssl req -x509 -nodes -subj "//CN=localhost" -newkey rsa:4096 -sha256 -keyout server.key -out server.crt -days 3650

 이러한 인증서는 추가 구성 없이는 응용 프로그램에서 신뢰할 수 없습니다. 글로벌 CA 또는 회사의 CA에서 신뢰하는 인증서를 사용하는 것이 좋습니다.

 

Configuring the Server

 grpc 서버가 TLS를 사용하도록 허용하려면 다음 옵션을 사용하여 구성해야 합니다.:

grpc.server.security.enabled=true grpc.server.security.certificateChain=file:certificates/server.crt grpc.server.security.privateKey=file:certificates/server.key #grpc.server.security.privateKeyPassword=MyStrongPassword

 여기에서 지원되는 옵션을 알아보려면 Spring의 리소스 문서를 참조하십시오. 해당 클라이언트 구성은 Client Security 페이지를 참조하십시오

 

Mutual Certificate Authentication

 신뢰할 수 있는 클라이언트만 서버에 연결할 수 있도록 하려면 상호 인증서 인증을 사용할 수 있습니다. 이는 클라이언트가 'x509' 인증서를 사용하여 자신을 인증하도록 허용하거나 강제합니다.

 상호 인증을 사용하려면 다음 속성을 구성에 추가하십시오.

grpc.server.security.trustCertCollection=file:certificates/trusted-clients.crt.collection grpc.server.security.clientAuth=REQUIRE

 클라이언트 인증서를 연결하기만 하면 trusted-clients.crt.collection 파일을 만들 수 있습니다.

cat client.crt > trusted-clients.crt.collection*

 clientAuth 모드는 서버가 동작하는 방식을 정의합니다.:

- 'REQUIRE'는 클라이언트 인증서 인증을 의무화합니다.

- 'OPTIONAL'은 클라이언트가 인증서를 사용하여 자체 인증을 요청하지만 강제로 요청하지는 않습니다.

일부 중요한 서비스나 메서드만 보호하려는 경우 'OPTIONAL'을 사용할 수 있습니다. 특히 나중에는 인증을 적절하게 구성하는 것이 중요합니다.

 

Authentication and Authorization

grpc-spring-boot-security는 기본적으로 spring-security 를 지원하므로 잘 알려진 주석을 사용하여 응용 프로그램을 보호할 수 있습니다.

 

Configure Authentication

 grpc-client의 인증을 지원하려면 클라이언트의 인증 허용 방법을 정의해야 합니다. 이 작업은 GrpcAuthenticationReader를 정의하여 수행할 수 있습니다.

grpc-spring-boot-starter 은 수많은 내장 구현체와 함께 제공된다:

- [AnonymousAuthenticationReader]: 스프링 anonymous 권한에 이용

- [BasicGrpcAuthenticationReader]: 기본 권한에 이용

- [BearerAuthenticationReader]: OAuth 및 유사한 프로토콜에 이용

- [SSLContextGrpcAuthenticationReader]: 인증서 기반 인증에 이용

- [CompositeGrpcAuthenticationReader]: 순서대로 readers 를 사용할 때 이용

 

Bean 정의는 다음 예제와 비슷합니다.

@Bean 
public GrpcAuthenticationReader grpcAuthenticationReader() { 
    return new BasicGrpcAuthenticationReader(); 
}

 사용자가 인증하도록 강제하려면 CompositeGrpcAuthenticationReader를 사용하고 GrpcAuthenticationReader(throw AuthenticationException)를 추가하십시오. 이렇게 하면 인증이 실패한 것으로 표시되고 요청 처리가 중지됩니다. GrpcAuthenticationReader가 null을 반환하면 사용자는 인증되지 않은 상태로 계속됩니다. reader가 인증 정보/인증을 추출할 수 있는 경우, 스프링의 AuthenticationManager에 의해 인증 확인됩니다. 그런 다음 이 인스턴스는 사용자가 유효한 자격 증명을 보냈는지 여부를 결정합니다.

 

Example setups

 다음 절에는 다양한 인증 설정에 대한 구성 예가 나와 있습니다.:

참고: CompositeGrpcAuthenticationReader에서 reader 를 래핑할 필요는 없으며, 여러 메커니즘을 추가해야 한다.

// BasicAuth
@Bean 
AuthenticationManager authenticationManager() { 
    final List<AuthenticationProvider> providers = new ArrayList<>(); 
    providers**.add(...)**; // Possibly DaoAuthenticationProvider 
    return new ProviderManager(providers); 
}

@Bean 
GrpcAuthenticationReader authenticationReader() { 
    final List<GrpcAuthenticationReader> readers = new ArrayList<>(); 
    readers.add(new BasicGrpcAuthenticationReader()); 
    return new CompositeGrpcAuthenticationReader(readers); 
}

// Bearer Authentication (OAuth2/OpenID-Connect)
@Bean 
AuthenticationManager authenticationManager() { 
    final List<AuthenticationProvider> providers = new ArrayList<>(); 
    providers.add(...); // Possibly JwtAuthenticationProvider 
    return new ProviderManager(providers); 
}

@Bean 
GrpcAuthenticationReader authenticationReader() { 
    final List<GrpcAuthenticationReader> readers = new ArrayList<>(); 
    // 실제 토큰 클래스는 스프링 보안 라이브러리(OAuth2/JWT/...)에 따라 달라집니다. 
    readers.add(new BearerAuthenticationReader(accessToken -> new BearerTokenAuthenticationToken(accessToken))); 
    return new CompositeGrpcAuthenticationReader(readers); 
}

 보유자 토큰의 권한/역할을 Spring Security의 GrantedAuthoritys에 매핑하는 GrantedAuthoritiesConverter를 정의할 수도 있습니다.

 

Certificate Authentication

@Bean 
AuthenticationManager authenticationManager() { 
    final List<AuthenticationProvider> providers = new ArrayList<>(); 
    providers.add**(new X509CertificateAuthenticationProvider(userDetailsService()**)); 
    return new ProviderManager(providers); 
}

@Bean 
GrpcAuthenticationReader authenticationReader() { 
    final List<GrpcAuthenticationReader> readers = new ArrayList<>(); 
    readers.add(new SSLContextGrpcAuthenticationReader()); 
    return new CompositeGrpcAuthenticationReader(readers); 
}

 상호 인증서 인증도 참조하십시오

 

Configure Authorization

 이 단계는 원하지 않는 액세스로부터 응용프로그램을 실제로 보호하므로 매우 중요합니다. 두 가지 방법으로 grpc-server를 보호할 수 있습니다.

 

gRPC security checks

 응용 프로그램을 보안 하는 한 가지 방법은 응용 프로그램 컨텍스트에 GrpcSecurityMetadataSource bean을 추가하는 것입니다. grpc 메서드 수준별로 보안 조건을 반환할 수 있습니다. 하드 코딩된 규칙을 사용하는 예제 콩 정의는 다음과 같을 수 있습니다.

import net.devh.boot.grpc.server.security.check.AccessPredicate; import net.devh.boot.grpc.server.security.check.ManualGrpcSecurityMetadataSource;

@Bean 
GrpcSecurityMetadataSource grpcSecurityMetadataSource() { 
    final ManualGrpcSecurityMetadataSource source = new ManualGrpcSecurityMetadataSource(); 
    source.set(MyServiceGrpc.getMethodA(), AccessPredicate.authenticated()); 
    source.set(MyServiceGrpc.getMethodB(), AccessPredicate.hasRole("ROLE_USER")); 
    source.set(MyServiceGrpc.getMethodC(), AccessPredicate.hasAllRole("ROLE_FOO", "ROLE_BAR")); 
    source.set(MyServiceGrpc.getMethodD(), auth -> "admin".equals(auth.getName())); 
    source.setDefault(AccessPredicate.denyAll()); return source; 
}

@Bean 
AccessDecisionManager accessDecisionManager() { 
    final List<AccessDecisionVoter<?>> voters = new ArrayList<>(); 
    voters.add(new AccessPredicateVoter()); 
    return new UnanimousBased(voters); 
}

 AccessDecisionManager를 구성해야 합니다. 그렇지 않으면 AccessPredicates를 처리하는 방법을 알 수 없습니다. 이 방법을 사용하면 구성을 외부 파일이나 데이터베이스로 이동할 수 있습니다. 하지만 그건 당신이 직접 시행해야 합니다.

 

Spring annotation security checks

 물론 스프링 시큐리티의 주석을 그냥 사용하는 것도 가능하다. 이 사용 사례의 경우 다음 주석을 @Configuration 클래스 중 하나에 추가해야 합니다.

@EnableGlobalMethodSecurity(___Enabled = true, proxyTargetClass = true)

 proxyTargetClass = true가 필요합니다! 만약 당신이 그것을 추가하는 것을 잊는다면, 당신은 많은 UNIMPLEMENTED 응답을 받게 될 것입니다. 그러나 MyServiceImpl#bindService() 메서드가 final 메서드 라는 경고가 표시됩니다. 보안을 무시할 수 있으므로 해당 메서드를 final 해제하지 마십시오.

 그런 다음 grpc 메서드 구현에 주석을 달 수 있습니다.

@Override 
@Secured("ROLE_ADMIN") 
// MyServiceGrpc.methodX 
public void methodX(Request request, StreamObserver<Response> responseObserver) { 
    [...] 
}

 

 이 라이브러리에서는 서비스를 구현하기 위해 ImplBase(grpc에서 생성)를 확장한다고 가정합니다. 그렇지 않으면 스프링 보안을 무시할 수 있습니다.

 

 

'Dev > 기타' 카테고리의 다른 글

Pull Request 과정에서 알게 된 점  (0) 2022.01.25
Build 과정에서 알게 된 점  (0) 2022.01.25
[gRPC] 통신 예제  (0) 2022.01.25
[gRPC] 개념 정리  (0) 2022.01.25
Armeria의 서킷 브레이커  (0) 2022.01.17