1. 개요

이 예제에서는 Spring Security Kerberos에 대한 개요를 제공합니다.

Kerberized 서비스에 액세스 할 수있는 권한을 부여하는 Kerberos 클라이언트를 Java로 작성할 것입니다. 또한 자체 내장 된 키 배포 센터를 실행하여 완전한 종단 간 Kerberos 인증을 수행 할 것입니다. Spring Security Kerberos 덕분에 외부 인프라가 필요하지 않습니다 .

2. Kerberos와 그 이점

Kerberos는 MIT가 1980 년대에 만든 네트워크 인증 프로토콜로, 특히 네트워크에서 인증을 중앙 집중화하는 데 유용합니다.

1987 년에 MIT는 그것을 오픈 소스 커뮤니티에 공개했으며 아직 활발하게 개발 중입니다. 2005 년에는 RFC 4120에 따라 IETF 표준으로 정식화되었습니다 . 

일반적으로 Kerberos는 기업 환경에서 사용됩니다 . 여기에서는 사용자가 각 서비스에 대해 개별적으로 인증 할 필요가 없도록 환경을 보호합니다 . 이 아키텍처 솔루션을 Single Sign-on이라고 합니다.

간단히 말해 Kerberos는 티켓팅 시스템입니다. 사용자 한 번 인증  하고 TGT ( Ticket-Granting Ticket )를받습니다. 그런 다음 네트워크 인프라는 해당 TGT를 서비스 티켓으로 교환합니다. 이러한 서비스 티켓을 통해 사용자는 TGT가 유효하고 일반적으로 몇 시간 동안 인프라 서비스와 상호 작용할 수 있습니다.

따라서 사용자가 한 번만 로그인하는 것이 좋습니다. 그러나 Security상의 이점도 있습니다. 이러한 환경에서는 사용자의 암호가 네트워크를 통해 전송되지 않습니다 . 대신 Kerberos는 메시지 암호화 및 암호 해독에 사용될 또 다른 비밀 키를 생성하는 요인으로 사용합니다.

또 다른 이점은 LDAP가 지원 하는 중앙 위치에서 사용자를 관리 할 수 있다는 입니다. 따라서 특정 사용자에 대해 중앙 데이터베이스에서 계정을 비활성화하면 인프라에서 그의 액세스가 취소됩니다. 따라서 관리자는 각 서비스에서 개별적으로 액세스를 취소 할 필요가 없습니다.

Spring의 SPNEGO / Kerberos 인증 소개 는 기술에 대한 심층적 인 개요를 제공합니다.

3. Kerberos화된 환경

따라서 Kerberos 프로토콜로 인증하기위한 환경을 만들어 보겠습니다. 환경은 동시에 실행되는 세 개의 개별 응용 프로그램으로 구성됩니다.

먼저 인증 지점 역할을 할 키 배포 센터 가 있습니다. 다음으로 Kerberos 프로토콜을 사용하도록 구성 할 클라이언트 및 서비스 응용 프로그램을 작성합니다.

이제 Kerberos를 실행하려면 약간의 설치 및 구성이 필요합니다. 그러나 Spring Security Kerberos를 활용 하므로 임베디드 모드에서 프로그래밍 방식으로 키 배포 센터를 실행할 것입니다. 또한 아래 표시된 MiniKdc 는 Kerberized 인프라와의 통합 테스트에 유용합니다.

3.1. 키 배포 센터 실행

먼저 키 배포 센터를 시작하여 TGT를 발급합니다.

String[] config = MiniKdcConfigBuilder.builder()
  .workDir(prepareWorkDir())
  .principals("client/localhost", "HTTP/localhost")
  .confDir("minikdc-krb5.conf")
  .keytabName("example.keytab")
  .build();

MiniKdc.main(config);

기본적으로 MiniKdc 에 일련의 주체와 구성 파일을 제공했습니다. 또한 MiniKdc 가 생성 하는 키탭 을 호출하도록 지시  했습니다.

MiniKdc클라이언트 및 서비스 애플리케이션에 제공 할 krb5.conf 파일을 생성합니다 . 이 파일에는 KDC를 찾을 수있는 정보 (주어진 영역의 호스트 및 포트)가 포함되어 있습니다.

MiniKdc.main 은 KDC를 시작하고 다음과 같은 내용을 출력해야합니다.

Standalone MiniKdc Running
---------------------------------------------------
  Realm           : EXAMPLE.COM
  Running at      : localhost:localhost
  krb5conf        : .\spring-security-sso\spring-security-sso-kerberos\krb-test-workdir\krb5.conf

  created keytab  : .\spring-security-sso\spring-security-sso-kerberos\krb-test-workdir\example.keytab
  with principals : [client/localhost, HTTP/localhost]

3.2. 클라이언트 애플리케이션

우리의 클라이언트는 RestTemplate  을 사용하여 REST API를 외부로 호출 하는 Spring Boot 애플리케이션이 될 것 입니다.

그러나 대신 KerberosRestTemplate사용할 입니다. keytab과 클라이언트 주체가 필요합니다.

@Configuration
public class KerberosConfig {

    @Value("${app.user-principal:client/localhost}")
    private String principal;

    @Value("${app.keytab-location}")
    private String keytabLocation;

    @Bean
    public RestTemplate restTemplate() {
        return new KerberosRestTemplate(keytabLocation, principal);
    }
}

그리고 그게 다야! KerberosRestTemplate  은 Kerberos 프로토콜의 클라이언트 측을 협상합니다.

