Skip to content

Commit 9699c43

Browse files
authored
extend rego rule coverage (#739)
1 parent fa49221 commit 9699c43

File tree

2 files changed

+251
-0
lines changed

2 files changed

+251
-0
lines changed

tests/templates/kuttl/opa/12-rego-rules.txt.j2

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ data:
2222
matches_identity(acl.identity)
2323
matches_resource(input.namespace, checked_table_name, acl.resource)
2424
action_sufficient_for_operation(acl.action, input.action)
25+
matches_operation(acl, input.operation)
26+
matches_families(acl, input.families)
2527
}
2628

2729
# Identity mentions the (long) userName explicitly
@@ -84,6 +86,30 @@ data:
8486
"CREATE": "full",
8587
"WRITE": "rw",
8688
"READ": "ro",
89+
"EXEC": "full",
90+
}
91+
92+
# If the ACL does not restrict operations, all operation types are permitted.
93+
matches_operation(acl, _) if {
94+
not acl.operations
95+
}
96+
97+
# If the ACL restricts operations, the requested OpType must be in the permitted set.
98+
matches_operation(acl, operation) if {
99+
acl.operations
100+
operation in acl.operations
101+
}
102+
103+
# If the ACL does not restrict families, all column families are permitted.
104+
matches_families(acl, _) if {
105+
not acl.families
106+
}
107+
108+
# If the ACL restricts families, every family present in the request must be allowed.
109+
# An empty families map (namespace-scoped or unfiltered scan) always passes.
110+
matches_families(acl, families) if {
111+
acl.families
112+
count({f | f := object.keys(families)[_]; not f in acl.families}) == 0
87113
}
88114

89115
groups_for_user := {
@@ -114,5 +140,9 @@ data:
114140
"identity": "user:readonlyuser/access-hbase.$NAMESPACE.svc.cluster.local@CLUSTER.LOCAL",
115141
"action": "ro",
116142
"resource": "hbase:namespace:",
143+
# Restrict to read-only operation types; exercises matches_operation non-null branch.
144+
"operations": ["EXISTS", "GET", "SCAN", "NONE"],
145+
# Restrict to known column families; exercises matches_families non-null branch.
146+
"families": ["cf1"],
117147
},
118148
]

tests/templates/kuttl/opa/41-access-hbase.yaml.j2

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,102 @@ data:
128128
exit;
129129
EOF4
130130

