5월부터 알고리즘을 공부하겠다는 맹세가 무색하게, 연초부터 하던 일이 매우 바빠져서 5,6,7월을 일로만 보냈다. 연초부터 약간씩 구성해오던 Kafka를 바탕으로 하여 그것과 연계된 서비스들을 이리저리 만들어내고 붙이고 했는데, 방화벽 레벨에서 제어를 하는 것과 별개로 Kafka의 보안 기능을 활용하고 싶다는 생각이 들어서 조금씩 보고 있는 중이다. Kafka의 보안 기능들은 JAAS 와 관련이 있으므로, Kafka의 보안 기능을 활용하기에 앞서서 해당 내용을 좀 정리하고 넘어가려고 정리 해 봄.
보통은 인증/인가에 관해서는 네트워크상에서 인증/인가 위주로 신경 썼고... 애플리케이션 자체의 권한에 대해서는 예전에 설치형으로 판매하던 솔루션에 대해서 구현한 적이 있긴 한데, 이걸 정리하면서 느낀 점은 그 때 좀 더 꼼꼼하게 했으면 어떨까? 하는 생각도 든다. 다음에 더 잘 하겠지...?
오라클 공홈의 문서를 바탕으로 하고 있기 때문에 오라클의 문서는 전문 번역 형식으로 적었다가는 뭔가 변호사한테 연락이 올 것 같아 겁나서 그냥 적당히 요약하는 식으로만 정리하려고 한다.
1. JAAS란 무엇인가?
- Java 2 SDK 에서 선택사양으로 도입하여, J2SDK 1.4에서 통합된 JAVA 인증 및 인가 서비스 (Java Authentication and Authorization Service)
- JAAS가 하는 일은 무엇인가?
- 사용자의 인증 : 현재 자바코드를 실행하고 있는 사용자가 누군인지 확실하고 안전하게 결정함
- 사용자의 인가 : 수행된 행위를 하는데 필요한 ACL (접근권한제어, 권한) 을 가지고 있는지 확인함
- JAAS의 구현 방식 : PAM (Pluggable Authentication Module), 플러그식 인증 모듈
- JAAS는 왜 나왔나?
- 전통적인 Java의 ACL 방식 : 코드의 작성자가 누구인가, 코드의 서명자가 누구인가에 따라 그 코드의 실행을 신뢰할 수 있는지 여부를 결정
- JAAS의 필요성 : 코드를 수행하는 사람이 누구인가? 를 검증할 필요성이 생김
- JAAS의 동작방식 : 플러그 방식으로 수행하여 인증기술과 애플리케이션을 독립적으로 유지할 수 있음.
- 인증프로세스는 아래의 객체를 인스턴스화하여 수행함
- LoginContext 객체 : 인증 기술의 차례를 결정하기 위해 구성을 참조
- LoginModule : 인증에 사용됨, username이나 password를 사용하거나, 음성이나 지문을 읽어서 확인
- 사용자 혹은 코드를 실행하는 서비스가 인증되면 JAAS 인증 컴포넌트는 Java의 코어 권한 제어 모델과 결합하여 리소스를 보호함, 인증이 성공하면 관련된 Principal 및 credential이 있는 LoginModule이 Subject를 업데이트 함
2. 코어 클래스와 인터페이스
- JAAS 와 연관된 코어 클래스 및 인터페이스는 3개로 분류할 수 있음 : Common(공통), Authentication(인증), Authorization(인가)
- Common 클래스 : 인증과 인가에서 공통적으로 사용함
- Subject(javax.security.auth.Subject)
- 요청의 주체
- 사람일 수도 있고 서비스일 수도 있음
- 다수의 식별 정보(Principal) 을 가지고 있을 수 있음 (이름을 가지고 있을 수도 있고 주민등록번호를 함께 가지고 있을 수도 있음)
- 보안에 관련된 증명 정보(Credential)를 가지고 있음 (공개된 것일수도, 비공개된 것일 수도 있음)
- Subject 객체의 속성인 principals, pubCredentials, privCredentials 는 Set으로 관리함
- Principal(java.security.Principal)
- java.security.Principal 과 java.io.Serialzable 인터페이스를 구현하여 작성
- 인증이 성공하였을 경우 Subject의 식별 정보를 나타내는데 사용함
- Credential(Any object)
- JAAS class library 에 속하지 않음
- 모든 클래스가 Credential이 될 수 있음
- 필요에 따라 javax.security.auth.Refreshable(갱신) 이나 javax.security.auth.Destroyable(파기) 관련 인터페이스를 구현하여 사용할 수 있음
- Subject(javax.security.auth.Subject)
- Authentication 클래스와 인터페이스
- 애플리케이션이 Subject (사용자 혹은 서비스)를 인증하는 과정은 다음과 같음
- LoginContext 인스턴스화
- LoginContext는 애플리케이션에 구성된 LoginModule들을 불러오기 위해 javax.security.auth.login.Configuration 을 탐색
- LoginContext의 login 메소드를 수행
- login 메소드는 불러온 LoginModule들을 수행하고, LoginModule들은 subject의 인증을 수행, 성고할 경우 Principal과 Credential을 Subject와 연결하고, Subject는 인증 상태가 됨
- LoginContext는 인증 상태를 애플리케이션에 반환
- 인증이 성공한 경우 애플리케이션은 LoginContext에서 Subject를 탐색
- LoginContext(javax.security.auth.login.LoginContext)
- Subject를 인증하는데 필요한 기본적인 메소드들(getSubject(), login(), logout())을 제공하며 인증 기술과 독립된 애플리케이션을 개발할 수 있도록 함
- 인증 서비스 혹은 특정 애플리케이션에 구성된 LoginModule을 결정하기 위해 Configuration을 찾음
- 이를 통해 애플리케이션의 수정 없이 각기 다른 LoginModule이 애플리케이션에 삽입 가능함
- LoginModule(javax.security.auth.spi.LoginModule)
- 애플리케이션에 삽입될 수 있는 각기 다른 인증 방식을 개발자가 구현할 수 있도록 해 줌
- LoginModule 별로 username/password 혹은 스마트카드, 생체 인증등을 다르게 구현 가능
- LoginModule 구현체 개발 관련 가이드는 아래의 링크를 참조 - https://docs.oracle.com/javase/8/docs/technotes/guides/security/jaas/JAASLMDevGuide.html
- CallbackHandler
- 인증 정보 취득을 위해 사용자와 LoginModule 간의 상호 작용이 필요한 경우에 사용
- 아이디 패스워드의 입력창을 만든다거나
- 카드의 PIN 넘버를 입력 받는다거나
- CallbackHandler는 LoginContext의 생성자에 인자로 전달할 수 있음
- LoginModule의 initialize 메소드의 인자로 바로 전달할 수도 있음
- Callback
- 인증 과정에서 상호 작용을 위한 동작으로 LoginModule에서 CallbackHandler로 넘겨지는 정보
- 애플리케이션이 Subject (사용자 혹은 서비스)를 인증하는 과정은 다음과 같음
- Authorization 클래스
- Authorization을 위한 전제 조건
- LoginContext 섹션에서 설명된 인증 과정이 수행됨
- 인증된 Access Control Context가 Subject 섹션에서 설명된 것과 연관됨
- Principal 기반 엔트리가 security policy 에 설정됨
- Policy
- Principal-based
- System 전체에 걸쳐 있는 Access control policy
- 다음의 링크 참조
- https://docs.oracle.com/javase/8/docs/technotes/guides/security/PolicyFiles.html
- AuthPermission
- JAAS 에 필요한 기본적인 퍼미션을 캡술화 시켰음.
- name (target_name) 을 생성자로 가지며, action list는 없음 (생성자에 action list가 있긴한데 소스코드 주석을 보면 should be null 이라고 되어 있음)
- Policy, Subject, LoginContext, Configuration 객체에 대한 접근을 보호하기 위해 쓰임
- target name은 아래의 링크 참고
- https://docs.oracle.com/javase/8/docs/api/javax/security/auth/AuthPermission.html
- PrivateCredentialPermission
- Subject의 private credential 을 보호하기 위해 씀
- JDK의 소스코드 상에는 생성자가 2개가 있긴한데, 실제로 public 생성자는 1개만 제공하고 있으며 인자로 들어가는 action 은 "read" 만 허용하도록 되어 있으므로 private credential 을 read 만 할 수 있도록 보호하는 역할을 한다고 봐야함
- Authorization을 위한 전제 조건
// javax.security.auth.PrivateCredentialPermission.java
public PrivateCredentialPermission(String name, String actions) {
super(name);
if (!"read".equalsIgnoreCase(actions))
throw new IllegalArgumentException
(ResourcesMgr.getString("actions.can.only.be.read."));
init(name);
}
사실 이 내용까지만 봐서는 대체 그래서 이걸로 뭘 하라는 거지? 라고 와닿기가 힘들다는 생각이 든다. 실제로 나도 그랬고... 자바 소스코드로 JAAS Authentication 을 간단히 짜보긴 했는데 현재로서는 좀 정확하게 이해하고 짰다고 보기는 힘든 것 같아서, 그 부분은 나중에 Authorization 과 더불어 한 번 더 정리가 되면 올려봐야겠음.
일단 이 부분을 정리한 이유는 Kafka 의 Security 부분에서 LoginModule 이나 각종 Conf 가 나오는데, 그 형태도 처음엔 생소했고, 대체 어떤 방식으로 동작을 하는 것인지 이해가 되지 않으니 레퍼런스 따라가기도 힘들어서 뭐가 뭔지를 몰라서 정리를 해 둔 것이므로... 다음 포스트는 이 내용에 대해서 대강 알아둔 상태에서 Kafka 의 인증을 세팅하는 것으로 해야겠다.
참고자료 :
https://docs.oracle.com/javase/8/docs/technotes/guides/security/jaas/JAASRefGuide.html
https://docs.oracle.com/javase/8/docs/technotes/guides/security/jaas/JAASLMDevGuide.html
'dev > Java&Spring' 카테고리의 다른 글
jib로 springboot 애플리케이션 컨테이너화 + registry 등록 (1) | 2019.09.30 |
---|---|
Spring Cloud Gateway 2.1.0RELEASE 레퍼런스 (2) | 2019.05.12 |
netflix hystrix-dashboard 가 뜨지 않을 때 (0) | 2019.05.08 |
Spring에서 Client Authentication (two-way TLS/SSL) 구현하기 (1) | 2019.04.07 |
Spring에서 insecure SSL 요청(RestTemplate, WebClient) (1) | 2019.04.06 |