Skip to content

Commit 7703fda

Browse files
abh1sarDaan Hoogland
authored andcommitted
[minio] Handle user's canned policy when a bucket is deleted
1 parent 46a6bba commit 7703fda

3 files changed

Lines changed: 67 additions & 28 deletions

File tree

api/src/main/java/com/cloud/agent/api/to/BucketTO.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,13 @@ public final class BucketTO {
2626

2727
private String secretKey;
2828

29+
private long accountId;
30+
2931
public BucketTO(Bucket bucket) {
3032
this.name = bucket.getName();
3133
this.accessKey = bucket.getAccessKey();
3234
this.secretKey = bucket.getSecretKey();
35+
this.accountId = bucket.getAccountId();
3336
}
3437

3538
public BucketTO(String name) {
@@ -47,4 +50,8 @@ public String getAccessKey() {
4750
public String getSecretKey() {
4851
return this.secretKey;
4952
}
53+
54+
public long getAccountId() {
55+
return this.accountId;
56+
}
5057
}

plugins/storage/object/minio/src/main/java/org/apache/cloudstack/storage/datastore/driver/MinIOObjectStoreDriverImpl.java

Lines changed: 54 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import java.util.ArrayList;
2525
import java.util.List;
2626
import java.util.Map;
27+
import java.util.Objects;
28+
import java.util.stream.Collectors;
2729

2830
import javax.crypto.KeyGenerator;
2931
import javax.crypto.SecretKey;
@@ -98,6 +100,51 @@ protected String getUserOrAccessKeyForAccount(Account account) {
98100
return String.format("%s-%s", ACS_PREFIX, account.getUuid());
99101
}
100102

103+
private void updateCannedPolicy(long storeId, Account account, String excludeBucket) {
104+
List<BucketVO> buckets = _bucketDao.listByObjectStoreIdAndAccountId(storeId, account.getId());
105+
106+
String resources = buckets.stream()
107+
.map(BucketVO::getName)
108+
.filter(name -> !Objects.equals(name, excludeBucket))
109+
.map(name -> "\"arn:aws:s3:::" + name + "/*\"")
110+
.collect(Collectors.joining(",\n"));
111+
String policy;
112+
if (resources.isEmpty()) {
113+
// Resource cannot be empty in a canned Policy so deny access to all resources if the user has no buckets
114+
policy = " {\n" +
115+
" \"Statement\": [\n" +
116+
" {\n" +
117+
" \"Action\": \"s3:*\",\n" +
118+
" \"Effect\": \"Deny\",\n" +
119+
" \"Resource\": [\"arn:aws:s3:::*\", \"arn:aws:s3:::*/*\"]\n" +
120+
" }\n" +
121+
" ],\n" +
122+
" \"Version\": \"2012-10-17\"\n" +
123+
" }";
124+
} else {
125+
policy = " {\n" +
126+
" \"Statement\": [\n" +
127+
" {\n" +
128+
" \"Action\": \"s3:*\",\n" +
129+
" \"Effect\": \"Allow\",\n" +
130+
" \"Resource\": [" + resources + "]\n" +
131+
" }\n" +
132+
" ],\n" +
133+
" \"Version\": \"2012-10-17\"\n" +
134+
" }";
135+
}
136+
137+
MinioAdminClient minioAdminClient = getMinIOAdminClient(storeId);
138+
String policyName = getUserOrAccessKeyForAccount(account) + "-policy";
139+
String userName = getUserOrAccessKeyForAccount(account);
140+
try {
141+
minioAdminClient.addCannedPolicy(policyName, policy);
142+
minioAdminClient.setPolicy(userName, false, policyName);
143+
} catch (NoSuchAlgorithmException | IOException | InvalidKeyException e) {
144+
throw new CloudRuntimeException(e);
145+
}
146+
}
147+
101148
@Override
102149
public Bucket createBucket(Bucket bucket, boolean objectLock) {
103150
//ToDo Client pool mgmt
@@ -125,33 +172,8 @@ public Bucket createBucket(Bucket bucket, boolean objectLock) {
125172
throw new CloudRuntimeException(e);
126173
}
127174

128-
List<BucketVO> buckets = _bucketDao.listByObjectStoreIdAndAccountId(storeId, accountId);
129-
StringBuilder resources_builder = new StringBuilder();
130-
for(BucketVO exitingBucket : buckets) {
131-
resources_builder.append("\"arn:aws:s3:::"+exitingBucket.getName()+"/*\",\n");
132-
}
133-
resources_builder.append("\"arn:aws:s3:::"+bucketName+"/*\"\n");
134-
135-
String policy = " {\n" +
136-
" \"Statement\": [\n" +
137-
" {\n" +
138-
" \"Action\": \"s3:*\",\n" +
139-
" \"Effect\": \"Allow\",\n" +
140-
" \"Principal\": \"*\",\n" +
141-
" \"Resource\": ["+resources_builder+"]" +
142-
" }\n" +
143-
" ],\n" +
144-
" \"Version\": \"2012-10-17\"\n" +
145-
" }";
146-
MinioAdminClient minioAdminClient = getMinIOAdminClient(storeId);
147-
String policyName = getUserOrAccessKeyForAccount(account) + "-policy";
148-
String userName = getUserOrAccessKeyForAccount(account);
149-
try {
150-
minioAdminClient.addCannedPolicy(policyName, policy);
151-
minioAdminClient.setPolicy(userName, false, policyName);
152-
} catch (Exception e) {
153-
throw new CloudRuntimeException(e);
154-
}
175+
updateCannedPolicy(storeId, account,null);
176+
155177
String accessKey = _accountDetailsDao.findDetail(accountId, MINIO_ACCESS_KEY).getValue();
156178
String secretKey = _accountDetailsDao.findDetail(accountId, MINIO_SECRET_KEY).getValue();
157179
ObjectStoreVO store = _storeDao.findById(storeId);
@@ -183,6 +205,8 @@ public List<Bucket> listBuckets(long storeId) {
183205
@Override
184206
public boolean deleteBucket(BucketTO bucket, long storeId) {
185207
String bucketName = bucket.getName();
208+
long accountId = bucket.getAccountId();
209+
Account account = _accountDao.findById(accountId);
186210
MinioClient minioClient = getMinIOClient(storeId);
187211
try {
188212
if(!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
@@ -197,6 +221,9 @@ public boolean deleteBucket(BucketTO bucket, long storeId) {
197221
} catch (Exception e) {
198222
throw new CloudRuntimeException(e);
199223
}
224+
225+
updateCannedPolicy(storeId, account, bucketName);
226+
200227
return true;
201228
}
202229

plugins/storage/object/minio/src/test/java/org/apache/cloudstack/storage/datastore/driver/MinIOObjectStoreDriverImplTest.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,15 @@ public void testCreateBucket() throws Exception {
129129
@Test
130130
public void testDeleteBucket() throws Exception {
131131
String bucketName = "test-bucket";
132-
BucketTO bucket = new BucketTO(bucketName);
132+
BucketVO bucketVO = new BucketVO(1L, 1L, 1L, bucketName, 1, false, false, false, null);
133+
BucketTO bucket = new BucketTO(bucketVO);
134+
when(accountDao.findById(1L)).thenReturn(account);
135+
when(account.getUuid()).thenReturn(UUID.randomUUID().toString());
136+
when(bucketDao.listByObjectStoreIdAndAccountId(anyLong(), anyLong())).thenReturn(new ArrayList<BucketVO>());
133137
doReturn(minioClient).when(minioObjectStoreDriverImpl).getMinIOClient(anyLong());
134138
when(minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())).thenReturn(true);
135139
doNothing().when(minioClient).removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
140+
doReturn(minioAdminClient).when(minioObjectStoreDriverImpl).getMinIOAdminClient(anyLong());
136141
boolean success = minioObjectStoreDriverImpl.deleteBucket(bucket, 1L);
137142
assertTrue(success);
138143
verify(minioClient, times(1)).bucketExists(any());

0 commit comments

Comments
 (0)