Skip to content

Commit 4658e76

Browse files
Add models for policy generation
Signed-off-by: jackschofield23 <jack.schofield@answerdigital.com>
1 parent c3fa294 commit 4658e76

File tree

12 files changed

+239
-5
lines changed

12 files changed

+239
-5
lines changed

src/Storage/API/IStorageService.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,5 @@ public interface IStorageService
171171
/// <param name="cancellationToken">Optional cancellation token. Defaults to default(CancellationToken)</param>
172172
/// <returns>Task</returns>
173173
Task CreateFolderWithCredentials(string bucketName, string folderPath, Credentials credentials, CancellationToken cancellationToken = default);
174-
175174
}
176175
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// SPDX-FileCopyrightText: © 2021-2022 MONAI Consortium
2+
// SPDX-License-Identifier: Apache License 2.0
3+
4+
using Ardalis.GuardClauses;
5+
using Monai.Deploy.Storage.Common.Policies;
6+
7+
namespace Monai.Deploy.Storage.Common.Extensions
8+
{
9+
public static class PolicyExtensions
10+
{
11+
public static Policy ToPolicy(string bucketName, string folderName)
12+
{
13+
Guard.Against.NullOrWhiteSpace(bucketName, nameof(bucketName));
14+
Guard.Against.NullOrWhiteSpace(folderName, nameof(folderName));
15+
16+
var pathList = GetPathList(folderName);
17+
18+
return new Policy
19+
{
20+
Statement = new List<Statement>
21+
{
22+
new Statement
23+
{
24+
Sid = "AllowUserToSeeBucketListInTheConsole",
25+
Action = new string[] {"s3:ListAllMyBuckets", "s3:GetBucketLocation" },
26+
Effect = "Allow",
27+
Resource = new string[] { "arn:aws:s3:::*" }
28+
},
29+
new Statement
30+
{
31+
Sid = "AllowRootAndHomeListingOfBucket",
32+
Action = new string[] { "s3:ListBucket" },
33+
Effect = "Allow",
34+
Resource = new string[] { $"arn:aws:s3:::{bucketName}" },
35+
Condition = new Condition
36+
{
37+
StringEquals = new StringEquals
38+
{
39+
S3Prefix = pathList.ToArray(),
40+
S3Delimiter = new string[] { "/" }
41+
}
42+
}
43+
},
44+
new Statement
45+
{
46+
Sid = "AllowListingOfUserFolder",
47+
Action = new string[] { "s3:ListBucket" },
48+
Effect = "Allow",
49+
Resource = new string[] { $"arn:aws:s3:::{bucketName}" },
50+
Condition = new Condition
51+
{
52+
StringEquals = new StringEquals
53+
{
54+
S3Prefix = new string[] {$"{folderName}/*" }
55+
}
56+
}
57+
},
58+
new Statement
59+
{
60+
Sid = "AllowAllS3ActionsInUserFolder",
61+
Action = new string[] { "s3:*" },
62+
Effect = "Allow",
63+
Resource = new string[] { $"arn:aws:s3:::{bucketName}/{folderName}/*" },
64+
},
65+
}
66+
};
67+
}
68+
69+
public static List<string> GetPathList(string folderName)
70+
{
71+
Guard.Against.NullOrWhiteSpace(folderName, nameof(folderName));
72+
73+
var pathList = new List<string> { folderName };
74+
75+
var lastPath = folderName;
76+
77+
while (lastPath.Contains("/"))
78+
{
79+
var path = lastPath.Substring(0, lastPath.LastIndexOf("/") + 1);
80+
pathList.Add(path);
81+
82+
lastPath = lastPath.Substring(0, lastPath.LastIndexOf("/"));
83+
}
84+
85+
pathList.Add("");
86+
87+
return pathList;
88+
}
89+
}
90+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// SPDX-FileCopyrightText: © 2021-2022 MONAI Consortium
2+
// SPDX-License-Identifier: Apache License 2.0
3+
4+
namespace Monai.Deploy.Storage.Common.Policies
5+
{
6+
public class Condition
7+
{
8+
public StringLike StringLike { get; set; }
9+
10+
public StringEquals StringEquals { get; set; }
11+
}
12+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// SPDX-FileCopyrightText: © 2021-2022 MONAI Consortium
2+
// SPDX-License-Identifier: Apache License 2.0
3+
4+
namespace Monai.Deploy.Storage.Common.Policies
5+
{
6+
public class Policy
7+
{
8+
public string Version { get; set; } = "2012-10-17";
9+
10+
public IList<Statement> Statement { get; set; } = new List<Statement>();
11+
}
12+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// SPDX-FileCopyrightText: © 2021-2022 MONAI Consortium
2+
// SPDX-License-Identifier: Apache License 2.0
3+
4+
namespace Monai.Deploy.Storage.Common.Policies
5+
{
6+
public class Statement
7+
{
8+
public string Sid { get; set; }
9+
10+
public string[] Action { get; set; }
11+
12+
public string Effect { get; set; }
13+
14+
public string[] Resource { get; set; }
15+
16+
public Condition Condition { get; set; }
17+
}
18+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// SPDX-FileCopyrightText: © 2021-2022 MONAI Consortium
2+
// SPDX-License-Identifier: Apache License 2.0
3+
4+
using Newtonsoft.Json;
5+
6+
namespace Monai.Deploy.Storage.Common.Policies
7+
{
8+
public class StringEquals
9+
{
10+
[JsonProperty(PropertyName = "s3:prefix")]
11+
public string[] S3Prefix { get; set; }
12+
13+
[JsonProperty(PropertyName = "s3:delimiter")]
14+
public string[] S3Delimiter { get; set; }
15+
}
16+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// SPDX-FileCopyrightText: © 2021-2022 MONAI Consortium
2+
// SPDX-License-Identifier: Apache License 2.0
3+
4+
using Newtonsoft.Json;
5+
6+
namespace Monai.Deploy.Storage.Common.Policies
7+
{
8+
public class StringLike
9+
{
10+
[JsonProperty(PropertyName = "s3:prefix")]
11+
public string[] S3Prefix { get; set; }
12+
}
13+
}

src/Storage/Configuration/ConfigurationKeys.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ internal static class ConfigurationKeys
1010
public static readonly string AccessToken = "accessToken";
1111
public static readonly string SecuredConnection = "securedConnection";
1212
public static readonly string Region = "region";
13+
public static readonly string CredentialServiceUrl = "credentialServiceUrl";
1314

1415
public static readonly string[] RequiredKeys = new[] { EndPoint, AccessKey, AccessToken, SecuredConnection, Region };
1516
}

src/Storage/MinIo/MinIoStorageService.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
using Minio;
1212
using Minio.DataModel;
1313
using Monai.Deploy.Storage.Common;
14+
using Monai.Deploy.Storage.Common.Extensions;
1415
using Monai.Deploy.Storage.Configuration;
16+
using Newtonsoft.Json;
1517

1618
namespace Monai.Deploy.Storage.MinIo
1719
{
@@ -39,6 +41,7 @@ public MinIoStorageService(IOptions<StorageServiceConfiguration> options, ILogge
3941
var accessKey = configuration.Settings[ConfigurationKeys.AccessKey];
4042
var accessToken = configuration.Settings[ConfigurationKeys.AccessToken];
4143
var securedConnection = configuration.Settings[ConfigurationKeys.SecuredConnection];
44+
var credentialServiceUrl = configuration.Settings[ConfigurationKeys.CredentialServiceUrl];
4245

4346
_client = new MinioClient(endpoint, accessKey, accessToken);
4447

@@ -49,8 +52,8 @@ public MinIoStorageService(IOptions<StorageServiceConfiguration> options, ILogge
4952

5053
var config = new AmazonSecurityTokenServiceConfig
5154
{
52-
AuthenticationRegion = RegionEndpoint.EUWest2.SystemName, // Should match the `MINIO_REGION` environment variable.
53-
ServiceURL = "http://" + endpoint, // replace http://localhost:9000 with URL of your MinIO server
55+
AuthenticationRegion = RegionEndpoint.EUWest2.SystemName,
56+
ServiceURL = credentialServiceUrl
5457
};
5558

5659
_tokenServiceClient = new AmazonSecurityTokenServiceClient(accessKey, accessToken, config);
@@ -162,11 +165,14 @@ public async Task<Credentials> CreateTemporaryCredentials(string bucketName, str
162165
Guard.Against.NullOrWhiteSpace(bucketName, nameof(bucketName));
163166
Guard.Against.NullOrEmpty(folderName, nameof(folderName));
164167

168+
var policy = PolicyExtensions.ToPolicy(bucketName, folderName);
169+
170+
var policyString = JsonConvert.SerializeObject(policy, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
171+
165172
var assumeRoleRequest = new AssumeRoleRequest
166173
{
167174
DurationSeconds = durationSeconds,
168-
Policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"AllowUserToSeeBucketListInTheConsole\",\"Action\":[\"s3:ListAllMyBuckets\",\"s3:GetBucketLocation\"],\"Effect\":\"Allow\",\"Resource\":[\"arn:aws:s3:::*\"]},{\"Sid\":\"AllowRootAndHomeListingOfBucket\",\"Action\":[\"s3:ListBucket\"],\"Effect\":\"Allow\",\"Resource\":[\"arn:aws:s3:::" +
169-
bucketName + "\"],\"Condition\":{\"StringEquals\":{\"s3:prefix\":[\"\",\"" + folderName + "\"],\"s3:delimiter\":[\"/\"]}}},{\"Sid\":\"AllowListingOfUserFolder\",\"Action\":[\"s3:ListBucket\"],\"Effect\":\"Allow\",\"Resource\":[\"arn:aws:s3:::" + bucketName + "\"],\"Condition\":{\"StringLike\":{\"s3:prefix\":[\"" + folderName + "/*\"]}}},{\"Sid\":\"AllowAllS3ActionsInUserFolder\",\"Effect\":\"Allow\",\"Action\":[\"s3:*\"],\"Resource\":[\"arn:aws:s3:::" + $"{bucketName}/{folderName}" + "/*\"]}]}"
175+
Policy = policyString
170176
};
171177

172178
var role = await _tokenServiceClient.AssumeRoleAsync(assumeRoleRequest, cancellationToken: cancellationToken);

src/Storage/Monai.Deploy.Storage.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,6 @@ SPDX-License-Identifier: Apache License 2.0
4848
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1" />
4949
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
5050
<PackageReference Include="Minio" Version="3.1.13" />
51+
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
5152
</ItemGroup>
5253
</Project>

0 commit comments

Comments
 (0)