인포레터에서 최신 DevOps 트렌드를 격주로 만나보세요!
데이터베이스 접근 제어
데이터베이스 접근 제어는 데이터베이스와 그 내부 데이터에 대한 역할 기반 접근 제어를 구성할 수 있는 Teleport 기능입니다. 데이터베이스 접근 제어를 사용하면 사용자가 필요한 데이터만 관리할 수 있는 권한을 부여받도록 할 수 있습니다.
접근 제어는 두 가지 수준의 세분화로 구성됩니다:
- 데이터베이스 서버: Teleport 클러스터에 등록된 데이터베이스 리소스.
- 데이터베이스 객체: 테이블, 뷰 또는 저장 프로시저.
데이터베이스 서버와 데이터베이스 객체 모두, 데이터베이스 접근 제어는 Teleport 레이블에 따라 접근을 부여하거나 거부합니다. 데이터베이스를 Teleport에 등록할 때, 데이터베이스와 연결된 레이블을 구성할 수 있습니다. 데이터베이스 객체의 경우, 가져오기 규칙을 정의하여 Teleport 데이터베이스 서비스가 가져오기 규칙 내에서 구성된 레이블과 일치하는 데이터베이스에서 가져온 데이터베이스 객체에 레이블을 적용하도록 지시할 수 있습니다.
사용자가 데이터베이스에 연결할 때, 데이터베이스 서비스는 사용자의 Teleport 역할에 따라 레이블을 확인하여 선택적으로 권한을 부여합니다.
데이터베이스 서비스는 연결의 지속 시간 동안 객체 수준의 권한을 부여하고 연결이 종료되면 이를 자동으로 철회합니다.
Teleport 역할 및 예제에 대한 보다 일반적인 설명은 RBAC를 참조하십시오. 이 섹션은 데이터베이스 접근을 위한 RBAC 구성에 중점을 둡니다.
데이터베이스 객체에 대한 데이터베이스 접근 제어는 PostgreSQL 데이터베이스만 지원합니다.
역할 구성
Teleport의 역할 리소스는 다음과 같은 데이터베이스 접근 제한 도구를 제공합니다:
kind: role
version: v5
metadata:
name: developer
spec:
allow:
# 이 역할이 접근할 수 있는 데이터베이스 인스턴스에 대한 레이블 선택기.
#
# 이는 데이터베이스 서비스에 설정된 정적/동적 레이블과 비교됩니다.
db_labels:
environment: ["dev", "stage"]
# 이 역할이 연결할 수 있는 데이터베이스 계정 이름.
db_users: ["viewer", "editor"]
# 이 역할이 연결할 수 있는 데이터베이스 이름.
#
# 이는 "db_service"의 "name" 필드와 동일하지 않으며, 특정 데이터베이스 인스턴스 내의 데이터베이스 이름입니다.
#
# 또한, 이 설정은 PostgreSQL에만 영향을 미칩니다. 현재 MySQL 데이터베이스/스키마에는 영향을 미치지 않습니다.
db_names: ["main", "metrics", "postgres"]
와일드카드를 사용하여 모든 데이터베이스 이름/사용자와 일치시킬 수 있습니다.
예를 들어, 다음 역할은 프로덕션 데이터베이스 내의 모든 데이터베이스/사용자에 대한 접근을 허용하지만 내부 "postgres" 데이터베이스/사용자는 제외합니다:
kind: role
version: v5
metadata:
name: developer
spec:
allow:
db_labels:
environment: ["prod"]
db_users: ["*"]
db_names: ["*"]
deny:
db_users: ["postgres"]
db_names: ["postgres"]
거부 규칙
거부 규칙은 공격적으로 일치합니다. 위의 예에서 "postgres" 데이터베이스 계정(데이터베이스 인스턴스나 데이터베이스 이름에 관계없이) 또는 "postgres" 데이터베이스 이름(데이터베이스 인스턴스나 데이터베이스 계정에 관계없이)을 사용하려는 데이터베이스 연결은 거부됩니다.
데이터베이스 이름
서로 다른 데이터베이스 서버가 논리 데이터베이스를 처리하는 방식에는 차이가 있으며, 이는 db_names
역할 필드가 연결 시도에 적용되는 방식에서 차이를 만듭니다.
PostgreSQL은 여러 개의 논리 데이터베이스를 지원하며, 각 논리 데이터베이스는 여러 스키마를 포함할 수 있습니다. 다른 데이터베이스로 변경하려면 사용자가 현재 데이터베이스에서 연결을 끊고 새 연결을 설정해야 합니다. PostgreSQL 연결 시도 중에 db_names
필드는 사용자가 연결하고 있는 논리 데이터베이스의 이름과 비교됩니다.
MySQL에서는 논리 "데이터베이스"와 "스키마"가 서로 동의어이며, 사용자가 연결된 후의 권한 범위는 데이터베이스 내 계정에 설정된 권한 부여에 의해 결정됩니다. 따라서 db_names
역할 필드는 현재 MySQL 연결 시도에서는 적용되지 않습니다.
템플릿 변수
다른 역할 필드와 마찬가지로 db_*
필드는 템플릿 변수를 지원합니다.
external.xyz
특성은 외부 싱글 사인온 공급자의 값으로 대체됩니다. OIDC의 경우 "xyz" 클레임의 값으로 대체됩니다. SAML의 경우 "xyz" 주장의 값으로 대체됩니다.
Teleport 역할에서 특성이 작동하는 방식에 대한 전체 세부정보는 Teleport 액세스 제어 참조를 참조하십시오.
예를 들어, 사용자의 Okta databases
주장으로 허용된 데이터베이스 이름을 할당하려는 경우 역할의 모습은 다음과 같습니다:
spec:
allow:
db_names: ["{{external.databases}}"]
{{internal.db_users}}
및 {{internal.db_names}}
변수는 원격 클러스터와 허용된 데이터베이스 계정과 이름을 공유할 수 있게 합니다. 이들은 루트 클러스터에서 연결되는 원격 사용자의 해당 속성으로 대체됩니다.
예를 들어, 루트 클러스터의 사용자가 다음과 같은 역할을 가지고 있다고 가정해 보십시오:
spec:
allow:
db_users: ["postgres"]
db_names: ["postgres"]
리프 클러스터의 역할은 사용자의 허용된 데이터베이스 계정과 이름을 사용하도록 설정할 수 있습니다:
spec:
allow:
db_users: ["{{internal.db_users}}"]
db_names: ["{{internal.db_names}}"]
데이터베이스 객체 가져오기 규칙
Teleport의 데이터베이스 객체 가져오기 규칙은 Teleport에 가져온 데이터베이스 객체에 적용할 레이블을 정의하는 리소스입니다. 특정 객체가 어떤 규칙과도 일치하지 않는 경우 가져와지지 않습니다.
기본 가져오기 규칙
기본적으로, 가져오기 규칙이 없을 경우 (예: 새 클러스터를 만들거나 모든 규칙을 삭제할 경우), Teleport는 시작 시 자동으로 import_all_objects
규칙을 생성합니다:
kind: db_object_import_rule
metadata:
name: import_all_objects
spec:
# 우선순위는 규칙이 얼마나 중요한지를 결정하며, 낮은 숫자는 낮은 우선순위를 나타냅니다.
# 충돌이 발생할 경우, 같은 레이블이 두 개의 규칙에 의해 적용되면,
# 더 높은 우선순위의 규칙에 의해 적용된 레이블이 우선합니다.
priority: 0
# database_labels는 이 규칙의 범위에 해당하는 데이터베이스 리소스를 지정하는 필터입니다.
database_labels:
- name: "*"
values:
- "*"
# 매핑이 일치하는 경우 데이터베이스 객체에 적용할 레이블 세트를 도입합니다.
# 레이블이 없는 데이터베이스 객체는 가져와지지 않습니다.
mappings:
- add_labels:
database: "{{obj.database}}"
object_kind: "{{obj.object_kind}}"
name: "{{obj.name}}"
protocol: "{{obj.protocol}}"
schema: "{{obj.schema}}"
database_service_name: "{{obj.database_service_name}}"
# match는 가져올 객체를 추가하며, 비어 있을 수 없습니다.
match:
# 모든 테이블 이름의 목록
table_names:
- "*"
# 추가 매핑을 여기서 추가할 수 있습니다.
# - add_labels: ...
version: v1
이 규칙은 모든 객체를 가져와서 그 본질적인 속성을 사용하여 레이블을 지정합니다.
기본 가져오기 규칙 사용자 정의
기본 db_object_import_rule
은 다른 Teleport 리소스처럼 수정할 수 있습니다.
예를 들어, 개발자에게 읽기 전용 또는 읽기-쓰기 권한으로 특정 테이블을 지정하기 위해 설계된 다음과 같은 규칙을 고려해 보십시오:
kind: db_object_import_rule
metadata:
name: ownership_nonprod
spec:
priority: 100
database_labels:
# 'dev' 및 'staging' 환경에 영향을 미칩니다.
# Prod 환경은 다른 규칙을 가질 수 있습니다.
- name: "env"
values:
- "staging"
- "dev"
- "prod"
mappings:
# 프로젝트 레이블 적용
- add_labels:
project: horizon
# match 섹션은 필수이며, 최소한 하나의 비어 있지 않은 하위 섹션을 포함해야 합니다.
match:
table_names:
- "*"
# scope는 선택적 섹션으로 데이터베이스와 스키마 이름으로 객체를 추가 필터링할 수 있게 해줍니다. 생략하면 이 필터링이 비활성화됩니다.
scope:
database_names:
- "horizon"
- "horizon_v2"
schema_names:
- "application"
- "data_import"
# 각 테이블에 대해 `dept: hr` 레이블을 추가합니다.
- add_labels:
dept: hr
match:
table_names:
- "*"
scope:
schema_names:
- "recruitment"
- "salaries"
- "pto"
- "hr_scratchpad"
version: v1
데이터베이스 관리자 사용자
데이터베이스 관리자 사용자는 최종 사용자에게 권한을 부여하는 책임이 있습니다. 데이터베이스 객체 가져오기 규칙을 사용하기 전에 데이터베이스 관리자 사용자를 지정해야 합니다. 데이터베이스 관리자 사용자를 지정하려면 다음 내용을 Teleport Database Service를 실행하는 에이전트의 동적 데이터베이스 리소스 또는 구성 파일에 추가하십시오:
kind: db
version: v3
metadata:
# ...
spec:
# ...
admin_user: "teleport-admin"
db_service:
enabled: "yes"
databases:
- name: "example"
# ...
admin_user:
name: "teleport-admin"
이 경우 Teleport Database Service는 객체 가져오기 규칙을 실행하기 위해 teleport-admin
이라는 사용자를 활성화해야 합니다. 관리 사용자가 데이터베이스의 사용자 관리에 필요한 권한을 가지고 있는지 확인하십시오. 그렇지 않으면 데이터베이스 구성에 따라 객체 가져오기 규칙이 실패할 수 있습니다:
tsh db connect postgres-db --db-name postgres --db-user teleport-userpsql: error: connection to server at "localhost" (::1), port 50800 failed: Connection refused Is the server running on that host and accepting TCP/IP connections?connection to server at "localhost" (127.0.0.1), port 50800 failed: your Teleport role requires automatic database user provisioning but an attempt to activate database user "teleport-user" failed due to the following error: ERROR: permission denied for table pg_subscription (SQLSTATE 42501)ERROR: exit status 2
데이터베이스 객체 권한 규칙 실행
Teleport Database Service는 사용자가 데이터베이스에 연결하기 전에 해당 사용자의 역할을 확인합니다.
데이터베이스 연결 중 데이터베이스 객체 권한을 부여하려면 사용자가 특정 기준을 충족하는 역할과 연결되어 있어야 합니다:
spec.allow.db_labels
는 특정 데이터베이스의 데이터베이스 레이블과 일치해야 합니다.- 데이터베이스 사용자 자동 프로비저닝이 활성화되어야 합니다
(
spec.options.create_db_user_mode
가off
로 설정되지 않거나spec.options.create_db_user: true
여야 합니다). spec.allow.db_permissions.match
의 레이블 키/값 쌍은 특정 데이터베이스 객체의 레이블과 일치해야 합니다.
사용자는 동일한 데이터베이스에 여러 개의 동시 연결을 유지할 수 있습니다. 모든 연결은 동일한 권한을 가져야 하며, 그렇지 않으면 새 연결이 거부됩니다. 마지막 활성 연결이 종료되면 모든 사용자 권한이 자동으로 취소됩니다.
테이블의 레이블은 적절한 역할과 일치해야 합니다. 다음은 ownership_nonprod
규칙에 의해 적용된 dept
레이블을 사용하는 역할의 예로, 데이터베이스에서 HR 기록에 대한 읽기 전용 액세스를 부여합니다. hr_scratchpad
테이블은 추가적으로 편집 가능하게 만들어집니다. 반면, dept: sales
로 레이블이 지정된 모든 객체는 사용자가 가질 수 있는 모든 권한을 제거하여 사용 불가능하게 됩니다. 와일드카드 권한은 사양의 deny
부분(spec.deny.db_permissions
)에서만 허용됩니다:
version: v7
kind: role
metadata:
name: dept_hr_permissions
spec:
allow:
db_labels:
"*": "*"
db_names:
- "*"
db_permissions:
# 기본 권한: 읽기 전용
- match:
object_kind: table
dept: hr
permissions:
- SELECT
# 선택 테이블에 대한 추가 권한
- match:
object_kind: table
dept: hr
name: hr_scratchpad
permissions:
- SELECT
- UPDATE
- DELETE
- INSERT
deny:
db_permissions:
# `dept: sales` 테이블과의 모든 상호작용을 명시적으로 금지합니다.
- match:
dept: sales
permissions:
- "*"
options:
create_db_user_mode: keep
데이터베이스 객체 가져오기 규칙 문제 해결
데이터베이스 객체 가져오기 문제를 진단하기 위해 Teleport 데이터베이스 서비스 로그를 참조하십시오. 이 로그는 데이터베이스에서 가져온 객체 수, 가져온 객체 수(가져오기 규칙과 일치하지 않는 객체의 차이를 포함), 사용자에게 부여된 권한이 있는 객체 수를 나타냅니다:
INFO [DB:SERVIC] 데이터베이스에서 가져온 데이터베이스 객체 (table:75). db:my-postgres id:b4a33740-1d82-4a8d-b2be-2aa90ae9d2eb total:75 postgres/users.go:212
INFO [DB:SERVIC] 가져온 데이터베이스 객체 (table:75). db:my-postgres err_count:0 id:b4a33740-1d82-4a8d-b2be-2aa90ae9d2eb total:75 postgres/users.go:216
INFO [DB:SERVIC] 계산된 데이터베이스 권한: "INSERT": 75 객체 (table:75), "SELECT": 75 객체 (table:75), "UPDATE": 75 객체 (table:75). db:my-postgres id:b4a33740-1d82-4a8d-b2be-2aa90ae9d2eb user:teleport-user postgres/users.go:223