Blog JSystems - uwalniamy wiedzę!

Szukaj

PostgreSQL

Jak odebrać uprawnienia i usunąć rolę, która jest właścicielem obiektów

W skrócie

  • Próbujesz usunąć rolę i dostajesz "role cannot be dropped because some objects depend on it" - baza nie pozwala, bo rola jest właścicielem tabel albo ma nadane uprawnienia.
  • W PostgreSQL nie można usunąć roli, dopóki cokolwiek do niej należy lub od niej zależy - trzeba najpierw przekazać własność i odebrać nadania.
  • Przepisujemy własność obiektów na inną rolę, kasujemy pozostałe uprawnienia, a dopiero potem wykonujemy DROP ROLE.

Usunięcie użytkownika brzmi jak jedno polecenie, a kończy się komunikatem błędu: PostgreSQL odmawia skasowania roli, która jest właścicielem obiektów albo ma gdzieś nadane uprawnienia. To zabezpieczenie, nie kaprys - baza nie chce zostawić tabel bez właściciela ani wiszących wpisów uprawnień. Cała sztuka polega na uporządkowaniu zależności we właściwej kolejności: najpierw oddajemy własność, potem odbieramy nadania, i dopiero na końcu usuwamy rolę.

Jak to wygląda w praktyce

Pracownik odchodzi, chcesz posprzątać jego konto i wykonujesz DROP ROLE jan;. Zamiast potwierdzenia dostajesz: ERROR: role "jan" cannot be dropped because some objects depend on it, a poniżej DETAIL: owner of table raporty, owner of sequence raporty_id_seq, privileges for table klienci. Baza wylicza wszystko, co blokuje usunięcie: obiekty, których jan jest właścicielem, oraz uprawnienia, które ma na cudzych tabelach. Próbujesz usunąć samą tabelę, ale to nie Twój obiekt i nie chcesz kasować danych - chcesz je tylko przepisać na kogoś innego. Bywa też trudniej: jan jest właścicielem obiektów w kilku bazach, a komunikat o zależnościach dotyczy każdej z nich osobno.

Dlaczego tak się dzieje

Każdy obiekt w PostgreSQL - tabela, sekwencja, widok, funkcja, schemat - ma właściciela, którym jest jakaś rola. Gdyby baza pozwoliła usunąć rolę będącą właścicielem, obiekty zostałyby osierocone, bez podmiotu odpowiedzialnego za uprawnienia. Dlatego silnik blokuje DROP ROLE, dopóki istnieje choć jedna taka zależność. Do tego dochodzą uprawnienia nadane roli na obiektach należących do innych (na przykład GRANT SELECT na cudzej tabeli) - te wpisy również trzymają rolę przy życiu. Ważny szczegół: zależności są lokalne dla bazy danych. Rola jest bytem globalnym w klastrze, ale jej własność i uprawnienia dotyczą konkretnych obiektów w konkretnych bazach, więc porządki trzeba zrobić w każdej bazie, w której rola coś posiada lub gdzie ma nadania. PostgreSQL daje na to wygodne polecenia zbiorcze, dzięki którym nie trzeba przechodzić obiekt po obiekcie.

Jak to rozwiązać krok po kroku

  1. Najpierw zorientuj się w skali. Komunikat błędu z DROP ROLE wylicza część zależności, ale pełen obraz da wyszukanie obiektów, których rola jest właścicielem - w psql pomocne bywa filtrowanie po właścicielu, na przykład \dt pokazuje kolumnę Owner.
  2. Połącz się z pierwszą bazą, w której rola coś posiada, i przepisz własność wszystkich jej obiektów na inną rolę jednym poleceniem: REASSIGN OWNED BY jan TO archiwum;. To przeniesie tabele, sekwencje, widoki i pozostałe obiekty na rolę archiwum, nie ruszając danych.
  3. Usuń pozostałe zależności roli w tej bazie - czyli uprawnienia nadane jej na cudzych obiektach oraz ewentualne obiekty, których nie chcesz przepisywać: DROP OWNED BY jan;. Po REASSIGN OWNED zostają głównie wpisy uprawnień, które to polecenie sprząta.
  4. Powtórz oba polecenia w każdej innej bazie, w której jan był właścicielem lub miał nadania - zależności są per-baza, więc jedna baza nie załatwia pozostałych.
  5. Odbierz członkostwo w rolach grupowych, jeśli było nadane: REVOKE grupa_raportujacych FROM jan;. To domyka powiązania na poziomie ról.
  6. Dopiero teraz usuń rolę: DROP ROLE jan;. Bez pozostałych zależności polecenie przejdzie bez błędu.

