보안 개요(Security overview)

보안 개요(Security overview)

이 문서는 Apache Druid 보안 기능의 개요, 구성 방법, 그리고 Druid를 보호하기 위한 몇 가지 모범 사례를 제공해요. 이 문서에서는 TLS, 인증(authentication), 권한 부여(authorization)를 구성하는 방법과 Druid의 보안 신뢰 모델을 설명드릴게요.

출처: 문서

본문

이 문서는 Apache Druid 보안 기능의 개요, 구성 지침, 그리고 Druid를 보호하기 위한 몇 가지 모범 사례를 제공합니다. 기본적으로 Druid의 보안 기능은 비활성화되어 있어 초기 배포 경험을 단순하게 해줘요. 하지만 프로덕션 배포에서는 보안 기능(TLS, 인증, 권한 부여)을 반드시 구성해야 합니다.

모범 사례

다음 권장 사항은 Druid 클러스터 설정에 적용됩니다:

  • Druid를 권한이 없는(비-root) Unix 사용자로 실행하세요. root 사용자로 Druid를 실행하지 마세요. Druid 관리자는 Druid를 실행하는 Unix 사용자 계정과 동일한 OS 권한을 가져요. 인증 및 권한 부여 모델(Authentication and authorization model)을 참고하세요. Druid 프로세스가 OS root 사용자 계정으로 실행 중이라면, Druid 관리자는 /etc/passwd 같은 민감한 파일을 포함해 root 계정이 접근할 수 있는 모든 파일을 읽거나 쓸 수 있습니다.
  • 프로덕션 환경과 신뢰할 수 없는 네트워크로 접근할 수 있는 다른 환경에 대해서는 Druid 클러스터에 대한 인증(authentication)을 활성화하세요.
  • 권한 부여(authorization)를 활성화하고, 권한 부여가 활성화되지 않은 상태에서는 웹 콘솔을 노출하지 마세요. 권한 부여가 활성화되지 않으면 웹 콘솔에 접근할 수 있는 모든 사용자는 웹 콘솔 프로세스를 실행하는 운영 체제 사용자와 동일한 권한을 가져요.
  • 사용자에게 자신의 기능을 수행하는 데 필요한 최소한의 권한만 부여하세요. 예를 들어 데이터만 쿼리하면 되는 사용자가 데이터소스에 쓰거나 상태(state)를 보도록 허용하지 마세요.
  • 프로덕션 시스템의 구성 스펙에 평문 패스워드를 제공하지 마세요. 예를 들어 KafkaSupervisorIngestionSpec의 consumerProperties 필드에 민감한 속성을 넣지 말아야 해요. 자세한 내용은 Environment variable dynamic config provider 문서를 참고하세요.
  • JavaScript 가이드의 Security 섹션에 명시된 대로 JavaScript를 비활성화하세요.

다음 권장 사항은 Druid가 실행되는 네트워크에 적용됩니다:

  • 클러스터 내 통신을 암호화하려면 TLS를 활성화하세요.
  • API 게이트웨이를 사용해서:

신뢰할 수 없는 네트워크에서의 접근을 제한하고 사용자가 접근해야 하는 특정 API의 허용 목록을 만들고 계정 잠금(account lockout)과 스로틀링(throttling) 기능을 구현하세요.

  • 가능하면 방화벽과 기타 네트워크 계층 필터링을 사용해 사용 사례에 특화된 Druid 서비스와 포트만 노출하세요. 예를 들어 쿼리를 실행하는 다운스트림 애플리케이션에만 Broker 포트를 노출하세요. 특정 IP 주소나 IP 범위로 접근을 제한해 보안을 더욱 강화할 수 있어요.

