deriva-acl-config¶
Using deriva-acl-config to configure ACLs¶
The deriva-acl-config
utility reads a configuration file and uses it to set ACLs for an ermrest catalog (or for a schema or table within that catalog). Usage is:
deriva-acl-config
[-g
|--groups-only
] [-n
|--dryrun
] [-v
|--verbose
] [-s
|--schema
schema] [-t
|--table
table] [--host host
] [--config-file
config_file] [--credential-file
credential_file] catalog
where the required arguments are:
catalog: an ermrest catalog number (e.g., 1)
--config_file
file: the name of a configuration file
Options are:
-credential_file
file: read credentials from the named file (if not specified, look for credentials maintained by deriva-auth
)
--groups-only
: create and populate a group table (used for dynamic ACLs) based on the contents of the config file
--dryrun
: do nothing, just print out the catalog schema that would be applied
--verbose
: verbose, print acls and acl bindings for each object
--schema
schema: operate only on the named schema, not the whole catalog
--table
table: operate only on the named table, not the whole catalog (requires the --schema
option)
--host
host: configure the server on the specified host (default localhost
)
Config file format¶
The config file is a json file divided into the following stanzas:
groups
: defines a set of named group lists, which can be used in ACL definitions later in the config file.
group_list_table
: the schema and table name of a table to populate with the information from the groups
stanza, so you can use the same named group lists in both static and dynamic ACLs and maintain them in one place. This table will typically be the last step in most dynamic ACL projections.
acl_definitions
: static ACL definitions (e.g., “{“write”: “consortium”, “select”: “everyone”}) that can be referred to later on in the config file (in this example, consortium
and everyone
are group lists defined in the groups
stanza).
acl_bindings
: dynamic ACL definitions
catalog_acl
: the ACL for the catalog; this will be one of the ACLs defined in the acl_definitions
stanza.
schema_acls
: ACLs for individual schemas. Static ACLs (from acl_definitions
) stanza are assigned to schemas.
table_acls
: ACLs for individual tables. Static ACLs (from acl_definitions
) and dynamic ACLs (from acl_bindings
) are assigned to tabless.
column_acls
: ACLs for individual columns. Static ACLs (from acl_definitions
) and dynamic ACLs (from acl_bindings
) are assigned to columns
foreign_key_acls
: ACLs for foreign keys. Static ACLs (from acl_definitions
) and dynamic ACLs (from acl_bindings
) are assigned to foreign keys
The groups stanza¶
The groups
stanza is a list of entries of the form
name: [values]
where name is a name that will be used to refer to a set of groups, and values is a list of group entries. The entries can be either the actual group IDs (from webauthn) or names of previously-defined groups. For example:
"groups" : {
"empty": [],
"public": ["*"],
"isrd-staff": ["https://auth.globus.org/176baec4-ed26-11e5-8e88-22000ab4b42b"],
"isrd-systems": ["https://auth.globus.org/3938e0d0-ed35-11e5-8641-22000ab4b42b"],
"isrd-testers": ["https://auth.globus.org/9d596ac6-22b9-11e6-b519-22000aef184d"],
"isrd-all": ["isrd-staff", "isrd-systems", "isrd-testers"]
}
The group_list_table stanza¶
If you’re defining dynamic ACLs, at some point you’ll probably want a table in your catalog somewhere that maps names to lists of groups. The group_list_table stanza specifies the schema and table name of a table to create for this list of groups. For example:
"group_list_table" : {"schema" : "_acl_admin", "table" : "group_lists"}
This will cause the _acl_admin.group_lists
table to be created (if it doesn’t already exist) and populated with the information specified in the groups
stanza. The name
column of the table will be the primary key and will contain group name, and the groups
column will be the fully-expanded group list. The example groups
stanza above will create this table:
name | groups
--------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
isrd-staff | {https://auth.globus.org/176baec4-ed26-11e5-8e88-22000ab4b42b}
isrd-testers | {https://auth.globus.org/9d596ac6-22b9-11e6-b519-22000aef184d}
isrd-systems | {https://auth.globus.org/3938e0d0-ed35-11e5-8641-22000ab4b42b}
isrd-all | {https://auth.globus.org/176baec4-ed26-11e5-8e88-22000ab4b42b,https://auth.globus.org/9d596ac6-22b9-11e6-b519-22000aef184d,https://auth.globus.org/3938e0d0-ed35-11e5-8641-22000ab4b42b}
public | {*}
empty | {}
The acl_definitions stanza¶
This is where you define static ACLs for later use. The syntax is a list of
name: value
entries, where the name is a name you can refer to later, to assign these ACLs to objects, and the value is the ACL itself (which will probably contain references to the groups defined in the groups
stanza). For example:
"acl_definitions" : {
"unrestricted_read" : {"select" : "public", "create": "isrd-systems", "write": "isrd-systems"},
"isrd_read" : {"select" : "isrd-all", "create": "isrd-systems", "write": "isrd-systems"},
"secret" : {"select" : "empty"}
}
In this example, the unrestricted_read
ACL grants read access to everyone and restricts create and write access to the isrd-systems
group; the isrd_read
ACL is the same,except that it grants read access only to the isrd-all
set of groups. Note that this stanza only defines the set of permissions and who they’re associated with; by itself, it doesn’t apply these ACLs to any object in the catalog.
The acl_bindings stanza¶
This is where you define dynamic ACLs for later use. The syntax is a list of
name: value
pairs, where the name is a name you can refer to later, and the value is a dynamic ACL. For example:
"acl_bindings" : {
"a_binding" : {
"scope_acl": "isrd-staff",
"types" : ["select"],
"projection" : [{"outbound_col" : "allowed_groups"}, "groups"],
"projection_type" : "acl"
}
This defines an ACL binding called a_binding
. The syntax of the binding itself is the same as defined in the ermrest ACL docs, with one exception: to specify an outbound foreign key, you can either use ermrest-standard outbound
syntax and use the constraint name, or you can use outbound_col
and specify the name of a column on which a foreign key is defined. It will also populate the scope_acl
based on the referenced group list. For example, if you apply the binding a_binding
to this table:
Column | Type | Modifiers
----------------+------+-----------
my_data | text |
allowed_groups | text | not null
Foreign-key constraints:
"mytable_allowed_groups_fkey" FOREIGN KEY (allowed_groups) REFERENCES _acl_admin.group_lists(name)
then the actual ermrest dynamic ACL will be:
"a_binding" : {
"scope_acl": ["https://auth.globus.org/176baec4-ed26-11e5-8e88-22000ab4b42b"],
"types" : ["select"],
"projection" : [{"outbound" : "mytable_allowed_groups_fkey"}, "groups"],
"projection_type" : "acl"
}
This can be useful if you want to apply the same dynamic ACL to mutliple tables, since each table’s foreign key will have a different name by default.
The catalog_acls stanza¶
This is where ACLs for the catalog itself are set. (Note: there’s a bootstrapping issue for new catalogs - since this tool uses ermrest, you need to already have permission on the catalog before you can set any new permissions). For example:
"catalog_acl" : {"acl" : "unrestricted_read"}
This applies the unrestricted_read
ACL defined above to the catalog.
The schema_acls stanza¶
This is where ACLs for schemas are set. The syntax is a list of entries of the form:
{schema_descriptor: value, acl_descriptor: value}
A schema_descriptor is either:
"schema":
schema_name
or
"schema_pattern:"
regular_expression
When setting permissions on a schema:
- if an exact
schema
match is found, the associated ACL is used (and any matchingschema_pattern
entries are ignored). - If no exact
schema
match is found and exactly one matchingschema_pattern
entry is found, then that ACL is used. - If no exact
schema
match is found and more than one matchingschema_pattern
entry is found, then an error is thrown.
An acl descriptor has the form
"acl":
name_of_acl_defined_earlier
or
"no_acl": true
If an acl
is specified, the named static ACL is expanded and applied to the schema. If no_acl
is specified, no ACL is applied to the schema (and as a result, it inherits whatever permissions are set by the catalog ACL).
For example:
"schema_acls" : [
{"schema" : "Vocabulary", "no_acl" : "true"},
{"schema" : "ISRD_Internal", "acl" : "isrd_read"},
{"schema_pattern" : ".*", "acl": "secret"}
]
This, paired with the catalog_acl stanza above, allows anyone to read the Vocabulary schema and ISRD people to read the “ISRD_Internal”. It forbids anyone from reading any other schema in the catalog.
The table_acls stanza¶
This is where ACLs for tables are set. The syntax is a list of entries of the form: {schema_descriptor, table_descriptor, [acl_descriptor], [acl_bindings_descriptor]} A schema descriptor has the same form as in the schema_acls stanza.
A table_descriptor is either:
"table":
table_name
or
"table_pattern:"
regular_expression
Regular expression matching is used:
- If an entry with an exact
schema
andtable
match is found, the associated ACL is used (and any other matching entries are ignored). - Otherwise, if entry with an exact
schema
match and exactly onetable_pattern
match is found, that ACL is used. - Otherwise, if exactly one entry with a
schema_pattern
andtable_pattern
match is found, that ACL is used. - If none of the above is true, and multiple matching entries are found, then an error is thrown.
An acl_descriptor is the same as defined above.
An acl_bindings_descriptor
has the form:
"acl_bindings":
[list_of_bindings]`
where list_of_bindings is a list of ACL bindings defined in the acl_bindings stanza.
The column_acls stanza¶
This is where ACLs for columns are set. The syntax is a list of entries of the form: {schema_descriptor, table_descriptor, column_descriptor, [acl_descriptor], [acl_bindings_descriptor] [invalidate_bindings_descriptor]} The schema, table, acl, and acl_bindings descriptors have the same form as above. The column_descriptor is either:
"column":
table_name
or
"column_pattern:"
regular_expression
Regular expression matching is used:
- If an entry with exact
schema
,table
, andcolumn
matches is found, the associated ACL is used (and any other matching entries are ignored). - Otherwise, if exactly one entry is found with
schema
,table
, andcolumn
matches is found, that ACL is used - If multiple regular-expression matches are found and no exact match is found, an exception is thrown.
The invalidate_bindings
descriptor has the form:
"invalidate_bindings"
: [list_of_bindings]
where list_of_bindings is a list of bindng names to invalidate (i.e., ACL bindings that were defined on the column’s table but that should not be applied to the column).
The foreign_key_acls stanza¶
This is where ACLs for foreign keys are set. The syntax is a list of entries of the form:
{schema_descriptor, table_descriptor, fkey_schema_descriptor, fkey_name_descriptor, [acl_descriptor], [acl_bindings_descriptor], [invalidate_bindings_descriptor]}
The schema, table, acl, acl_bindings, and invalidate_bindings descriptors have the same form as above. The fkey_schema_descriptor is either:
"foreign_key_schema":
foreign_key_schema_name
or
"foreign_key_schema_pattern":
regular_expression
The fkey_name_descriptor is either:
"foreign_key":
foreign_key_name
or
"foreign_key_pattern":
regular_expression
These specify the foreign key schema and name. As with the column_acls stanza:
- If an exact match is found, it’s used
- If no exact match is found and exactly one regular expression match is found, it’s used.
- If no exact match is found and more than one regular expression match is found, an error is thrown.
Security Considerations¶
There’s no guarantee of the order in which changes will be applied. For example, if your current state restricts access to a table, like this:
"table_acls" : [
{"schema" : "myschema", "table" : "mytable", "acl": "restricted_access"}
]
and you decide to change to a configuration that restricts access only to one sensitive column in that table:
"table_acls" : [
{"schema" : "myschema", "table" : "mytable", "acl": "open_access"}
],
"column_acls" : [
{"schema" : "myschema", "table" : "mytable", "column" : "sensitive_column", "acl": "restricted_access"}
]
then it’s possible that the change to the table ACL will occur before the change to the column ACL, temporarily exposing the table and all its columns. The solution is to run acl_config
in two passes, first adding the new restrictions and then removing the old ones.