131+
# Tests get, delete, and append within the developer's own namespace.
132+
cat > /tmp/dev-extra-script << 'EOF5'
133+
get 'developers:test', 'row1';
134+
delete 'developers:test', 'row1', 'cf1';
135+
append 'developers:test', 'row2', 'cf1', 'extra';
136+
exit;
137+
EOF5
138+
139+
# Admin creates/disables/drops a table; takes a snapshot, clones it, restores it, then cleans up.
140+
# Covers: preCreateTable, preDisableTable, preDeleteTable, preSnapshot, preCloneSnapshot,
141+
# preListSnapshot, preRestoreSnapshot, preEnableTable, preDeleteSnapshot.
142+
cat > /tmp/admin-ddl-script << 'EOF6'
143+
create 'developers:admin_table', 'cf1';
144+
disable 'developers:admin_table';
145+
drop 'developers:admin_table';
146+
snapshot 'developers:test', 'test_snap';
147+
clone_snapshot 'test_snap', 'developers:cloned_table';
148+
disable 'developers:cloned_table';
149+
drop 'developers:cloned_table';
150+
list_snapshots;
151+
disable 'developers:test';
152+
restore_snapshot 'test_snap';
153+
enable 'developers:test';
154+
delete_snapshot 'test_snap';
155+
exit;
156+
EOF6
157+
158+
# Developer attempts to write to a namespace they do not own — must be denied.
159+
cat > /tmp/denial-dev-script << 'EOF7'
160+
put 'public:test', 'rowX', 'cf1', 'unauthorized';
161+
exit;
162+
EOF7
163+
164+
# Read-only user attempts a write — must be denied.
165+
cat > /tmp/denial-readonly-script << 'EOF8'
166+
put 'developers:test', 'row4', 'cf1', 'unauthorized';
167+
exit;
168+
EOF8
169+
170+
# Developer checks existence, increments a counter, and describes own table and namespace.
171+
# Covers: preExists, preIncrement, preGetTableDescriptors/postGetTableDescriptors,
172+
# preGetNamespaceDescriptor.
173+
cat > /tmp/dev-describe-script << 'EOF9'
174+
exists 'developers:test', 'row2';
175+
incr 'developers:test', 'counter_row', 'cf1:counter', 5;
176+
describe 'developers:test';
177+
describe_namespace 'developers';
178+
exit;
179+
EOF9
180+
181+
# Developer lists all tables — only own namespace should appear in the results.
182+
# Covers: postGetTableNames (filtered per-user).
183+
cat > /tmp/dev-list-script << 'EOF10'
184+
list;
185+
exit;
186+
EOF10
187+
188+
# Admin manages namespaces and tables, and exercises global admin commands.
189+
# Covers: preModifyNamespace, preDeleteNamespace, preTableFlush, preModifyTable,
190+
# preTruncateTable, preBalance, preBalanceSwitch, preGetProcedures, preGetLocks.
191+
cat > /tmp/admin-extended-script << 'EOF11'
192+
create_namespace 'temp_ns';
193+
alter_namespace 'temp_ns', {NAME => 'temp_ns'};
194+
drop_namespace 'temp_ns';
195+
create 'developers:mgmt_table', 'cf1';
196+
flush 'developers:mgmt_table';
197+
alter 'developers:mgmt_table', {NAME => 'cf1', COMPRESSION => 'NONE'};
198+
create 'developers:truncate_me', 'cf1';
199+
truncate 'developers:truncate_me';
200+
disable 'developers:truncate_me';
201+
drop 'developers:truncate_me';
202+
disable 'developers:mgmt_table';
203+
drop 'developers:mgmt_table';
204+
balancer;
205+
balance_switch false;
206+
balance_switch true;
207+
list_procedures;
208+
list_locks;
209+
exit;
210+
EOF11
211+
212+
# Readonlyuser exercises read operations — exercises the matches_families Rego branch
213+
# (ACL restricts readonlyuser to cf1; an empty families map on get/exists always passes).
214+
cat > /tmp/readonly-extended-script << 'EOF12'
215+
get 'developers:test', 'row2';
216+
exists 'developers:test', 'row2';
217+
exit;
218+
EOF12
219+
220+
# Developer attempts to describe a namespace they do not own — must be denied.
221+
# Covers: preGetNamespaceDescriptor (denial path).
222+
cat > /tmp/denial-dev-describe-public-script << 'EOF13'
223+
describe_namespace 'public';
224+
exit;
225+
EOF13
226+
131227
#------------------------------------------
132228
# Admin should be able to create namespaces
133229
#------------------------------------------
@@ -193,5 +289,130 @@ data:
193289
exit 1
194290
fi
195291

