Skip to content

Commit d471780

Browse files
authored
Merge pull request #1580 from aws/asmarp/limit-cdk-permissions
chore: restrict permissions for IAM role used by smoke tests
2 parents 331859d + 1b0af6e commit d471780

File tree

2 files changed

+80
-62
lines changed

2 files changed

+80
-62
lines changed

LambdaRuntimeDockerfiles/Infrastructure/src/Infrastructure/PipelineStack.cs

Lines changed: 78 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,13 @@ internal PipelineStack(
290290
}
291291
});
292292

293+
var smokeTestsLambdaFunctionRole = new Role(this, "SmokeTestsLambdaFunctionRole", new RoleProps
294+
{
295+
RoleName = $"image-function-tests-{Guid.NewGuid()}",
296+
ManagedPolicies = new IManagedPolicy[] { ManagedPolicy.FromAwsManagedPolicyName("service-role/AWSLambdaBasicExecutionRole") },
297+
AssumedBy = new ServicePrincipal("lambda.amazonaws.com")
298+
});
299+
293300
// Smoke test AMD64 image
294301
var amd64SmokeTests = new Project(this, "SmokeTests-amd64", new ProjectProps
295302
{
@@ -314,24 +321,82 @@ internal PipelineStack(
314321
{"AWS_LAMBDA_DOTNET_FRAMEWORK_VERSION", new BuildEnvironmentVariable {Value = framework}},
315322
{"AWS_LAMBDA_DOTNET_FRAMEWORK_CHANNEL", new BuildEnvironmentVariable {Value = channel}},
316323
{"AWS_LAMBDA_DOTNET_BUILD_IMAGE", new BuildEnvironmentVariable {Value = dockerBuildImage}},
317-
{"AWS_LAMBDA_DOTNET_SDK_VERSION", new BuildEnvironmentVariable {Value = configuration.DotnetSdkVersions.ContainsKey(framework) ? configuration.DotnetSdkVersions[framework] : string.Empty }}
318-
}
324+
{"AWS_LAMBDA_DOTNET_SDK_VERSION", new BuildEnvironmentVariable {Value = configuration.DotnetSdkVersions.ContainsKey(framework) ? configuration.DotnetSdkVersions[framework] : string.Empty }},
325+
{"AWS_LAMBDA_SMOKETESTS_LAMBDA_ROLE", new BuildEnvironmentVariable {Value = smokeTestsLambdaFunctionRole.RoleArn}}
326+
},
319327
});
320328

321-
var smokeTestsPolicy = new PolicyStatement(new PolicyStatementProps
329+
var smokeTestsPolicies = new List<PolicyStatement>();
330+
331+
// ECR Policies
332+
smokeTestsPolicies.Add(new PolicyStatement(new PolicyStatementProps
322333
{
323334
Effect = Effect.ALLOW,
324335
Actions = new[]
325336
{
326-
"sts:*",
327-
"iam:*",
328-
"ecr:*",
329-
"lambda:*"
337+
"ecr:BatchCheckLayerAvailability",
338+
"ecr:BatchDeleteImage",
339+
"ecr:BatchGetImage",
340+
"ecr:CompleteLayerUpload",
341+
"ecr:CreateRepository",
342+
"ecr:DescribeRepositories",
343+
"ecr:GetAuthorizationToken",
344+
"ecr:GetDownloadUrlForLayer",
345+
"ecr:InitiateLayerUpload",
346+
"ecr:PutImage",
347+
"ecr:UploadLayerPart"
348+
},
349+
Resources = new[] {
350+
$"arn:aws:ecr:{configuration.Region}:{configuration.AccountId}:repository/image-function-tests",
351+
$"arn:aws:ecr:{configuration.Region}:{configuration.AccountId}:repository/{ecrRepositoryName}"
352+
}
353+
}));
354+
355+
// The following ECR policy needs to specify * as the resource since that is what is explicitly stated by the following error:
356+
// An error occurred (AccessDeniedException) when calling the GetAuthorizationToken operation:
357+
// User: *** is not authorized to perform: ecr:GetAuthorizationToken on resource: * because no identity-based policy
358+
// allows the ecr:GetAuthorizationToken action
359+
smokeTestsPolicies.Add(new PolicyStatement(new PolicyStatementProps
360+
{
361+
Effect = Effect.ALLOW,
362+
Actions = new[]
363+
{
364+
"ecr:GetAuthorizationToken"
330365
},
331366
Resources = new[] { "*" }
332-
});
367+
}));
333368

