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

adding iam manager and user service #229

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions charts/templates/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ data:
namespace: {{ .Values.namespace }}
replication-group: {{ .Values.replicationGroup }}
awsSignatureV4: {{ default false .Values.ecsConnection.awsSignatureV4 }}
iamManager: {{ default false .Values.ecsConnection.iamManager }}
{{- if .Values.certificate }}
certificate: {{ toYaml .Values.certificate | indent 6 }}
{{- end }}
Expand Down
1 change: 1 addition & 0 deletions charts/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ ecsConnection:
password: <PASSWORD>
s3endpoint: "https://object.ecstestdrive.com"
awsSignatureV4: false # Use AWS signature V4 to authenticate S3 requests (use V2 if false)
iamManager: false

# Broker API security
api:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,9 @@ public BucketWipeFactory bucketWipeFactory() {
return new BucketWipeFactory();
}

@Bean
public UserService userService() { return new UserService(); }

private static String[] getArgs() {
return args;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public void checkConfig() {
private boolean useSsl;
private boolean awsSignatureV4 = false;
private boolean ignoreSslValidation;
private boolean iamManager = false;

private String repositorySecret;
private String repositoryUser = "user";
Expand Down Expand Up @@ -281,6 +282,10 @@ public void setDefaultReclaimPolicy(String defaultReclaimPolicy) {

public void setAwsSignatureV4(boolean awsSignatureV4) { this.awsSignatureV4 = awsSignatureV4; }

public boolean isIamManager() { return iamManager; }

public void setIamManager(boolean iamManager) { this.iamManager = iamManager; }

public void setPathStyleAccess(boolean pathStyleAccess) {
this.pathStyleAccess = pathStyleAccess;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public class Constants {
public static final String CREDENTIALS_INSTANCE_ID = "instanceId";

public static final String USER_PERMISSIONS = "permissions";
public static final String POLICY_URN = "policy_urn";
public static final List<String> FULL_CONTROL = Collections.singletonList("full_control");

public static String NAME_PARAMETER = "name";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,26 @@ public UserSecretKey createBindingUser() throws EcsManagementClientException, IO
Map<String, Object> parameters = createRequest.getParameters();

List<String> permissions = null;
String policyUrn = null;

if (parameters != null) {
permissions = (List<String>) parameters.get(USER_PERMISSIONS);
policyUrn = (String) parameters.get(POLICY_URN);
}

if(policyUrn != null && permissions != null) {
throw new IllegalArgumentException("Can not apply policy urn and user permissions at the same time");
}

if (permissions == null) {
if (permissions == null && policyUrn == null) {
ecs.addUserToBucket(bucket, namespace, binding.getName());
} else {
} else if (policyUrn == null) {
ecs.addUserToBucket(bucket, namespace, binding.getName(), permissions);
} else {
ecs.addUserToBucket(bucket, namespace, binding.getName(), policyUrn);
}


if (ecs.getBucketFileEnabled(bucket, namespace)) {
String export = "";
if (parameters != null) {
Expand All @@ -66,6 +76,7 @@ public UserSecretKey createBindingUser() throws EcsManagementClientException, IO
volumeMounts = createVolumeExport(export, new URL(ecs.getObjectEndpoint()), bucket, namespace, parameters);
}

LOG.info("Permissions handled");
return userSecretKey;
}

Expand All @@ -92,7 +103,13 @@ public void removeBinding() throws EcsManagementClientException, IOException {

LOG.info("Removing binding '{}' user from bucket '{}' in namespace '{}'", bindingId, bucket, namespace);

ecs.removeUserFromBucket(bucket, namespace, binding.getName());
Map<String, Object> credentials = binding.getCredentials();

if(credentials != null && credentials.containsKey(POLICY_URN)) {
ecs.removeUserFromBucket(bucket, namespace, binding.getName(), (String) credentials.get(POLICY_URN));
} else {
ecs.removeUserFromBucket(bucket, namespace, binding.getName());
}
ecs.deleteUser(binding.getName(), namespace);
}

Expand Down Expand Up @@ -130,6 +147,10 @@ public Map<String, Object> getCredentials(UserSecretKey secretKey, Map<String, O
credentials.put(VOLUME_EXPORT_UID, unixID);
}

if(parameters != null && parameters.containsKey(POLICY_URN)) {
credentials.put(POLICY_URN, parameters.get(POLICY_URN));
}

return credentials;
}

Expand Down
71 changes: 20 additions & 51 deletions src/main/java/com/emc/ecs/servicebroker/service/EcsService.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ public class EcsService implements StorageService {
@Autowired
protected BucketWipeFactory bucketWipeFactory;

@Autowired
protected UserService userService;

protected BucketWipeOperations bucketWipe;

private String objectEndpoint;
Expand Down Expand Up @@ -316,17 +319,11 @@ public boolean aclExists(String bucketName, String namespace) throws EcsManageme
@Override
public UserSecretKey createUser(String id, String namespace) {
try {
UserSecretKey key;
String userId = prefix(id);
key = userService.createUser(connection, userId, namespace);
return key;

logger.info("Creating user '{}' in namespace '{}'", userId, namespace);
ObjectUserAction.create(connection, userId, namespace);

logger.info("Creating secret for user '{}'", userId);
ObjectUserSecretAction.create(connection, userId);

UserSecretKey userSecretKey = ObjectUserSecretAction.list(connection, userId).get(0);

return userSecretKey;
} catch (Exception e) {
throw new ServiceBrokerException(e.getMessage(), e);
}
Expand All @@ -345,7 +342,8 @@ public void deleteUserMap(String username, String namespace, String uid) throws
@Override
public Boolean userExists(String userId, String namespace) throws ServiceBrokerException {
try {
return ObjectUserAction.exists(connection, prefix(userId), namespace);
return userService.userExists(connection, prefix(userId), namespace);

} catch (Exception e) {
throw new ServiceBrokerException(e.getMessage(), e);
}
Expand All @@ -354,12 +352,7 @@ public Boolean userExists(String userId, String namespace) throws ServiceBrokerE
@Override
public void deleteUser(String userId, String namespace) throws EcsManagementClientException {
try {
if (userExists(userId, namespace)) {
logger.info("Deleting user '{}' in namespace '{}'", userId, namespace);
ObjectUserAction.delete(connection, prefix(userId));
} else {
logger.info("User {} no longer exists, assume already deleted", prefix(userId));
}
userService.deleteUser(connection, prefix(userId), namespace);
} catch (Exception e) {
throw new ServiceBrokerException(e.getMessage(), e);
}
Expand All @@ -376,46 +369,22 @@ public void addUserToBucket(String bucketId, String namespace, String username)

@Override
public void addUserToBucket(String bucketId, String namespace, String username, List<String> permissions) throws EcsManagementClientException {
logger.info("Adding user '{}' to bucket '{}' in '{}' with {} access", prefix(username), prefix(bucketId), namespace, permissions);

BucketAcl acl = BucketAclAction.get(connection, prefix(bucketId), namespace);

List<BucketUserAcl> userAcl = acl.getAcl().getUserAccessList();
userAcl.add(new BucketUserAcl(prefix(username), permissions));
acl.getAcl().setUserAccessList(userAcl);

BucketAclAction.update(connection, prefix(bucketId), acl);

if (!getBucketFileEnabled(bucketId, namespace)) {
BucketPolicy bucketPolicy = new BucketPolicy(
"2012-10-17",
"DefaultPCFBucketPolicy",
new BucketPolicyStatement("DefaultAllowTotalAccess",
new BucketPolicyEffect("Allow"),
new BucketPolicyPrincipal(prefix(username)),
new BucketPolicyActions(Collections.singletonList("s3:*")),
new BucketPolicyResource(Collections.singletonList(prefix(bucketId)))
)
);
BucketPolicyAction.update(connection, prefix(bucketId), bucketPolicy, namespace);
}
userService.addUserToBucket(connection, prefix(bucketId), namespace, prefix(username), permissions);
}

@Override
public void removeUserFromBucket(String bucket, String namespace, String username) throws EcsManagementClientException {
if (!aclExists(prefix(bucket), namespace)) {
logger.info("ACL {} no longer exists when removing user {}", prefix(bucket), prefix(username));
return;
}

BucketAcl acl = BucketAclAction.get(connection, prefix(bucket), namespace);
public void addUserToBucket(String bucketId, String namespace, String username, String policyUrn) throws EcsManagementClientException {
userService.addUserToBucket(connection, prefix(bucketId), namespace, prefix(username), policyUrn);
}

List<BucketUserAcl> newUserAcl = acl.getAcl().getUserAccessList()
.stream().filter(a -> !a.getUser().equals(prefix(username)))
.collect(Collectors.toList());
acl.getAcl().setUserAccessList(newUserAcl);
@Override
public void removeUserFromBucket(String bucket, String namespace, String username) throws EcsManagementClientException {
userService.removeUserFromBucket(connection, prefix(bucket), namespace, prefix(username));
}

BucketAclAction.update(connection, prefix(bucket), acl);
@Override
public void removeUserFromBucket(String bucket, String namespace, String username, String policyUrn) throws EcsManagementClientException {
userService.removeUserFromBucket(connection, prefix(bucket), namespace, prefix(username), policyUrn);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ public class ObjectstoreService extends EcsService {
@Autowired
private S3Client s3Client;

@Autowired
private UserService userService;

@PostConstruct
void initialize() {
if (broker.isConfigValidationMode()) {
Expand Down Expand Up @@ -85,17 +88,9 @@ public UserSecretKey createUser(String id, String accountId) {
try {
String userId = prefix(id);

logger.info("Creating user '{}' in account '{}'", userId, accountId);
IAMUserAction.create(objectscaleGateway, userId, accountId);

logger.info("Creating secret for user '{}'", userId);
IamAccessKey iamKey = IAMAccessKeyAction.create(objectscaleGateway, userId, accountId);

UserSecretKey key = new UserSecretKey();
key.setAccessKey(iamKey.getAccessKeyId());
key.setSecretKey(iamKey.getSecretAccessKey());
key.setKeyTimestamp(iamKey.getCreateDate());
UserSecretKey key = userService.createUser(objectscaleGateway, userId, accountId);
return key;

} catch (Exception e) {
throw new ServiceBrokerException(e.getMessage(), e);
}
Expand All @@ -104,18 +99,7 @@ public UserSecretKey createUser(String id, String accountId) {
@Override
public void deleteUser(String userId, String accountId) throws EcsManagementClientException {
try {
if (userExists(userId, accountId)) {
logger.info("Deleting access keys of user '{}' in account '{}'", userId, accountId);
List<IamAccessKey> accessKeys = IAMAccessKeyAction.list(objectscaleGateway, prefix(userId), accountId);
for (IamAccessKey key : accessKeys) {
IAMAccessKeyAction.delete(objectscaleGateway, key.getAccessKeyId(), prefix(userId), accountId);
}

logger.info("Deleting user '{}' in account '{}'", userId, accountId);
IAMUserAction.delete(objectscaleGateway, prefix(userId), accountId);
} else {
logger.info("User {} no longer exists, assume already deleted", prefix(userId));
}
userService.deleteUser(connection, prefix(userId), accountId);
} catch (Exception e) {
throw new ServiceBrokerException(e.getMessage(), e);
}
Expand All @@ -124,79 +108,20 @@ public void deleteUser(String userId, String accountId) throws EcsManagementClie
@Override
public Boolean userExists(String userId, String accountId) throws ServiceBrokerException {
try {
return IAMUserAction.exists(objectscaleGateway, prefix(userId), accountId);
return userService.userExists(connection, prefix(userId), accountId);
} catch (Exception e) {
throw new ServiceBrokerException(e.getMessage(), e);
}
}

@Override
public void addUserToBucket(String bucketId, String accountId, String username) {
logger.info("Adding user '{}' default access to bucket '{}' in '{}'", prefix(username), prefix(bucketId), accountId);

// TODO get them from broker config?

String objectscaleId = broker.getObjectscaleId();
String objectstoreId = broker.getObjectstoreId();

// 1. Create policy
String bucketARN = "arn:aws:s3:" + objectscaleId + ":" + objectstoreId + ":" + prefix(bucketId);
String objectsARN = bucketARN + "/*";

String policyDocument = "{\n" +
" \"Version\":\"2012-10-17\",\n" +
" \"Statement\":[\n" +
" {\n" +
" \"Effect\":\"Allow\",\n" +
" \"Action\":[\"s3:ListBucket\"],\n" +
" \"Resource\":\"" + bucketARN + "\"\n" +
" },\n" +
" {\n" +
" \"Effect\":\"Allow\",\n" +
" \"Action\":[\n" +
" \"s3:PutObject\",\n" +
" \"s3:PutObjectAcl\",\n" +
" \"s3:GetObject\",\n" +
" \"s3:GetObjectAcl\",\n" +
" \"s3:DeleteObject\"\n" +
" ],\n" +
" \"Resource\":\"" + objectsARN + "\"\n" +
" }\n" +
" ]\n" +
"}";

String policyName = policyName(prefix(bucketId), FULL_CONTROL);

IamPolicy iamPolicy = IAMPolicyAction.get(objectscaleGateway, policyName, accountId);
if (iamPolicy == null) {
iamPolicy = IAMPolicyAction.create(objectscaleGateway, policyName, policyDocument, accountId);
}

// 2. add policy to user
IAMUserPolicyAction.attach(objectscaleGateway, prefix(username), iamPolicy.getArn(), accountId);
}

private String policyName(String bucketId, List<String> permissions) {
if (permissions == null || isEqualList(FULL_CONTROL, permissions)) {
return prefix(bucketId) + "-policy";
} else {
List<String> copy = new ArrayList<>(permissions);
Collections.sort(copy);
String join = String.join("-", copy);
return prefix(bucketId) + "-policy-" + join;
}
userService.addUserToBucket(objectscaleGateway, prefix(bucketId), accountId, prefix(username), FULL_CONTROL);
}

@Override
public void removeUserFromBucket(String bucketId, String accountId, String userId) throws EcsManagementClientException {
String policyName = policyName(prefix(bucketId), FULL_CONTROL);
IamPolicy iamPolicy = IAMPolicyAction.get(objectscaleGateway, policyName, accountId);
if (iamPolicy != null) {
IAMUserPolicyAction.detach(objectscaleGateway, prefix(userId), iamPolicy.getArn(), accountId);
} else {
logger.warn("Cannot find iamPolicy to remove from user: " + policyName);
}

userService.removeUserFromBucket(connection ,prefix(bucketId), accountId, prefix(userId));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@ public interface StorageService {
void addUserToBucket(String bucketId, String namespace, String username);

void addUserToBucket(String bucketId, String namespace, String username, List<String> permissions) throws EcsManagementClientException;
void addUserToBucket(String bucketId, String namespace, String username, String policyUrn) throws EcsManagementClientException;

void removeUserFromBucket(String bucket, String namespace, String username) throws EcsManagementClientException;
void removeUserFromBucket(String bucket, String namespace, String username, String policyUrn) throws EcsManagementClientException;

void createUserMap(String username, String namespace, int uid) throws EcsManagementClientException;

Expand Down
Loading