1
0
forked from baron/baron-sso
Files
baron-sso/docs/tenant-maintenance-procedures.md

4.2 KiB

Tenant 유지보수 절차

이 문서는 관리자가 비정기적으로 수행할 수 있는 tenant 데이터 정합성 점검 및 정리 절차를 정리한다.

Orphan 사용자 tenant 소속정보 정리

대상

다음 중 하나에 해당하는 활성 Baron 사용자는 orphan 소속정보 정리 대상이다.

  • users.tenant_id가 존재하지 않거나 soft-deleted 된 tenants.id를 가리킨다.
  • users.company_code가 활성 tenants.slug와 매칭되지 않는다.
  • users.company_codes 배열 중 하나 이상이 활성 tenants.slug와 매칭되지 않는다.

정리 시 다음 필드를 비운다.

  • tenant_id
  • company_code
  • company_codes

사전 확인

SELECT
	u.email,
	u.tenant_id,
	u.company_code,
	u.company_codes
FROM users AS u
WHERE u.deleted_at IS NULL
  AND (
	(
		u.tenant_id IS NOT NULL
		AND NOT EXISTS (
			SELECT 1
			FROM tenants AS t
			WHERE t.id = u.tenant_id
			  AND t.deleted_at IS NULL
		)
	)
	OR (
		NULLIF(BTRIM(u.company_code), '') IS NOT NULL
		AND NOT EXISTS (
			SELECT 1
			FROM tenants AS t
			WHERE LOWER(t.slug) = LOWER(BTRIM(u.company_code))
			  AND t.deleted_at IS NULL
		)
	)
	OR EXISTS (
		SELECT 1
		FROM UNNEST(COALESCE(u.company_codes, ARRAY[]::text[])) AS code(value)
		WHERE NULLIF(BTRIM(code.value), '') IS NOT NULL
		  AND NOT EXISTS (
			SELECT 1
			FROM tenants AS t
			WHERE LOWER(t.slug) = LOWER(BTRIM(code.value))
			  AND t.deleted_at IS NULL
		  )
	)
  );

Kratos identity traits도 같은 기준으로 정리한다.

  • traits.tenant_id
  • traits.companyCode
  • traits.companyCodes

Baron users만 실행

Go 구현 경로를 사용하는 권장 명령은 다음과 같다.

go run ./cmd/adminctl clear-orphan-user-tenant-memberships --dry-run
go run ./cmd/adminctl clear-orphan-user-tenant-memberships

컨테이너나 배포 환경에서는 같은 명령을 adminctl 바이너리로 실행한다.

adminctl clear-orphan-user-tenant-memberships --dry-run
adminctl clear-orphan-user-tenant-memberships

SQL만 직접 실행해야 하는 경우에는 다음 스크립트를 사용할 수 있다.

docker exec -i baron_postgres psql -U baron -d baron_sso < scripts/clear_orphan_user_tenant_memberships.sql

실행 결과에는 정리된 사용자와 기존 소속정보가 출력된다.

Baron users와 Kratos identity traits 함께 실행

로컬 Docker Compose 기준 기본 컨테이너명은 다음과 같다.

  • Baron DB: baron_postgres
  • Kratos DB: ory_postgres
scripts/clear_orphan_tenant_memberships.sh

컨테이너명이나 DB 접속 정보가 다르면 환경변수로 override 한다.

BARON_CONTAINER=baron_postgres \
BARON_DB_USER=baron \
BARON_DB_NAME=baron_sso \
KRATOS_CONTAINER=ory_postgres \
KRATOS_DB_USER=ory \
KRATOS_DB_NAME=ory_kratos \
scripts/clear_orphan_tenant_memberships.sh

사후 확인

사전 확인 쿼리를 다시 실행했을 때 결과가 0건이어야 한다.

Kratos identity traits는 다음 쿼리로 확인한다.

SELECT
	id,
	traits->>'email' AS email,
	traits->>'tenant_id' AS tenant_id,
	traits->>'companyCode' AS company_code,
	traits->'companyCodes' AS company_codes
FROM identities
WHERE COALESCE(traits->>'tenant_id', '') <> ''
   OR COALESCE(traits->>'companyCode', '') <> ''
   OR traits ? 'companyCodes';

Soft-deleted tenant slug 점검

tenants.slug는 DB unique index이므로 soft-deleted row도 slug를 점유한다. 현재 삭제 로직은 삭제 전에 slug에 -deleted-... suffix를 붙여 재사용 가능하게 만들지만, 과거 데이터나 수동 변경으로 삭제된 row가 원래 slug를 계속 점유하면 AdminFront 검색에는 보이지 않으면서 생성은 unique violation으로 실패할 수 있다.

legacy 점유 row 확인

SELECT
	id,
	slug,
	name,
	deleted_at
FROM tenants
WHERE deleted_at IS NOT NULL
  AND slug NOT LIKE '%-deleted-%'
ORDER BY deleted_at DESC;

정책

  • 활성 tenant가 같은 slug를 가지고 있으면 생성 실패가 정상이다.
  • soft-deleted tenant만 같은 slug를 점유하고 있으면 생성 직전에 해당 deleted row의 slug를 release 한다.
  • FindBySlug와 검색 API는 활성 tenant만 반환하므로, 생성 제약도 활성 tenant 기준으로 체감되도록 맞춘다.