|
| 1 | +# Copied from tests/templates/kuttl/kerberos/12-rego-rules.yaml |
| 2 | +--- |
| 3 | +apiVersion: v1 |
| 4 | +kind: ConfigMap |
| 5 | +metadata: |
| 6 | + name: hdfs-regorules |
| 7 | + labels: |
| 8 | + opa.stackable.tech/bundle: "true" |
| 9 | +data: |
| 10 | + hdfs.rego: | |
| 11 | + package hdfs |
| 12 | +
|
| 13 | + import rego.v1 |
| 14 | +
|
| 15 | + default allow = false |
| 16 | +
|
| 17 | + # HDFS authorizer |
| 18 | + allow if { |
| 19 | + some acl in acls |
| 20 | + matches_identity(input.callerUgi.shortUserName, acl.identity) |
| 21 | + matches_resource(input.path, acl.resource) |
| 22 | + action_sufficient_for_operation(acl.action, input.operationName) |
| 23 | + } |
| 24 | +
|
| 25 | + # HDFS group mapper (this returns a list of strings) |
| 26 | + groups := {group | |
| 27 | + raw = groups_for_user[input.username][_] |
| 28 | + # Keycloak groups have trailing slashes |
| 29 | + group := trim_prefix(raw, "/") |
| 30 | + } |
| 31 | +
|
| 32 | + # Identity mentions the user explicitly |
| 33 | + matches_identity(user, identity) if { |
| 34 | + identity == concat("", ["user:", user]) |
| 35 | + } |
| 36 | +
|
| 37 | + # Identity mentions group the user is part of |
| 38 | + matches_identity(user, identity) if { |
| 39 | + some group in groups_for_user[user] |
| 40 | + identity == concat("", ["group:", group]) |
| 41 | + } |
| 42 | +
|
| 43 | + # Resource mentions the file explicitly |
| 44 | + matches_resource(file, resource) if { |
| 45 | + resource == concat("", ["hdfs:file:", file]) |
| 46 | + } |
| 47 | +
|
| 48 | + # Resource mentions the directory explicitly |
| 49 | + matches_resource(file, resource) if { |
| 50 | + trim_suffix(resource, "/") == concat("", ["hdfs:dir:", file]) |
| 51 | + } |
| 52 | +
|
| 53 | + # Resource mentions a folder higher up the tree, which will will grant access recursively |
| 54 | + matches_resource(file, resource) if { |
| 55 | + startswith(resource, "hdfs:dir:/") |
| 56 | + # directories need to have a trailing slash |
| 57 | + endswith(resource, "/") |
| 58 | + startswith(file, trim_prefix(resource, "hdfs:dir:")) |
| 59 | + } |
| 60 | +
|
| 61 | + action_sufficient_for_operation(action, operation) if { |
| 62 | + action_hierarchy[action][_] == action_for_operation[operation] |
| 63 | + } |
| 64 | +
|
| 65 | + action_hierarchy := { |
| 66 | + "full": ["full", "rw", "ro"], |
| 67 | + "rw": ["rw", "ro"], |
| 68 | + "ro": ["ro"], |
| 69 | + } |
| 70 | +
|
| 71 | + # To get a (hopefully complete) list of actions run "ack 'String operationName = '" in the hadoop source code |
| 72 | + action_for_operation := { |
| 73 | + # The "rename" operation will be actually called on both - the source and the target location. |
| 74 | + # Because of this you need to have rw permissions on the source and target file - which is desired |
| 75 | +
|
| 76 | + "abandonBlock": "rw", |
| 77 | + "addCacheDirective": "rw", |
| 78 | + "addCachePool": "full", |
| 79 | + "addErasureCodingPolicies": "full", |
| 80 | + "allowSnapshot": "full", |
| 81 | + "append": "rw", |
| 82 | + "cancelDelegationToken": "ro", |
| 83 | + "checkAccess": "ro", |
| 84 | + "clearQuota": "full", |
| 85 | + "clearSpaceQuota": "full", |
| 86 | + "completeFile": "rw", |
| 87 | + "computeSnapshotDiff": "full", |
| 88 | + "concat": "rw", |
| 89 | + "contentSummary": "ro", |
| 90 | + "create": "rw", |
| 91 | + "createEncryptionZone": "full", |
| 92 | + "createSnapshot": "full", |
| 93 | + "createSymlink": "rw", |
| 94 | + "delete": "rw", |
| 95 | + "deleteSnapshot": "full", |
| 96 | + "disableErasureCodingPolicy": "full", |
| 97 | + "disallowSnapshot": "full", |
| 98 | + "enableErasureCodingPolicy": "full", |
| 99 | + "finalizeRollingUpgrade": "full", |
| 100 | + "fsck": "full", |
| 101 | + "fsckGetBlockLocations": "full", |
| 102 | + "fsync": "rw", |
| 103 | + "gcDeletedSnapshot": "full", |
| 104 | + "getAclStatus": "ro", |
| 105 | + "getAdditionalBlock": "ro", |
| 106 | + "getAdditionalDatanode": "ro", |
| 107 | + "getDelegationToken": "ro", |
| 108 | + "getECTopologyResultForPolicies": "ro", |
| 109 | + "getErasureCodingCodecs": "ro", |
| 110 | + "getErasureCodingPolicies": "ro", |
| 111 | + "getErasureCodingPolicy": "ro", |
| 112 | + "getEZForPath": "ro", |
| 113 | + "getfileinfo": "ro", |
| 114 | + "getPreferredBlockSize": "ro", |
| 115 | + "getStoragePolicy": "ro", |
| 116 | + "getXAttrs": "ro", |
| 117 | + "isFileClosed": "ro", |
| 118 | + "listCacheDirectives": "ro", |
| 119 | + "listCachePools": "ro", |
| 120 | + "listCorruptFileBlocks": "ro", |
| 121 | + "listEncryptionZones": "ro", |
| 122 | + "listOpenFiles": "ro", |
| 123 | + "listReencryptionStatus": "ro", |
| 124 | + "ListSnapshot": "ro", # Yeah, this really starts with a capital letter |
| 125 | + "listSnapshottableDirectory": "ro", |
| 126 | + "listStatus": "ro", |
| 127 | + "listXAttrs": "ro", |
| 128 | + "mkdirs": "rw", |
| 129 | + "modifyAclEntries": "full", |
| 130 | + "modifyCacheDirective": "rw", |
| 131 | + "modifyCachePool": "full", |
| 132 | + "open": "ro", |
| 133 | + "queryRollingUpgrade": "ro", |
| 134 | + "quotaUsage": "ro", |
| 135 | + "recoverLease": "full", |
| 136 | + "reencryptEncryptionZone": "full", |
| 137 | + "removeAcl": "full", |
| 138 | + "removeAclEntries": "full", |
| 139 | + "removeCacheDirective": "rw", |
| 140 | + "removeCachePool": "full", |
| 141 | + "removeDefaultAcl": "full", |
| 142 | + "removeErasureCodingPolicy": "full", |
| 143 | + "removeXAttr": "rw", |
| 144 | + "rename": "rw", |
| 145 | + "renameSnapshot": "full", |
| 146 | + "renewDelegationToken": "ro", |
| 147 | + "satisfyStoragePolicy": "full", |
| 148 | + "setAcl": "full", |
| 149 | + "setErasureCodingPolicy": "full", |
| 150 | + "setOwner": "full", |
| 151 | + "setPermission": "full", |
| 152 | + "setQuota": "full", |
| 153 | + "setReplication": "full", |
| 154 | + "setSpaceQuota": "full", |
| 155 | + "setStoragePolicy": "full", |
| 156 | + "setTimes": "rw", |
| 157 | + "setXAttr": "rw", |
| 158 | + "startRollingUpgrade": "full", |
| 159 | + "truncate": "rw", |
| 160 | + "unsetErasureCodingPolicy": "full", |
| 161 | + "unsetStoragePolicy": "full", |
| 162 | + } |
| 163 | +
|
| 164 | + # Actions I think are only relevant for the whole filesystem, and not specific to a file or directory |
| 165 | + admin_actions := { |
| 166 | + "checkRestoreFailedStorage": "ro", |
| 167 | + "datanodeReport": "ro", |
| 168 | + "disableRestoreFailedStorage": "full", |
| 169 | + "enableRestoreFailedStorage": "full", |
| 170 | + "finalizeUpgrade": "rw", |
| 171 | + "getDatanodeStorageReport": "ro", |
| 172 | + "metaSave": "ro", |
| 173 | + "monitorHealth": "ro", |
| 174 | + "refreshNodes": "rw", |
| 175 | + "rollEditLog": "rw", |
| 176 | + "saveNamespace": "full", |
| 177 | + "setBalancerBandwidth": "rw", |
| 178 | + "slowDataNodesReport": "ro", |
| 179 | + "transitionToActive": "full", |
| 180 | + "transitionToObserver": "full", |
| 181 | + "transitionToStandby": "full", |
| 182 | + } |
| 183 | +
|
| 184 | + groups_for_user := {"admin": ["admins"], "alice": ["developers"], "bob": []} |
| 185 | +
|
| 186 | + acls := [ |
| 187 | + { |
| 188 | + "identity": "group:admins", |
| 189 | + "action": "full", |
| 190 | + "resource": "hdfs:dir:/", |
| 191 | + }, |
| 192 | + { |
| 193 | + "identity": "group:developers", |
| 194 | + "action": "rw", |
| 195 | + "resource": "hdfs:dir:/developers/", |
| 196 | + }, |
| 197 | + { |
| 198 | + "identity": "group:developers", |
| 199 | + "action": "ro", |
| 200 | + "resource": "hdfs:dir:/developers-ro/", |
| 201 | + }, |
| 202 | + { |
| 203 | + "identity": "user:alice", |
| 204 | + "action": "rw", |
| 205 | + "resource": "hdfs:dir:/alice/", |
| 206 | + }, |
| 207 | + { |
| 208 | + "identity": "user:bob", |
| 209 | + "action": "rw", |
| 210 | + "resource": "hdfs:dir:/bob/", |
| 211 | + }, |
| 212 | + { |
| 213 | + "identity": "user:bob", |
| 214 | + "action": "ro", |
| 215 | + "resource": "hdfs:dir:/developers/", |
| 216 | + }, |
| 217 | + { |
| 218 | + "identity": "user:bob", |
| 219 | + "action": "rw", |
| 220 | + "resource": "hdfs:file:/developers/file-from-bob", |
| 221 | + }, |
| 222 | + ] |
0 commit comments