따라서 엔드 포인트 app.access-url 에서 호스팅되는 Kerberized 서비스의 일부 데이터를 쿼리하는 빠른 클래스를 만들어 보겠습니다 .

@Service
class SampleClient {

    @Value("${app.access-url}")
    private String endpoint;

    private RestTemplate restTemplate;

    // constructor, getter, setter

    String getData() {
        return restTemplate.getForObject(endpoint, String.class);
    }
}

이제이 클래스가 호출 할 무언가를 갖도록 서비스 애플리케이션을 만들어 보겠습니다!

3.3. 서비스 신청

Spring Security를 ​​사용하여 적절한 Kerberos 특정 bean으로 구성합니다.

또한 서비스에는 주체가 있으며 키 탭도 사용됩니다.

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Value("${app.service-principal:HTTP/localhost}")
    private String servicePrincipal;

    @Value("${app.keytab-location}")
    private String keytabLocation;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
          .authorizeRequests()
            .antMatchers("/", "/home").permitAll()
            .anyRequest().authenticated()
            .and() 
          .exceptionHandling()
            .authenticationEntryPoint(spnegoEntryPoint())
            .and()
          .formLogin()
            .loginPage("/login").permitAll()
            .and()
          .logout().permitAll()
            .and()
          .addFilterBefore(spnegoAuthenticationProcessingFilter(authenticationManagerBean()),
            BasicAuthenticationFilter.class);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
          .authenticationProvider(kerberosAuthenticationProvider())
          .authenticationProvider(kerberosServiceAuthenticationProvider());
    }

    @Bean
    public KerberosAuthenticationProvider kerberosAuthenticationProvider() {
        KerberosAuthenticationProvider provider = new KerberosAuthenticationProvider();
        // provider configuration
        return provider;
    }

    @Bean
    public SpnegoEntryPoint spnegoEntryPoint() {
        return new SpnegoEntryPoint("/login");
    }

    @Bean
    public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter(
      AuthenticationManager authenticationManager) {
        SpnegoAuthenticationProcessingFilter filter = new SpnegoAuthenticationProcessingFilter();
        // filter configuration
        return filter;
    }

    @Bean
    public KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider() {
        KerberosServiceAuthenticationProvider provider = new KerberosServiceAuthenticationProvider();
        // auth provider configuration  
        return provider;
    }

    @Bean
    public SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator() {
        SunJaasKerberosTicketValidator ticketValidator = new SunJaasKerberosTicketValidator();
        // validator configuration
        return ticketValidator;
    }
}

소개 기사는 우리가 간결 여기에 전체 방법을 생략하고, 그래서 모든 구현 위에 포함되어 있습니다.

SPNEGO 인증을 위해 Spring Security를 ​​구성했습니다 . 이렇게하면 HTTP 프로토콜을 통해 인증 할 수 있지만 코어 Java를 사용하여 SPNEGO 인증을 얻을 수도 있습니다 .

4. 테스트

이제 통합 테스트를 실행하여 클라이언트가 Kerberos 프로토콜을 통해 외부 서버에서 데이터를 성공적으로 검색했음을 보여줍니다 . 이 테스트를 실행하려면 인프라를 실행해야하므로 MiniKdc 와 서비스 응용 프로그램을 모두 시작해야합니다.

기본적으로 클라이언트 애플리케이션 SampleClient 를 사용하여 서비스 애플리케이션에 요청합니다. 테스트 해 보겠습니다.

@Autowired
private SampleClient sampleClient;

@Test
public void givenKerberizedRestTemplate_whenServiceCall_thenSuccess() {
    assertEquals("data from kerberized server", sampleClient.getData());
}

KerberizedRestTemplate 이없는 서비스를 사용하여 중요 하다는 것을 증명할 수도 있습니다.

@Test
public void givenRestTemplate_whenServiceCall_thenFail() {
    sampleClient.setRestTemplate(new RestTemplate());
    assertThrows(RestClientException.class, sampleClient::getData);
}

참고로 두 번째 테스트에서 자격 증명 캐시 에 이미 저장된 티켓을 재사용 할 수 있는 가능성 이 있습니다 . 이것은 HttpUrlConnection 에서 사용되는 자동 SPNEGO 협상으로 인해 발생합니다 .

결과적으로 데이터가 실제로 반환되어 테스트가 무효화 될 수 있습니다. 필요에 따라 시스템 속성 http.use.global.creds = false를 통해 티켓 캐시 사용을 비활성화 할 수 있습니다 .

5. 결론

이 예제에서는  중앙 집중식 사용자 관리를위한 Kerberos 와 Spring Security가 Kerberos 프로토콜 및 SPNEGO 인증 메커니즘을 지원하는 방법 을 살펴 보았습니다 .

MiniKdc사용  하여 임베디드 KDC를 세우고 매우 간단한 Kerberized 클라이언트와 서버를 만들었습니다. 이 설정은 탐색에 편리했으며 특히 테스트를위한 통합 테스트를 만들 때 유용했습니다.

이제 우리는 표면을 긁었습니다. 더 자세히 알아 보려면 Kerberos 위키 페이지 또는 해당 RFC를 확인하세요 . 또한 공식 문서 페이지 가 유용 할 것입니다. 그 외에도 코어 자바에서 작업을 수행 할 수있는 방법을 알아보기 위해 다음 Oracle 사용방법(예제) 에서 자세히 보여줍니다.

평소처럼 코드는 GitHub 페이지 에서 찾을 수 있습니다 .