다음 권장 사항은 Druid의 권한 부여 및 인증 모델에 적용됩니다:

  • WRITE 권한은 신뢰할 수 있는 사용자에게만 DATASOURCE에 대해 부여하세요. Druid의 신뢰 모델은 그 사용자들이 웹 콘솔 프로세스를 실행하는 운영 체제 사용자와 동일한 권한을 가진다고 가정합니다. 또한 WRITE 권한이 있는 사용자는 데이터소스를 변경할 수 있고, 수집에 영향을 줄 수 있는 태스크와 슈퍼바이저 업데이트(POST) API 둘 다에 접근할 수 있어요.
  • STATE READ, STATE WRITE, CONFIG WRITE, DATASOURCE WRITE 권한은 높은 신뢰를 받는 사용자에게만 부여하세요. 이 권한들은 데이터소스에 관계없이 Druid 서버 프로세스를 대신해 자원에 접근할 수 있게 해줍니다.
  • Druid 클라이언트 애플리케이션이 덜 신뢰되는 사용자가 수집 태스크의 input source를 제어하도록 허용한다면, 사용자의 URL을 검증하세요. 검사되지 않은 URL을 네트워크나 로컬 파일 시스템 내의 다른 위치와 자원으로 가리키는 것이 가능합니다.

TLS 활성화

TLS를 활성화하면 외부 클라이언트와 Druid 클러스터 사이, 그리고 클러스터 내 서비스 사이의 트래픽이 암호화돼요.

키 생성

Druid에서 TLS를 활성화하기 전에 KeyStore와 truststore를 생성하세요. 하나의 Druid 프로세스(예: Broker)가 다른 Druid 프로세스(예: Historical)를 접촉할 때, 첫 번째 서비스는 두 번째 서비스(서버로 간주)에 대한 클라이언트가 됩니다. 클라이언트는 클라이언트가 신뢰하는 인증서를 포함하는 trustStore를 사용해요. 예를 들어 Broker가 그렇습니다. 서버는 자체적으로 안전하게 식별하는 데 사용되는 개인 키와 인증서 체인을 포함하는 KeyStore를 사용합니다.

다음 예시는 Java keytool로 서버용 KeyStore를 생성한 다음, 클라이언트가 키를 신뢰하도록 trustStore를 만드는 방법을 보여줘요:

  • Java keytool 명령으로 KeyStore를 생성하세요:
keytool -keystore keystore.jks -alias druid -genkey -keyalg RSA
  • 공개 인증서를 내보내세요:
keytool -export -alias druid -keystore keystore.jks -rfc -file public.cert
  • trustStore를 생성하세요:
keytool -import -file public.cert -alias druid -keystore truststore.jks

Druid는 임베디드 웹 서버로 Jetty를 사용합니다. Jetty 문서의 Configuring SSL/TLS KeyStores를 참고하세요. 프로덕션 환경에서는 자체 서명(self-signed) 인증서를 사용하지 마세요. 대신 현재 공개 키 인프라(PKI)에 의존해 신뢰할 수 있는 키를 생성하고 배포하세요.

Druid TLS 구성 업데이트

모든 노드의 모든 Druid 서비스에 대해 common.runtime.properties를 편집하세요. 다음 TLS 옵션을 추가하거나 업데이트하고, 완료되면 클러스터를 재시작하세요.

# Turn on TLS globally
druid.enableTlsPort=true

# Disable non-TLS communicatoins
druid.enablePlaintextPort=false

# For Druid processes acting as a client
# Load simple-client-sslcontext to enable client side TLS
# Add the following to extension load list
druid.extensions.loadList=[......., "simple-client-sslcontext"]

# Setup client side TLS
druid.client.https.protocol=TLSv1.2
druid.client.https.trustStoreType=jks
druid.client.https.trustStorePath=truststore.jks # replace with correct trustStore file
druid.client.https.trustStorePassword=secret123  # replace with your own password

# Setup server side TLS
druid.server.https.keyStoreType=jks
druid.server.https.keyStorePath=my-keystore.jks # replace with correct keyStore file
druid.server.https.keyStorePassword=secret123 # replace with your own password
druid.server.https.certAlias=druid

자세한 내용은 TLS support와 Simple SSLContext Provider Module 문서를 참고하세요.

인증 및 권한 부여

