package core.aws.resource.ec2;
import com.amazonaws.auth.policy.Action;
import com.amazonaws.auth.policy.Condition;
import com.amazonaws.auth.policy.Policy;
import com.amazonaws.auth.policy.Principal;
import com.amazonaws.auth.policy.Resource;
import com.amazonaws.auth.policy.Statement;
import com.amazonaws.services.identitymanagement.model.Role;
import core.aws.client.AWS;
import core.aws.util.Asserts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
/**
* @author neo
*/
class InstanceProfileHelper {
private final Logger logger = LoggerFactory.getLogger(InstanceProfileHelper.class);
void validatePolicyDocument(String policyJSON) {
Policy policy = Policy.fromJson(policyJSON);
Asserts.isFalse(policy.getStatements().isEmpty(), "statement is required");
for (Statement statement : policy.getStatements()) {
Asserts.isFalse(statement.getActions().isEmpty(), "action is required");
}
}
boolean policyChanged(String localPolicyJSON, com.amazonaws.services.identitymanagement.model.InstanceProfile remoteInstanceProfile) {
String instanceProfileName = remoteInstanceProfile.getInstanceProfileName();
List<Role> roles = remoteInstanceProfile.getRoles();
Asserts.isFalse(roles.isEmpty(), "instance profile does not not have role, please check whether the role failed to add to instance profile, instanceProfileName={}",
instanceProfileName);
Asserts.equals(roles.size(), 1, "instance profile should only have one role, check whether it's modified not by cmn, instanceProfileName={}, roles={}",
instanceProfileName, roles);
Role role = roles.get(0);
Optional<Policy> remotePolicy = AWS.iam.findRolePolicy(role.getRoleName(), role.getRoleName());
if (!remotePolicy.isPresent()) {
logger.warn("role policy doesn't exist, it could be due to failure of last sync, it will try to create this time, instanceProfileName={}", instanceProfileName);
return true;
}
Policy localPolicy = Policy.fromJson(localPolicyJSON);
return policyChanged(localPolicy, remotePolicy.get());
}
boolean policyChanged(Policy policy1, Policy policy2) {
Collection<Statement> statements1 = policy1.getStatements();
Collection<Statement> statements2 = policy2.getStatements();
if (statements1.size() != statements2.size()) return true;
for (Statement statement1 : statements1) {
if (!containStatement(statements2, statement1)) return true;
}
return false;
}
private boolean containStatement(Collection<Statement> statements, Statement statement) {
return statements.stream().anyMatch(statement1 -> statementEquals(statement1, statement));
}
private Boolean statementEquals(Statement statement1, Statement statement2) {
List<Action> actions1 = statement1.getActions();
List<Action> actions2 = statement2.getActions();
boolean actionMatches = actions1.size() == actions2.size()
&& actions1.stream().allMatch(action1 -> actions2.stream().anyMatch(action2 -> action1.getActionName().equals(action2.getActionName())));
if (!actionMatches) return false;
boolean effectMatches = statement1.getEffect().equals(statement2.getEffect());
if (!effectMatches) return false;
List<Resource> resources1 = statement1.getResources();
List<Resource> resources2 = statement2.getResources();
boolean resourceMatches = resources1.size() == resources2.size()
&& resources1.stream().allMatch(resource1 -> resources2.stream().anyMatch(resource2 -> resource1.getId().equals(resource2.getId())));
if (!resourceMatches) return false;
List<Condition> conditions1 = statement1.getConditions();
List<Condition> conditions2 = statement2.getConditions();
boolean conditionMatches = conditions1.size() == conditions2.size()
&& conditions1.stream().allMatch(condition1 -> conditions2.stream().anyMatch(condition2 -> conditionEquals(condition1, condition2)));
if (!conditionMatches) return false;
List<Principal> principals1 = statement1.getPrincipals();
List<Principal> principals2 = statement2.getPrincipals();
boolean principleMatches = principals1.size() == principals2.size()
&& principals1.stream().allMatch(principle1 -> principals2.stream().anyMatch(principal2 -> principleEquals(principle1, principal2)));
if (!principleMatches) return false;
return true;
}
private boolean principleEquals(Principal principle1, Principal principal2) {
return principle1.getId().equals(principal2.getId())
&& principle1.getProvider().equals(principal2.getProvider());
}
private boolean conditionEquals(Condition condition1, Condition condition2) {
if (!condition1.getConditionKey().equals(condition2.getConditionKey())) return false;
if (!condition1.getType().equals(condition2.getType())) return false;
List<String> values2 = condition2.getValues();
if (condition1.getValues().size() != values2.size()) return false;
for (String value : condition1.getValues()) {
if (!values2.contains(value)) return false;
}
return true;
}
}