postgres: Wie kann ich die Indexerstellung zulassen, aber keine Tabellenmutationen oder Tabellenabbrüche durch denselben Benutzer?

8

Ich richte einen Postgres-Server mit einer (meistens) schreibgeschützten Arbeitslast ein.

Ich möchte mir und meinen Kollegen erlauben, Indizes nach eigenem Ermessen zu erstellen / zu löschen, ohne dass wir Tabellen löschen oder die Tabellen mutieren dürfen.

Ich habe Zeit damit verbracht, die Grant / Revoke-Dokumentation sowie die Rollendokumentationsseiten zu lesen, aber es scheint, dass die Rollen der Tabellenbesitzer beide Befugnisse erhalten.

Eine Sache, die ich fand, war, dass Grant Grant Create on Tablespace angeblich die Indexerstellung ermöglicht, aber es hat nicht funktioniert (Hinweis, ich habe keine anderen Tablespaces erstellt).

um genau zu sein, habe ich versucht:

mydb=# grant create on tablespace pg_default to bob;
GRANT

... dann auf Bob umgestellt:

mydb=> create index on foo(a);
ERROR:  must be owner of relation foo

Ich habe auch versucht, Bob zu einem Besitzer zu machen, aber dann hat Bob das Recht, Tabellen zu löschen, und es gibt anscheinend keine Möglichkeit, dieses Privileg zu widerrufen. Also bin ich mit beidem oder keinem festgefahren.

Irgendwelche Ideen?

orm
quelle

Antworten:

7

Auf SQL-Ebene ist dies nicht möglich, da alle diese Aufgaben vom Tabellenbesitz abhängen.

Der CREATEWert für einen Tabellenbereich ist erforderlich , reicht jedoch nicht aus , um einen Index für eine Tabelle zu erstellen und den Index in diesem Tabellenbereich zu speichern. Wenn Sie nicht über das CREATERecht für den Tabellenbereich verfügen, in den Sie den Index einfügen möchten, können Sie CREATE INDEXdiesen Index nicht verwenden. Dieses Recht zu haben, reicht jedoch nicht aus. Andernfalls könnte jeder Index für jede Tabelle erstellen, wenn er das Recht hätte, irgendetwas in einem beliebigen Tabellenbereich zu erstellen, und das wollen wir nicht. Indizes haben Leistungskosten, nehmen während der Erstellung schwere Sperren in Anspruch, und vielleicht am wichtigsten ist, dass ein Ausdrucksindex über eine böswillige Funktion oder einen böswilligen Operator Daten über die Tabelle verlieren kann. Sie müssen also auch die Tabelle besitzen, für die der Index erstellt werden soll.

Die Unterstützung für ein separates INDEXRecht für eine Tabelle könnte zu PostgreSQL hinzugefügt werden, wurde jedoch nicht unterstützt und wird möglicherweise nicht akzeptiert, wenn sie eingereicht wird. Im Moment müssen Sie den Tisch nicht mehr besitzen.

Sie können eine C-Erweiterung schreiben, die eine installiert ProcessUtility_hook, die überprüft, welche Vorgänge ausgeführt werden, und die aktuelle Benutzeridentität, und diese dann ablehnt oder gegebenenfalls zulässt. Beispiele für die ProcessUtility_hookVerwendung in contrib/sepgsqlund extern in der bdr_commandfilter.cDatei finden Sie im Quellcode des BDR-Projekts. Sie müssen die Erweiterung kompilieren, im Dateisystem installieren und dann hinzufügen, um sie zu shared_preload_librariesinstallieren. Daher benötigen Sie vollständigen Zugriff auf den Server auf Dateisystemebene und normalerweise Root-Zugriff.

Ein praktischerer Ansatz besteht darin, eine SECURITY DEFINERFunktion als Wrapper zu verwenden. Schreiben Sie eine PL / PgSQL-Funktion, die als Tabelleneigentümer ausgeführt wird und die zu indizierende Tabelle, die zu indizierenden Spalten usw. als Argumente akzeptiert. Lassen Sie den CREATE INDEXAusdruck erstellen format(...)und übergeben Sie ihn dann an EXECUTE. Haben nicht erlauben dem Benutzer , beliebige SQL - Ausdrücke als Argumente zu übergeben, oder du bist im Grunde ihnen vollen Zugriff über SQL - Injection zu geben. Willst du mehrere Spalten? Sie müssen colname text[]als Argument und quote_identjedes akzeptieren . Und so weiter. Suchen Sie nach "dynamic SQL plpgsql", um mehr über diesen Ansatz zu erfahren.

Craig Ringer
quelle
2
Lassen Sie mich hinzufügen, dass bei großen / ausgelasteten Tabellen das Erstellen von Indizes CONCURRENTLYhäufig der richtige Weg ist, um ein Blockieren zu vermeiden. Dies ist aus einer Funktion leider nicht möglich.
Dekso
3

Obwohl plpgsql- Ereignisauslöser in aktuellen Versionen ziemlich begrenzt sind, können Sie das besondere Ergebnis erzielen, wenn Sie nur DROP TABLEmit ihnen nicht zulassen .

Bedenken Sie:

CREATE OR REPLACE FUNCTION no_drop() RETURNS event_trigger AS $$
BEGIN
    IF (tg_tag = 'DROP TABLE') THEN
      RAISE exception 'DROP TABLE is not allowed';
    END IF;
END;
$$ LANGUAGE plpgsql;

CREATE EVENT TRIGGER nodrop_trigger ON sql_drop
   EXECUTE PROCEDURE no_drop();

Als Benutzer postgres (Superuser):

test = # create table foo (bar int);
TABELLE ERSTELLEN
test = # drop table foo;
FEHLER: DROP TABLE ist nicht erlaubt

Auf der anderen Seite CREATE INDEXfunktioniert:

test = # index idx auf foo erstellen (bar);
INDEX ERSTELLEN
Daniel Vérité
quelle