인증과 권한 부여를 구성해서 Druid API에 대한 접근을 제어할 수 있어요. 그런 다음 다음 섹션들에서 설명하는 대로 사용자, 역할(roles), 권한(permissions)을 구성하세요. 클러스터의 모든 Druid 서버에서 common.runtime.properties 파일에 구성 변경을 하세요.

Druid의 운영 컨텍스트에서 authenticator는 사용자 신원이 검증되는 방식을 제어합니다. authorizer는 사용자 역할을 사용해 인증된 사용자를 접근이 허용된 데이터소스와 연결해요. 데이터소스별로 가장 세분화된 권한을 설정할 수 있어요.

인증자(Authenticator) 활성화

Druid에서 요청을 인증하려면 Authenticator를 구성하세요. HTTP basic 인증, LDAP, Kerberos용 Authenticator 확장이 존재합니다. 다음은 basic auth를 활성화하기 위한 샘플 구성 단계를 안내합니다:

  • common.runtime.properties의 druid.extensions.loadList에 druid-basic-security 확장을 추가하세요. 예를 들어 quickstart 설치의 경우 속성 파일은 conf/druid/cluster/_common에 있습니다: druid.extensions.loadList=["druid-basic-security", "druid-histogram", "druid-datasketches", "druid-kafka-indexing-service"]
  • 같은 common.runtime.properties 파일에서 basic Authenticator, Authorizer, Escalator 설정을 구성하세요. Escalator는 Druid 프로세스들이 서로 어떻게 인증하는지 정의합니다. 예시 구성: # Druid basic securitydruid.auth.authenticatorChain=["MyBasicMetadataAuthenticator"]druid.auth.authenticator.MyBasicMetadataAuthenticator.type=basic# Default password for 'admin' user, should be changed for production.druid.auth.authenticator.MyBasicMetadataAuthenticator.initialAdminPassword=password1# Default password for internal 'druid_system' user, should be changed for production.druid.auth.authenticator.MyBasicMetadataAuthenticator.initialInternalClientPassword=password2# Uses the metadata store for storing users.# You can use the authentication API to create new users and grant permissionsdruid.auth.authenticator.MyBasicMetadataAuthenticator.credentialsValidator.type=metadata# If true and if the request credential doesn't exist in this credentials store,# the request will proceed to next Authenticator in the chain.druid.auth.authenticator.MyBasicMetadataAuthenticator.skipOnFailure=falsedruid.auth.authenticator.MyBasicMetadataAuthenticator.authorizerName=MyBasicMetadataAuthorizer# Escalatordruid.escalator.type=basicdruid.escalator.internalClientUsername=druid_systemdruid.escalator.internalClientPassword=password2druid.escalator.authorizerName=MyBasicMetadataAuthorizerdruid.auth.authorizers=["MyBasicMetadataAuthorizer"]druid.auth.authorizer.MyBasicMetadataAuthorizer.type=basic
  • 클러스터를 재시작하세요.

자세한 내용은 다음 주제들을 참고하세요:

  • 인증 및 권한 부여: Authenticator, Escalator, Authorizer에 대한 자세한 내용. (Authentication and Authorization)
  • 위 예시에서 사용한 확장에 대한 자세한 내용: Basic Security
  • Kerberos 인증: Kerberos
  • 권한에 대한 자세한 내용: 사용자 인증 및 권한 부여 (User authentication and authorization)
  • SQL 시스템 테이블에 대한 권한: SQL permissions

Authorizer 활성화

basic auth 확장을 활성화한 후 Druid Coordinator의 user 엔드포인트를 통해 사용자, 역할, 권한을 추가할 수 있어요. 참고로 개별 사용자에게 직접 권한을 할당할 수는 없습니다. 반드시 역할(roles)을 통해 할당해야 합니다.

