Hadoop Key Management Server
Hadoop Key Management Server (KMS) - 문서 세트
Hadoop KMS는 Hadoop의 KeyProvider API 기반의 암호화 키 관리 서버예요. REST API를 사용해 HTTP로 통신하는 클라이언트와 서버 컴포넌트를 제공해요. 클라이언트는 KMS HTTP REST API를 사용해 KMS와 상호작용하는 KeyProvider 구현이에요.
출처: 문서
본문
Hadoop KMS는 Hadoop의 KeyProvider API를 기반으로 하는 암호화 키 관리 서버예요. REST API를 사용해 HTTP로 통신하는 클라이언트와 서버 컴포넌트를 제공해요. 클라이언트는 KMS HTTP REST API를 사용해 KMS와 상호작용하는 KeyProvider 구현이에요. KMS와 그 클라이언트는 내장 보안을 가지며 HTTP SPNEGO Kerberos 인증과 HTTPS 보안 전송을 지원해요. KMS는 Java Jetty 웹 애플리케이션이에요.
KMS 클라이언트 구성 (KMS Client Configuration)
KMS 클라이언트 KeyProvider는 kms 스킴을 사용하며, 임베디드 URL은 KMS의 URL이어야 해요. 예를 들어 http://localhost:9600/kms에서 실행되는 KMS라면 KeyProvider URI는 kms://http@localhost:9600/kms예요. 그리고 https://localhost:9600/kms에서 실행되는 KMS라면 KeyProvider URI는 kms://https@localhost:9600/kms예요.
core-site.xml에서 HDFS NameNode를 KMS 클라이언트로 구성하는 예:
<property>
<name>hadoop.security.key.provider.path</name>
<value>kms://http@localhost:9600/kms</value>
<description>
The KeyProvider to use when interacting with encryption keys used
when reading and writing to an encryption zone.
</description>
</property>
KMS 시작/중지 (KMS Start/Stop the KMS)
KMS를 시작/중지하려면 hadoop --daemon start|stop kms를 사용해요. 예:
hadoop-3.5.0 $ hadoop --daemon start kms
참고: kms.sh 스크립트는 deprecated예요. 이제 hadoop kms의 래퍼일 뿐이에요.
KMS 구성 (KMS Configuration)
KMS 백킹(backing) KeyProvider 속성을 etc/hadoop/kms-site.xml 구성 파일에서 구성해요:
<property>
<name>hadoop.kms.key.provider.uri</name>
<value>jceks://file@/${user.home}/kms.keystore</value>
</property>
<property>
<name>hadoop.security.keystore.java-keystore-provider.password-file</name>
<value>kms.keystore.password</value>
</property>
비밀번호 파일은 클래스패스를 통해 Hadoop의 구성 디렉터리에서 찾아요.
참고: 구성 변경 사항을 적용하려면 KMS를 다시 시작해야 해요.
참고: KMS 서버는 백킹 제공자로 아무 KeyProvider 구현이나 선택할 수 있어요. 여기 예시는 JavaKeyStoreProvider를 사용하는데, 이것은 실험 목적으로만 사용해야 하고 프로덕션에서는 절대 사용하면 안 돼요. JavaKeyStoreProvider의 자세한 사용법과 주의사항은 Credential Provider API의 Keystore Passwords 섹션을 참고하세요.
KMS HTTP 구성 (KMS HTTP Configuration)
KMS는 HTTP 포트를 9600으로 사전 구성해요. KMS는 etc/hadoop/kms-site.xml에서 다음 HTTP 구성 속성을 지원해요.
참고: 구성 변경 사항을 적용하려면 KMS를 다시 시작해야 해요.
KMS 캐시 (KMS Cache)
KMS에는 두 가지 종류의 캐싱이 있어요: 암호화 키를 캐싱하는 CachingKeyProvider와 EEK를 캐싱하는 KeyProvider.
CachingKeyProvider
KMS는 기본 KeyProvider에 대한 과도한 히트를 피하기 위해 짧은 기간 동안 암호화 키를 캐시해요. 이 캐시는 기본적으로 활성화돼 있어요 (hadoop.kms.cache.enable boolean 속성을 false로 설정해 비활성화할 수 있어요).
이 캐시는 getCurrentKey(), getKeyVersion(), getMetadata() 3가지 메서드에만 사용돼요. getCurrentKey() 메서드의 경우 캐시 항목은 키가 접근되는 횟수와 무관하게 최대 30000밀리초 동안 유지돼요 (오래된 키가 current로 간주되는 것을 방지). getKeyVersion()과 getMetadata() 메서드의 경우 캐시 항목은 기본 비활성 타임아웃 600000밀리초(10분) 동안 유지돼요. 키가 deleteKey()로 삭제되거나 invalidateCache()가 호출되면 캐시가 무효화돼요.
이 구성들은 etc/hadoop/kms-site.xml 구성 파일의 다음 속성으로 변경할 수 있어요:
<property>
<name>hadoop.kms.cache.enable</name>
<value>true</value>
</property>
<property>
<name>hadoop.kms.cache.timeout.ms</name>
<value>600000</value>
</property>
<property>
<name>hadoop.kms.current.key.cache.timeout.ms</name>
<value>30000</value>
</property>
KeyProvider
구조적으로 서버 측(예: KMS)과 클라이언트 측(예: NameNode) 모두 EEK용 캐시를 가져요. 캐시에서 구성 가능한 항목:
- 캐시 크기. 각 키 이름 아래에 캐시할 수 있는 EEK의 최대 수.
- 캐시의 낮은 워터마크. 각 키 이름에 대해 get 호출 후 캐시된 EEK 수가 (size * low watermark)보다 적으면 이 키 이름 아래의 캐시가 비동기적으로 채워져요. 각 키 이름에 대해 비동기 채우기용 스레드는 1개만 실행될 수 있어요.
- 키 이름 전반에 걸쳐 캐시의 큐를 채우도록 허용된 비동기 스레드의 전체 최대 수.
- 캐시 만료 시간(밀리초). 내부적으로 Guava 캐시가 구현으로 사용되며 만료 방식은
expireAfterAccess예요.
비동기 채우기 메커니즘 때문에 rollNewVersion() 후에도 호출자가 이전 EEK를 얻을 수 있다는 점에 유의하세요. 최악의 경우 호출자는 (서버 측 캐시 크기 + 클라이언트 측 캐시 크기)만큼의 오래된 EEK를 얻거나, 양쪽 캐시가 만료될 때까지 얻을 수 있어요. 이 동작은 캐시 락킹을 피하기 위한 트레이드오프이며, 이전 버전 EEK가 여전히 복호화에 사용될 수 있으므로 허용 가능해요.
서버 측은 etc/hadoop/kms-site.xml 구성 파일의 다음 속성으로 변경할 수 있어요:
<property>
<name>hadoop.security.kms.encrypted.key.cache.size</name>
<value>500</value>
</property>
<property>
<name>hadoop.security.kms.encrypted.key.cache.low.watermark</name>
<value>0.3</value>
</property>
<property>
<name>hadoop.security.kms.encrypted.key.cache.num.fill.threads</name>
<value>2</value>
</property>
<property>
<name>hadoop.security.kms.encrypted.key.cache.expiry</name>
<value>43200000</value>
</property>
클라이언트 측은 etc/hadoop/core-site.xml 구성 파일의 다음 속성으로 변경할 수 있어요:
<property>
<name>hadoop.security.kms.client.encrypted.key.cache.size</name>
<value>500</value>
</property>
<property>
<name>hadoop.security.kms.client.encrypted.key.cache.low-watermark</name>
<value>0.3</value>
</property>
<property>
<name>hadoop.security.kms.client.encrypted.key.cache.num.refill.threads</name>
<value>2</value>
</property>
<property>
<name>hadoop.security.kms.client.encrypted.key.cache.expiry</name>
<value>43200000</value>
</property>
KMS 집계 감사 로그 (KMS Aggregated Audit logs)
감사 로그는 GET_KEY_VERSION, GET_CURRENT_KEY, DECRYPT_EEK, GENERATE_EEK, REENCRYPT_EEK 연산에 대한 API 접근에 대해 집계돼요. 항목은 구성 가능한 집계 간격 동안 (user,key,operation) 결합 키로 그룹화되고, 이후 주어진 키에 대한 지정된 엔드포인트에 대한 사용자의 접근 횟수가 감사 로그로 플러시돼요.
집계 간격은 다음 속성으로 구성돼요:
<property>
<name>hadoop.kms.aggregation.delay.ms</name>
<value>10000</value>
</property>
KMS 보안 구성 (KMS Security Configuration)
Kerberos HTTP SPNEGO 인증 활성화 (Enabling Kerberos HTTP SPNEGO Authentication)
- KDC 서버의 정보로 Kerberos
etc/krb5.conf파일을 구성해요. - KMS용 서비스 principal과 그 keytab을 만들어요. 반드시 HTTP 서비스 principal이어야 해요.
etc/hadoop/kms-site.xml을 올바른 보안 값으로 구성해요. 예:
<property>
<name>hadoop.kms.authentication.type</name>
<value>kerberos</value>
</property>
<property>
<name>hadoop.kms.authentication.kerberos.keytab</name>
<value>${user.home}/kms.keytab</value>
</property>
<property>
<name>hadoop.kms.authentication.kerberos.principal</name>
<value>HTTP/localhost</value>
</property>
<property>
<name>hadoop.kms.authentication.kerberos.name.rules</name>
<value>DEFAULT</value>
</property>
참고: 구성 변경 사항을 적용하려면 KMS를 다시 시작해야 해요.
KMS Proxyuser 구성 (KMS Proxyuser Configuration)
각 proxyuser는 etc/hadoop/kms-site.xml에서 다음 속성으로 구성해야 해요:
<property>
<name>hadoop.kms.proxyuser.#USER#.users</name>
<value>*</value>
</property>
<property>
<name>hadoop.kms.proxyuser.#USER#.groups</name>
<value>*</value>
</property>
<property>
<name>hadoop.kms.proxyuser.#USER#.hosts</name>
<value>*</value>
</property>
#USER#는 구성할 proxyuser의 사용자 이름이에요. users 속성은 impersonate될 수 있는 사용자를 나타내요. groups 속성은 impersonate되는 사용자가 반드시 속해야 하는 그룹을 나타내요. users 또는 groups 속성 중 적어도 하나는 정의되어야 해요. 둘 다 지정되면 구성된 proxyuser가 users 목록의 사용자와 groups 목록의 그룹 중 하나에 속하는 사용자를 impersonate할 수 있어요. hosts 속성은 proxyuser가 impersonation 요청을 할 수 있는 호스트를 나타내요. users, groups, hosts가 *면 사용자/그룹/호스트에 대한 제한이 없다는 뜻이에요.
HTTPS (SSL)를 통한 KMS (KMS over HTTPS (SSL))
etc/hadoop/kms-site.xml에서 SSL을 활성화해요:
<property>
<name>hadoop.kms.ssl.enabled</name>
<value>true</value>
<description>
Whether SSL is enabled. Default is false, i.e. disabled.
</description>
</property>
etc/hadoop/ssl-server.xml을 올바른 값으로 구성해요. 예:
<property>
<name>ssl.server.keystore.location</name>
<value>${user.home}/.keystore</value>
<description>Keystore to be used. Must be specified.</description>
</property>
<property>
<name>ssl.server.keystore.password</name>
<value></value>
<description>Must be specified.</description>
</property>
<property>
<name>ssl.server.keystore.keypassword</name>
<value></value>
<description>Must be specified.</description>
</property>
SSL 비밀번호는 자격 증명 제공자로 보호할 수 있어요. Credential Provider API 를 참고하세요.
KMS용 SSL 인증서를 만들어야 해요. kms Unix 사용자로, Java keytool 명령을 사용해 SSL 인증서를 만들어요:
$ keytool -genkey -alias jetty -keyalg RSA
대화형 프롬프트에서 일련의 질문을 받게 돼요. .keystore라는 이름의 keystore 파일을 만들며, 사용자 홈 디렉터리에 위치해요. "keystore password"에 입력한 비밀번호는 구성 디렉터리의 ssl-server.xml에 설정한 ssl.server.keystore.password 속성 값과 일치해야 해요. "What is your first and last name?"(즉 "CN")에 대한 답은 KMS가 실행될 머신의 호스트 이름이어야 해요.
참고: 구성 변경 사항을 적용하려면 KMS를 다시 시작해야 해요.
참고: 일부 오래된 SSL 클라이언트는 KMS 서버가 지원하지 않는 약한 암호화(cipher)를 사용할 수 있어요. SSL 클라이언트를 업그레이드하는 것을 권장해요.
ACL (Access Control Lists)
KMS는 세밀한 권한 제어를 위한 ACL(Access Control Lists)을 지원해요. KMS에는 두 가지 수준의 ACL이 존재해요: KMS ACL과 Key ACL.
KMS ACL은 KMS 연산 수준에서 접근을 제어하며 Key ACL보다 앞서요. 특히 KMS ACL 수준에서 권한이 부여된 경우에만 Key ACL에 대한 권한 검사가 수행돼요.
KMS ACL과 Key ACL의 구성과 사용법은 아래 섹션들에서 설명돼요.
KMS ACL
KMS ACL 구성은 KMS etc/hadoop/kms-acls.xml 구성 파일에 정의돼요. 이 파일은 변경되면 핫-리로드돼요. KMS는 ACL 구성 속성 집합을 통해 KMS 연산에 대한 세밀한 접근 제어와 블랙리스트를 모두 지원해요. KMS에 접근하는 사용자는 먼저 요청한 연산의 Access Control List에 포함되는지 검사된 다음, 접근이 허용되기 전에 연산의 Black list에서 제외되는지 검사돼요.
<configuration>
<property>
<name>hadoop.kms.acl.CREATE</name>
<value>*</value>
<description>
ACL for create-key operations.
If the user is not in the GET ACL, the key material is not returned
as part of the response.
</description>
</property>
<property>
<name>hadoop.kms.blacklist.CREATE</name>
<value>hdfs,foo</value>
<description>
Blacklist for create-key operations.
If the user is in the Blacklist, the key material is not returned
as part of the response.
</description>
</property>
<property>
<name>hadoop.kms.acl.DELETE</name>
<value>*</value>
<description>
ACL for delete-key operations.
</description>
</property>
<property>
<name>hadoop.kms.blacklist.DELETE</name>
<value>hdfs,foo</value>
<description>
Blacklist for delete-key operations.
</description>
</property>
<property>
<name>hadoop.kms.acl.ROLLOVER</name>
<value>*</value>
<description>
ACL for rollover-key operations.
If the user is not in the GET ACL, the key material is not returned
as part of the response.
</description>
</property>
<property>
<name>hadoop.kms.blacklist.ROLLOVER</name>
<value>hdfs,foo</value>
<description>
Blacklist for rollover-key operations.
</description>
</property>
<property>
<name>hadoop.kms.acl.GET</name>
<value>*</value>
<description>
ACL for get-key-version and get-current-key operations.
</description>
</property>
<property>
<name>hadoop.kms.blacklist.GET</name>
<value>hdfs,foo</value>
<description>
ACL for get-key-version and get-current-key operations.
</description>
</property>
<property>
<name>hadoop.kms.acl.GET_KEYS</name>
<value>*</value>
<description>
ACL for get-keys operation.
</description>
</property>
<property>
<name>hadoop.kms.blacklist.GET_KEYS</name>
<value>hdfs,foo</value>
<description>
Blacklist for get-keys operation.
</description>
</property>
<property>
<name>hadoop.kms.acl.GET_METADATA</name>
<value>*</value>
<description>
ACL for get-key-metadata and get-keys-metadata operations.
</description>
</property>
<property>
<name>hadoop.kms.blacklist.GET_METADATA</name>
<value>hdfs,foo</value>
<description>
Blacklist for get-key-metadata and get-keys-metadata operations.
</description>
</property>
<property>
<name>hadoop.kms.acl.SET_KEY_MATERIAL</name>
<value>*</value>
<description>
Complimentary ACL for CREATE and ROLLOVER operation to allow the client
to provide the key material when creating or rolling a key.
</description>
</property>
<property>
<name>hadoop.kms.blacklist.SET_KEY_MATERIAL</name>
<value>hdfs,foo</value>
<description>
Complimentary Blacklist for CREATE and ROLLOVER operation to allow the client
to provide the key material when creating or rolling a key.
</description>
</property>
<property>
<name>hadoop.kms.acl.GENERATE_EEK</name>
<value>*</value>
<description>
ACL for generateEncryptedKey
CryptoExtension operations
</description>
</property>
<property>
<name>hadoop.kms.blacklist.GENERATE_EEK</name>
<value>hdfs,foo</value>
<description>
Blacklist for generateEncryptedKey
CryptoExtension operations
</description>
</property>
<property>
<name>hadoop.kms.acl.DECRYPT_EEK</name>
<value>*</value>
<description>
ACL for decrypt EncryptedKey
CryptoExtension operations
</description>
</property>
<property>
<name>hadoop.kms.blacklist.DECRYPT_EEK</name>
<value>hdfs,foo</value>
<description>
Blacklist for decrypt EncryptedKey
CryptoExtension operations
</description>
</property>
</configuration>
Key ACL
KMS는 Key 수준에서 모든 비-읽기 연산에 대한 접근 제어를 지원해요. 모든 Key Access 연산은 다음으로 분류돼요:
MANAGEMENT- createKey, deleteKey, rolloverNewVersionGENERATE_EEK- generateEncryptedKey, reencryptEncryptedKey, reencryptEncryptedKeys, warmUpEncryptedKeysDECRYPT_EEK- decryptEncryptedKeyREAD- getKeyVersion, getKeyVersions, getMetadata, getKeysMetadata, getCurrentKeyALL- 위의 모든 것
이것들은 KMS etc/hadoop/kms-acls.xml에 정의할 수 있어요. 키 접근이 명시적으로 구성되지 않은 모든 키에 대해 연산 유형의 일부에 대한 기본 키 접근 제어(default key access control)를 구성할 수 있어요. 또한 연산 유형의 일부에 대한 "whitelist" 키 ACL을 구성할 수도 있어요. whitelist 키 ACL은 명시적 또는 기본 키별 ACL에 더해 키에 접근 권한을 부여해요. 즉, 키별 ACL이 명시적으로 설정되지 않았다면 사용자는 기본 키별 ACL 또는 whitelist 키 ACL에 있으면 접근 권한이 부여돼요. 키별 ACL이 명시적으로 설정되었다면 사용자는 키별 ACL 또는 whitelist 키 ACL에 있으면 접근 권한이 부여돼요. 특정 키에 ACL이 구성되지 않았고 기본 ACL도 없고 요청한 연산에 대한 whitelist 키 ACL도 없다면 접근이 DENIED돼요.
참고: 기본/default와 whitelist 키 ACL은 ALL 연산 한정어를 지원하지 않아요.
<property>
<name>key.acl.testKey1.MANAGEMENT</name>
<value>*</value>
<description>
ACL for create-key, deleteKey and rolloverNewVersion operations.
</description>
</property>
<property>
<name>key.acl.testKey2.GENERATE_EEK</name>
<value>*</value>
<description>
ACL for generateEncryptedKey operations.
</description>
</property>
<property>
<name>key.acl.testKey3.DECRYPT_EEK</name>
<value>admink3</value>
<description>
ACL for decryptEncryptedKey operations.
</description>
</property>
<property>
<name>key.acl.testKey4.READ</name>
<value>*</value>
<description>
ACL for getKeyVersion, getKeyVersions, getMetadata, getKeysMetadata,
getCurrentKey operations
</description>
</property>
<property>
<name>key.acl.testKey5.ALL</name>
<value>*</value>
<description>
ACL for ALL operations.
</description>
</property>
<property>
<name>whitelist.key.acl.MANAGEMENT</name>
<value>admin1</value>
<description>
whitelist ACL for MANAGEMENT operations for all keys.
</description>
</property>
<!--
'testKey3' key ACL is defined. Since a 'whitelist'
key is also defined for DECRYPT_EEK, in addition to
admink3, admin1 can also perform DECRYPT_EEK operations
on 'testKey3'
-->
<property>
<name>whitelist.key.acl.DECRYPT_EEK</name>
<value>admin1</value>
<description>
whitelist ACL for DECRYPT_EEK operations for all keys.
</description>
</property>
<property>
<name>default.key.acl.MANAGEMENT</name>
<value>user1,user2</value>
<description>
default ACL for MANAGEMENT operations for all keys that are not
explicitly defined.
</description>
</property>
<property>
<name>default.key.acl.GENERATE_EEK</name>
<value>user1,user2</value>
<description>
default ACL for GENERATE_EEK operations for all keys that are not
explicitly defined.
</description>
</property>
<property>
<name>default.key.acl.DECRYPT_EEK</name>
<value>user1,user2</value>
<description>
default ACL for DECRYPT_EEK operations for all keys that are not
explicitly defined.
</description>
</property>
<property>
<name>default.key.acl.READ</name>
<value>user1,user2</value>
<description>
default ACL for READ operations for all keys that are not
explicitly defined.
</description>
</property>
KMS 위임 토큰 구성 (KMS Delegation Token Configuration)
KMS는 Kerberos 자격 증명 없는 프로세스에서 키 제공자에 인증할 위임 토큰(delegation token)을 지원해요. KMS 위임 토큰 인증은 기본 Hadoop 인증을 확장해요. Hadoop 인증과 마찬가지로 KMS 위임 토큰은 위임 토큰 인증을 사용해 가져오거나 갱신해서는 안 돼요. 자세한 내용은 Hadoop Auth 페이지를 참고하세요.
추가로 KMS 위임 토큰 비밀 관리자는 다음 속성으로 구성할 수 있어요:
<property>
<name>hadoop.kms.authentication.delegation-token.update-interval.sec</name>
<value>86400</value>
<description>
How often the master key is rotated, in seconds. Default value 1 day.
</description>
</property>
<property>
<name>hadoop.kms.authentication.delegation-token.max-lifetime.sec</name>
<value>604800</value>
<description>
Maximum lifetime of a delegation token, in seconds. Default value 7 days.
</description>
</property>
<property>
<name>hadoop.kms.authentication.delegation-token.renew-interval.sec</name>
<value>86400</value>
<description>
Renewal interval of a delegation token, in seconds. Default value 1 day.
</description>
</property>
<property>
<name>hadoop.kms.authentication.delegation-token.removal-scan-interval.sec</name>
<value>3600</value>
<description>
Scan interval to remove expired delegation tokens.
</description>
</property>
고가용성 (High Availability)
여러 KMS 인스턴스를 사용해 고가용성과 확장성을 제공할 수 있어요. 현재 여러 KMS 인스턴스를 지원하는 두 가지 접근 방식이 있어요: 로드-밸런서/VIP 뒤에서 KMS 인스턴스를 실행하거나, LoadBalancingKMSClientProvider를 사용하는 것이에요. 두 접근 방식 모두에서, 같은 클라이언트의 요청이 서로 다른 KMS 인스턴스에 의해 처리될 수 있기 때문에 KMS 인스턴스는 단일 논리적 서비스로 올바르게 동작하도록 특별히 구성되어야 해요. 특히 Kerberos Principals 구성, HTTP Authentication Signature, Delegation Tokens에 특별한 주의가 필요해요.
로드-밸런서 또는 VIP 뒤 (Behind a Load-Balancer or VIP)
KMS 클라이언트와 서버는 HTTP를 통한 REST API로 통신하므로, 로드-밸런서 또는 VIP를 사용해 들어오는 트래픽을 분산해 확장성과 HA를 달성할 수 있어요. 이 모드에서 클라이언트는 서버 측의 여러 KMS 인스턴스를 인식하지 못해요.
LoadBalancingKMSClientProvider 사용 (Using LoadBalancingKMSClientProvider)
로드-밸런서 또는 VIP 뒤에서 여러 KMS 인스턴스를 실행하는 것의 대안은 LoadBalancingKMSClientProvider를 사용하는 것이에요. 이 접근 방식에서 KMS 클라이언트(예: HDFS NameNode)는 여러 KMS 인스턴스를 인식하고 라운드-로빈 방식으로 요청을 보내요. hadoop.security.key.provider.path에 여러 URI가 지정되면 LoadBalancingKMSClientProvider가 암시적으로 사용돼요.
core-site.xml의 다음 예제는 두 개의 KMS 인스턴스 kms01.example.com과 kms02.example.com을 구성해요. 호스트 이름은 세미콜론으로 구분되며 모든 KMS 인스턴스는 같은 포트에서 실행되어야 해요.
<property>
<name>hadoop.security.key.provider.path</name>
<value>kms://[email protected];kms02.example.com:9600/kms</value>
<description>
The KeyProvider to use when interacting with encryption keys used
when reading and writing to an encryption zone.
</description>
</property>
KMS 인스턴스에 대한 요청이 실패하면 클라이언트는 다음 인스턴스로 재시도해요. 모든 인스턴스가 실패할 때만 요청이 실패로 반환돼요.
HTTP Kerberos Principals 구성 (HTTP Kerberos Principals Configuration)
KMS 인스턴스가 로드-밸런서 또는 VIP 뒤에 있으면 클라이언트는 VIP의 호스트 이름을 사용해요. Kerberos SPNEGO 인증에서 URL의 호스트 이름은 서버의 Kerberos 서비스 이름인 HTTP/#HOSTNAME#을 구성하는 데 사용돼요. 이것은 모든 KMS 인스턴스가 로드-밸런서 또는 VIP 호스트 이름을 가진 Kerberos 서비스 이름을 가져야 함을 의미해요. 특정 KMS 인스턴스에 직접 접근할 수 있으려면 KMS 인스턴스도 자신의 호스트 이름을 가진 Kerberos 서비스 이름을 가져야 해요. 이것은 모니터링과 관리 목적에 필요해요. 두 Kerberos 서비스 principal 자격 증명(로드-밸런서/VIP 호스트 이름용과 실제 KMS 인스턴스 호스트 이름용) 모두 인증에 구성된 keytab 파일에 있어야 해요. 그리고 구성에 지정된 principal 이름은 '*'여야 해요. 예:
<property>
<name>hadoop.kms.authentication.kerberos.principal</name>
<value>*</value>
</property>
참고: HTTPS를 사용한다면 KMS 인스턴스가 사용하는 SSL 인증서가 여러 호스트 이름을 지원하도록 구성되어야 해요 (방법은 Java 7 keytool SAN 확장 지원 참고).
HTTP Authentication Signature
KMS는 HTTP 인증에 Hadoop Authentication을 사용해요. Hadoop Authentication은 클라이언트가 성공적으로 인증하면 서명된 HTTP Cookie를 발행해요. 이 HTTP Cookie는 만료 시간이 있으며, 그 후에는 새 인증 시퀀스를 트리거해요. 이것은 클라이언트의 매 HTTP 요청마다 인증을 트리거하는 것을 피하기 위해 수행돼요. KMS 인스턴스는 다른 KMS 인스턴스가 서명한 HTTP Cookie 서명을 검증해야 해요. 이를 위해 모든 KMS 인스턴스가 서명 비밀을 공유해야 해요. 자세한 설명과 구성 예제는 SignerSecretProvider Configuration 을 참고하세요. KMS 구성은 아래 예제처럼 hadoop.kms.authentication 접두사를 붙여야 한다는 점에 유의하세요.
이 비밀 공유는 kms-site.xml의 다음 속성으로 KMS에 구성된 ZooKeeper 서비스를 사용해 할 수 있어요:
<property>
<name>hadoop.kms.authentication.signer.secret.provider</name>
<value>zookeeper</value>
<description>
Indicates how the secret to sign the authentication cookies will be
stored. Options are 'random' (default), 'file' and 'zookeeper'.
If using a setup with multiple KMS instances, 'zookeeper' should be used.
If using file, signature.secret.file should be configured and point to the secret file.
</description>
</property>
<property>
<name>hadoop.kms.authentication.signer.secret.provider.zookeeper.path</name>
<value>/hadoop-kms/hadoop-auth-signature-secret</value>
<description>
The Zookeeper ZNode path where the KMS instances will store and retrieve
the secret from. All KMS instances that need to coordinate should point to the same path.
</description>
</property>
<property>
<name>hadoop.kms.authentication.signer.secret.provider.zookeeper.connection.string</name>
<value>#HOSTNAME#:#PORT#,...</value>
<description>
The Zookeeper connection string, a list of hostnames and port comma
separated.
</description>
</property>
<property>
<name>hadoop.kms.authentication.signer.secret.provider.zookeeper.auth.type</name>
<value>sasl</value>
<description>
The Zookeeper authentication type, 'none' (default) or 'sasl' (Kerberos).
</description>
</property>
<property>
<name>hadoop.kms.authentication.signer.secret.provider.zookeeper.kerberos.keytab</name>
<value>/etc/hadoop/conf/kms.keytab</value>
<description>
The absolute path for the Kerberos keytab with the credentials to
connect to Zookeeper.
</description>
</property>
<property>
<name>hadoop.kms.authentication.signer.secret.provider.zookeeper.kerberos.principal</name>
<value>kms/#HOSTNAME#</value>
<description>
The Kerberos service principal used to connect to Zookeeper.
</description>
</property>
위임 토큰 (Delegation Tokens)
HTTP 인증과 유사하게 KMS는 위임 토큰에도 Hadoop Authentication을 사용해요. HA에서 매 KMS 인스턴스는 다른 KMS 인스턴스가 준 위임 토큰을 검증해야 해요. 이를 위해 모든 KMS 인스턴스는 ZKDelegationTokenSecretManager를 사용해 TokenIdentifiers와 DelegationKeys를 ZooKeeper에서 검색해야 해요. etc/hadoop/kms-site.xml의 샘플 구성:
<property>
<name>hadoop.kms.authentication.zk-dt-secret-manager.enable</name>
<value>true</value>
<description>
If true, Hadoop KMS uses ZKDelegationTokenSecretManager to persist
TokenIdentifiers and DelegationKeys in ZooKeeper.
</description>
</property>
<property>
<name>hadoop.kms.authentication.zk-dt-secret-manager.zkConnectionString</name>
<value>#HOSTNAME#:#PORT#,...</value>
<description>
The ZooKeeper connection string, a comma-separated list of hostnames and port.
</description>
</property>
<property>
<name>hadoop.kms.authentication.zk-dt-secret-manager.znodeWorkingPath</name>
<value>/hadoop-kms/zkdtsm</value>
<description>
The ZooKeeper znode path where the KMS instances will store and retrieve
the secret from. All the KMS instances that need to coordinate should point to the same path.
</description>
</property>
<property>
<name>hadoop.kms.authentication.zk-dt-secret-manager.zkAuthType</name>
<value>sasl</value>
<description>
The ZooKeeper authentication type, 'none' (default) or 'sasl' (Kerberos).
</description>
</property>
<property>
<name>hadoop.kms.authentication.zk-dt-secret-manager.kerberos.keytab</name>
<value>/etc/hadoop/conf/kms.keytab</value>
<description>
The absolute path for the Kerberos keytab with the credentials to
connect to ZooKeeper. This parameter is effective only when
hadoop.kms.authentication.zk-dt-secret-manager.zkAuthType is set to 'sasl'.
</description>
</property>
<property>
<name>hadoop.kms.authentication.zk-dt-secret-manager.kerberos.principal</name>
<value>kms/#HOSTNAME#</value>
<description>
The Kerberos service principal used to connect to ZooKeeper.
This parameter is effective only when
hadoop.kms.authentication.zk-dt-secret-manager.zkAuthType is set to 'sasl'.
</description>
</property>
KMS HTTP REST API
키 생성 (Create a Key)
요청:
POST http://HOST:PORT/kms/v1/keys
Content-Type: application/json
{
"name" : "<key-name>",
"cipher" : "<cipher>",
"length" : <length>, //int
"material" : "<material>", //base64
"description" : "<description>"
}
응답:
201 CREATED
LOCATION: http://HOST:PORT/kms/v1/key/<key-name>
Content-Type: application/json
{
"name" : "versionName",
"material" : "<material>", //base64, not present without GET ACL
}
키 롤오버 (Rollover Key)
요청:
POST http://HOST:PORT/kms/v1/key/<key-name>
Content-Type: application/json
{
"material" : "<material>",
}
응답:
200 OK
Content-Type: application/json
{
"name" : "versionName",
"material" : "<material>", //base64, not present without GET ACL
}
키 캐시 무효화 (Invalidate Cache of a Key)
요청:
POST http://HOST:PORT/kms/v1/key/<key-name>/_invalidatecache
응답:
200 OK
키 삭제 (Delete Key)
요청:
DELETE http://HOST:PORT/kms/v1/key/<key-name>
응답:
200 OK
키 메타데이터 조회 (Get Key Metadata)
요청:
GET http://HOST:PORT/kms/v1/key/<key-name>/_metadata
응답:
200 OK
Content-Type: application/json
{
"name" : "<key-name>",
"cipher" : "<cipher>",
"length" : <length>, //int
"description" : "<description>",
"created" : <millis-epoc>, //long
"versions" : <versions> //int
}
현재 키 조회 (Get Current Key)
요청:
GET http://HOST:PORT/kms/v1/key/<key-name>/_currentversion
응답:
200 OK
Content-Type: application/json
{
"name" : "versionName",
"material" : "<material>", //base64
}
현재 KeyVersion에 대한 암호화 키 생성 (Generate Encrypted Key for Current KeyVersion)
요청:
GET http://HOST:PORT/kms/v1/key/<key-name>/_eek?eek_op=generate&num_keys=<number-of-keys-to-generate>
응답:
200 OK
Content-Type: application/json
[
{
"versionName" : "<encryptionVersionName>",
"iv" : "<iv>", //base64
"encryptedKeyVersion" : {
"versionName" : "EEK",
"material" : "<material>", //base64
}
},
{
"versionName" : "<encryptionVersionName>",
"iv" : "<iv>", //base64
"encryptedKeyVersion" : {
"versionName" : "EEK",
"material" : "<material>", //base64
}
},
...
]
암호화 키 복호화 (Decrypt Encrypted Key)
요청:
POST http://HOST:PORT/kms/v1/keyversion/<version-name>/_eek?eek_op=decrypt
Content-Type: application/json
{
"name" : "<key-name>",
"iv" : "<iv>", //base64
"material" : "<material>", //base64
}
응답:
200 OK
Content-Type: application/json
{
"name" : "EK",
"material" : "<material>", //base64
}
최신 KeyVersion으로 암호화 키 재암호화 (Re-encrypt Encrypted Key With The Latest KeyVersion)
이 명령은 이전에 생성된 암호화 키를 가져와 KeyProvider의 최신 KeyVersion 암호화 키를 사용해 재암호화해요. 최신 KeyVersion이 암호화 키 생성에 사용된 것과 같다면 같은 암호화 키가 반환돼요. 이것은 보통 암호화 키의 Rollover 후에 유용해요. 암호화 키를 재암호화하면 최신 버전의 암호화 키를 사용해 암호화되지만 키 소재(material)와 초기화 벡터는 그대로 유지돼요.
요청:
POST http://HOST:PORT/kms/v1/keyversion/<version-name>/_eek?eek_op=reencrypt
Content-Type: application/json
{
"name" : "<key-name>",
"iv" : "<iv>", //base64
"material" : "<material>", //base64
}
응답:
200 OK
Content-Type: application/json
{
"versionName" : "<encryptionVersionName>",
"iv" : "<iv>", //base64
"encryptedKeyVersion" : {
"versionName" : "EEK",
"material" : "<material>", //base64
}
}
최신 KeyVersion으로 암호화 키 일괄 재암호화 (Batch Re-encrypt Encrypted Keys With The Latest KeyVersion)
위의 암호화 키 재암호화의 배치(batched) 버전이에요. 이 명령은 이전에 생성된 암호화 키 목록을 가져와 KeyProvider의 최신 KeyVersion 암호화 키를 사용해 재암호화하고, 같은 순서로 재암호화된 암호화 키를 반환해요. 각 암호화 키에 대해 최신 KeyVersion이 암호화 키 생성에 사용된 것과 같다면 아무 조치도 취하지 않고 같은 암호화 키가 반환돼요. 이것은 보통 암호화 키의 Rollover 후에 유용해요. 배치 요청의 모든 암호화 키는 같은 암호화 키 이름 아래에 있어야 하지만, 암호화 키의 서로 다른 버전 아래에 있을 수 있어요.
요청:
POST http://HOST:PORT/kms/v1/key/<key-name>/_reencryptbatch
Content-Type: application/json
[
{
"versionName" : "<encryptionVersionName>",
"iv" : "<iv>", //base64
"encryptedKeyVersion" : {
"versionName" : "EEK",
"material" : "<material>", //base64
}
},
{
"versionName" : "<encryptionVersionName>",
"iv" : "<iv>", //base64
"encryptedKeyVersion" : {
"versionName" : "EEK",
"material" : "<material>", //base64
}
},
...
]
응답:
200 OK
Content-Type: application/json
[
{
"versionName" : "<encryptionVersionName>",
"iv" : "<iv>", //base64
"encryptedKeyVersion" : {
"versionName" : "EEK",
"material" : "<material>", //base64
}
},
{
"versionName" : "<encryptionVersionName>",
"iv" : "<iv>", //base64
"encryptedKeyVersion" : {
"versionName" : "EEK",
"material" : "<material>", //base64
}
},
...
]
키 버전 조회 (Get Key Version)
요청:
GET http://HOST:PORT/kms/v1/keyversion/<version-name>
응답:
200 OK
Content-Type: application/json
{
"name" : "<name>",
"versionName" : "<version>",
"material" : "<material>", //base64
}
키 버전들 조회 (Get Key Versions)
요청:
GET http://HOST:PORT/kms/v1/key/<key-name>/_versions
응답:
200 OK
Content-Type: application/json
[
{
"name" : "<name>",
"versionName" : "<version>",
"material" : "<material>", //base64
},
{
"name" : "<name>",
"versionName" : "<version>",
"material" : "<material>", //base64
},
...
]
키 이름들 조회 (Get Key Names)
요청:
GET http://HOST:PORT/kms/v1/keys/names
응답:
200 OK
Content-Type: application/json
[
"<key-name>",
"<key-name>",
...
]
키 메타데이터들 조회 (Get Keys Metadata)
요청:
GET http://HOST:PORT/kms/v1/keys/metadata?key=<key-name>&key=<key-name>,...
응답:
200 OK
Content-Type: application/json
[
{
"name" : "<key-name>",
"cipher" : "<cipher>",
"length" : <length>, //int
"description" : "<description>",
"created" : <millis-epoc>, //long
"versions" : <versions> //int
},
{
"name" : "<key-name>",
"cipher" : "<cipher>",
"length" : <length>, //int
"description" : "<description>",
"created" : <millis-epoc>, //long
"versions" : <versions> //int
},
...
]
deprecated 환경 변수 (Deprecated Environment Variables)
다음 환경 변수는 deprecated예요. 대신 해당 구성 속성을 설정하세요.
| Environment Variable | Configuration Property | Configuration File |
|---|---|---|
KMS_TEMP |
hadoop.http.temp.dir |
kms-site.xml |
KMS_HTTP_PORT |
hadoop.kms.http.port |
kms-site.xml |
KMS_MAX_HTTP_HEADER_SIZE |
hadoop.http.max.request.header.size and hadoop.http.max.response.header.size |
kms-site.xml |
KMS_MAX_THREADS |
hadoop.http.max.threads |
kms-site.xml |
KMS_SSL_ENABLED |
hadoop.kms.ssl.enabled |
kms-site.xml |
KMS_SSL_KEYSTORE_FILE |
ssl.server.keystore.location |
ssl-server.xml |
KMS_SSL_KEYSTORE_PASS |
ssl.server.keystore.password |
ssl-server.xml |
기본 HTTP 서비스 (Default HTTP Services)
| Name | Description |
|---|---|
/conf |
구성 속성 표시 |
/jmx |
Java JMX 관리 인터페이스 |
/logLevel |
클래스별 로그 레벨 조회 또는 설정 |
/logs |
로그 파일 표시 |
/stacks |
JVM 스택 표시 |
/static/index.html |
정적 홈 페이지 |
/prof |
Async Profiler 엔드포인트 |
서블릿 /conf, /jmx, /logLevel, /logs, /stacks, /prof에 대한 접근을 제어하려면 kms-site.xml에서 다음 속성을 구성해요:
<property>
<name>hadoop.security.authorization</name>
<value>true</value>
<description>Is service-level authorization enabled?</description>
</property>
<property>
<name>hadoop.security.instrumentation.requires.admin</name>
<value>true</value>
<description>
Indicates if administrator ACLs are required to access
instrumentation servlets (JMX, METRICS, CONF, STACKS, PROF).
</description>
</property>
<property>
<name>hadoop.kms.http.administrators</name>
<value></value>
<description>ACL for the admins, this configuration is used to control
who can access the default KMS servlets. The value should be a comma
separated list of users and groups. The user list comes first and is
separated by a space followed by the group list,
e.g. "user1,user2 group1,group2". Both users and groups are optional,
so "user1", " group1", "", "user1 group1", "user1,user2 group1,group2"
are all valid (note the leading space in " group1"). '*' grants access
to all users and groups, e.g. '*', '* ' and ' *' are all valid.
</description>
</property>
더 알아보기 (Learn more)
- 원문: 문서