334-
amd64SmokeTests.AddToRolePolicy(smokeTestsPolicy);
369+
// IAM Policies
370+
smokeTestsPolicies.Add(new PolicyStatement(new PolicyStatementProps
371+
{
372+
Effect = Effect.ALLOW,
373+
Actions = new[]
374+
{
375+
"iam:PassRole"
376+
},
377+
Resources = new[] { smokeTestsLambdaFunctionRole.RoleArn }
378+
}));
379+
380+
// Lambda Policies
381+
smokeTestsPolicies.Add(new PolicyStatement(new PolicyStatementProps
382+
{
383+
Effect = Effect.ALLOW,
384+
Actions = new[]
385+
{
386+
"lambda:CreateFunction",
387+
"lambda:DeleteFunction",
388+
"lambda:GetFunction",
389+
"lambda:GetFunctionConfiguration",
390+
"lambda:InvokeFunction",
391+
"lambda:UpdateFunctionConfiguration"
392+
},
393+
Resources = new[] {
394+
$"arn:aws:lambda:{configuration.Region}:{configuration.AccountId}:function:image-function-tests-*"
395+
}
396+
}));
397+
398+
foreach (var policy in smokeTestsPolicies)
399+
amd64SmokeTests.AddToRolePolicy(policy);
335400

336401
var smokeTestsActions = new List<Action>();
337402
smokeTestsActions.Add(new CodeBuildAction(new CodeBuildActionProps
@@ -367,11 +432,13 @@ internal PipelineStack(
367432
{"AWS_LAMBDA_DOTNET_FRAMEWORK_VERSION", new BuildEnvironmentVariable {Value = framework}},
368433
{"AWS_LAMBDA_DOTNET_FRAMEWORK_CHANNEL", new BuildEnvironmentVariable {Value = channel}},
369434
{"AWS_LAMBDA_DOTNET_BUILD_IMAGE", new BuildEnvironmentVariable {Value = dockerBuildImage}},
370-
{"AWS_LAMBDA_DOTNET_SDK_VERSION", new BuildEnvironmentVariable {Value = configuration.DotnetSdkVersions.ContainsKey(framework) ? configuration.DotnetSdkVersions[framework] : string.Empty }}
435+
{"AWS_LAMBDA_DOTNET_SDK_VERSION", new BuildEnvironmentVariable {Value = configuration.DotnetSdkVersions.ContainsKey(framework) ? configuration.DotnetSdkVersions[framework] : string.Empty }},
436+
{"AWS_LAMBDA_SMOKETESTS_LAMBDA_ROLE", new BuildEnvironmentVariable {Value = smokeTestsLambdaFunctionRole.RoleArn}}
371437
}
372438
});
373439

374-
arm64SmokeTests.AddToRolePolicy(smokeTestsPolicy);
440+
foreach (var policy in smokeTestsPolicies)
441+
arm64SmokeTests.AddToRolePolicy(policy);
375442

