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,
|
.markDistributed = false,
|
||||||
};
|
};
|
||||||
static DistributeObjectOps Any_SecLabel = {
|
static DistributeObjectOps Any_SecLabel = {
|
||||||
.deparse = DeparseSecLabelStmt,
|
.deparse = NULL,
|
||||||
.qualify = NULL,
|
.qualify = NULL,
|
||||||
.preprocess = 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,
|
.operationType = DIST_OPS_ALTER,
|
||||||
.address = SecLabelStmtObjectAddress,
|
.address = SecLabelStmtObjectAddress,
|
||||||
.markDistributed = false,
|
.markDistributed = false,
|
||||||
|
@ -2119,8 +2146,28 @@ GetDistributeObjectOps(Node *node)
|
||||||
|
|
||||||
case T_SecLabelStmt:
|
case T_SecLabelStmt:
|
||||||
{
|
{
|
||||||
|
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;
|
return &Any_SecLabel;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case T_RenameStmt:
|
case T_RenameStmt:
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,19 +15,18 @@
|
||||||
#include "distributed/commands/utility_hook.h"
|
#include "distributed/commands/utility_hook.h"
|
||||||
#include "distributed/coordinator_protocol.h"
|
#include "distributed/coordinator_protocol.h"
|
||||||
#include "distributed/deparser.h"
|
#include "distributed/deparser.h"
|
||||||
|
#include "distributed/listutils.h"
|
||||||
#include "distributed/log_utils.h"
|
#include "distributed/log_utils.h"
|
||||||
#include "distributed/metadata/distobject.h"
|
#include "distributed/metadata/distobject.h"
|
||||||
#include "distributed/metadata_sync.h"
|
#include "distributed/metadata_sync.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PostprocessSecLabelStmt prepares the commands that need to be run on all workers to assign
|
* PostprocessRoleSecLabelStmt prepares the commands that need to be run on all workers to assign
|
||||||
* security labels on distributed objects, currently supporting just Role objects.
|
* security labels on distributed roles. It also ensures that all object dependencies exist on all
|
||||||
* It also ensures that all object dependencies exist on all
|
* nodes for the role in the SecLabelStmt.
|
||||||
* nodes for the object in the SecLabelStmt.
|
|
||||||
*/
|
*/
|
||||||
List *
|
List *
|
||||||
PostprocessSecLabelStmt(Node *node, const char *queryString)
|
PostprocessRoleSecLabelStmt(Node *node, const char *queryString)
|
||||||
{
|
{
|
||||||
if (!EnableAlterRolePropagation || !ShouldPropagate())
|
if (!EnableAlterRolePropagation || !ShouldPropagate())
|
||||||
{
|
{
|
||||||
|
@ -42,8 +41,78 @@ PostprocessSecLabelStmt(Node *node, const char *queryString)
|
||||||
return NIL;
|
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())
|
||||||
{
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
* 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
|
* label command with notices, the user expects that from the worker node
|
||||||
|
@ -52,24 +121,11 @@ PostprocessSecLabelStmt(Node *node, const char *queryString)
|
||||||
if (EnableUnsupportedFeatureMessages && IsCoordinator())
|
if (EnableUnsupportedFeatureMessages && IsCoordinator())
|
||||||
{
|
{
|
||||||
ereport(NOTICE, (errmsg("not propagating SECURITY LABEL commands whose "
|
ereport(NOTICE, (errmsg("not propagating SECURITY LABEL commands whose "
|
||||||
"object type is not role"),
|
"object type is not role or table or column"),
|
||||||
errhint("Connect to worker nodes directly to manually "
|
errhint("Connect to worker nodes directly to manually "
|
||||||
"run the same SECURITY LABEL command.")));
|
"run the same SECURITY LABEL command.")));
|
||||||
}
|
}
|
||||||
return NIL;
|
return NIL;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,37 +10,16 @@
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "catalog/namespace.h"
|
||||||
#include "nodes/parsenodes.h"
|
#include "nodes/parsenodes.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
|
|
||||||
#include "distributed/deparser.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
|
static void
|
||||||
AppendSecLabelStmt(StringInfo buf, SecLabelStmt *stmt)
|
BeginSecLabel(StringInfo buf, SecLabelStmt *stmt)
|
||||||
{
|
{
|
||||||
|
initStringInfo(buf);
|
||||||
appendStringInfoString(buf, "SECURITY LABEL ");
|
appendStringInfoString(buf, "SECURITY LABEL ");
|
||||||
|
|
||||||
if (stmt->provider != NULL)
|
if (stmt->provider != NULL)
|
||||||
|
@ -49,31 +28,84 @@ AppendSecLabelStmt(StringInfo buf, SecLabelStmt *stmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
appendStringInfoString(buf, "ON ");
|
appendStringInfoString(buf, "ON ");
|
||||||
|
}
|
||||||
switch (stmt->objtype)
|
|
||||||
{
|
|
||||||
case OBJECT_ROLE:
|
static void
|
||||||
{
|
EndSecLabel(StringInfo buf, SecLabelStmt *stmt)
|
||||||
appendStringInfo(buf, "ROLE %s ", quote_identifier(strVal(stmt->object)));
|
{
|
||||||
break;
|
appendStringInfo(buf, "IS %s", (stmt->label != NULL) ?
|
||||||
}
|
quote_literal_cstr(stmt->label) : "NULL");
|
||||||
|
}
|
||||||
/* normally, we shouldn't reach this */
|
|
||||||
default:
|
|
||||||
{
|
/*
|
||||||
ereport(ERROR, (errmsg("unsupported security label statement for"
|
* DeparseRoleSecLabelStmt builds and returns a string representation of the
|
||||||
" deparsing")));
|
* SecLabelStmt for application on a remote server. The SecLabelStmt is for
|
||||||
}
|
* a role object.
|
||||||
}
|
*/
|
||||||
|
char *
|
||||||
appendStringInfoString(buf, "IS ");
|
DeparseRoleSecLabelStmt(Node *node)
|
||||||
|
{
|
||||||
if (stmt->label != NULL)
|
SecLabelStmt *secLabelStmt = castNode(SecLabelStmt, node);
|
||||||
{
|
char *role_name = strVal(secLabelStmt->object);
|
||||||
appendStringInfo(buf, "%s", quote_literal_cstr(stmt->label));
|
StringInfoData buf = { 0 };
|
||||||
}
|
|
||||||
else
|
BeginSecLabel(&buf, secLabelStmt);
|
||||||
{
|
appendStringInfo(&buf, "ROLE %s ", quote_identifier(role_name));
|
||||||
appendStringInfoString(buf, "NULL");
|
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
|
* GetDistributedObjectAddressList returns a list of ObjectAddresses that contains all
|
||||||
* distributed objects as marked in pg_dist_object
|
* distributed objects as marked in pg_dist_object
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "catalog/pg_constraint.h"
|
#include "catalog/pg_constraint.h"
|
||||||
#include "catalog/pg_index.h"
|
#include "catalog/pg_index.h"
|
||||||
#include "catalog/pg_namespace.h"
|
#include "catalog/pg_namespace.h"
|
||||||
|
#include "catalog/pg_seclabel.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "commands/sequence.h"
|
#include "commands/sequence.h"
|
||||||
#include "foreign/foreign.h"
|
#include "foreign/foreign.h"
|
||||||
|
@ -57,6 +58,7 @@
|
||||||
#include "distributed/citus_ruleutils.h"
|
#include "distributed/citus_ruleutils.h"
|
||||||
#include "distributed/commands.h"
|
#include "distributed/commands.h"
|
||||||
#include "distributed/coordinator_protocol.h"
|
#include "distributed/coordinator_protocol.h"
|
||||||
|
#include "distributed/deparser.h"
|
||||||
#include "distributed/listutils.h"
|
#include "distributed/listutils.h"
|
||||||
#include "distributed/metadata_cache.h"
|
#include "distributed/metadata_cache.h"
|
||||||
#include "distributed/metadata_sync.h"
|
#include "distributed/metadata_sync.h"
|
||||||
|
@ -83,6 +85,7 @@ static char * CitusCreateAlterColumnarTableSet(char *qualifiedRelationName,
|
||||||
const ColumnarOptions *options);
|
const ColumnarOptions *options);
|
||||||
static char * GetTableDDLCommandColumnar(void *context);
|
static char * GetTableDDLCommandColumnar(void *context);
|
||||||
static TableDDLCommand * ColumnarGetTableOptionsDDL(Oid relationId);
|
static TableDDLCommand * ColumnarGetTableOptionsDDL(Oid relationId);
|
||||||
|
static List * CreateSecurityLabelCommands(Oid relationId);
|
||||||
|
|
||||||
/* exports for SQL callable functions */
|
/* exports for SQL callable functions */
|
||||||
PG_FUNCTION_INFO_V1(master_get_table_metadata);
|
PG_FUNCTION_INFO_V1(master_get_table_metadata);
|
||||||
|
@ -665,6 +668,9 @@ GetPreLoadTableCreationCommands(Oid relationId,
|
||||||
List *policyCommands = CreatePolicyCommands(relationId);
|
List *policyCommands = CreatePolicyCommands(relationId);
|
||||||
tableDDLEventList = list_concat(tableDDLEventList, policyCommands);
|
tableDDLEventList = list_concat(tableDDLEventList, policyCommands);
|
||||||
|
|
||||||
|
List *securityLabelCommands = CreateSecurityLabelCommands(relationId);
|
||||||
|
tableDDLEventList = list_concat(tableDDLEventList, securityLabelCommands);
|
||||||
|
|
||||||
/* revert back to original search_path */
|
/* revert back to original search_path */
|
||||||
PopEmptySearchPath(saveNestLevel);
|
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
|
* IndexImpliedByAConstraint is a helper function to be used while scanning
|
||||||
* pg_index. It returns true if the index identified by the given indexForm is
|
* 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;
|
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:
|
default:
|
||||||
{
|
{
|
||||||
ereport(WARNING, (errmsg("unsafe statement type in name extension"),
|
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);
|
SafeSnprintf(extendedName, NAMEDATALEN, "%s%s", (*name), shardIdAndSeparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Otherwise, we need to truncate the name further to accommodate
|
* Otherwise, we need to truncate the name further to accommodate
|
||||||
* a sufficient hash value. The resulting name will avoid collision
|
* a sufficient hash value. The resulting name will avoid collision
|
||||||
|
|
|
@ -546,7 +546,9 @@ extern List * AlterSchemaRenameStmtObjectAddress(Node *node, bool missing_ok, bo
|
||||||
isPostprocess);
|
isPostprocess);
|
||||||
|
|
||||||
/* seclabel.c - forward declarations*/
|
/* 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 List * SecLabelStmtObjectAddress(Node *node, bool missing_ok, bool isPostprocess);
|
||||||
extern void citus_test_object_relabel(const ObjectAddress *object, const char *seclabel);
|
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);
|
extern void QualifyTextSearchDictionaryCommentStmt(Node *node);
|
||||||
|
|
||||||
/* forward declarations for deparse_seclabel_stmts.c */
|
/* 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 */
|
/* forward declarations for deparse_sequence_stmts.c */
|
||||||
extern char * DeparseDropSequenceStmt(Node *node);
|
extern char * DeparseDropSequenceStmt(Node *node);
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
extern bool ObjectExists(const ObjectAddress *address);
|
extern bool ObjectExists(const ObjectAddress *address);
|
||||||
extern bool CitusExtensionObject(const ObjectAddress *objectAddress);
|
extern bool CitusExtensionObject(const ObjectAddress *objectAddress);
|
||||||
extern bool IsAnyObjectDistributed(const List *addresses);
|
extern bool IsAnyObjectDistributed(const List *addresses);
|
||||||
|
extern bool IsAnyParentObjectDistributed(const List *addresses);
|
||||||
extern bool ClusterHasDistributedFunctionWithDistArgument(void);
|
extern bool ClusterHasDistributedFunctionWithDistArgument(void);
|
||||||
extern void MarkObjectDistributed(const ObjectAddress *distAddress);
|
extern void MarkObjectDistributed(const ObjectAddress *distAddress);
|
||||||
extern void MarkObjectDistributedWithName(const ObjectAddress *distAddress, char *name,
|
extern void MarkObjectDistributedWithName(const ObjectAddress *distAddress, char *name,
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
--
|
--
|
||||||
-- SECLABEL
|
-- 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
|
-- first we remove one of the worker nodes to be able to test
|
||||||
-- citus_add_node later
|
-- citus_add_node later
|
||||||
SELECT citus_remove_node('localhost', :worker_2_port);
|
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)
|
(2 rows)
|
||||||
|
|
||||||
RESET citus.enable_metadata_sync;
|
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;
|
SET citus.shard_replication_factor to 1;
|
||||||
-- distributed table
|
-- distributed table
|
||||||
CREATE TABLE a (a int);
|
CREATE TABLE a (a int);
|
||||||
|
@ -43,22 +46,12 @@ CREATE VIEW v_dist AS SELECT * FROM a;
|
||||||
-- distributed function
|
-- distributed function
|
||||||
CREATE FUNCTION notice(text) RETURNS void LANGUAGE plpgsql AS $$
|
CREATE FUNCTION notice(text) RETURNS void LANGUAGE plpgsql AS $$
|
||||||
BEGIN RAISE NOTICE '%', $1; END; $$;
|
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';
|
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.
|
HINT: Connect to worker nodes directly to manually run the same SECURITY LABEL command.
|
||||||
SECURITY LABEL ON VIEW v_dist IS 'citus_classified';
|
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.
|
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;
|
SELECT node_type, result FROM get_citus_tests_label_provider_labels('notice(text)') ORDER BY node_type;
|
||||||
node_type | result
|
node_type | result
|
||||||
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
||||||
|
@ -74,17 +67,9 @@ SELECT node_type, result FROM get_citus_tests_label_provider_labels('v_dist') OR
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
\c - - - :worker_1_port
|
\c - - - :worker_1_port
|
||||||
SECURITY LABEL ON TABLE a IS 'citus_classified';
|
|
||||||
SECURITY LABEL ON FUNCTION notice IS 'citus_unclassified';
|
SECURITY LABEL ON FUNCTION notice IS 'citus_unclassified';
|
||||||
SECURITY LABEL ON VIEW v_dist IS 'citus_classified';
|
SECURITY LABEL ON VIEW v_dist IS 'citus_classified';
|
||||||
\c - - - :master_port
|
\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;
|
SELECT node_type, result FROM get_citus_tests_label_provider_labels('notice(text)') ORDER BY node_type;
|
||||||
node_type | result
|
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"}
|
worker_1 | {"label": "citus_classified", "objtype": "view", "provider": "citus '!tests_label_provider"}
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
DROP TABLE a CASCADE;
|
|
||||||
NOTICE: drop cascades to view v_dist
|
|
||||||
DROP FUNCTION notice;
|
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.log_remote_commands TO on;
|
||||||
SET citus.grep_remote_commands = '%SECURITY LABEL%';
|
SET citus.grep_remote_commands = '%SECURITY LABEL%';
|
||||||
-- we have exactly one provider loaded, so we may not include the provider in the command
|
-- 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';
|
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'
|
NOTICE: issuing SECURITY LABEL FOR "citus '!tests_label_provider" ON ROLE "user 2" IS 'citus_classified'
|
||||||
DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
|
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
|
\c - - - :worker_1_port
|
||||||
SET citus.log_remote_commands TO on;
|
SET citus.log_remote_commands TO on;
|
||||||
SET citus.grep_remote_commands = '%SECURITY LABEL%';
|
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"}
|
worker_1 | {"label": "citus_classified", "objtype": "role", "provider": "citus '!tests_label_provider"}
|
||||||
(2 rows)
|
(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;
|
RESET citus.log_remote_commands;
|
||||||
SECURITY LABEL for "citus '!tests_label_provider" ON ROLE "user 2" IS 'citus ''!unclassified';
|
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;
|
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"user 2"') ORDER BY node_type;
|
||||||
|
@ -156,13 +191,223 @@ 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"}
|
worker_1 | {"label": "citus_classified", "objtype": "role", "provider": "citus '!tests_label_provider"}
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
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;
|
||||||
node_type | result
|
node_type | result
|
||||||
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
||||||
coordinator | {"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 '!unclassified", "objtype": "role", "provider": "citus '!tests_label_provider"}
|
worker_1 | {"label": "citus_classified", "objtype": "table", "provider": "citus '!tests_label_provider"}
|
||||||
(2 rows)
|
(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
|
-- 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.log_remote_commands TO on;
|
||||||
SET citus.grep_remote_commands = '%SECURITY LABEL%';
|
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'
|
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
|
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'
|
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
|
DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx
|
||||||
?column?
|
?column?
|
||||||
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
||||||
|
@ -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"}
|
worker_2 | {"label": "citus '!unclassified", "objtype": "role", "provider": "citus '!tests_label_provider"}
|
||||||
(3 rows)
|
(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
|
-- disable the GUC and check that the command is not propagated
|
||||||
SET citus.enable_alter_role_propagation TO off;
|
SET citus.enable_alter_role_propagation TO off;
|
||||||
SECURITY LABEL ON ROLE user1 IS 'citus_unclassified';
|
SECURITY LABEL ON ROLE user1 IS 'citus_unclassified';
|
||||||
NOTICE: not propagating SECURITY LABEL commands to other nodes
|
NOTICE: not propagating SECURITY LABEL commands to other nodes
|
||||||
HINT: Connect to other nodes directly to manually assign necessary labels.
|
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;
|
SELECT node_type, result FROM get_citus_tests_label_provider_labels('user1') ORDER BY node_type;
|
||||||
node_type | result
|
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"}
|
worker_2 | {"label": "citus_classified", "objtype": "role", "provider": "citus '!tests_label_provider"}
|
||||||
(3 rows)
|
(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
|
\c - - - :worker_2_port
|
||||||
SET citus.log_remote_commands TO on;
|
SET citus.log_remote_commands TO on;
|
||||||
SET citus.grep_remote_commands = '%SECURITY LABEL%';
|
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';
|
SECURITY LABEL ON ROLE user1 IS 'citus ''!unclassified';
|
||||||
NOTICE: not propagating SECURITY LABEL commands to other nodes
|
NOTICE: not propagating SECURITY LABEL commands to other nodes
|
||||||
HINT: Connect to other nodes directly to manually assign necessary labels.
|
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;
|
SELECT node_type, result FROM get_citus_tests_label_provider_labels('user1') ORDER BY node_type;
|
||||||
node_type | result
|
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"}
|
worker_2 | {"label": "citus '!unclassified", "objtype": "role", "provider": "citus '!tests_label_provider"}
|
||||||
(3 rows)
|
(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;
|
RESET citus.enable_alter_role_propagation;
|
||||||
|
\c - - - :master_port
|
||||||
-- cleanup
|
-- 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;
|
RESET citus.log_remote_commands;
|
||||||
DROP ROLE user1, "user 2";
|
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
|
-- 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
|
-- first we remove one of the worker nodes to be able to test
|
||||||
-- citus_add_node later
|
-- 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;
|
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;
|
SET citus.shard_replication_factor to 1;
|
||||||
-- distributed table
|
-- distributed table
|
||||||
CREATE TABLE a (a int);
|
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 $$
|
CREATE FUNCTION notice(text) RETURNS void LANGUAGE plpgsql AS $$
|
||||||
BEGIN RAISE NOTICE '%', $1; END; $$;
|
BEGIN RAISE NOTICE '%', $1; END; $$;
|
||||||
|
|
||||||
SECURITY LABEL ON TABLE a IS 'citus_classified';
|
|
||||||
SECURITY LABEL ON FUNCTION notice IS 'citus_unclassified';
|
SECURITY LABEL ON FUNCTION notice IS 'citus_unclassified';
|
||||||
SECURITY LABEL ON VIEW v_dist IS 'citus_classified';
|
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('notice(text)') ORDER BY node_type;
|
||||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('v_dist') 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
|
\c - - - :worker_1_port
|
||||||
SECURITY LABEL ON TABLE a IS 'citus_classified';
|
|
||||||
SECURITY LABEL ON FUNCTION notice IS 'citus_unclassified';
|
SECURITY LABEL ON FUNCTION notice IS 'citus_unclassified';
|
||||||
SECURITY LABEL ON VIEW v_dist IS 'citus_classified';
|
SECURITY LABEL ON VIEW v_dist IS 'citus_classified';
|
||||||
|
|
||||||
\c - - - :master_port
|
\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('notice(text)') ORDER BY node_type;
|
||||||
SELECT node_type, result FROM get_citus_tests_label_provider_labels('v_dist') 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;
|
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.log_remote_commands TO on;
|
||||||
SET citus.grep_remote_commands = '%SECURITY LABEL%';
|
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 ON ROLE user1 IS 'citus_unclassified';
|
||||||
SECURITY LABEL for "citus '!tests_label_provider" ON ROLE "user 2" IS 'citus_classified';
|
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
|
\c - - - :worker_1_port
|
||||||
SET citus.log_remote_commands TO on;
|
SET citus.log_remote_commands TO on;
|
||||||
SET citus.grep_remote_commands = '%SECURITY LABEL%';
|
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';
|
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('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;
|
RESET citus.log_remote_commands;
|
||||||
SECURITY LABEL for "citus '!tests_label_provider" ON ROLE "user 2" IS 'citus ''!unclassified';
|
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;
|
SELECT node_type, result FROM get_citus_tests_label_provider_labels('"user 2"') ORDER BY node_type;
|
||||||
\c - - - :master_port
|
\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('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
|
-- 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.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('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('"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
|
-- disable the GUC and check that the command is not propagated
|
||||||
SET citus.enable_alter_role_propagation TO off;
|
SET citus.enable_alter_role_propagation TO off;
|
||||||
SECURITY LABEL ON ROLE user1 IS 'citus_unclassified';
|
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('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
|
\c - - - :worker_2_port
|
||||||
SET citus.log_remote_commands TO on;
|
SET citus.log_remote_commands TO on;
|
||||||
SET citus.grep_remote_commands = '%SECURITY LABEL%';
|
SET citus.grep_remote_commands = '%SECURITY LABEL%';
|
||||||
SET citus.enable_alter_role_propagation TO off;
|
SET citus.enable_alter_role_propagation TO off;
|
||||||
SECURITY LABEL ON ROLE user1 IS 'citus ''!unclassified';
|
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('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;
|
RESET citus.enable_alter_role_propagation;
|
||||||
|
|
||||||
|
\c - - - :master_port
|
||||||
-- cleanup
|
-- 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;
|
RESET citus.log_remote_commands;
|
||||||
DROP ROLE user1, "user 2";
|
DROP ROLE user1, "user 2";
|
||||||
|
DROP SCHEMA label_test CASCADE;
|
||||||
|
|
Loading…
Reference in New Issue