다음 단계는 샘플 설정 절차를 안내합니다. 기본 Coordinator API 포트는 비-TLS 연결의 경우 8081, 보안 연결의 경우 8281입니다.

  • druid-ext/basic-security/authentication/db/MyBasicMetadataAuthenticator/users/<USERNAME>에 POST 요청을 보내 사용자를 생성하세요. <USERNAME>을 생성하려는 새 사용자 이름으로 바꾸세요. 예를 들어: curl -u admin:password1 -XPOST https://my-coordinator-ip:8281/druid-ext/basic-security/authentication/db/MyBasicMetadataAuthenticator/users/myname TLS가 활성화되어 있다면 curl 명령을 그에 맞게 조정하세요. 예를 들어 Druid 서버가 자체 서명 인증서를 사용한다면, curl 명령에 insecure 옵션을 포함해 인증서 검사를 생략하도록 선택할 수 있어요.
  • druid-ext/basic-security/authentication/db/MyBasicMetadataAuthenticator/users/<USERNAME>/credentials에 POST 요청을 보내 사용자에 대한 자격 증명(credential)을 추가하세요. 예를 들어: curl -u admin:password1 -H'Content-Type: application/json' -XPOST https://my-coordinator-ip:8281/druid-ext/basic-security/authentication/db/MyBasicMetadataAuthenticator/users/myname/credentials --data-raw '{"password": "my_password"}'
  • 생성한 각 authenticator 사용자에 대해 druid-ext/basic-security/authorization/db/MyBasicMetadataAuthorizer/users/<USERNAME>에 POST 요청을 보내 대응하는 authorizer 사용자를 생성하세요. 예를 들어: curl -u admin:password1 -XPOST https://my-coordinator-ip:8281/druid-ext/basic-security/authorization/db/MyBasicMetadataAuthorizer/users/myname
  • druid-ext/basic-security/authorization/db/MyBasicMetadataAuthorizer/roles/<ROLENAME>에 POST 요청을 보내 권한을 제어할 authorizer 역할을 생성하세요. 예를 들어: curl -u admin:password1 -XPOST https://my-coordinator-ip:8281/druid-ext/basic-security/authorization/db/MyBasicMetadataAuthorizer/roles/myrole
  • druid-ext/basic-security/authorization/db/MyBasicMetadataAuthorizer/users/<USERNAME>/roles/<ROLENAME>에 POST 요청을 보내 사용자에게 역할을 할당하세요. 예를 들어: curl -u admin:password1 -XPOST https://my-coordinator-ip:8281/druid-ext/basic-security/authorization/db/MyBasicMetadataAuthorizer/users/myname/roles/myrole | jq
  • 마지막으로 druid-ext/basic-security/authorization/db/MyBasicMetadataAuthorizer/roles/<ROLENAME>/permissions에서 역할에 권한을 첨부해 그들이 Druid와 어떻게 상호작용할 수 있는지 제어하세요. 예를 들어: curl -u admin:password1 -H'Content-Type: application/json' -XPOST --data-binary @perms.json https://my-coordinator-ip:8281/druid-ext/basic-security/authorization/db/MyBasicMetadataAuthorizer/roles/myrole/permissions

perms.json의 페이로드는 다음 형식이어야 해요: [ { "resource": { "type": "DATASOURCE", "name": "<PATTERN>" }, "action": "READ" }, { "resource": { "type": "STATE", "name": "STATE" }, "action": "READ" }]

참고: Druid는 리소스 이름을 정규 표현식(regex)으로 취급합니다. 특정 데이터소스 이름이나 regex를 사용해 한 번에 여러 데이터소스에 권한을 부여할 수 있어요.

LDAP 인증자 구성

기본 메타데이터 인증자(basic metadata authenticator)를 사용하는 대안으로, 사용자 인증에 LDAP을 사용할 수 있어요. Druid를 LDAP/LDAPS용으로 구성하는 방법은 Configure LDAP authentication 문서를 참고하세요.

Druid 보안 신뢰 모델