376443
smokeTestsActions.Add(new CodeBuildAction(new CodeBuildActionProps
377444
{

LambdaRuntimeDockerfiles/SmokeTests/test/ImageFunction.SmokeTests/ImageFunctionTests.cs

Lines changed: 2 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ public class ImageFunctionTests : IDisposable
4141
private static readonly RegionEndpoint TestRegion = RegionEndpoint.USWest2;
4242
private readonly AmazonLambdaClient _lambdaClient;
4343
private readonly AmazonIdentityManagementServiceClient _iamClient;
44-
private readonly string _executionRoleName;
4544
private string _executionRoleArn;
4645

4746
private static readonly string LambdaAssumeRolePolicy =
@@ -67,16 +66,17 @@ public class ImageFunctionTests : IDisposable
6766

6867
public ImageFunctionTests()
6968
{
70-
_executionRoleName = $"{TestIdentifier}-{Guid.NewGuid()}";
7169
_functionName = $"{TestIdentifier}-{Guid.NewGuid()}";
7270
var lambdaConfig = new AmazonLambdaConfig()
7371
{
7472
RegionEndpoint = TestRegion
7573
};
7674
_lambdaClient = new AmazonLambdaClient(lambdaConfig);
7775
_iamClient = new AmazonIdentityManagementServiceClient(TestRegion);
76+
_executionRoleArn = Environment.GetEnvironmentVariable("AWS_LAMBDA_SMOKETESTS_LAMBDA_ROLE");
7877
_imageUri = Environment.GetEnvironmentVariable("AWS_LAMBDA_IMAGE_URI");
7978

79+
Assert.NotNull(_executionRoleArn);
8080
Assert.NotNull(_imageUri);
8181

8282
SetupAsync().GetAwaiter().GetResult();
@@ -166,7 +166,6 @@ private async Task<InvokeResponse> InvokeFunctionAsync(string payload)
166166

167167
private async Task SetupAsync()
168168
{
169-
await CreateRoleAsync();
170169
await CreateFunctionAsync();
171170
}
172171

@@ -227,29 +226,6 @@ await _lambdaClient.CreateFunctionAsync(new CreateFunctionRequest
227226
}
228227
}
229228

230-
private async Task CreateRoleAsync()
231-
{
232-
var response = await _iamClient.CreateRoleAsync(new CreateRoleRequest
233-
{
234-
RoleName = _executionRoleName,
235-
Description = $"Test role for {TestIdentifier}.",
236-
AssumeRolePolicyDocument = LambdaAssumeRolePolicy
237-
});
238-
_executionRoleArn = response.Role.Arn;
239-
240-
// Wait 10 seconds to let execution role propagate
241-
await Task.Delay(10000);
242-
243-
await _iamClient.AttachRolePolicyAsync(new AttachRolePolicyRequest
244-
{
245-
RoleName = _executionRoleName,
246-
PolicyArn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
247-
});
248-
249-
// Wait 10 seconds to let execution role propagate
250-
await Task.Delay(10000);
251-
}
252-
253229
private static string GetArchitecture()
254230
{
255231
switch (RuntimeInformation.ProcessArchitecture)
@@ -297,7 +273,6 @@ protected virtual void Dispose(bool disposing)
297273

298274
private async Task TearDownAsync()
299275
{
300-
await DeleteRoleIfExistsAsync();
301276
await DeleteFunctionIfExistsAsync();
302277
}
303278

@@ -316,30 +291,6 @@ await _lambdaClient.DeleteFunctionAsync(new DeleteFunctionRequest
316291
}
317292
}
318293

319-
private async Task DeleteRoleIfExistsAsync()
320-
{
321-
try
322-
{
323-
await _iamClient.DetachRolePolicyAsync(new DetachRolePolicyRequest
324-
{
325-
RoleName = _executionRoleName,
326-
PolicyArn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
327-
});
328-
329-
// Wait 10 seconds to let execution role propagate
330-
await Task.Delay(10000);
331-
332-
await _iamClient.DeleteRoleAsync(new DeleteRoleRequest
333-
{
334-
RoleName = _executionRoleName
335-
});
336-
}
337-
catch (NoSuchEntityException)
338-
{
339-
// No action required
340-
}
341-
}
342-
343294
#endregion
344295
}
345296
}

0 commit comments

Comments
 (0)