Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#5336] feat(auth-ranger): Remove MANAGED_BY_GRAVITINO limit and compatible for existing ranger policy #5629

Merged
merged 15 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ public Boolean onRoleDeleted(Role role) throws AuthorizationPluginException {
.toArray(RoleChange[]::new));
// Lastly, delete the role in the Ranger
try {
rangerClient.deleteRole(role.name(), rangerAdminName, rangerServiceName);
rangerClient.deleteRole(
rangerHelper.generateGravitinoRoleName(role.name()), rangerAdminName, rangerServiceName);
} catch (RangerServiceException e) {
// Ignore exception to support idempotent operation
LOG.warn("Ranger delete role: {} failed!", role, e);
Expand Down Expand Up @@ -333,6 +334,8 @@ public Boolean onOwnerSet(MetadataObject metadataObject, Owner preOwner, Owner n
ownerRoleName = RangerHelper.GRAVITINO_CATALOG_OWNER_ROLE;
}
rangerHelper.createRangerRoleIfNotExists(ownerRoleName, true);
rangerHelper.createRangerRoleIfNotExists(
RangerHelper.GRAVITINO_PLACEHOLDER_OWNER_ROLE, true);
try {
if (preOwnerUserName != null || preOwnerGroupName != null) {
GrantRevokeRoleRequest revokeRoleRequest =
Expand Down Expand Up @@ -607,7 +610,6 @@ public Boolean onGroupAcquired(Group group) {
*/
private boolean doAddSecurableObject(String roleName, RangerSecurableObject securableObject) {
RangerPolicy policy = rangerHelper.findManagedPolicy(securableObject);

if (policy != null) {
// Check the policy item's accesses and roles equal the Ranger securable object's privilege
List<RangerPrivilege> allowPrivilies =
Expand All @@ -621,15 +623,23 @@ private boolean doAddSecurableObject(String roleName, RangerSecurableObject secu

Set<RangerPrivilege> policyPrivileges =
policy.getPolicyItems().stream()
.filter(policyItem -> policyItem.getRoles().contains(roleName))
.filter(
policyItem ->
policyItem
.getRoles()
.contains(rangerHelper.generateGravitinoRoleName(roleName)))
.flatMap(policyItem -> policyItem.getAccesses().stream())
.map(RangerPolicy.RangerPolicyItemAccess::getType)
.map(RangerPrivileges::valueOf)
.collect(Collectors.toSet());

Set<RangerPrivilege> policyDenyPrivileges =
policy.getDenyPolicyItems().stream()
.filter(policyItem -> policyItem.getRoles().contains(roleName))
.filter(
policyItem ->
policyItem
.getRoles()
.contains(rangerHelper.generateGravitinoRoleName(roleName)))
.flatMap(policyItem -> policyItem.getAccesses().stream())
.map(RangerPolicy.RangerPolicyItemAccess::getType)
.map(RangerPrivileges::valueOf)
Expand Down Expand Up @@ -721,11 +731,7 @@ private boolean doRemoveSecurableObject(
&& policyItem.getGroups().isEmpty());

try {
if (policy.getPolicyItems().isEmpty() && policy.getDenyPolicyItems().isEmpty()) {
rangerClient.deletePolicy(policy.getId());
} else {
rangerClient.updatePolicy(policy.getId(), policy);
}
rangerClient.updatePolicy(policy.getId(), policy);
} catch (RangerServiceException e) {
LOG.error("Failed to remove the policy item from the Ranger policy {}!", policy);
throw new AuthorizationPluginException(
Expand All @@ -738,6 +744,7 @@ private void removePolicyItemIfEqualRoleName(
RangerPolicy.RangerPolicyItem policyItem,
RangerSecurableObject rangerSecurableObject,
String roleName) {
roleName = rangerHelper.generateGravitinoRoleName(roleName);
boolean match =
policyItem.getAccesses().stream()
.allMatch(
Expand Down Expand Up @@ -974,7 +981,23 @@ private void removePolicyByMetadataObject(List<String> metadataNames) {
.forEach(
policy -> {
try {
rangerClient.deletePolicy(policy.getId());
policy.setPolicyItems(
policy.getPolicyItems().stream()
.filter(i -> !rangerHelper.isGravitinoManagedPolicyItemAccess(i))
.collect(Collectors.toList()));
policy.setDenyPolicyItems(
policy.getDenyPolicyItems().stream()
.filter(i -> !rangerHelper.isGravitinoManagedPolicyItemAccess(i))
.collect(Collectors.toList()));
policy.setRowFilterPolicyItems(
policy.getRowFilterPolicyItems().stream()
.filter(i -> !rangerHelper.isGravitinoManagedPolicyItemAccess(i))
.collect(Collectors.toList()));
policy.setDataMaskPolicyItems(
policy.getDataMaskPolicyItems().stream()
.filter(i -> !rangerHelper.isGravitinoManagedPolicyItemAccess(i))
.collect(Collectors.toList()));
rangerClient.updatePolicy(policy.getId(), policy);
} catch (RangerServiceException e) {
LOG.error("Failed to rename the policy {}!", policy);
throw new RuntimeException(e);
Expand Down Expand Up @@ -1003,25 +1026,29 @@ private void updatePolicyByMetadataObject(
.forEach(
policy -> {
try {
// Update the policy name
String policyName = policy.getName();
List<String> policyNames = Lists.newArrayList(DOT_SPLITTER.splitToList(policyName));
Preconditions.checkArgument(
policyNames.size() >= oldMetadataNames.size(),
String.format("The policy name(%s) is invalid!", policyName));
int index = operationTypeIndex.get(operationType);
if (policyNames.get(index).equals(RangerHelper.RESOURCE_ALL)) {
// Doesn't need to rename the policy `*`
return;

// Update the policy name is following Gravitino's spec
if (policy.getName().equals(DOT_JOINER.join(oldMetadataNames))) {
List<String> policyNames =
Lists.newArrayList(DOT_SPLITTER.splitToList(policyName));
Preconditions.checkArgument(
policyNames.size() >= oldMetadataNames.size(),
String.format("The policy name(%s) is invalid!", policyName));
if (policyNames.get(index).equals(RangerHelper.RESOURCE_ALL)) {
// Doesn't need to rename the policy `*`
return;
}
policyNames.set(index, newMetadataNames.get(index));
policy.setName(DOT_JOINER.join(policyNames));
}
policyNames.set(index, newMetadataNames.get(index));
// Update the policy resource name to new name
policy
.getResources()
.put(
rangerHelper.policyResourceDefines.get(index),
new RangerPolicy.RangerPolicyResource(newMetadataNames.get(index)));
policy.setName(DOT_JOINER.join(policyNames));

boolean alreadyExist =
existNewPolicies.stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
package org.apache.gravitino.authorization.ranger;

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.util.HashMap;
import java.util.HashSet;
Expand Down Expand Up @@ -61,6 +60,11 @@ public class RangerHelper {
public static final String GRAVITINO_METALAKE_OWNER_ROLE = "GRAVITINO_METALAKE_OWNER_ROLE";
public static final String GRAVITINO_CATALOG_OWNER_ROLE = "GRAVITINO_CATALOG_OWNER_ROLE";

// marking owner policy items
public static final String GRAVITINO_PLACEHOLDER_OWNER_ROLE = "GRAVITINO_PLACEHOLDER_OWNER_ROLE";

public static final String GRAVITINO_ROLE_PREFIX = "GRAVITINO_";

theoryxu marked this conversation as resolved.
Show resolved Hide resolved
public RangerHelper(
RangerClient rangerClient,
String rangerAdminName,
Expand All @@ -75,13 +79,18 @@ public RangerHelper(
}

/**
* For easy management, each privilege will create one RangerPolicyItemAccess in the policy.
* There are two types of policy items. Gravitino managed policy items: They contain one privilege
* each. User-defined policy items: They could contain multiple privileges and not be managed and
* checked by Gravitino.
*
* @param policyItem The policy item to check
* @throws AuthorizationPluginException If the policy item contains more than one access type
*/
void checkPolicyItemAccess(RangerPolicy.RangerPolicyItem policyItem)
throws AuthorizationPluginException {
if (!isGravitinoManagedPolicyItemAccess(policyItem)) {
return;
theoryxu marked this conversation as resolved.
Show resolved Hide resolved
}
if (policyItem.getAccesses().size() != 1) {
throw new AuthorizationPluginException(
"The access type only have one in the delegate Gravitino management policy");
Expand Down Expand Up @@ -120,7 +129,9 @@ void addPolicyItem(RangerPolicy policy, String roleName, RangerSecurableObject s
policyItem -> {
return policyItem.getAccesses().stream()
.anyMatch(
access -> access.getType().equals(rangerPrivilege.getName()));
access ->
access.getType().equals(rangerPrivilege.getName())
&& isGravitinoManagedPolicyItemAccess(policyItem));
})
.collect(Collectors.toList());
} else {
Expand All @@ -130,7 +141,9 @@ void addPolicyItem(RangerPolicy policy, String roleName, RangerSecurableObject s
policyItem -> {
return policyItem.getAccesses().stream()
.anyMatch(
access -> access.getType().equals(rangerPrivilege.getName()));
access ->
access.getType().equals(rangerPrivilege.getName())
&& isGravitinoManagedPolicyItemAccess(policyItem));
})
.collect(Collectors.toList());
}
Expand All @@ -142,7 +155,7 @@ void addPolicyItem(RangerPolicy policy, String roleName, RangerSecurableObject s
new RangerPolicy.RangerPolicyItemAccess();
access.setType(rangerPrivilege.getName());
policyItem.getAccesses().add(access);
policyItem.getRoles().add(roleName);
policyItem.getRoles().add(generateGravitinoRoleName(roleName));
if (Privilege.Condition.ALLOW == rangerPrivilege.condition()) {
policy.getPolicyItems().add(policyItem);
} else {
Expand All @@ -154,8 +167,10 @@ void addPolicyItem(RangerPolicy policy, String roleName, RangerSecurableObject s
.forEach(
policyItem -> {
// If the role is not in the policy item, then add it
if (!policyItem.getRoles().contains(roleName)) {
policyItem.getRoles().add(roleName);
if (!policyItem
.getRoles()
.contains(generateGravitinoRoleName(roleName))) {
policyItem.getRoles().add(generateGravitinoRoleName(roleName));
}
});
}
Expand All @@ -172,7 +187,6 @@ public List<RangerPolicy> wildcardSearchPolies(List<String> metadataNames)
throws AuthorizationPluginException {
Map<String, String> searchFilters = new HashMap<>();
searchFilters.put(SearchFilter.SERVICE_NAME, rangerServiceName);
searchFilters.put(SearchFilter.POLICY_LABELS_PARTIAL, MANAGED_BY_GRAVITINO);
for (int i = 0; i < metadataNames.size(); i++) {
searchFilters.put(
SearchFilter.RESOURCE_PREFIX + policyResourceDefines.get(i), metadataNames.get(i));
Expand Down Expand Up @@ -224,8 +238,7 @@ public RangerPolicy findManagedPolicy(RangerMetadataObject rangerMetadataObject)
}
// Only return the policies that are managed by Gravitino.
if (policies.size() > 1) {
throw new AuthorizationPluginException(
"Every metadata object has only a Gravitino managed policy.");
throw new AuthorizationPluginException("Each metadata object can have at most one policy.");
}

if (policies.isEmpty()) {
Expand All @@ -242,7 +255,12 @@ public RangerPolicy findManagedPolicy(RangerMetadataObject rangerMetadataObject)
return policy;
}

public boolean isGravitinoManagedPolicyItemAccess(RangerPolicy.RangerPolicyItem policyItem) {
return policyItem.getRoles().stream().anyMatch(role -> role.startsWith(GRAVITINO_ROLE_PREFIX));
}

protected boolean checkRangerRole(String roleName) throws AuthorizationPluginException {
roleName = generateGravitinoRoleName(roleName);
try {
rangerClient.getRole(roleName, rangerAdminName, rangerServiceName);
} catch (RangerServiceException e) {
Expand All @@ -252,8 +270,16 @@ protected boolean checkRangerRole(String roleName) throws AuthorizationPluginExc
return true;
}

public String generateGravitinoRoleName(String roleName) {
if (roleName.startsWith(GRAVITINO_ROLE_PREFIX)) {
return roleName;
}
return GRAVITINO_ROLE_PREFIX + roleName;
}

protected GrantRevokeRoleRequest createGrantRevokeRoleRequest(
String roleName, String userName, String groupName) {
roleName = generateGravitinoRoleName(roleName);
Set<String> users =
StringUtils.isEmpty(userName) ? Sets.newHashSet() : Sets.newHashSet(userName);
Set<String> groups =
Expand All @@ -278,11 +304,13 @@ protected GrantRevokeRoleRequest createGrantRevokeRoleRequest(
* @param isOwnerRole The role is owner role or not
*/
protected RangerRole createRangerRoleIfNotExists(String roleName, boolean isOwnerRole) {
roleName = generateGravitinoRoleName(roleName);
if (isOwnerRole) {
Preconditions.checkArgument(
roleName.equalsIgnoreCase(GRAVITINO_METALAKE_OWNER_ROLE)
|| roleName.equalsIgnoreCase(GRAVITINO_CATALOG_OWNER_ROLE),
"The role name should be GRAVITINO_METALAKE_OWNER_ROLE or GRAVITINO_CATALOG_OWNER_ROLE");
|| roleName.equalsIgnoreCase(GRAVITINO_CATALOG_OWNER_ROLE)
|| roleName.equalsIgnoreCase(GRAVITINO_PLACEHOLDER_OWNER_ROLE),
"The role name should be GRAVITINO_METALAKE_OWNER_ROLE or GRAVITINO_CATALOG_OWNER_ROLE or GRAVITINO_PLACEHOLDER_OWNER_ROLE");
theoryxu marked this conversation as resolved.
Show resolved Hide resolved
} else {
Preconditions.checkArgument(
!roleName.equalsIgnoreCase(GRAVITINO_METALAKE_OWNER_ROLE)
Expand Down Expand Up @@ -325,6 +353,7 @@ protected void updatePolicyOwner(RangerPolicy policy, Owner preOwner, Owner newO
});
});
})
.filter(this::isGravitinoManagedPolicyItemAccess)
.collect(Collectors.toList());
// Add or remove the owner in the policy item
matchPolicyItems.forEach(
Expand Down Expand Up @@ -376,6 +405,8 @@ protected void updatePolicyOwner(RangerPolicy policy, Owner preOwner, Owner newO
} else {
policyItem.getGroups().add(newOwner.name());
}
// mark the policy item is created by Gravitino
policyItem.getRoles().add(GRAVITINO_PLACEHOLDER_OWNER_ROLE);
theoryxu marked this conversation as resolved.
Show resolved Hide resolved
}
policy.getPolicyItems().add(policyItem);
});
Expand All @@ -385,7 +416,6 @@ protected RangerPolicy createPolicyAddResources(RangerMetadataObject metadataObj
RangerPolicy policy = new RangerPolicy();
policy.setService(rangerServiceName);
policy.setName(metadataObject.fullName());
policy.setPolicyLabels(Lists.newArrayList(RangerHelper.MANAGED_BY_GRAVITINO));
theoryxu marked this conversation as resolved.
Show resolved Hide resolved
List<String> nsMetadataObject = metadataObject.names();
for (int i = 0; i < nsMetadataObject.size(); i++) {
RangerPolicy.RangerPolicyResource policyResource =
Expand All @@ -411,6 +441,8 @@ protected RangerPolicy addOwnerToNewPolicy(RangerMetadataObject metadataObject,
} else {
policyItem.getGroups().add(newOwner.name());
}
// mark the policy item is created by Gravitino
policyItem.getRoles().add(GRAVITINO_PLACEHOLDER_OWNER_ROLE);
}
policy.getPolicyItems().add(policyItem);
});
Expand All @@ -428,7 +460,7 @@ protected RangerPolicy addOwnerRoleToNewPolicy(
policyItem
.getAccesses()
.add(new RangerPolicy.RangerPolicyItemAccess(ownerPrivilege.getName()));
policyItem.getRoles().add(ownerRoleName);
policyItem.getRoles().add(generateGravitinoRoleName(ownerRoleName));
policy.getPolicyItems().add(policyItem);
});
return policy;
Expand All @@ -454,8 +486,8 @@ protected void updatePolicyOwnerRole(RangerPolicy policy, String ownerRoleName)
// Add or remove the owner role in the policy item
matchPolicyItems.forEach(
policyItem -> {
if (!policyItem.getRoles().contains(ownerRoleName)) {
policyItem.getRoles().add(ownerRoleName);
if (!policyItem.getRoles().contains(generateGravitinoRoleName(ownerRoleName))) {
policyItem.getRoles().add(generateGravitinoRoleName(ownerRoleName));
}
theoryxu marked this conversation as resolved.
Show resolved Hide resolved
});

Expand All @@ -480,8 +512,8 @@ protected void updatePolicyOwnerRole(RangerPolicy policy, String ownerRoleName)
policyItem
.getAccesses()
.add(new RangerPolicy.RangerPolicyItemAccess(ownerPrivilege.getName()));
if (!policyItem.getRoles().contains(ownerRoleName)) {
policyItem.getRoles().add(ownerRoleName);
if (!policyItem.getRoles().contains(generateGravitinoRoleName(ownerRoleName))) {
policyItem.getRoles().add(generateGravitinoRoleName(ownerRoleName));
}
policy.getPolicyItems().add(policyItem);
});
Expand Down
Loading
Loading