292+
#--------------------------------------------------------
293+
# Developer should be able to get, delete and append in own namespace
294+
# (covers preGetOp, preDelete, preAppend)
295+
#--------------------------------------------------------
296+
kdestroy; kinit -kt /stackable/kerberos/keytab developer/access-hbase.$NAMESPACE.svc.cluster.local; klist
297+
298+
expected=$(bin/hbase shell /tmp/dev-extra-script 2>&1 | grep 'Took ' | wc -l)
299+
if [ $expected == 3 ]; then
300+
echo "Test passed"
301+
else
302+
echo "Test failed"
303+
exit 1
304+
fi
305+
306+
#--------------------------------------------------------
307+
# Developer can check existence, increment a counter, and describe own table and namespace
308+
# (covers preExists, preIncrement, preGetTableDescriptors, preGetNamespaceDescriptor)
309+
#--------------------------------------------------------
310+
kdestroy; kinit -kt /stackable/kerberos/keytab developer/access-hbase.$NAMESPACE.svc.cluster.local; klist
311+
312+
expected=$(bin/hbase shell /tmp/dev-describe-script 2>&1 | grep 'Took ' | wc -l)
313+
if [ $expected == 4 ]; then
314+
echo "Test passed"
315+
else
316+
echo "Test failed"
317+
exit 1
318+
fi
319+
320+
#--------------------------------------------------------
321+
# Developer list is filtered to own namespace (covers postGetTableNames)
322+
#--------------------------------------------------------
323+
list_output=$(bin/hbase shell /tmp/dev-list-script 2>&1)
324+
in_list=$(echo "$list_output" | grep 'developers:test' | wc -l)
325+
not_in_list=$(echo "$list_output" | grep 'public:test' | wc -l)
326+
if [ $in_list -gt 0 ] && [ $not_in_list -eq 0 ]; then
327+
echo "Test passed"
328+
else
329+
echo "Test failed"
330+
exit 1
331+
fi
332+
333+
#--------------------------------------------------------
334+
# Admin should be able to perform table DDL and snapshot operations
335+
# (covers preCreateTable, preDisableTable, preDeleteTable,
336+
# preSnapshot, preCloneSnapshot, preListSnapshot,
337+
# preRestoreSnapshot, preEnableTable, preDeleteSnapshot)
338+
#--------------------------------------------------------
339+
kdestroy; kinit -kt /stackable/kerberos/keytab admin/access-hbase.$NAMESPACE.svc.cluster.local; klist
340+
341+
expected=$(bin/hbase shell /tmp/admin-ddl-script 2>&1 | grep 'Took ' | wc -l)
342+
if [ $expected == 12 ]; then
343+
echo "Test passed"
344+
else
345+
echo "Test failed"
346+
exit 1
347+
fi
348+
349+
#--------------------------------------------------------
350+
# Admin can manage namespaces/tables and run global admin commands
351+
# (covers preModifyNamespace, preDeleteNamespace, preTableFlush, preModifyTable,
352+
# preTruncateTable, preBalance, preBalanceSwitch, preGetProcedures, preGetLocks)
353+
#--------------------------------------------------------
354+
expected=$(bin/hbase shell /tmp/admin-extended-script 2>&1 | grep 'Took ' | wc -l)
355+
if [ $expected == 17 ]; then
356+
echo "Test passed"
357+
else
358+
echo "Test failed"
359+
exit 1
360+
fi
361+
362+
#--------------------------------------------------------
363+
# Readonlyuser can read rows (exercises matches_families non-null branch in Rego)
364+
#--------------------------------------------------------
365+
kdestroy; kinit -kt /stackable/kerberos/keytab readonlyuser/access-hbase.$NAMESPACE.svc.cluster.local; klist
366+
367+
expected=$(bin/hbase shell /tmp/readonly-extended-script 2>&1 | grep 'Took ' | wc -l)
368+
if [ $expected == 2 ]; then
369+
echo "Test passed"
370+
else
371+
echo "Test failed"
372+
exit 1
373+
fi
374+
375+
#--------------------------------------------------------
376+
# Developer should NOT be able to write to another namespace
377+
# (denial: prePut on public:test)
378+
#--------------------------------------------------------
379+
kdestroy; kinit -kt /stackable/kerberos/keytab developer/access-hbase.$NAMESPACE.svc.cluster.local; klist
380+
381+
expected=$(bin/hbase shell /tmp/denial-dev-script 2>&1 | grep 'OPA denied the request' | wc -l)
382+
if [ $expected -gt 0 ]; then
383+
echo "Test passed"
384+
else
385+
echo "Test failed"
386+
exit 1
387+
fi
388+
389+
#--------------------------------------------------------
390+
# Readonlyuser should NOT be able to write
391+
# (denial: prePut on developers:test)
392+
#--------------------------------------------------------
393+
kdestroy; kinit -kt /stackable/kerberos/keytab readonlyuser/access-hbase.$NAMESPACE.svc.cluster.local; klist
394+
395+
expected=$(bin/hbase shell /tmp/denial-readonly-script 2>&1 | grep 'OPA denied the request' | wc -l)
396+
if [ $expected -gt 0 ]; then
397+
echo "Test passed"
398+
else
399+
echo "Test failed"
400+
exit 1
401+
fi
402+
403+
#--------------------------------------------------------
404+
# Developer cannot describe a namespace they do not own
405+
# (denial: preGetNamespaceDescriptor on public namespace)
406+
#--------------------------------------------------------
407+
kdestroy; kinit -kt /stackable/kerberos/keytab developer/access-hbase.$NAMESPACE.svc.cluster.local; klist
408+
409+
expected=$(bin/hbase shell /tmp/denial-dev-describe-public-script 2>&1 | grep 'OPA denied the request' | wc -l)
410+
if [ $expected -gt 0 ]; then
411+
echo "Test passed"
412+
else
413+
echo "Test failed"
414+
exit 1
415+
fi
416+
196417
echo "All tests passed!"
197418
exit 0

0 commit comments

Comments
 (0)