Add rbac "roles" and "permissions" tables to ovn southbound database schema.
Signed-off-by: Lance Richardson <lrich...@redhat.com> --- ovn/northd/ovn-northd.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++++ ovn/ovn-sb.ovsschema | 26 ++++++- ovn/ovn-sb.xml | 39 ++++++++++ 3 files changed, 253 insertions(+), 2 deletions(-) diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c index 8c8f16b..412c04d 100644 --- a/ovn/northd/ovn-northd.c +++ b/ovn/northd/ovn-northd.c @@ -5442,6 +5442,182 @@ check_and_add_supported_dhcpv6_opts_to_sb_db(struct northd_context *ctx) hmap_destroy(&dhcpv6_opts_to_add); } +static const char *rbac_chassis_auth[] = + {"chassis"}; +static const char *rbac_chassis_update[] = + {"nb_cfg", "external_ids", "encaps", "vtep_logical_switches"}; + +static const char *rbac_encap_auth[] = + {"chassis"}; +static const char *rbac_encap_update[] = + {"type", "options", "ip"}; + +static const char *rbac_port_binding_auth[] = + {""}; +static const char *rbac_port_binding_update[] = + {"chassis"}; + +static const char *rbac_mac_binding_auth[] = + {""}; +static const char *rbac_mac_binding_update[] = + {"logical_port", "ip", "mac", "datapath"}; + +static struct rbac_perm_cfg { + const char *table; + const char **auth; + int n_auth; + bool insdel; + const char **update; + int n_update; + const struct sbrec_rbac_permission *row; +} rbac_perm_cfg[] = { + { + "Chassis", + rbac_chassis_auth, + ARRAY_SIZE(rbac_chassis_auth), + true, + rbac_chassis_update, + ARRAY_SIZE(rbac_chassis_update), + NULL + },{ + "Encap", + rbac_encap_auth, + ARRAY_SIZE(rbac_encap_auth), + true, + rbac_encap_update, + ARRAY_SIZE(rbac_encap_update), + NULL + },{ + "Port_Binding", + rbac_port_binding_auth, + ARRAY_SIZE(rbac_port_binding_auth), + false, + rbac_port_binding_update, + ARRAY_SIZE(rbac_port_binding_update), + NULL + },{ + "MAC_Binding", + rbac_mac_binding_auth, + ARRAY_SIZE(rbac_mac_binding_auth), + true, + rbac_mac_binding_update, + ARRAY_SIZE(rbac_mac_binding_update), + NULL + }, + {NULL} +}; + +static bool +ovn_rbac_validate_perm(const struct sbrec_rbac_permission *perm) +{ + struct rbac_perm_cfg *pcfg; + int i, j, n_found; + + for (pcfg = rbac_perm_cfg; pcfg->table; pcfg++) { + if (!strcmp(perm->table, pcfg->table)) { + break; + } + } + if (!pcfg->table) { + return false; + } + if (perm->n_authorization != pcfg->n_auth || + perm->n_update != pcfg->n_update) { + return false; + } + if (perm->insert_delete != pcfg->insdel) { + return false; + } + /* verify perm->authorization vs. pcfg->auth */ + n_found = 0; + for (i = 0; i < pcfg->n_auth; i++) { + for (j = 0; j < perm->n_authorization; j++) { + if (!strcmp(pcfg->auth[i], perm->authorization[j])) { + n_found++; + break; + } + } + } + if (n_found != pcfg->n_auth) { + return false; + } + + /* verify perm->update vs. pcfg->update */ + n_found = 0; + for (i = 0; i < pcfg->n_update; i++) { + for (j = 0; j < perm->n_update; j++) { + if (!strcmp(pcfg->update[i], perm->update[j])) { + n_found++; + break; + } + } + } + if (n_found != pcfg->n_update) { + return false; + } + + /* Success, db state matches expected state */ + pcfg->row = perm; + return true; +} + +static void +ovn_rbac_create_perm(struct rbac_perm_cfg *pcfg, + struct northd_context *ctx, + const struct sbrec_rbac_role *rbac_role) +{ + struct sbrec_rbac_permission *rbac_perm; + + rbac_perm = sbrec_rbac_permission_insert(ctx->ovnsb_txn); + sbrec_rbac_permission_set_table(rbac_perm, pcfg->table); + sbrec_rbac_permission_set_authorization(rbac_perm, + pcfg->auth, + pcfg->n_auth); + sbrec_rbac_permission_set_insert_delete(rbac_perm, pcfg->insdel); + sbrec_rbac_permission_set_update(rbac_perm, + pcfg->update, + pcfg->n_update); + sbrec_rbac_role_update_permissions_setkey(rbac_role, pcfg->table, + rbac_perm); +} + +static void +check_and_update_rbac(struct northd_context *ctx) +{ + const struct sbrec_rbac_role *rbac_role = NULL; + const struct sbrec_rbac_permission *perm_row, *perm_next; + const struct sbrec_rbac_role *role_row, *role_row_next; + struct rbac_perm_cfg *pcfg; + + for (pcfg = rbac_perm_cfg; pcfg->table; pcfg++) { + pcfg->row = NULL; + } + + SBREC_RBAC_PERMISSION_FOR_EACH_SAFE(perm_row, perm_next, ctx->ovnsb_idl) { + if (!ovn_rbac_validate_perm(perm_row)) { + sbrec_rbac_permission_delete(perm_row); + } + } + SBREC_RBAC_ROLE_FOR_EACH_SAFE(role_row, role_row_next, ctx->ovnsb_idl) { + if (strcmp(role_row->name, "ovn-controller")) { + sbrec_rbac_role_delete(role_row); + } else { + rbac_role = role_row; + } + } + + if (!rbac_role) { + rbac_role = sbrec_rbac_role_insert(ctx->ovnsb_txn); + sbrec_rbac_role_set_name(rbac_role, "ovn-controller"); + } + + for (pcfg = rbac_perm_cfg; pcfg->table; pcfg++) { + if (!pcfg->row) { + ovn_rbac_create_perm(pcfg, ctx, rbac_role); + } + } +} + /* Updates the sb_cfg and hv_cfg columns in the northbound NB_Global table. */ static void update_northbound_cfg(struct northd_context *ctx, @@ -5653,6 +5829,19 @@ main(int argc, char *argv[]) add_column_noalert(ovnsb_idl_loop.idl, &sbrec_address_set_col_name); add_column_noalert(ovnsb_idl_loop.idl, &sbrec_address_set_col_addresses); + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_rbac_role); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_rbac_role_col_name); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_rbac_role_col_permissions); + + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_rbac_permission); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_rbac_permission_col_table); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_rbac_permission_col_authorization); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_rbac_permission_col_insert_delete); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_rbac_permission_col_update); + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_chassis); ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_nb_cfg); @@ -5671,6 +5860,7 @@ main(int argc, char *argv[]) if (ctx.ovnsb_txn) { check_and_add_supported_dhcp_opts_to_sb_db(&ctx); check_and_add_supported_dhcpv6_opts_to_sb_db(&ctx); + check_and_update_rbac(&ctx); } unixctl_server_run(unixctl); diff --git a/ovn/ovn-sb.ovsschema b/ovn/ovn-sb.ovsschema index 0212a5e..8b2c9cc 100644 --- a/ovn/ovn-sb.ovsschema +++ b/ovn/ovn-sb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Southbound", "version": "1.9.0", - "cksum": "2240045372 9719", + "cksum": "2346040377 10748", "tables": { "SB_Global": { "columns": { @@ -173,6 +173,7 @@ "min": 0, "max": 1}}, "read_only": {"type": "boolean"}, + "role": {"type": "string"}, "other_config": {"type": {"key": "string", "value": "string", "min": 0, @@ -198,4 +199,25 @@ "value": "string", "min": 0, "max": "unlimited"}}}, - "maxRows": 1}}} + "maxRows": 1}, + "RBAC_Role": { + "columns": { + "name": {"type": "string"}, + "permissions": { + "type": {"key": {"type": "string"}, + "value": {"type": "uuid", + "refTable": "RBAC_Permission", + "refType": "weak"}, + "min": 0, "max": "unlimited"}}}, + "isRoot": true}, + "RBAC_Permission": { + "columns": { + "table": {"type": "string"}, + "authorization": {"type": {"key": "string", + "min": 0, + "max": "unlimited"}}, + "insert_delete": {"type": "boolean"}, + "update" : {"type": {"key": "string", + "min": 0, + "max": "unlimited"}}}, + "isRoot": true}}} diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml index 4e95c80..3bd8aa1 100644 --- a/ovn/ovn-sb.xml +++ b/ovn/ovn-sb.xml @@ -2479,6 +2479,9 @@ tcp.flags = RST; <code>true</code> to restrict these connections to read-only transactions, <code>false</code> to allow them to modify the database. </column> + <column name="role"> + String containing name of role for this connection entry. + </column> </group> <group title="Client Failure Detection and Handling"> @@ -2653,4 +2656,40 @@ tcp.flags = RST; <column name="external_ids"/> </group> </table> + <table name="RBAC_Role"> + Roles table for role-based access controls. + + <column name="name"> + String containing the role name, corresponding to the <code>role</code> + column in the <code>Connection</code> table. + </column> + + <column name="permissions"> + A string:uuid map mapping table names to rows in the + <code>RBAC_Permission</code> table. + </column> + </table> + <table name="RBAC_Permission"> + Permissions table for role-based access controls. + + <column name="table"> + Name of table to which this row applies. + </column> + + <column name="authorization"> + Set of strings identifying columns and column:key pairs to be compared + with client ID. At least one match is required in order to be + authorized. A zero-length string is treated as a special value + indicating all clients should be considered authorized. + </column> + + <column name="insert_delete"> + Boolean value, if "true" then row insertions and authorized row + deletions are allowed. + </column> + <column name="update"> + Set of strings identifying columns and column:key pairs that authorized + clients are allowed to modify. + </column> + </table> </database> -- 2.7.4 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev