데이터베이스 접근 제어
데이터베이스 접근 제어는 데이터베이스와 그 내부 데이터에 대한 역할 기반 접근 제어를 구성할 수 있는 Teleport 기능입니다. 접근 제어는 두 수준의 세분성을 포함합니다: 데이터베이스 서버와 데이터베이스 객체 모두에 대해 데이터베이스 접근 제어는 Teleport 레이블을 기반으로 접근을 허용하거나 거부합니다.
데이터베이스 접근 제어는 데이터베이스와 그 내부 데이터에 대한 역할 기반 접근 제어를 구성할 수 있는 Teleport 기능입니다. 데이터베이스 접근 제어를 통해 사용자가 필요한 데이터만 관리할 수 있는 권한을 갖도록 보장할 수 있습니다.
접근 제어는 두 수준의 세분성을 포함합니다:
- 데이터베이스 서버: Teleport 클러스터에 등록된 데이터베이스 리소스.
- 데이터베이스 객체: 테이블, 뷰 또는 저장 프로시저.
데이터베이스 서버와 데이터베이스 객체 모두에 대해 데이터베이스 접근 제어는 Teleport 레이블을 기반으로 접근을 허용하거나 거부합니다. Teleport에 데이터베이스를 등록할 때 데이터베이스와 관련된 레이블을 구성할 수 있습니다. 데이터베이스 객체의 경우 Teleport Database Service가 가져오기 규칙 내에서 구성된 레이블과 일치하는 데이터베이스에서 가져온 데이터베이스 객체에 레이블을 적용하도록 지시하는 가져오기 규칙을 정의할 수 있습니다.
사용자가 데이터베이스에 연결하면 Database Service는 레이블을 사용자의 Teleport 역할에 대해 선택적으로 확인하여 권한을 부여합니다.
Database Service는 연결 기간 동안 객체 수준 권한을 부여하고 연결이 종료되면 자동으로 취소합니다.
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, MongoDB 및 Cloud Spanner 데이터베이스에서만 적용됩니다.
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 필드는 사용자가 연결하는 논리적 데이터베이스 이름에 대해 확인됩니다.
PostgreSQL과 유사하게 Teleport는 MongoDB 및 Cloud Spanner 데이터베이스에 대해서도 db_names를 적용합니다.
MySQL에서 논리적 "데이터베이스"와 "스키마"는 서로 동의어이며 연결 후 사용자가 갖는 권한의 범위는
데이터베이스 내 계정에 설정된 권한 부여에 의해 결정됩니다. 따라서 db_names 역할 필드는
현재 MySQL 연결 시도에 적용되지 않습니다.
템플릿 변수#
다른 역할 필드와 유사하게 db_* 필드는 템플릿 변수를 지원합니다.
external.xyz 특성은 외부 싱글 사인온 제공자의 값으로 교체됩니다.
OIDC의 경우 "xyz" 클레임의 값으로 교체됩니다. SAML의 경우 "xyz" 어설션 값으로 교체됩니다.
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는 규칙의 중요도를 결정하며 낮은 숫자는 낮은 우선순위를 나타냅니다.
# 충돌 시, 두 규칙이 동일한 레이블을 적용하는 경우 우선순위가 높은 규칙에서 적용된 레이블이 우선합니다.
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
이 규칙은 모든 객체를 가져오고 템플릿 구문을 사용하여 고유한 속성으로 레이블을 지정합니다.
기본 가져오기 규칙 사용자 정의#
다른 Teleport 리소스와 마찬가지로 기본 db_object_import_rule을 수정할 수 있습니다.
예를 들어, 특정 테이블을 개발자가 읽기 전용 또는 읽기/쓰기 방식으로 접근할 수 있도록 지정하는 다음 규칙을 고려해 보십시오:
kind: db_object_import_rule
metadata:
name: ownership_nonprod
spec:
priority: 100
database_labels:
# `dev` 및 `staging` 환경에 영향을 줍니다.
# 프로덕션 환경에는 다른 규칙이 있을 수 있습니다.
- name: 'env'
values:
- 'staging'
- 'dev'
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는 적어도 하나의 가져오기 규칙이 정의되어 있어야 합니다. 없는 경우 Teleport Auth Service는 시작 시 기본 가져오기 규칙을 만듭니다.
데이터베이스 객체를 가져오지 않으려면 어떤 데이터베이스와도 일치하지 않는 규칙을 만드십시오. 아래 예시에서 매칭 레이블 값의 목록이 비어 있으므로 어떤 데이터베이스도 이 선택기와 일치하지 않습니다.
kind: db_object_import_rule
metadata:
name: import_no_objects
spec:
database_labels:
- {}
mappings:
- {}
version: v1
사용자 정의 규칙을 만들고 기본 규칙을 제거합니다:
$ tctl create -f import_no_objects.yaml
rule "import_no_objects" has been created
$ tctl rm db_object_import_rule/import_all_objects
Rule "import_all_objects" has been deleted
데이터베이스 관리자 사용자#
데이터베이스 관리자 사용자는 최종 사용자에게 권한을 부여하는 역할을 합니다. 데이터베이스 객체 가져오기 규칙을 사용하기 전에 데이터베이스 관리자 사용자를 지정해야 합니다. 데이터베이스 관리자 사용자를 지정하려면 Teleport Database Service를 실행하는 에이전트에 대한 동적 데이터베이스 리소스 또는 구성 파일에 다음을 추가합니다:
kind: db
version: v3
metadata:
# ...
spec:
# ...
admin_user:
name: "teleport-admin"
db_service:
enabled: true
databases:
- name: "example"
# ...
admin_user:
name: "teleport-admin"
이 경우 Teleport Database Service는 객체 가져오기 규칙을 실행하기 위해 teleport-admin이라는 사용자를
활성화할 것으로 예상합니다. 관리자 사용자가 데이터베이스에서 사용자를 관리하는 데 필요한 권한이 있는지 확인하십시오.
그렇지 않으면 데이터베이스 구성 방법에 따라 객체 가져오기 규칙이 실패할 수 있습니다:
$ tsh db connect postgres-db --db-name postgres --db-user teleport-user
psql: 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의 레이블 키/값 쌍은 특정 데이터베이스 객체의 레이블에 해당해야 합니다.
사용자는 동일한 데이터베이스에 대한 여러 동시 연결을 유지할 수 있습니다. 모든 연결에는 동일한 권한이 있어야 합니다. 그렇지 않으면 새 연결이 거부됩니다. 마지막 활성 연결이 종료되면 모든 사용자 권한이 자동으로 취소됩니다.
테이블의 레이블은 적절한 역할과 매칭되어야 합니다. 다음은 HR 레코드에 대한 읽기 전용 접근을 부여하는
ownership_nonprod 규칙에 의해 적용된 dept 레이블을 활용하는 역할 예시입니다.
hr_scratchpad 테이블은 추가로 편집 가능하게 됩니다. 반면에 dept: sales 레이블이 있는
모든 객체는 사용자가 받을 수 있는 모든 권한을 제거하여 사용 불가능하게 됩니다.
와일드카드 권한은 spec의 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 Database Service 로그를 참조하십시오. 이 로그는 데이터베이스에서 가져온 객체 수, 가져온 객체 수(차이는 가져오기 규칙과 일치하지 않는 객체를 포함), 사용자에게 권한이 부여된 객체 수를 나타냅니다:
INFO [DB:SERVIC] Database objects fetched from the database (table:75). db:my-postgres id:b4a33740-1d82-4a8d-b2be-2aa90ae9d2eb total:75 postgres/users.go:212
INFO [DB:SERVIC] Database objects imported (table:75). db:my-postgres err_count:0 id:b4a33740-1d82-4a8d-b2be-2aa90ae9d2eb total:75 postgres/users.go:216
INFO [DB:SERVIC] Calculated database permissions: "INSERT": 75 objects (table:75), "SELECT": 75 objects (table:75), "UPDATE": 75 objects (table:75). db:my-postgres id:b4a33740-1d82-4a8d-b2be-2aa90ae9d2eb user:teleport-user postgres/users.go:223
