Trino 보안이 어려운 이유
Trino는 MySQL, Iceberg, Kafka, PostgreSQL 등 여러 데이터소스를 단일 SQL로 접근하는 쿼리 페더레이션 엔진이다. 데이터가 한 곳에 있지 않고 여러 시스템에 분산돼 있다는 것은 곧, 보안 제어를 어느 한 데이터베이스 레이어에서만 걸 수 없다는 뜻이다.
Trino의 보안은 크게 두 가지 질문으로 나뉜다.
- 인증(Authentication): 이 사용자가 정말 그 사람인가?
- 인가(Authorization): 그 사람이 이 데이터를 볼 자격이 있는가?
둘은 독립적으로 구성하지만, 인증이 먼저 통과되어야 인가가 의미를 갖는다. 그리고 둘 모두 TLS 위에서만 제대로 동작한다.
모든 보안의 전제 조건: TLS
Trino는 LDAP, OAuth2, PASSWORD 인증을 사용할 때 반드시 TLS(HTTPS)를 활성화해야 한다. 평문 HTTP 환경에서는 비밀번호와 토큰이 네트워크에 노출된다.
config.properties에 다음을 추가한다.
http-server.https.enabled=true
http-server.https.port=8443
http-server.https.keystore.path=/etc/trino/keystore.jks
http-server.https.keystore.key=keystore_password클러스터 내부 워커-코디네이터 통신에도 공유 시크릿(internal communication secret)을 설정해야 한다.
internal-communication.shared-secret=<무작위 긴 문자열>이 두 설정 없이 PASSWORD 계열 인증을 활성화하면 Trino가 시작을 거부한다.
인증: LDAP
LDAP 인증은 기업 내 Active Directory나 OpenLDAP 서버를 Trino의 사용자 검증 백엔드로 사용한다. 사용자가 CLI나 JDBC로 접속할 때 입력한 비밀번호를 LDAP 서버에 바인드 시도해 검증한다.
설정 파일
etc/config.properties (코디네이터)
http-server.authentication.type=PASSWORDetc/password-authenticator.properties
password-authenticator.name=ldap
ldap.url=ldaps://ldap.company.com:636
ldap.ssl.truststore.path=/etc/trino/ldap-server.pem
ldap.user-bind-pattern=uid=${USER},ou=users,dc=company,dc=com${USER}는 로그인 시 입력한 사용자 이름으로 치환된다.
그룹 멤버십 제한
특정 그룹에 속한 사용자만 접속하게 하려면 서비스 계정으로 LDAP를 검색해야 한다.
ldap.bind-dn=cn=trino-svc,ou=service,dc=company,dc=com
ldap.bind-password=<서비스계정비밀번호>
ldap.user-base-dn=ou=users,dc=company,dc=com
ldap.group-auth-pattern=(&(objectClass=groupOfNames)(cn=trino-users)(member=uid=${USER},ou=users,dc=company,dc=com))LDAP 검색 필터는 LDAP 서버 스키마에 맞춰야 한다. objectClass나 그룹 속성명이 서버마다 다르므로 ldapsearch로 먼저 확인하는 것이 좋다.
인증: OAuth2 / OIDC
OAuth2 인증은 외부 IdP(Identity Provider — Keycloak, Okta, Google, Azure AD 등)를 통해 사용자 인증을 위임한다. 브라우저 기반 Web UI 로그인에 특히 유용하며, PKCE(Proof Key for Code Exchange) 흐름을 통해 CLI/JDBC도 지원한다.
동작 흐름
Web UI 요청 → 코디네이터
302 Redirect → IdP 로그인
Keycloak/Okta → 인증 코드
/oauth2/callback → 토큰 교환
Access + ID Token
=oauth2 authentication.oauth2.issuer
=https://idp/realm/company authentication.oauth2.client-id
=trino authentication.oauth2.client-secret
=<secret>
설정
etc/config.properties
http-server.authentication.type=oauth2
http-server.https.enabled=true
http-server.https.port=8443
http-server.authentication.oauth2.issuer=https://keycloak.company.com/realms/data
http-server.authentication.oauth2.client-id=trino
http-server.authentication.oauth2.client-secret=<클라이언트시크릿>OIDC 호환 IdP는 <issuer>/.well-known/openid-configuration에 메타데이터를 게시한다. Trino는 이 엔드포인트를 자동으로 읽어 authorization_endpoint, token_endpoint, jwks_uri 등을 가져온다. 따라서 개별 URL을 다 입력할 필요가 없다.
리프레시 토큰 활성화
http-server.authentication.oauth2.refresh-tokens=true
http-server.authentication.oauth2.scopes=openid,offline_accessoffline_access 스코프를 요청해야 IdP가 리프레시 토큰을 발급한다. 리프레시 토큰이 없으면 액세스 토큰 만료 시 재인증이 필요하다.
LDAP vs OAuth2 선택 기준
| 기준 | LDAP | OAuth2/OIDC |
|---|---|---|
| 기존 인프라 | Active Directory가 있는 경우 | SSO/IdP가 이미 있는 경우 |
| 브라우저 로그인 | 지원 (기본 인증) | 지원 (리다이렉트 흐름) |
| MFA 지원 | 어려움 | IdP에서 자연스럽게 지원 |
| 비밀번호 관리 | LDAP 서버 | IdP (Keycloak, Okta 등) |
| CLI 지원 | 기본 지원 | PKCE 흐름 필요 |
인가: 파일 기반 접근 제어 (Fine-Grained ACL)
Trino는 인증된 사용자가 어떤 카탈로그, 스키마, 테이블, 컬럼에 접근할 수 있는지를 JSON 파일로 정의한다.
설정 활성화
etc/access-control.properties
access-control.name=file
security.config-file=/etc/trino/access-control/rules.jsonrules.json 경로는 절대 경로 또는 코디네이터 기준 상대 경로다.
규칙 구조
{
"catalogs": [
{
"user": "admin",
"catalog": ".*",
"allow": "all"
},
{
"group": "data-engineers",
"catalog": "iceberg",
"allow": "read-only"
},
{
"catalog": ".*",
"allow": "none"
}
],
"schemas": [
{
"user": "analyst_.*",
"catalog": "iceberg",
"schema": "warehouse",
"owner": false
}
],
"tables": [
{
"user": "reporting_user",
"catalog": "iceberg",
"schema": "warehouse",
"table": "orders",
"privileges": ["SELECT"]
}
]
}규칙은 위에서 아래로 첫 번째 매칭 규칙이 적용된다. 마지막에 "allow": "none" 같은 기본 거부 규칙을 두지 않으면 의도치 않게 모든 사용자가 접근할 수 있게 된다.
컬럼 마스킹과 행 필터링
테이블 규칙에서 특정 컬럼을 숨기거나 마스킹할 수 있다.
"tables": [
{
"user": "analyst",
"catalog": "iceberg",
"schema": "warehouse",
"table": "customers",
"privileges": ["SELECT"],
"columns": [
{
"name": "email",
"allow": false
},
{
"name": "phone",
"mask": "regexp_replace(phone, '\\d{4}$', '****')",
"mask_environment": {
"user": "data_masking_user"
}
}
],
"filter": "region = 'KR'",
"filter_environment": {
"user": "row_filter_user"
}
}
]mask는 SQL 표현식으로, 원본 컬럼값을 인자로 받아 결과를 반환한다. filter는 WHERE 조건처럼 동작해 조건에 맞는 행만 보인다.
인가: Open Policy Agent (OPA)
파일 기반 ACL은 규칙이 수백 개로 늘어나면 관리가 어렵다. OPA(Open Policy Agent)는 Rego 언어로 정책을 정의하고, HTTP API로 Trino에서 인가 결정을 위임받는다. 2024년 Trino 438부터 공식 내장됐다.
SQL 요청 → Trino 코디네이터
OPA 플러그인 ⇄ OPA 서버
http://opa:8181 → Rego 정책
allow: true/false
허용/거부 테이블 SELECT
허용/거부 컬럼 마스킹
표현식 반환 행 필터
SQL WHERE 반환
설정
etc/access-control.properties
access-control.name=opa
opa.policy.uri=http://opa-server:8181/v1/data/trino/allow컬럼 마스킹과 행 필터링 엔드포인트를 따로 지정할 수도 있다.
opa.policy.row-filters-uri=http://opa-server:8181/v1/data/trino/rowFilters
opa.policy.column-masking-uri=http://opa-server:8181/v1/data/trino/columnMasks간단한 Rego 정책 예시
package trino
import future.keywords.in
default allow = false
# admin 그룹은 모든 작업 허용
allow {
input.context.identity.groups[_] == "admin"
}
# data-engineers는 iceberg 카탈로그 읽기 허용
allow {
input.context.identity.groups[_] == "data-engineers"
input.action.operation in {"SelectFromColumns", "FilterColumns"}
input.action.resource.table.catalogName == "iceberg"
}OPA는 Trino에서 보내는 JSON 입력(input)을 평가하고 allow: true/false를 반환한다.
파일 기반 ACL vs OPA 선택 기준
| 기준 | 파일 기반 ACL | OPA |
|---|---|---|
| 규칙 수 | 수십 개 이하 | 수백~수천 개 |
| 동적 업데이트 | 파일 교체 후 재로드 | API/Git 기반 정책 배포 |
| 기업 전체 정책 통합 | 어려움 | 여러 시스템에서 동일 OPA 재사용 |
| 감사(Audit) 로깅 | 없음 | OPA Decision Log로 기록 |
| 복잡도 | 낮음 | Rego 학습 필요 |
다중 인증 방식 조합
Trino는 여러 인증 방식을 동시에 활성화할 수 있다.
# LDAP과 PASSWORD FILE을 함께 사용
http-server.authentication.type=PASSWORD,OAUTH2이 경우 브라우저 접속은 OAuth2 흐름을, CLI/JDBC는 PASSWORD(LDAP 또는 파일) 인증을 사용할 수 있다. 인증 방식은 요청의 Authorization 헤더 형식에 따라 자동으로 선택된다.
보안 설정 체크리스트
- TLS가 활성화됐는지, 유효한 인증서가 사용됐는지 확인한다.
- 내부 통신 시크릿(
internal-communication.shared-secret)을 설정한다. - 기본 접근 제어 규칙에
"allow": "none"(전체 거부) 폴백을 추가한다. - 컬럼 마스킹과 행 필터 SQL 표현식을 최소 권한 사용자로 실행되도록
mask_environment를 설정한다. - OPA 사용 시 OPA 서버 가용성 모니터링을 추가한다 — OPA가 응답하지 않으면 Trino 전체 쿼리가 차단된다.
- LDAP 비밀번호는 설정 파일에 평문으로 남지 않도록 환경 변수나 시크릿 매니저를 활용한다.
- 정기적으로
SHOW GRANTS와SHOW COLUMNS FROM <table>로 컬럼 접근 상태를 확인한다.
References
- Trino Security Overview, https://trino.io/docs/current/security/overview.html
- Trino LDAP Authentication, https://trino.io/docs/current/security/ldap.html
- Trino OAuth2 Authentication, https://trino.io/docs/current/security/oauth2.html
- Trino File-based Access Control, https://trino.io/docs/current/security/file-system-access-control.html
- Trino Open Policy Agent Access Control, https://trino.io/docs/current/security/opa-access-control.html
- Trino Blog: Open Policy Agent for Trino arrived (2024), https://trino.io/blog/2024/02/06/opa-arrived.html
- Starburst: LDAP Authentication, https://docs.starburst.io/latest/security/ldap.html
- Joel Coenraadts: Authorizing Trino with OPA, https://jcoenraadts.medium.com/authorizing-trino-with-opa-062b16c424e8
- Vivek Jain: Building a Production-Ready Trino Cluster, https://medium.com/@vjain143/building-a-production-ready-trino-cluster-for-heavy-workloads-a-guide-to-right-sizing-your-0cd8b0908be0