Postgres – vsetko, co si chtel vediet, ale bal sa spytat svojho seniora, aby si nevypadal ako jelito 11. Users and roles.
Narozdiel od obecneho zvyku rozdelovat pristupy medzi userov a grupy (roly) a la Oracle, postgres to ma jednoduche: v zasade existuje len rola (ROLE), ktora moze byt zapuzdrovana do inych roli. Prikaz CREATE USER a CREATE GROUP su len aliasom ku komandu CREATE ROLE. Malym rozdielom je, ze v pripade CREATE USER je uzivatel vytvoreny automaticky s privilegiom LOGIN, zatailco u CREATE ROLE nie. Konzekventne prikaz SELECT * FROM PG_USER; ukaze len userov, ktori sa mozu lognut, zatialco SELECT * FROM PG_ROLES; ukaze absolutne vsetkych userov.
Inymi sposobmi na listovanie userov je psql \du+ a SELECT * FROM PG_SHADOW;
Ak chceme vyuzivat princip grup, tak je nutne vytvorit rolu, ktora bude zapuzdrovat userov:
- CREATE ROLE grp_admins INHERIT;
- CREATE ROLE franta;
- GRANT grp_admins TO franta;
Bez inherit by samozrejme zapuzdrovala, ale user by nezdedil opravnenia grupy.
pg_ident a pg_hba
Tieto dva konfiguraky upravuju obecny pristup k celemu DB clusteru. pg_ident.conf mapuje system userov na db userov, napr.:
MAPNAME SYSTEM-USERNAME PG-USERNAME
local_admins root postgres
Znamena, root sa bude mapovat na postgres premennou local_admins
pg_hba.conf ma vlastnu syntax, a roota v predchadzajucom pripade autmaticky namapujeme na postgres nasledovne:
TYPE DATABASE USER ADDRESS METHOD
local all postgres peer map=local_admins
Inak zaznam v hba.confe pre LDAP ma takuto syntax:
host all all “allowed IP” ldap ldapserver=192.168.1.1 ldapbasedn=”cn=users,dc=example,dc=com” ldapbindpasswd=”password” ldapsearchattribute=””
hesla a hashe
Do verzie 10 sa pouzivali pre storovanie DB hesiel 2 metody: plaintext (vyzadovany napr. LDAPom) a md5 (+SSL/TLS). Obe metody su heknutelne odposluchom, alebo dumpom databazy.
Aktualne (ver. 10 – 15) sa pouziva hlavne md5 (Irenko, proc?) a SCRAM-SHA-256 . Hash hesla sa uklada do pg_authid (na aws standarne nedostupna!!!).
Ako funguje hashovanie pomocou md5? Ako salt sa pouziva username (rolname) a na vysledny string sa prida na zaciatok retazec md5, ergo rolpassword=(‘md5’||md5(passwords || rolname)); Ma to jednu zaujimavu konzekvenciu, pretoze ak niekto pouzije heslo rovnake, ako username, da sa na to prist :) :
SELECT *
FROM pg_authid
WHERE rolpassword=(‘md5’||md5(rolname||rolname));
co nas mimochodom privadza k passwordchecku….
passwordcheck
paswordcheck je modul instalovany s balikom postgresql-contrib. Na jeho inicializaciu ho staci zaradit v konfe do shared_preload_libraries. Co robi? V zasade 2 veci (vid source):
male triky
- pokial zabudnes heslo pre rolu postgres a nemas trust medzi rootom a postgresom, tak si vyedituj pg_hba.conf a zmen md5 na trust, po prihlaseni ALTER ROLE postgres…
- Je lepsie pouzivat \password na psql konzole, nez ALTER USER xyz WITH PASSWORD ‘abcd’; V prvom pripade totiz novy password nie je v historii psql konzoly.
privileges a default privileges
Mať role je veľký pekný, ale pokiaľ role nemajú privileges, tak sú k ničomu. V postgrese je tomu tak, že všetko nad objektom (akýmkoľvek) môže superuser (postgres) a owner (ten, kto objekt, napr. tabuľku vytvoril). Všetci ostatní musia mať privileges buď explicitne nagrantované, alebo podedené z default privileges.
\dp = vylistuje privileges
\ddp = vylistuje default privileges
Pri vylistovaní su privileges ukázané akronymom podobným ako ACL a za lomítkom je uvedený grantor. Zoznam privileges a “ACL” akronym k tomu sú v tejto dobrej prehľadnej tabuľke.
Default privileges su oprávnenia, ktoré budú aplikovať v budúcnosti a dajú sa aplikovať per schéma.
efective privileges pre konkrétneho usera
Najčastejšou otázkou je, aké aktuálne privileges má konkrétny user. Je možné sa pýtať dvoma spůsobmi:
a) spýtať sa na konkrétne privilege pre konkrétneho usera nad konkrétnym objektom pomocou funkcií “has privilege”, ktoré vracajú boolovskú hodnotu, napr:
SELECT has_table_privilege('dobo', 'mytable', 'INSERT, SELECT');
b) nechať si vylistovať agregovane userov a privileges za pomocu custom dotazu:
SELECT r.rolname AS user_name,
c.oid::regclass AS table_name,
p.perm AS privilege_type
FROM pg_class c CROSS JOIN
pg_roles r CROSS JOIN
unnest(ARRAY['SELECT','INSERT','UPDATE','DELETE','TRUNCATE','REFERENCES','TRIGGER']) p(perm)
WHERE relkind = 'r' AND
relnamespace NOT IN (SELECT oid FROM pg_namespace WHERE nspname in ('pg_catalog','information_schema')) AND
has_table_privilege(rolname, c.oid, p.perm);