mirror of https://github.com/citusdata/citus.git
Propagate SECURITY LABEL on tables and columns. (#7956)
Issue #7709 asks for security labels on columns to be propagated, to support the `anon` extension. Before, Citus supported security labels on roles (#7735) and this PR adds support for propagating security labels on tables and columns. All scenarios that involve propagating metadata for a Citus table now include the security labels on the table and on the columns of the table. These scenarios are: - When a table becomes distributed using `create_distributed_table()` or `create_reference_table()`, its security labels (if any) are propageted. - When a security label is defined on a distributed table, or one of its columns, the label is propagated. - When a node is added to a Citus cluster, all distributed tables have their security labels propagated. - When a column of a distributed table is dropped, any security labels on the column are also dropped. - When a column is added to a distributed table, security labels can be defined on the column and are propagated. - Security labels on a distributed table or its columns are not propagated when `citus.enable_metadata_sync` is enabled. Regress test `seclabel` is extended with tests to cover these scenarios. The implementation is somewhat involved because it impacts DDL propagation of Citus tables, but can be broken down as follows: - distributed_object_ops has `Role_SecLabel`, `Table_SecLabel` and `Column_SecLabel` to take care of security labels on roles, tables and columns. `Any_SecLabel` is used for all other security labels and is essentially a nop. - Deparser support - `DeparseRoleSecLabelStmt()`, `DeparseTableSecLabelStmt()` and `DeparseColumnSecLabelStmt()` take care of deparsing security label statements on roles, tables and columns respectively. - When reconstructing the DDL for a citus table, security labels on the table or its columns are included by having `GetPreLoadTableCreationCommands()` call a new function `CreateSecurityLabelCommands()` to take care of any security labels on the table or its columns. - When changing a distributed table name to a shard name before running a command locally on a worker, function `RelayEventExtendNames()` checks for security labels on a table or its columns.pull/7976/head
parent
ea7aa6712d
commit
d4dd44e715
|
@ -399,10 +399,37 @@ static DistributeObjectOps Any_Rename = {
|
|||
.markDistributed = false,
|
||||
};
|
||||
static DistributeObjectOps Any_SecLabel = {
|
||||
.deparse = DeparseSecLabelStmt,
|
||||
.deparse = NULL,
|
||||
.qualify = NULL,
|
||||
.preprocess = NULL,
|
||||
.postprocess = PostprocessSecLabelStmt,
|
||||
.postprocess = PostprocessAnySecLabelStmt,
|
||||
.operationType = DIST_OPS_ALTER,
|
||||
.address = SecLabelStmtObjectAddress,
|
||||
.markDistributed = false,
|
||||
};
|
||||
static DistributeObjectOps Role_SecLabel = {
|
||||
.deparse = DeparseRoleSecLabelStmt,
|
||||
.qualify = NULL,
|
||||
.preprocess = NULL,
|
||||
.postprocess = PostprocessRoleSecLabelStmt,
|
||||
.operationType = DIST_OPS_ALTER,
|
||||
.address = SecLabelStmtObjectAddress,
|
||||
.markDistributed = false,
|
||||
};
|
||||
static DistributeObjectOps Table_SecLabel = {
|
||||
.deparse = DeparseTableSecLabelStmt,
|
||||
.qualify = NULL,
|
||||
.preprocess = NULL,
|
||||
.postprocess = PostprocessTableOrColumnSecLabelStmt,
|
||||
.operationType = DIST_OPS_ALTER,
|
||||
.address = SecLabelStmtObjectAddress,
|
||||
.markDistributed = false,
|
||||
};
|
||||
static DistributeObjectOps Column_SecLabel = {
|
||||
.deparse = DeparseColumnSecLabelStmt,
|
||||
.qualify = NULL,
|
||||
.preprocess = NULL,
|
||||
.postprocess = PostprocessTableOrColumnSecLabelStmt,
|
||||
.operationType = DIST_OPS_ALTER,
|
||||
.address = SecLabelStmtObjectAddress,
|
||||
.markDistributed = false,
|
||||
|
@ -2119,7 +2146,27 @@ GetDistributeObjectOps(Node *node)
|
|||
|
||||
case T_SecLabelStmt:
|
||||
{
|
||||
return &Any_SecLabel;
|
||||
SecLabelStmt *stmt = castNode(SecLabelStmt, node);
|
||||
switch (stmt->objtype)
|
||||
{
|
||||
case OBJECT_ROLE:
|
||||
{
|
||||
return &Role_SecLabel;
|
||||
}
|
||||
|
||||
case OBJECT_TABLE:
|
||||
{
|
||||
return &Table_SecLabel;
|
||||
}
|
||||
|
||||
case OBJECT_COLUMN:
|
||||
{
|
||||
return &Column_SecLabel;
|
||||
}
|
||||
|
||||
default:
|
||||
return &Any_SecLabel;
|
||||
}
|
||||
}
|
||||
|
||||
case T_RenameStmt:
|
||||
|
|
|
@ -15,19 +15,18 @@
|
|||
#include "distributed/commands/utility_hook.h"
|
||||
#include "distributed/coordinator_protocol.h"
|
||||
#include "distributed/deparser.h"
|
||||
#include "distributed/listutils.h"
|
||||
#include "distributed/log_utils.h"
|
||||
#include "distributed/metadata/distobject.h"
|
||||
#include "distributed/metadata_sync.h"
|
||||
|
||||
|
||||
/*
|
||||
* PostprocessSecLabelStmt prepares the commands that need to be run on all workers to assign
|
||||
* security labels on distributed objects, currently supporting just Role objects.
|
||||
* It also ensures that all object dependencies exist on all
|
||||
* nodes for the object in the SecLabelStmt.
|
||||
* PostprocessRoleSecLabelStmt prepares the commands that need to be run on all workers to assign
|
||||
* security labels on distributed roles. It also ensures that all object dependencies exist on all
|
||||
* nodes for the role in the SecLabelStmt.
|
||||
*/
|
||||
List *
|
||||
PostprocessSecLabelStmt(Node *node, const char *queryString)
|
||||
PostprocessRoleSecLabelStmt(Node *node, const char *queryString)
|
||||
{
|
||||
if (!EnableAlterRolePropagation || !ShouldPropagate())
|
||||
{
|
||||
|
@ -42,34 +41,91 @@ PostprocessSecLabelStmt(Node *node, const char *queryString)
|
|||
return NIL;
|
||||
}
|
||||
|
||||
if (secLabelStmt->objtype != OBJECT_ROLE)
|
||||
EnsurePropagationToCoordinator();
|
||||
EnsureAllObjectDependenciesExistOnAllNodes(objectAddresses);
|
||||
|
||||
const char *secLabelCommands = DeparseTreeNode((Node *) secLabelStmt);
|
||||
List *commandList = list_make3(DISABLE_DDL_PROPAGATION,
|
||||
(void *) secLabelCommands,
|
||||
ENABLE_DDL_PROPAGATION);
|
||||
return NodeDDLTaskList(REMOTE_NODES, commandList);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* PostprocessTableOrColumnSecLabelStmt prepares the commands that need to be run on all
|
||||
* workers to assign security labels on distributed tables or the columns of a distributed
|
||||
* table. It also ensures that all object dependencies exist on all nodes for the table in
|
||||
* the SecLabelStmt.
|
||||
*/
|
||||
List *
|
||||
PostprocessTableOrColumnSecLabelStmt(Node *node, const char *queryString)
|
||||
{
|
||||
if (!EnableAlterRolePropagation || !ShouldPropagate())
|
||||
{
|
||||
/*
|
||||
* If we are not in the coordinator, we don't want to interrupt the security
|
||||
* label command with notices, the user expects that from the worker node
|
||||
* the command will not be propagated
|
||||
*/
|
||||
if (EnableUnsupportedFeatureMessages && IsCoordinator())
|
||||
{
|
||||
ereport(NOTICE, (errmsg("not propagating SECURITY LABEL commands whose "
|
||||
"object type is not role"),
|
||||
errhint("Connect to worker nodes directly to manually "
|
||||
"run the same SECURITY LABEL command.")));
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
|
||||
SecLabelStmt *secLabelStmt = castNode(SecLabelStmt, node);
|
||||
|
||||
List *objectAddresses = GetObjectAddressListFromParseTree(node, false, true);
|
||||
if (!IsAnyParentObjectDistributed(objectAddresses))
|
||||
{
|
||||
return NIL;
|
||||
}
|
||||
|
||||
EnsurePropagationToCoordinator();
|
||||
EnsureAllObjectDependenciesExistOnAllNodes(objectAddresses);
|
||||
|
||||
const char *secLabelCommands = DeparseTreeNode((Node *) secLabelStmt);
|
||||
|
||||
List *commandList = list_make3(DISABLE_DDL_PROPAGATION,
|
||||
(void *) secLabelCommands,
|
||||
ENABLE_DDL_PROPAGATION);
|
||||
List *DDLJobs = NodeDDLTaskList(REMOTE_NODES, commandList);
|
||||
ListCell *lc = NULL;
|
||||
|
||||
return NodeDDLTaskList(REMOTE_NODES, commandList);
|
||||
/*
|
||||
* The label is for a table or a column, so we need to set the targetObjectAddress
|
||||
* of the DDLJob to the relationId of the table. This is needed to ensure that
|
||||
* the search path is correctly set for the remote security label command; it
|
||||
* needs to be able to resolve the table that the label is being defined on.
|
||||
*/
|
||||
Assert(list_length(objectAddresses) == 1);
|
||||
ObjectAddress *target = linitial(objectAddresses);
|
||||
Oid relationId = target->objectId;
|
||||
Assert(relationId != InvalidOid);
|
||||
|
||||
foreach(lc, DDLJobs)
|
||||
{
|
||||
DDLJob *ddlJob = (DDLJob *) lfirst(lc);
|
||||
ObjectAddressSet(ddlJob->targetObjectAddress, RelationRelationId, relationId);
|
||||
}
|
||||
|
||||
return DDLJobs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* PostprocessAnySecLabelStmt is used for any other object types
|
||||
* that are not supported by Citus. It issues a notice to the client
|
||||
* if appropriate. Is effectively a nop.
|
||||
*/
|
||||
List *
|
||||
PostprocessAnySecLabelStmt(Node *node, const char *queryString)
|
||||
{
|
||||
/*
|
||||
* If we are not in the coordinator, we don't want to interrupt the security
|
||||
* label command with notices, the user expects that from the worker node
|
||||
* the command will not be propagated
|
||||
*/
|
||||
if (EnableUnsupportedFeatureMessages && IsCoordinator())
|
||||
{
|
||||
ereport(NOTICE, (errmsg("not propagating SECURITY LABEL commands whose "
|
||||
"object type is not role or table or column"),
|
||||
errhint("Connect to worker nodes directly to manually "
|
||||
"run the same SECURITY LABEL command.")));
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -10,37 +10,16 @@
|
|||
|
||||
#include "postgres.h"
|
||||
|
||||
#include "catalog/namespace.h"
|
||||
#include "nodes/parsenodes.h"
|
||||
#include "utils/builtins.h"
|
||||
|
||||
#include "distributed/deparser.h"
|
||||
|
||||
static void AppendSecLabelStmt(StringInfo buf, SecLabelStmt *stmt);
|
||||
|
||||
/*
|
||||
* DeparseSecLabelStmt builds and returns a string representing of the
|
||||
* SecLabelStmt for application on a remote server.
|
||||
*/
|
||||
char *
|
||||
DeparseSecLabelStmt(Node *node)
|
||||
{
|
||||
SecLabelStmt *secLabelStmt = castNode(SecLabelStmt, node);
|
||||
StringInfoData buf = { 0 };
|
||||
initStringInfo(&buf);
|
||||
|
||||
AppendSecLabelStmt(&buf, secLabelStmt);
|
||||
|
||||
return buf.data;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* AppendSecLabelStmt generates the string representation of the
|
||||
* SecLabelStmt and appends it to the buffer.
|
||||
*/
|
||||
static void
|
||||
AppendSecLabelStmt(StringInfo buf, SecLabelStmt *stmt)
|
||||
BeginSecLabel(StringInfo buf, SecLabelStmt *stmt)
|
||||
{
|
||||
initStringInfo(buf);
|
||||
appendStringInfoString(buf, "SECURITY LABEL ");
|
||||
|
||||
if (stmt->provider != NULL)
|
||||
|
@ -49,31 +28,84 @@ AppendSecLabelStmt(StringInfo buf, SecLabelStmt *stmt)
|
|||
}
|
||||
|
||||
appendStringInfoString(buf, "ON ");
|
||||
|
||||
switch (stmt->objtype)
|
||||
{
|
||||
case OBJECT_ROLE:
|
||||
{
|
||||
appendStringInfo(buf, "ROLE %s ", quote_identifier(strVal(stmt->object)));
|
||||
break;
|
||||
}
|
||||
|
||||
/* normally, we shouldn't reach this */
|
||||
default:
|
||||
{
|
||||
ereport(ERROR, (errmsg("unsupported security label statement for"
|
||||
" deparsing")));
|
||||
}
|
||||
}
|
||||
|
||||
appendStringInfoString(buf, "IS ");
|
||||
|
||||
if (stmt->label != NULL)
|
||||
{
|
||||
appendStringInfo(buf, "%s", quote_literal_cstr(stmt->label));
|
||||
}
|
||||
else
|
||||
{
|
||||
appendStringInfoString(buf, "NULL");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
EndSecLabel(StringInfo buf, SecLabelStmt *stmt)
|
||||
{
|
||||
appendStringInfo(buf, "IS %s", (stmt->label != NULL) ?
|
||||
quote_literal_cstr(stmt->label) : "NULL");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* DeparseRoleSecLabelStmt builds and returns a string representation of the
|
||||
* SecLabelStmt for application on a remote server. The SecLabelStmt is for
|
||||
* a role object.
|
||||
*/
|
||||
char *
|
||||
DeparseRoleSecLabelStmt(Node *node)
|
||||
{
|
||||
SecLabelStmt *secLabelStmt = castNode(SecLabelStmt, node);
|
||||
char *role_name = strVal(secLabelStmt->object);
|
||||
StringInfoData buf = { 0 };
|
||||
|
||||
BeginSecLabel(&buf, secLabelStmt);
|
||||
appendStringInfo(&buf, "ROLE %s ", quote_identifier(role_name));
|
||||
EndSecLabel(&buf, secLabelStmt);
|
||||
|
||||
return buf.data;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* DeparseTableSecLabelStmt builds and returns a string representation of the
|
||||
* SecLabelStmt for application on a remote server. The SecLabelStmt is for a
|
||||
* table.
|
||||
*/
|
||||
char *
|
||||
DeparseTableSecLabelStmt(Node *node)
|
||||
{
|
||||
SecLabelStmt *secLabelStmt = castNode(SecLabelStmt, node);
|
||||
List *names = (List *) secLabelStmt->object;
|
||||
StringInfoData buf = { 0 };
|
||||
|
||||
BeginSecLabel(&buf, secLabelStmt);
|
||||
appendStringInfo(&buf, "TABLE %s", quote_identifier(strVal(linitial(names))));
|
||||
if (list_length(names) > 1)
|
||||
{
|
||||
appendStringInfo(&buf, ".%s", quote_identifier(strVal(lsecond(names))));
|
||||
}
|
||||
appendStringInfoString(&buf, " ");
|
||||
EndSecLabel(&buf, secLabelStmt);
|
||||
|
||||
return buf.data;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* DeparseColumnSecLabelStmt builds and returns a string representation of the
|
||||
* SecLabelStmt for application on a remote server. The SecLabelStmt is for a
|
||||
* column of a distributed table.
|
||||
*/
|
||||
char *
|
||||
DeparseColumnSecLabelStmt(Node *node)
|
||||
{
|
||||
SecLabelStmt *secLabelStmt = castNode(SecLabelStmt, node);
|
||||
List *names = (List *) secLabelStmt->object;
|
||||
StringInfoData buf = { 0 };
|
||||
|
||||
BeginSecLabel(&buf, secLabelStmt);
|
||||
appendStringInfo(&buf, "COLUMN %s.%s",
|
||||
quote_identifier(strVal(linitial(names))),
|
||||
quote_identifier(strVal(lsecond(names))));
|
||||
if (list_length(names) > 2)
|
||||
{
|
||||
appendStringInfo(&buf, ".%s", quote_identifier(strVal(lthird(names))));
|
||||
}
|
||||
appendStringInfoString(&buf, " ");
|
||||
EndSecLabel(&buf, secLabelStmt);
|
||||
|
||||
return buf.data;
|
||||
}
|
||||
|
|
|
@ -566,6 +566,38 @@ IsAnyObjectDistributed(const List *addresses)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* IsAnyParentObjectDistributed - true if at least one of the
|
||||
* given addresses is distributed. If an address has a non-zero
|
||||
* objectSubId, it checks the parent object (the object with
|
||||
* the same classId and objid, but with objectSubId = 0). For
|
||||
* example, a column address will check the table address.
|
||||
* If the address has a zero objectSubId, it checks the address
|
||||
* itself.
|
||||
*/
|
||||
bool
|
||||
IsAnyParentObjectDistributed(const List *addresses)
|
||||
{
|
||||
bool isDistributed = false;
|
||||
ListCell *lc = NULL;
|
||||
foreach(lc, addresses)
|
||||
{
|
||||
ObjectAddress *address = (ObjectAddress *) lfirst(lc);
|
||||
int32 savedObjectSubId = address->objectSubId;
|
||||
address->objectSubId = 0;
|
||||
isDistributed = IsObjectDistributed(address);
|
||||
address->objectSubId = savedObjectSubId;
|
||||
|
||||
if (isDistributed)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return isDistributed;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* GetDistributedObjectAddressList returns a list of ObjectAddresses that contains all
|
||||
* distributed objects as marked in pg_dist_object
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "catalog/pg_constraint.h"
|
||||
#include "catalog/pg_index.h"
|
||||
#include "catalog/pg_namespace.h"
|
||||
#include "catalog/pg_seclabel.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "commands/sequence.h"
|
||||
#include "foreign/foreign.h"
|
||||
|
@ -57,6 +58,7 @@
|
|||
#include "distributed/citus_ruleutils.h"
|
||||
#include "distributed/commands.h"
|
||||
#include "distributed/coordinator_protocol.h"
|
||||
#include "distributed/deparser.h"
|
||||
#include "distributed/listutils.h"
|
||||
#include "distributed/metadata_cache.h"
|
||||
#include "distributed/metadata_sync.h"
|
||||
|
@ -83,6 +85,7 @@ static char * CitusCreateAlterColumnarTableSet(char *qualifiedRelationName,
|
|||
const ColumnarOptions *options);
|
||||
static char * GetTableDDLCommandColumnar(void *context);
|
||||
static TableDDLCommand * ColumnarGetTableOptionsDDL(Oid relationId);
|
||||
static List * CreateSecurityLabelCommands(Oid relationId);
|
||||
|
||||
/* exports for SQL callable functions */
|
||||
PG_FUNCTION_INFO_V1(master_get_table_metadata);
|
||||
|
@ -665,6 +668,9 @@ GetPreLoadTableCreationCommands(Oid relationId,
|
|||
List *policyCommands = CreatePolicyCommands(relationId);
|
||||
tableDDLEventList = list_concat(tableDDLEventList, policyCommands);
|
||||
|
||||
List *securityLabelCommands = CreateSecurityLabelCommands(relationId);
|
||||
tableDDLEventList = list_concat(tableDDLEventList, securityLabelCommands);
|
||||
|
||||
/* revert back to original search_path */
|
||||
PopEmptySearchPath(saveNestLevel);
|
||||
|
||||
|
@ -833,6 +839,109 @@ GetTableRowLevelSecurityCommands(Oid relationId)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* CreateSecurityLabelCommands - return the SECURITY LABEL commands on
|
||||
* the table identified by relationId. It is used by GetPreLoadTableCreationCommands()
|
||||
* to reconstruct the security labels on the table and its columns.
|
||||
*/
|
||||
static List *
|
||||
CreateSecurityLabelCommands(Oid relationId)
|
||||
{
|
||||
List *securityLabelCommands = NIL;
|
||||
|
||||
if (!RegularTable(relationId)) /* should be an Assert ? */
|
||||
{
|
||||
return securityLabelCommands;
|
||||
}
|
||||
|
||||
Relation pg_seclabel = table_open(SecLabelRelationId, AccessShareLock);
|
||||
ScanKeyData skey[1];
|
||||
ScanKeyInit(&skey[0], Anum_pg_seclabel_objoid, BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(relationId));
|
||||
SysScanDesc scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId,
|
||||
true, NULL, 1, &skey[0]);
|
||||
HeapTuple tuple = NULL;
|
||||
List *table_name = NIL;
|
||||
Relation relation = NULL;
|
||||
TupleDesc tupleDescriptor = NULL;
|
||||
List *securityLabelStmts = NULL;
|
||||
ListCell *lc;
|
||||
|
||||
while (HeapTupleIsValid(tuple = systable_getnext(scan)))
|
||||
{
|
||||
SecLabelStmt *secLabelStmt = makeNode(SecLabelStmt);
|
||||
|
||||
if (relation == NULL)
|
||||
{
|
||||
relation = relation_open(relationId, AccessShareLock);
|
||||
if (!RelationIsVisible(relationId))
|
||||
{
|
||||
char *nsname = get_namespace_name(RelationGetNamespace(relation));
|
||||
table_name = lappend(table_name, makeString(nsname));
|
||||
}
|
||||
char *relname = get_rel_name(relationId);
|
||||
table_name = lappend(table_name, makeString(relname));
|
||||
}
|
||||
|
||||
Datum datumArray[Natts_pg_seclabel];
|
||||
bool isNullArray[Natts_pg_seclabel];
|
||||
|
||||
heap_deform_tuple(tuple, RelationGetDescr(pg_seclabel), datumArray,
|
||||
isNullArray);
|
||||
int subObjectId = DatumGetInt32(
|
||||
datumArray[Anum_pg_seclabel_objsubid - 1]);
|
||||
secLabelStmt->provider = TextDatumGetCString(
|
||||
datumArray[Anum_pg_seclabel_provider - 1]);
|
||||
secLabelStmt->label = TextDatumGetCString(
|
||||
datumArray[Anum_pg_seclabel_label - 1]);
|
||||
|
||||
if (subObjectId > 0)
|
||||
{
|
||||
/* Its a column; construct the name */
|
||||
secLabelStmt->objtype = OBJECT_COLUMN;
|
||||
List *col_name = list_copy(table_name);
|
||||
|
||||
if (tupleDescriptor == NULL)
|
||||
{
|
||||
tupleDescriptor = RelationGetDescr(relation);
|
||||
}
|
||||
|
||||
Form_pg_attribute attrForm = TupleDescAttr(tupleDescriptor, subObjectId - 1);
|
||||
char *attributeName = NameStr(attrForm->attname);
|
||||
col_name = lappend(col_name, makeString(attributeName));
|
||||
|
||||
secLabelStmt->object = (Node *) col_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert(subObjectId == 0);
|
||||
secLabelStmt->objtype = OBJECT_TABLE;
|
||||
secLabelStmt->object = (Node *) table_name;
|
||||
}
|
||||
|
||||
securityLabelStmts = lappend(securityLabelStmts, secLabelStmt);
|
||||
}
|
||||
|
||||
foreach(lc, securityLabelStmts)
|
||||
{
|
||||
Node *stmt = (Node *) lfirst(lc);
|
||||
char *secLabelStmtString = DeparseTreeNode(stmt);
|
||||
TableDDLCommand *secLabelCommand = makeTableDDLCommandString(secLabelStmtString);
|
||||
securityLabelCommands = lappend(securityLabelCommands, secLabelCommand);
|
||||
}
|
||||
|
||||
systable_endscan(scan);
|
||||
table_close(pg_seclabel, AccessShareLock);
|
||||
|
||||
if (relation != NULL)
|
||||
{
|
||||
relation_close(relation, AccessShareLock);
|
||||
}
|
||||
|
||||
return securityLabelCommands;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* IndexImpliedByAConstraint is a helper function to be used while scanning
|
||||
* pg_index. It returns true if the index identified by the given indexForm is
|
||||
|
|
|
@ -591,6 +591,58 @@ RelayEventExtendNames(Node *parseTree, char *schemaName, uint64 shardId)
|
|||
break;
|
||||
}
|
||||
|
||||
case T_SecLabelStmt:
|
||||
{
|
||||
SecLabelStmt *secLabelStmt = (SecLabelStmt *) parseTree;
|
||||
|
||||
/* Should be looking at a security label for a table or column */
|
||||
if (secLabelStmt->objtype == OBJECT_TABLE || secLabelStmt->objtype ==
|
||||
OBJECT_COLUMN)
|
||||
{
|
||||
List *qualified_name = (List *) secLabelStmt->object;
|
||||
String *table_name = NULL;
|
||||
|
||||
switch (list_length(qualified_name))
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
table_name = castNode(String, linitial(qualified_name));
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
{
|
||||
table_name = castNode(String, lsecond(qualified_name));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
/* Unlikely, but just in case */
|
||||
ereport(ERROR, (errmsg(
|
||||
"unhandled name type in security label; name is: \"%s\"",
|
||||
NameListToString(qualified_name))));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now change the table name: <dist table> -> <shard table> */
|
||||
char *relationName = strVal(table_name);
|
||||
AppendShardIdToName(&relationName, shardId);
|
||||
strVal(table_name) = relationName;
|
||||
}
|
||||
else
|
||||
{
|
||||
ereport(WARNING, (errmsg(
|
||||
"unsafe object type in security label statement"),
|
||||
errdetail("Object type: %u",
|
||||
(uint32) secLabelStmt->objtype)));
|
||||
}
|
||||
|
||||
break; /* End of handling Security Label */
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
ereport(WARNING, (errmsg("unsafe statement type in name extension"),
|
||||
|
@ -846,7 +898,6 @@ AppendShardIdToName(char **name, uint64 shardId)
|
|||
{
|
||||
SafeSnprintf(extendedName, NAMEDATALEN, "%s%s", (*name), shardIdAndSeparator);
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise, we need to truncate the name further to accommodate
|
||||
* a sufficient hash value. The resulting name will avoid collision
|
||||
|
|
|
@ -546,7 +546,9 @@ extern List * AlterSchemaRenameStmtObjectAddress(Node *node, bool missing_ok, bo
|
|||
isPostprocess);
|
||||
|
||||
/* seclabel.c - forward declarations*/
|
||||
extern List * PostprocessSecLabelStmt(Node *node, const char *queryString);
|
||||
extern List * PostprocessAnySecLabelStmt(Node *node, const char *queryString);
|
||||
extern List * PostprocessRoleSecLabelStmt(Node *node, const char *queryString);
|
||||
extern List * PostprocessTableOrColumnSecLabelStmt(Node *node, const char *queryString);
|
||||
extern List * SecLabelStmtObjectAddress(Node *node, bool missing_ok, bool isPostprocess);
|
||||
extern void citus_test_object_relabel(const ObjectAddress *object, const char *seclabel);
|
||||
|
||||
|
|
|
@ -292,7 +292,9 @@ extern void QualifyTextSearchConfigurationCommentStmt(Node *node);
|
|||
extern void QualifyTextSearchDictionaryCommentStmt(Node *node);
|
||||
|
||||
/* forward declarations for deparse_seclabel_stmts.c */
|
||||
extern char * DeparseSecLabelStmt(Node *node);
|
||||
extern char * DeparseRoleSecLabelStmt(Node *node);
|
||||
extern char * DeparseTableSecLabelStmt(Node *node);
|
||||
extern char * DeparseColumnSecLabelStmt(Node *node);
|
||||
|
||||
/* forward declarations for deparse_sequence_stmts.c */
|
||||
extern char * DeparseDropSequenceStmt(Node *node);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
extern bool ObjectExists(const ObjectAddress *address);
|
||||
extern bool CitusExtensionObject(const ObjectAddress *objectAddress);
|
||||
extern bool IsAnyObjectDistributed(const List *addresses);
|
||||
extern bool IsAnyParentObjectDistributed(const List *addresses);
|
||||
extern bool ClusterHasDistributedFunctionWithDistArgument(void);
|
||||
extern void MarkObjectDistributed(const ObjectAddress *distAddress);
|
||||
extern void MarkObjectDistributedWithName(const ObjectAddress *distAddress, char *name,
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
--
|
||||
-- SECLABEL
|
||||
--
|
||||
-- Test suite for SECURITY LABEL ON ROLE statements
|
||||
-- Test suite for SECURITY LABEL statements:
|
||||
-- SECURITY LABEL ON <object> IS <definition>
|
||||
--
|
||||
-- Citus can propagate ROLE, TABLE and COLUMN objects
|
||||
-- first we remove one of the worker nodes to be able to test
|
||||
-- citus_add_node later
|
||||
SELECT citus_remove_node('localhost', :worker_2_port);
|
||||
|
@ -28,7 +30,8 @@ SELECT node_type, result FROM get_citus_tests_label_provider_labels('user1') ORD
|
|||
(2 rows)
|
||||
|
||||
RESET citus.enable_metadata_sync;
|
||||
-- check that we only support propagating for roles
|
||||
-- check that we only support propagating for roles, tables and columns;
|
||||
-- support for VIEW and FUNCTION is not there (yet)
|
||||
SET citus.shard_replication_factor to 1;
|
||||
-- distributed table
|
||||
CREATE TABLE a (a int);
|
||||
|
@ -43,22 +46,12 @@ CREATE VIEW v_dist AS SELECT * FROM a;
|
|||
-- distributed function
|
||||
CREATE FUNCTION notice(text) RETURNS void LANGUAGE plpgsql AS $$
|
||||
BEGIN RAISE NOTICE '%', $1; END; $$;
|
||||
SECURITY LABEL ON TABLE a IS 'citus_classified';
|
||||
NOTICE: not propagating SECURITY LABEL commands whose object type is not role
|
||||
HINT: Connect to worker nodes directly to manually run the same SECURITY LABEL command.
|
||||
SECURITY LABEL ON FUNCTION notice IS 'citus_unclassified';
|
||||
NOTICE: not propagating SECURITY LABEL commands whose object type is not role
|
||||
NOTICE: not propagating SECURITY LABEL commands whose object type is not role or table or column
|
||||
HINT: Connect to worker nodes directly to manually run the same SECURITY LABEL command.
|
||||
SECURITY LABEL ON VIEW v_dist IS 'citus_classified';
|
||||
NOTICE: not propagating SECURITY LABEL commands whose object type is not role
|
||||
NOTICE: not propagating SECURITY LABEL commands whose object type is not role or table or column
|
||||
HINT: Connect to worker nodes directly to manually run the same SECURITY LABEL command.
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 |
|
||||
(2 rows)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('notice(text)') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
|
@ -74,17 +67,9 @@ SELECT node_type, result FROM get_citus_tests_label_provider_labels('v_dist') OR
|
|||
(2 rows)
|
||||
|
||||
\c - - - :worker_1_port
|
||||
SECURITY LABEL ON TABLE a IS 'citus_classified';
|
||||
SECURITY LABEL ON FUNCTION notice IS 'citus_unclassified';
|
||||
SECURITY LABEL ON VIEW v_dist IS 'citus_classified';
|
||||
\c - - - :master_port
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('notice(text)') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
|
@ -99,10 +84,8 @@ SELECT node_type, result FROM get_citus_tests_label_provider_labels('v_dist') OR
|
|||
worker_1 | {"label": "citus_classified", "objtype": "view", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
DROP TABLE a CASCADE;
|
||||
NOTICE: drop cascades to view v_dist
|
||||
DROP FUNCTION notice;
|
||||
-- test that SECURITY LABEL statement is actually propagated for ROLES
|
||||
-- test that SECURITY LABEL statement is actually propagated for ROLES, TABLES and COLUMNS
|
||||
SET citus.log_remote_commands TO on;
|
||||
SET citus.grep_remote_commands = '%SECURITY LABEL%';
|
||||
-- we have exactly one provider loaded, so we may not include the provider in the command
|
||||
|
@ -118,6 +101,41 @@ DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
|
|||
SECURITY LABEL for "citus '!tests_label_provider" ON ROLE "user 2" IS 'citus_classified';
|
||||
NOTICE: issuing SECURITY LABEL FOR "citus '!tests_label_provider" ON ROLE "user 2" IS 'citus_classified'
|
||||
DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
|
||||
SECURITY LABEL ON TABLE a IS 'citus_classified';
|
||||
NOTICE: issuing SECURITY LABEL ON TABLE a IS 'citus_classified'
|
||||
DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
|
||||
SECURITY LABEL for "citus '!tests_label_provider" ON COLUMN a.a IS 'citus_classified';
|
||||
NOTICE: issuing SECURITY LABEL FOR "citus '!tests_label_provider" ON COLUMN a.a IS 'citus_classified'
|
||||
DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
|
||||
-- ROLE, TABLE and COLUMN should be propagated to the worker
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('user1') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_unclassified", "objtype": "role", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_unclassified", "objtype": "role", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"user 2"') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "role", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "role", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a.a') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
\c - - - :worker_1_port
|
||||
SET citus.log_remote_commands TO on;
|
||||
SET citus.grep_remote_commands = '%SECURITY LABEL%';
|
||||
|
@ -139,6 +157,23 @@ SELECT node_type, result FROM get_citus_tests_label_provider_labels('user1') ORD
|
|||
worker_1 | {"label": "citus_classified", "objtype": "role", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a.a') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
SECURITY LABEL for "citus '!tests_label_provider" ON COLUMN a.a IS 'citus ''!unclassified';
|
||||
NOTICE: issuing SECURITY LABEL FOR "citus '!tests_label_provider" ON COLUMN a.a IS 'citus ''!unclassified'
|
||||
DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a.a') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus '!unclassified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus '!unclassified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
RESET citus.log_remote_commands;
|
||||
SECURITY LABEL for "citus '!tests_label_provider" ON ROLE "user 2" IS 'citus ''!unclassified';
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"user 2"') ORDER BY node_type;
|
||||
|
@ -150,19 +185,229 @@ SELECT node_type, result FROM get_citus_tests_label_provider_labels('"user 2"')
|
|||
|
||||
\c - - - :master_port
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('user1') ORDER BY node_type;
|
||||
node_type | result
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "role", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "role", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"user 2"') ORDER BY node_type;
|
||||
node_type | result
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus '!unclassified", "objtype": "role", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus '!unclassified", "objtype": "role", "provider": "citus '!tests_label_provider"}
|
||||
coordinator | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a.a') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus '!unclassified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus '!unclassified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
SET citus.shard_replication_factor to 1;
|
||||
-- Distributed table with delimited identifiers
|
||||
CREATE TABLE "Dist T" ("col.1" int);
|
||||
SELECT create_distributed_table('"Dist T"', 'col.1');
|
||||
create_distributed_table
|
||||
---------------------------------------------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SECURITY LABEL ON TABLE "Dist T" IS 'citus_classified';
|
||||
SECURITY LABEL ON COLUMN "Dist T"."col.1" IS 'citus_classified';
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"Dist T"') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"Dist T".col.1') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
-- Add and Drop column
|
||||
CREATE TABLE tddl (a1 int, b1 int, c1 int);
|
||||
SELECT create_distributed_table('tddl', 'c1');
|
||||
create_distributed_table
|
||||
---------------------------------------------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
ALTER TABLE tddl ADD COLUMN d1 varchar(128);
|
||||
-- Security label on tddl.d1 is propagated to all nodes
|
||||
SECURITY LABEL ON COLUMN tddl.d1 IS 'citus_classified';
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('tddl.d1') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
-- Drop column d1, security label should be removed from all nodes
|
||||
ALTER TABLE tddl DROP COLUMN d1;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('tddl.d1') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator |
|
||||
worker_1 |
|
||||
(2 rows)
|
||||
|
||||
-- Define security labels before distributed table creation
|
||||
CREATE TABLE tb (a1 int, b1 int, c1 int);
|
||||
SECURITY LABEL ON TABLE tb IS 'citus_classified';
|
||||
SECURITY LABEL ON COLUMN tb.a1 IS 'citus_classified';
|
||||
SELECT create_distributed_table('tb', 'a1');
|
||||
create_distributed_table
|
||||
---------------------------------------------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('tb') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('tb.a1') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
-- Similar test with reference table; security labels should be propagated to the worker.
|
||||
CREATE TABLE tref (a1 int, b1 int, c1 int);
|
||||
SECURITY LABEL ON TABLE tref IS 'citus_classified';
|
||||
SECURITY LABEL ON COLUMN tref.b1 IS 'citus_classified';
|
||||
SELECT create_reference_table('tref');
|
||||
create_reference_table
|
||||
---------------------------------------------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('tref') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('tref.b1') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
-- Distributed table with delimited identifiers - 2
|
||||
CREATE TABLE "Dist T2" ("col one" int);
|
||||
SELECT create_distributed_table('"Dist T2"', 'col one');
|
||||
create_distributed_table
|
||||
---------------------------------------------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SECURITY LABEL ON TABLE "Dist T2" IS 'citus_classified';
|
||||
SECURITY LABEL ON COLUMN "Dist T2"."col one" IS 'citus_classified';
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"Dist T2"') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"Dist T2".col one') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
-- Repeat the table and column tests using an explicit schema
|
||||
CREATE SCHEMA label_test;
|
||||
SET search_path TO label_test;
|
||||
CREATE TABLE dist_test1 (a int);
|
||||
SELECT create_distributed_table('dist_test1', 'a');
|
||||
create_distributed_table
|
||||
---------------------------------------------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
-- Define security labels on a distributed table
|
||||
SECURITY LABEL ON TABLE dist_test1 IS 'citus_classified';
|
||||
SECURITY LABEL ON COLUMN dist_test1.a IS 'citus ''!unclassified';
|
||||
SELECT node_type, result FROM public.get_citus_tests_label_provider_labels('label_test.dist_test1') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
SELECT node_type, result FROM public.get_citus_tests_label_provider_labels('label_test.dist_test1.a') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus '!unclassified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus '!unclassified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
CREATE TABLE dist_test2 (a int);
|
||||
SECURITY LABEL on TABLE dist_test2 IS 'citus_unclassified';
|
||||
SECURITY LABEL on COLUMN dist_test2.a IS 'citus ''!unclassified';
|
||||
-- Distributing a table means security labels on the table and its columns are propagated
|
||||
SELECT create_distributed_table('dist_test2', 'a');
|
||||
create_distributed_table
|
||||
---------------------------------------------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT node_type, result FROM public.get_citus_tests_label_provider_labels('label_test.dist_test2') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_unclassified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_unclassified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
SELECT node_type, result FROM public.get_citus_tests_label_provider_labels('label_test.dist_test2.a') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus '!unclassified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus '!unclassified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
-- Add and Drop column
|
||||
CREATE TABLE tddl (a1 int, b1 int, c1 int);
|
||||
SELECT create_distributed_table('tddl', 'c1');
|
||||
create_distributed_table
|
||||
---------------------------------------------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
ALTER TABLE tddl ADD COLUMN d1 varchar(128);
|
||||
-- Security label on tddl.d1 is propagated to all nodes
|
||||
SECURITY LABEL ON COLUMN tddl.d1 IS 'citus ''!unclassified';
|
||||
SELECT node_type, result FROM public.get_citus_tests_label_provider_labels('label_test.tddl.d1') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus '!unclassified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus '!unclassified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
(2 rows)
|
||||
|
||||
-- Drop column d1, security label should be removed from all nodes
|
||||
ALTER TABLE tddl DROP COLUMN d1;
|
||||
SELECT node_type, result FROM public.get_citus_tests_label_provider_labels('label_test.tddl.d1') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator |
|
||||
worker_1 |
|
||||
(2 rows)
|
||||
|
||||
RESET search_path;
|
||||
-- add a new node and check that it also propagates the SECURITY LABEL statement to the new node
|
||||
SET citus.log_remote_commands TO on;
|
||||
SET citus.grep_remote_commands = '%SECURITY LABEL%';
|
||||
|
@ -170,6 +415,20 @@ SELECT 1 FROM citus_add_node('localhost', :worker_2_port);
|
|||
NOTICE: issuing SELECT worker_create_or_alter_role('user1', 'CREATE ROLE user1 NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT NOLOGIN NOREPLICATION NOBYPASSRLS CONNECTION LIMIT -1 PASSWORD NULL', 'ALTER ROLE user1 NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT NOLOGIN NOREPLICATION NOBYPASSRLS CONNECTION LIMIT -1 PASSWORD NULL');SECURITY LABEL FOR "citus '!tests_label_provider" ON ROLE user1 IS 'citus_classified'
|
||||
DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
|
||||
NOTICE: issuing SELECT worker_create_or_alter_role('user 2', 'CREATE ROLE "user 2" NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT NOLOGIN NOREPLICATION NOBYPASSRLS CONNECTION LIMIT -1 PASSWORD NULL', 'ALTER ROLE "user 2" NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT NOLOGIN NOREPLICATION NOBYPASSRLS CONNECTION LIMIT -1 PASSWORD NULL');SECURITY LABEL FOR "citus '!tests_label_provider" ON ROLE "user 2" IS 'citus ''!unclassified'
|
||||
DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
|
||||
NOTICE: issuing SELECT pg_catalog.worker_drop_sequence_dependency('public.a');;DROP TABLE IF EXISTS public.a CASCADE;CREATE TABLE public.a (a integer) USING heap;ALTER TABLE public.a OWNER TO postgres;SECURITY LABEL FOR "citus '!tests_label_provider" ON TABLE public.a IS 'citus_classified';SECURITY LABEL FOR "citus '!tests_label_provider" ON COLUMN public.a.a IS 'citus ''!unclassified';SELECT worker_create_truncate_trigger('public.a')
|
||||
DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
|
||||
NOTICE: issuing SELECT pg_catalog.worker_drop_sequence_dependency('public."Dist T"');;DROP TABLE IF EXISTS public."Dist T" CASCADE;CREATE TABLE public."Dist T" ("col.1" integer) USING heap;ALTER TABLE public."Dist T" OWNER TO postgres;SECURITY LABEL FOR "citus '!tests_label_provider" ON TABLE public."Dist T" IS 'citus_classified';SECURITY LABEL FOR "citus '!tests_label_provider" ON COLUMN public."Dist T"."col.1" IS 'citus_classified';SELECT worker_create_truncate_trigger('public."Dist T"')
|
||||
DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
|
||||
NOTICE: issuing SELECT pg_catalog.worker_drop_sequence_dependency('public.tb');;DROP TABLE IF EXISTS public.tb CASCADE;CREATE TABLE public.tb (a1 integer, b1 integer, c1 integer) USING heap;ALTER TABLE public.tb OWNER TO postgres;SECURITY LABEL FOR "citus '!tests_label_provider" ON TABLE public.tb IS 'citus_classified';SECURITY LABEL FOR "citus '!tests_label_provider" ON COLUMN public.tb.a1 IS 'citus_classified';SELECT worker_create_truncate_trigger('public.tb')
|
||||
DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
|
||||
NOTICE: issuing SELECT pg_catalog.worker_drop_sequence_dependency('public.tref');;DROP TABLE IF EXISTS public.tref CASCADE;CREATE TABLE public.tref (a1 integer, b1 integer, c1 integer) USING heap;ALTER TABLE public.tref OWNER TO postgres;SECURITY LABEL FOR "citus '!tests_label_provider" ON TABLE public.tref IS 'citus_classified';SECURITY LABEL FOR "citus '!tests_label_provider" ON COLUMN public.tref.b1 IS 'citus_classified';SELECT worker_create_truncate_trigger('public.tref')
|
||||
DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
|
||||
NOTICE: issuing SELECT pg_catalog.worker_drop_sequence_dependency('public."Dist T2"');;DROP TABLE IF EXISTS public."Dist T2" CASCADE;CREATE TABLE public."Dist T2" ("col one" integer) USING heap;ALTER TABLE public."Dist T2" OWNER TO postgres;SECURITY LABEL FOR "citus '!tests_label_provider" ON TABLE public."Dist T2" IS 'citus_classified';SECURITY LABEL FOR "citus '!tests_label_provider" ON COLUMN public."Dist T2"."col one" IS 'citus_classified';SELECT worker_create_truncate_trigger('public."Dist T2"')
|
||||
DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
|
||||
NOTICE: issuing SELECT pg_catalog.worker_drop_sequence_dependency('label_test.dist_test1');;DROP TABLE IF EXISTS label_test.dist_test1 CASCADE;CREATE TABLE label_test.dist_test1 (a integer) USING heap;ALTER TABLE label_test.dist_test1 OWNER TO postgres;SECURITY LABEL FOR "citus '!tests_label_provider" ON TABLE label_test.dist_test1 IS 'citus_classified';SECURITY LABEL FOR "citus '!tests_label_provider" ON COLUMN label_test.dist_test1.a IS 'citus ''!unclassified';SELECT worker_create_truncate_trigger('label_test.dist_test1')
|
||||
DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
|
||||
NOTICE: issuing SELECT pg_catalog.worker_drop_sequence_dependency('label_test.dist_test2');;DROP TABLE IF EXISTS label_test.dist_test2 CASCADE;CREATE TABLE label_test.dist_test2 (a integer) USING heap;ALTER TABLE label_test.dist_test2 OWNER TO postgres;SECURITY LABEL FOR "citus '!tests_label_provider" ON TABLE label_test.dist_test2 IS 'citus_unclassified';SECURITY LABEL FOR "citus '!tests_label_provider" ON COLUMN label_test.dist_test2.a IS 'citus ''!unclassified';SELECT worker_create_truncate_trigger('label_test.dist_test2')
|
||||
DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
|
||||
?column?
|
||||
---------------------------------------------------------------------
|
||||
|
@ -177,7 +436,7 @@ DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
|
|||
(1 row)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('user1') ORDER BY node_type;
|
||||
node_type | result
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "role", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "role", "provider": "citus '!tests_label_provider"}
|
||||
|
@ -192,11 +451,114 @@ SELECT node_type, result FROM get_citus_tests_label_provider_labels('"user 2"')
|
|||
worker_2 | {"label": "citus '!unclassified", "objtype": "role", "provider": "citus '!tests_label_provider"}
|
||||
(3 rows)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_2 | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
(3 rows)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a.a') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus '!unclassified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus '!unclassified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_2 | {"label": "citus '!unclassified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
(3 rows)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"Dist T"') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_2 | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
(3 rows)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"Dist T".col.1') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_2 | {"label": "citus_classified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
(3 rows)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"Dist T2"') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_2 | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
(3 rows)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"Dist T2"."col one"') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator |
|
||||
worker_1 |
|
||||
worker_2 |
|
||||
(3 rows)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('tb') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_2 | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
(3 rows)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('tb.a1') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_2 | {"label": "citus_classified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
(3 rows)
|
||||
|
||||
-- Check that security labels in the label_test schema are propagated to the newly added node
|
||||
SELECT node_type, result FROM public.get_citus_tests_label_provider_labels('label_test.dist_test1') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_2 | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
(3 rows)
|
||||
|
||||
SELECT node_type, result FROM public.get_citus_tests_label_provider_labels('label_test.dist_test1.a') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus '!unclassified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus '!unclassified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_2 | {"label": "citus '!unclassified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
(3 rows)
|
||||
|
||||
SELECT node_type, result FROM public.get_citus_tests_label_provider_labels('label_test.dist_test2') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_unclassified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_unclassified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_2 | {"label": "citus_unclassified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
(3 rows)
|
||||
|
||||
SELECT node_type, result FROM public.get_citus_tests_label_provider_labels('label_test.dist_test2.a') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus '!unclassified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus '!unclassified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_2 | {"label": "citus '!unclassified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
(3 rows)
|
||||
|
||||
-- disable the GUC and check that the command is not propagated
|
||||
SET citus.enable_alter_role_propagation TO off;
|
||||
SECURITY LABEL ON ROLE user1 IS 'citus_unclassified';
|
||||
NOTICE: not propagating SECURITY LABEL commands to other nodes
|
||||
HINT: Connect to other nodes directly to manually assign necessary labels.
|
||||
SECURITY LABEL ON TABLE a IS 'citus_unclassified';
|
||||
NOTICE: not propagating SECURITY LABEL commands to other nodes
|
||||
HINT: Connect to other nodes directly to manually assign necessary labels.
|
||||
SECURITY LABEL ON COLUMN a.a IS 'citus_classified';
|
||||
NOTICE: not propagating SECURITY LABEL commands to other nodes
|
||||
HINT: Connect to other nodes directly to manually assign necessary labels.
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('user1') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
|
@ -205,6 +567,22 @@ SELECT node_type, result FROM get_citus_tests_label_provider_labels('user1') ORD
|
|||
worker_2 | {"label": "citus_classified", "objtype": "role", "provider": "citus '!tests_label_provider"}
|
||||
(3 rows)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_unclassified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_2 | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
(3 rows)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a.a') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus '!unclassified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_2 | {"label": "citus '!unclassified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
(3 rows)
|
||||
|
||||
\c - - - :worker_2_port
|
||||
SET citus.log_remote_commands TO on;
|
||||
SET citus.grep_remote_commands = '%SECURITY LABEL%';
|
||||
|
@ -212,6 +590,12 @@ SET citus.enable_alter_role_propagation TO off;
|
|||
SECURITY LABEL ON ROLE user1 IS 'citus ''!unclassified';
|
||||
NOTICE: not propagating SECURITY LABEL commands to other nodes
|
||||
HINT: Connect to other nodes directly to manually assign necessary labels.
|
||||
SECURITY LABEL ON TABLE a IS 'citus ''!unclassified';
|
||||
NOTICE: not propagating SECURITY LABEL commands to other nodes
|
||||
HINT: Connect to other nodes directly to manually assign necessary labels.
|
||||
SECURITY LABEL ON COLUMN a.a IS 'citus_unclassified';
|
||||
NOTICE: not propagating SECURITY LABEL commands to other nodes
|
||||
HINT: Connect to other nodes directly to manually assign necessary labels.
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('user1') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
|
@ -220,7 +604,36 @@ SELECT node_type, result FROM get_citus_tests_label_provider_labels('user1') ORD
|
|||
worker_2 | {"label": "citus '!unclassified", "objtype": "role", "provider": "citus '!tests_label_provider"}
|
||||
(3 rows)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_unclassified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
worker_2 | {"label": "citus '!unclassified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||
(3 rows)
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a.a') ORDER BY node_type;
|
||||
node_type | result
|
||||
---------------------------------------------------------------------
|
||||
coordinator | {"label": "citus_classified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_1 | {"label": "citus '!unclassified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
worker_2 | {"label": "citus_unclassified", "objtype": "column", "provider": "citus '!tests_label_provider"}
|
||||
(3 rows)
|
||||
|
||||
RESET citus.enable_alter_role_propagation;
|
||||
\c - - - :master_port
|
||||
-- cleanup
|
||||
DROP TABLE a CASCADE;
|
||||
NOTICE: drop cascades to view v_dist
|
||||
DROP TABLE "Dist T" CASCADE;
|
||||
DROP TABLE "Dist T2" CASCADE;
|
||||
DROP TABLE tb CASCADE;
|
||||
DROP TABLE tref CASCADE;
|
||||
DROP TABLE tddl CASCADE;
|
||||
RESET citus.log_remote_commands;
|
||||
DROP ROLE user1, "user 2";
|
||||
DROP SCHEMA label_test CASCADE;
|
||||
NOTICE: drop cascades to 3 other objects
|
||||
DETAIL: drop cascades to table label_test.dist_test1
|
||||
drop cascades to table label_test.dist_test2
|
||||
drop cascades to table label_test.tddl
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
--
|
||||
-- SECLABEL
|
||||
--
|
||||
-- Test suite for SECURITY LABEL ON ROLE statements
|
||||
-- Test suite for SECURITY LABEL statements:
|
||||
-- SECURITY LABEL ON <object> IS <definition>
|
||||
--
|
||||
-- Citus can propagate ROLE, TABLE and COLUMN objects
|
||||
|
||||
-- first we remove one of the worker nodes to be able to test
|
||||
-- citus_add_node later
|
||||
|
@ -22,7 +24,8 @@ SELECT node_type, result FROM get_citus_tests_label_provider_labels('user1') ORD
|
|||
|
||||
RESET citus.enable_metadata_sync;
|
||||
|
||||
-- check that we only support propagating for roles
|
||||
-- check that we only support propagating for roles, tables and columns;
|
||||
-- support for VIEW and FUNCTION is not there (yet)
|
||||
SET citus.shard_replication_factor to 1;
|
||||
-- distributed table
|
||||
CREATE TABLE a (a int);
|
||||
|
@ -33,28 +36,23 @@ CREATE VIEW v_dist AS SELECT * FROM a;
|
|||
CREATE FUNCTION notice(text) RETURNS void LANGUAGE plpgsql AS $$
|
||||
BEGIN RAISE NOTICE '%', $1; END; $$;
|
||||
|
||||
SECURITY LABEL ON TABLE a IS 'citus_classified';
|
||||
SECURITY LABEL ON FUNCTION notice IS 'citus_unclassified';
|
||||
SECURITY LABEL ON VIEW v_dist IS 'citus_classified';
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('notice(text)') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('v_dist') ORDER BY node_type;
|
||||
|
||||
\c - - - :worker_1_port
|
||||
SECURITY LABEL ON TABLE a IS 'citus_classified';
|
||||
SECURITY LABEL ON FUNCTION notice IS 'citus_unclassified';
|
||||
SECURITY LABEL ON VIEW v_dist IS 'citus_classified';
|
||||
|
||||
\c - - - :master_port
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('notice(text)') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('v_dist') ORDER BY node_type;
|
||||
|
||||
DROP TABLE a CASCADE;
|
||||
DROP FUNCTION notice;
|
||||
|
||||
-- test that SECURITY LABEL statement is actually propagated for ROLES
|
||||
-- test that SECURITY LABEL statement is actually propagated for ROLES, TABLES and COLUMNS
|
||||
SET citus.log_remote_commands TO on;
|
||||
SET citus.grep_remote_commands = '%SECURITY LABEL%';
|
||||
|
||||
|
@ -64,6 +62,15 @@ SECURITY LABEL ON ROLE user1 IS NULL;
|
|||
SECURITY LABEL ON ROLE user1 IS 'citus_unclassified';
|
||||
SECURITY LABEL for "citus '!tests_label_provider" ON ROLE "user 2" IS 'citus_classified';
|
||||
|
||||
SECURITY LABEL ON TABLE a IS 'citus_classified';
|
||||
SECURITY LABEL for "citus '!tests_label_provider" ON COLUMN a.a IS 'citus_classified';
|
||||
|
||||
-- ROLE, TABLE and COLUMN should be propagated to the worker
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('user1') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"user 2"') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a.a') ORDER BY node_type;
|
||||
|
||||
\c - - - :worker_1_port
|
||||
SET citus.log_remote_commands TO on;
|
||||
SET citus.grep_remote_commands = '%SECURITY LABEL%';
|
||||
|
@ -72,13 +79,110 @@ SELECT node_type, result FROM get_citus_tests_label_provider_labels('user1') ORD
|
|||
SECURITY LABEL for "citus '!tests_label_provider" ON ROLE user1 IS 'citus_classified';
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('user1') ORDER BY node_type;
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a.a') ORDER BY node_type;
|
||||
SECURITY LABEL for "citus '!tests_label_provider" ON COLUMN a.a IS 'citus ''!unclassified';
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a.a') ORDER BY node_type;
|
||||
|
||||
RESET citus.log_remote_commands;
|
||||
SECURITY LABEL for "citus '!tests_label_provider" ON ROLE "user 2" IS 'citus ''!unclassified';
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"user 2"') ORDER BY node_type;
|
||||
\c - - - :master_port
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('user1') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"user 2"') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a.a') ORDER BY node_type;
|
||||
|
||||
SET citus.shard_replication_factor to 1;
|
||||
|
||||
-- Distributed table with delimited identifiers
|
||||
CREATE TABLE "Dist T" ("col.1" int);
|
||||
SELECT create_distributed_table('"Dist T"', 'col.1');
|
||||
|
||||
SECURITY LABEL ON TABLE "Dist T" IS 'citus_classified';
|
||||
SECURITY LABEL ON COLUMN "Dist T"."col.1" IS 'citus_classified';
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"Dist T"') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"Dist T".col.1') ORDER BY node_type;
|
||||
|
||||
-- Add and Drop column
|
||||
CREATE TABLE tddl (a1 int, b1 int, c1 int);
|
||||
SELECT create_distributed_table('tddl', 'c1');
|
||||
|
||||
ALTER TABLE tddl ADD COLUMN d1 varchar(128);
|
||||
|
||||
-- Security label on tddl.d1 is propagated to all nodes
|
||||
SECURITY LABEL ON COLUMN tddl.d1 IS 'citus_classified';
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('tddl.d1') ORDER BY node_type;
|
||||
|
||||
-- Drop column d1, security label should be removed from all nodes
|
||||
ALTER TABLE tddl DROP COLUMN d1;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('tddl.d1') ORDER BY node_type;
|
||||
|
||||
-- Define security labels before distributed table creation
|
||||
CREATE TABLE tb (a1 int, b1 int, c1 int);
|
||||
SECURITY LABEL ON TABLE tb IS 'citus_classified';
|
||||
SECURITY LABEL ON COLUMN tb.a1 IS 'citus_classified';
|
||||
|
||||
SELECT create_distributed_table('tb', 'a1');
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('tb') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('tb.a1') ORDER BY node_type;
|
||||
|
||||
-- Similar test with reference table; security labels should be propagated to the worker.
|
||||
CREATE TABLE tref (a1 int, b1 int, c1 int);
|
||||
SECURITY LABEL ON TABLE tref IS 'citus_classified';
|
||||
SECURITY LABEL ON COLUMN tref.b1 IS 'citus_classified';
|
||||
|
||||
SELECT create_reference_table('tref');
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('tref') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('tref.b1') ORDER BY node_type;
|
||||
|
||||
-- Distributed table with delimited identifiers - 2
|
||||
CREATE TABLE "Dist T2" ("col one" int);
|
||||
SELECT create_distributed_table('"Dist T2"', 'col one');
|
||||
|
||||
SECURITY LABEL ON TABLE "Dist T2" IS 'citus_classified';
|
||||
SECURITY LABEL ON COLUMN "Dist T2"."col one" IS 'citus_classified';
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"Dist T2"') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"Dist T2".col one') ORDER BY node_type;
|
||||
|
||||
-- Repeat the table and column tests using an explicit schema
|
||||
CREATE SCHEMA label_test;
|
||||
SET search_path TO label_test;
|
||||
|
||||
CREATE TABLE dist_test1 (a int);
|
||||
SELECT create_distributed_table('dist_test1', 'a');
|
||||
-- Define security labels on a distributed table
|
||||
SECURITY LABEL ON TABLE dist_test1 IS 'citus_classified';
|
||||
SECURITY LABEL ON COLUMN dist_test1.a IS 'citus ''!unclassified';
|
||||
SELECT node_type, result FROM public.get_citus_tests_label_provider_labels('label_test.dist_test1') ORDER BY node_type;
|
||||
SELECT node_type, result FROM public.get_citus_tests_label_provider_labels('label_test.dist_test1.a') ORDER BY node_type;
|
||||
|
||||
CREATE TABLE dist_test2 (a int);
|
||||
SECURITY LABEL on TABLE dist_test2 IS 'citus_unclassified';
|
||||
SECURITY LABEL on COLUMN dist_test2.a IS 'citus ''!unclassified';
|
||||
-- Distributing a table means security labels on the table and its columns are propagated
|
||||
SELECT create_distributed_table('dist_test2', 'a');
|
||||
SELECT node_type, result FROM public.get_citus_tests_label_provider_labels('label_test.dist_test2') ORDER BY node_type;
|
||||
SELECT node_type, result FROM public.get_citus_tests_label_provider_labels('label_test.dist_test2.a') ORDER BY node_type;
|
||||
|
||||
-- Add and Drop column
|
||||
CREATE TABLE tddl (a1 int, b1 int, c1 int);
|
||||
SELECT create_distributed_table('tddl', 'c1');
|
||||
|
||||
ALTER TABLE tddl ADD COLUMN d1 varchar(128);
|
||||
|
||||
-- Security label on tddl.d1 is propagated to all nodes
|
||||
SECURITY LABEL ON COLUMN tddl.d1 IS 'citus ''!unclassified';
|
||||
SELECT node_type, result FROM public.get_citus_tests_label_provider_labels('label_test.tddl.d1') ORDER BY node_type;
|
||||
|
||||
-- Drop column d1, security label should be removed from all nodes
|
||||
ALTER TABLE tddl DROP COLUMN d1;
|
||||
SELECT node_type, result FROM public.get_citus_tests_label_provider_labels('label_test.tddl.d1') ORDER BY node_type;
|
||||
|
||||
RESET search_path;
|
||||
|
||||
-- add a new node and check that it also propagates the SECURITY LABEL statement to the new node
|
||||
SET citus.log_remote_commands TO on;
|
||||
|
@ -87,20 +191,52 @@ SELECT 1 FROM citus_add_node('localhost', :worker_2_port);
|
|||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('user1') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"user 2"') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a.a') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"Dist T"') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"Dist T".col.1') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"Dist T2"') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"Dist T2"."col one"') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('tb') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('tb.a1') ORDER BY node_type;
|
||||
-- Check that security labels in the label_test schema are propagated to the newly added node
|
||||
SELECT node_type, result FROM public.get_citus_tests_label_provider_labels('label_test.dist_test1') ORDER BY node_type;
|
||||
SELECT node_type, result FROM public.get_citus_tests_label_provider_labels('label_test.dist_test1.a') ORDER BY node_type;
|
||||
SELECT node_type, result FROM public.get_citus_tests_label_provider_labels('label_test.dist_test2') ORDER BY node_type;
|
||||
SELECT node_type, result FROM public.get_citus_tests_label_provider_labels('label_test.dist_test2.a') ORDER BY node_type;
|
||||
|
||||
-- disable the GUC and check that the command is not propagated
|
||||
SET citus.enable_alter_role_propagation TO off;
|
||||
SECURITY LABEL ON ROLE user1 IS 'citus_unclassified';
|
||||
SECURITY LABEL ON TABLE a IS 'citus_unclassified';
|
||||
SECURITY LABEL ON COLUMN a.a IS 'citus_classified';
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('user1') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a.a') ORDER BY node_type;
|
||||
|
||||
\c - - - :worker_2_port
|
||||
SET citus.log_remote_commands TO on;
|
||||
SET citus.grep_remote_commands = '%SECURITY LABEL%';
|
||||
SET citus.enable_alter_role_propagation TO off;
|
||||
SECURITY LABEL ON ROLE user1 IS 'citus ''!unclassified';
|
||||
SECURITY LABEL ON TABLE a IS 'citus ''!unclassified';
|
||||
SECURITY LABEL ON COLUMN a.a IS 'citus_unclassified';
|
||||
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('user1') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a') ORDER BY node_type;
|
||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('a.a') ORDER BY node_type;
|
||||
|
||||
RESET citus.enable_alter_role_propagation;
|
||||
|
||||
\c - - - :master_port
|
||||
-- cleanup
|
||||
DROP TABLE a CASCADE;
|
||||
DROP TABLE "Dist T" CASCADE;
|
||||
DROP TABLE "Dist T2" CASCADE;
|
||||
DROP TABLE tb CASCADE;
|
||||
DROP TABLE tref CASCADE;
|
||||
DROP TABLE tddl CASCADE;
|
||||
RESET citus.log_remote_commands;
|
||||
DROP ROLE user1, "user 2";
|
||||
DROP SCHEMA label_test CASCADE;
|
||||
|
|
Loading…
Reference in New Issue