Jak sprawdzić, że zadziałało

Najprostszy dowód to samo udane DROP ROLE jan; - jeśli przechodzi, żadna zależność już nie została. Zanim je wykonasz, warto potwierdzić, że przepisanie własności zadziałało: SELECT tablename, tableowner FROM pg_tables WHERE tableowner = 'jan'; powinno zwrócić pusty wynik, a te same tabele mają teraz właściciela archiwum. Że rola faktycznie zniknęła z całego klastra, sprawdzisz przez SELECT rolname FROM pg_roles WHERE rolname = 'jan'; - brak wiersza oznacza sukces (rola jest obiektem globalnym, więc wystarczy sprawdzić raz). Jeśli DROP ROLE nadal zgłasza zależności, przeczytaj sekcję DETAIL komunikatu: wskaże bazę i obiekt, który pominąłeś - najczęściej to inna baza, w której nie powtórzyłeś REASSIGN OWNED i DROP OWNED.

Wróć do listy: 100 najczęstszych pytań i problemów z PostgreSQL

Szkolenie Administracja, replikacja i tuning baz danych PostgreSQL

Sprawdź szkolenie: Administracja, replikacja i tuning baz danych PostgreSQL

To szkolenie może być dofinansowane z KFS lub BUR.

★★★★★Średnia ocena naszych szkoleń w Google: 5/5

Szkolenie Zaawansowana administracja PostgreSQL - HA, DR, monitoring, skalowanie

Sprawdź szkolenie: Zaawansowana administracja PostgreSQL (HA, DR, monitoring, skalowanie)

To szkolenie może być dofinansowane z KFS lub BUR.

★★★★★Średnia ocena naszych szkoleń w Google: 5/5

Najczęściej zadawane pytania

Dlaczego nie mogę usunąć roli w PostgreSQL?
Bo rola jest właścicielem jakichś obiektów albo ma nadane uprawnienia na cudzych obiektach. PostgreSQL blokuje DROP ROLE, żeby nie zostawić tabel bez właściciela ani wiszących wpisów uprawnień. Sekcja DETAIL komunikatu błędu wylicza konkretne zależności.
Jak przekazać własność wszystkich obiektów roli innej roli?
Jednym poleceniem REASSIGN OWNED BY stara_rola TO nowa_rola; wykonanym w danej bazie. Przeniesie ono tabele, sekwencje, widoki i pozostałe obiekty bez ruszania danych. Pozostałe wpisy uprawnień sprząta następnie DROP OWNED BY stara_rola;.
Czy REASSIGN OWNED wystarczy wykonać raz dla całego klastra?
Nie. Rola jest bytem globalnym, ale jej własność i uprawnienia są lokalne dla każdej bazy. REASSIGN OWNED i DROP OWNED trzeba powtórzyć w każdej bazie, w której rola coś posiadała lub miała nadania - inaczej DROP ROLE dalej zgłosi zależności z pominiętej bazy.
Jak potwierdzić, że rola została faktycznie usunięta?
Wykonaj SELECT rolname FROM pg_roles WHERE rolname = 'jan'; - brak wiersza oznacza, że rola zniknęła z całego klastra. Wcześniej warto sprawdzić SELECT tablename, tableowner FROM pg_tables WHERE tableowner = 'jan';, co powinno zwrócić pusty wynik po przepisaniu własności.

Komentarze (0)

Musisz być zalogowany by móc dodać komentarz. Zaloguj się przez Google

Brak komentarzy...