Druid의 신뢰 모델에서 사용자는 서로 다른 권한 수준을 가질 수 있습니다:

  • 자원 쓰기 권한(resource write permissions)이 있는 사용자는 druid 프로세스가 할 수 있는 모든 것을 할 수 있어요.
  • 인증된 읽기 전용 사용자는 권한이 있는 자원에 대해 쿼리를 실행할 수 있습니다.
  • 권한이 전혀 없는 인증된 사용자는 자원 접근이 필요하지 않은 쿼리를 실행할 수 있어요.

또한 Druid는 다음 원칙에 따라 동작합니다:

가장 안쪽 레이어부터:

  • Druid 프로세스는 프로세스를 실행하는 지정된 시스템 사용자에게 부여된 로컬 파일 접근 권한과 동일한 권한을 가집니다.
  • Druid 수집 시스템은 태스크를 실행하기 위한 새 프로세스를 만들 수 있습니다. 그 태스크들은 부모 프로세스의 사용자를 상속합니다. 이는 수집 태스크를 제출하도록 인가된 모든 사용자가, Druid 프로세스가 접근할 수 있는 모든 로컬 파일이나 외부 자원을 수집 태스크 권한으로 읽거나 쓸 수 있다는 뜻이에요.

참고: DATASOURCE WRITE는 Druid 프로세스처럼 행동할 수 있기 때문에 신뢰할 수 있는 사용자에게만 부여하세요.

클러스터 내에서:

  • Druid는 격리된 보호된 네트워크에서 동작하며 네트워크 내의 도달 가능한 IP가 적대자의 통제 하에 있지 않다고 가정합니다. Druid를 구현할 때 인바운드/아웃바운드 연결 모두를 보호하기 위해 방화벽과 기타 보안 조치를 설정하도록 주의하세요.
  • Druid는 API 호출과 데이터 전송을 포함해 클러스터 내 네트워크 트래픽이 암호화된다고 가정합니다. 기본 암호화 구현은 TLS를 사용합니다.
  • Druid는 메타데이터 저장소와 ZooKeeper 노드 같은 보조 서비스가 적대자의 통제 하에 있지 않다고 가정합니다.

클러스터에서 딥 스토리지로:

  • Druid는 딥 스토리지의 보안에 대해 가정하지 않습니다. 딥 스토리지와 인증하고 권한을 부여받기 위해 시스템의 네이티브 보안 정책을 따릅니다.
  • Druid는 딥 스토리지용 파일을 암호화하지 않습니다. 대신 모든 스토리지 유형의 암호화 스킴과 호환되도록 스토리지 시스템의 네이티브 암호화 기능에 의존합니다.

클러스터에서 클라이언트로:

  • Druid는 구성된 authenticator에 따라 클라이언트와 인증합니다.
  • Druid는 authorizer가 권한을 부여할 때만 동작을 수행합니다. 기본 구성은 allowAll authorizer입니다.

보안 이슈 보고

Apache Druid 팀은 보안을 매우 중요하게 생각합니다. Druid에서 앞서 설명한 보안 메커니즘을 우회하는 방법 같은 잠재적 보안 이슈를 발견한다면, 이 문제를 [email protected]로 보고해 주세요. 이는 비공개 메일링 리스트입니다. 보고하는 각 취약점마다 평문 이메일 한 통을 보내 주세요.

취약점 처리

다음 목록은 취약점 처리 프로세스를 요약합니다:

  • 보고자는 취약점을 [email protected]에 비공개로 보고합니다.
  • 보고자는 Druid 팀이 보고를 받았고 이슈를 조사할 것이라는 응답을 받습니다.
  • Druid 프로젝트 보안 팀은 보고자와 비공개로 협력해 취약점을 해결합니다.
  • Druid 팀은 취약점이 영향을 주는 패키지의 새 릴리스를 만들어 수정을 전달합니다.
  • Druid 팀은 취약점을 공개적으로 발표하고 수정을 적용하는 방법을 설명합니다.

커미터(committer)는 이 프로세스의 더 자세한 설명을 읽어야 합니다. 보안 취약점의 보고자도 도움이 될 수 있어요.