Skip to content

Commit

Permalink
utilize new methods in v2.117.0 CDK release; finalizes v0.41
Browse files Browse the repository at this point in the history
  • Loading branch information
Kapral67 committed Dec 28, 2023
1 parent ba0e62f commit 6bf4cd3
Show file tree
Hide file tree
Showing 21 changed files with 59 additions and 51 deletions.
4 changes: 2 additions & 2 deletions AdminClient/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ plugins {
}

group = 'org.familydirectory.sdk.adminclient'
version = '0.4'
version = '0.41'

compileJava {
sourceCompatibility = '21'
Expand All @@ -19,7 +19,7 @@ repositories {
}

dependencies {
implementation 'org.familydirectory.assets:familydirectory-service-assets:0.4'
implementation 'org.familydirectory.assets:familydirectory-service-assets:0.41'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.16.1'
implementation 'org.jetbrains:annotations:24.1.0'
implementation 'com.amazonaws:aws-lambda-java-core:1.2.3'
Expand Down
2 changes: 1 addition & 1 deletion CDK/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

<groupId>org.familydirectory.cdk</groupId>
<artifactId>familydirectory-cdk</artifactId>
<version>0.4</version>
<version>0.41</version>

<build>
<plugins>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

public final
class FamilyDirectoryCdkApp {
public static final String VERSION = "0.4";
public static final String VERSION = "0.41";
public static final String DEFAULT_ACCOUNT;
public static final String DEFAULT_REGION;
public static final Environment DEFAULT_ENV;
Expand All @@ -34,6 +34,7 @@ class FamilyDirectoryCdkApp {
public static final String API_STACK_NAME = "FamilyDirectoryApiGatewayStack";
public static final String AMPLIFY_STACK_NAME = "FamilyDirectoryAmplifyStack";
public static final String HTTPS_PREFIX = "https://";
public static final String GLOBAL_RESOURCE = "*";

static {
String account = getenv("CDK_DEFAULT_ACCOUNT");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import org.familydirectory.cdk.FamilyDirectoryCdkApp;
import org.familydirectory.cdk.cognito.FamilyDirectoryCognitoStack;
import org.familydirectory.cdk.domain.FamilyDirectoryDomainStack;
import org.jetbrains.annotations.NotNull;
import software.amazon.awscdk.Duration;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
Expand Down Expand Up @@ -44,7 +43,6 @@
import software.constructs.Construct;
import static java.lang.Boolean.FALSE;
import static java.util.Collections.singletonList;
import static java.util.Objects.requireNonNull;
import static software.amazon.awscdk.Fn.importValue;

public
Expand All @@ -66,7 +64,6 @@ class FamilyDirectoryApiGatewayStack extends Stack {
public static final boolean HTTP_API_PUBLIC_STAGE_AUTO_DEPLOY = true;
public static final String LAMBDA_INVOKE_PERMISSION_ACTION = "lambda:InvokeFunction";
public static final String API_GATEWAY_PERMISSION_PRINCIPAL = "apigateway.amazonaws.com";
public static final String EXECUTE_API_ARN_PREFIX = "arn:aws:execute-api:%s:%s:".formatted(FamilyDirectoryCdkApp.DEFAULT_REGION, FamilyDirectoryCdkApp.DEFAULT_ACCOUNT);

public
FamilyDirectoryApiGatewayStack (final Construct scope, final String id, final StackProps stackProps) {
Expand Down Expand Up @@ -145,16 +142,13 @@ class FamilyDirectoryApiGatewayStack extends Stack {
.methods(func.methods())
.integration(httpLambdaIntegration)
.build());

// TODO: More Programmatic Solution Available Once [this issue](https://github.com/aws/aws-cdk/issues/23301) is resolved
// Parts of Execute-Api Arn: https://docs.aws.amazon.com/apigateway/latest/developerguide/arn-format-reference.html#apigateway-execute-api-arns
final String sourceArn = "%s%s%s".formatted(EXECUTE_API_ARN_PREFIX, httpApi.getApiId(), getExecuteApiSuffix(func));

// Allow ApiGateway to invoke its respective Lambda Function
new CfnPermission(this, "Allow%sInvoke%s".formatted(HTTP_API_RESOURCE_ID, func.name()), CfnPermissionProps.builder()
.action(LAMBDA_INVOKE_PERMISSION_ACTION)
.functionName(function.getFunctionArn())
.principal(API_GATEWAY_PERMISSION_PRINCIPAL)
.sourceArn(sourceArn)
.sourceArn(httpApi.arnForExecuteApi(FamilyDirectoryCdkApp.GLOBAL_RESOURCE,
func.endpoint()))
.build());
}

Expand All @@ -167,9 +161,4 @@ class FamilyDirectoryApiGatewayStack extends Stack {
.build());
}

@NotNull
public static
String getExecuteApiSuffix (final @NotNull ApiFunction func) {
return "/*/*" + requireNonNull(func).endpoint();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import java.time.Instant;
import java.util.regex.Pattern;
import org.familydirectory.cdk.lambda.construct.utility.LambdaFunctionConstructUtility;
import org.familydirectory.cdk.FamilyDirectoryCdkApp;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import software.amazon.awscdk.customresources.AwsCustomResource;
Expand Down Expand Up @@ -32,8 +32,7 @@ class SSMParameterReader extends AwsCustomResource {
.policy(AwsCustomResourcePolicy.fromStatements(singletonList(PolicyStatement.Builder.create()
.actions(singletonList("ssm:GetParameter"))
.effect(Effect.ALLOW)
.resources(singletonList(
LambdaFunctionConstructUtility.GLOBAL_RESOURCE))
.resources(singletonList(FamilyDirectoryCdkApp.GLOBAL_RESOURCE))
.build())))
.build());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ class LambdaFunctionConstructUtility {
public static final Runtime RUNTIME = JAVA_21;
public static final Architecture ARCHITECTURE = ARM_64;
public static final String ROOT_ID = DdbUtils.ROOT_MEMBER_ID;
public static final String GLOBAL_RESOURCE = "*";

private
LambdaFunctionConstructUtility () {
Expand Down Expand Up @@ -111,7 +110,7 @@ void constructFunctionPermissions (final @NotNull Map<? extends LambdaFunctionMo
final String tableArn = importValue(table.arnExportName());
v.addToRolePolicy(create().effect(ALLOW)
.actions(actions)
.resources(List.of(tableArn, "%s/index/%s".formatted(tableArn, GLOBAL_RESOURCE)))
.resources(List.of(tableArn, "%s/index/%s".formatted(tableArn, FamilyDirectoryCdkApp.GLOBAL_RESOURCE)))
.build());
}));
// Assign Cognito Permissions
Expand All @@ -124,15 +123,15 @@ void constructFunctionPermissions (final @NotNull Map<? extends LambdaFunctionMo
// Assign Ses Permissions
ofNullable(k.sesActions()).ifPresent(actions -> v.addToRolePolicy(create().effect(ALLOW)
.actions(actions)
.resources(singletonList(GLOBAL_RESOURCE))
.resources(singletonList(FamilyDirectoryCdkApp.GLOBAL_RESOURCE))
.build()));

// Assign S3 Permissions
ofNullable(pdfBucket).map(IBucket::getBucketArn)
.ifPresent(pdfBucketArn -> ofNullable(k.sssActions()).ifPresent(actions -> v.addToRolePolicy(create().effect(ALLOW)
.actions(actions)
.resources(singletonList(
"%s/%s".formatted(pdfBucketArn, GLOBAL_RESOURCE)))
.resources(singletonList("%s/%s".formatted(pdfBucketArn,
FamilyDirectoryCdkApp.GLOBAL_RESOURCE)))
.build())));
});
}
Expand All @@ -148,7 +147,7 @@ void constructFunctionPermissions (final @NotNull Construct scope, final @NotNul
final String tableArn = importValue(table.arnExportName());
executionRole.addToPrincipalPolicy(create().effect(ALLOW)
.actions(actions)
.resources(List.of(tableArn, "%s/index/%s".formatted(tableArn, GLOBAL_RESOURCE)))
.resources(List.of(tableArn, "%s/index/%s".formatted(tableArn, FamilyDirectoryCdkApp.GLOBAL_RESOURCE)))
.build());
}));

Expand All @@ -161,7 +160,7 @@ void constructFunctionPermissions (final @NotNull Construct scope, final @NotNul
// Assign Ses Permissions
ofNullable(f.sesActions()).ifPresent(actions -> executionRole.addToPrincipalPolicy(create().effect(ALLOW)
.actions(actions)
.resources(singletonList(GLOBAL_RESOURCE))
.resources(singletonList(FamilyDirectoryCdkApp.GLOBAL_RESOURCE))
.build()));

// Assign S3 Permissions
Expand All @@ -170,7 +169,7 @@ void constructFunctionPermissions (final @NotNull Construct scope, final @NotNul
.actions(actions)
.resources(singletonList(
"%s/%s".formatted(pdfBucketArn,
GLOBAL_RESOURCE)))
FamilyDirectoryCdkApp.GLOBAL_RESOURCE)))
.build())));
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
package org.familydirectory.cdk.test.apigateway;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.familydirectory.assets.lambda.function.api.enums.ApiFunction;
import org.familydirectory.cdk.FamilyDirectoryCdkApp;
import org.familydirectory.cdk.apigateway.FamilyDirectoryApiGatewayStack;
import org.familydirectory.cdk.cognito.FamilyDirectoryCognitoStack;
import org.familydirectory.cdk.domain.FamilyDirectoryDomainStack;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Test;
import software.amazon.awscdk.App;
import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.assertions.Capture;
import software.amazon.awscdk.assertions.Template;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static java.util.Objects.requireNonNull;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static software.amazon.awscdk.assertions.Match.objectLike;

public
class FamilyDirectoryApiGatewayStackTest {

private static final String EXECUTE_API_ARN_PRESUFFIX = ":execute-api:%s:%s:".formatted(FamilyDirectoryCdkApp.DEFAULT_REGION, FamilyDirectoryCdkApp.DEFAULT_ACCOUNT);
private static final String HOSTED_ZONE_ID_PARAMETER_NAME = "%sParameter".formatted(FamilyDirectoryDomainStack.HOSTED_ZONE_ID_PARAMETER_NAME);
private static final String FULL_API_DOMAIN_NAME = "%s.".formatted(FamilyDirectoryApiGatewayStack.API_DOMAIN_NAME);

Expand Down Expand Up @@ -141,13 +147,23 @@ FamilyDirectoryDomainStack.HOSTED_ZONE_ID_PARAMETER_NAME, singletonMap("Ref", HO
.name(), func.endpoint()), "Target",
singletonMap("Fn::Join", List.of("", List.of("integrations/", singletonMap("Ref", integrationId)))))));

final Capture lambdaPermissionSourceArnCapture = new Capture();
template.hasResourceProperties("AWS::Lambda::Permission", objectLike(
Map.of("Action", FamilyDirectoryApiGatewayStack.LAMBDA_INVOKE_PERMISSION_ACTION, "FunctionName", singletonMap("Fn::ImportValue", func.arnExportName()), "Principal",
FamilyDirectoryApiGatewayStack.API_GATEWAY_PERMISSION_PRINCIPAL, "SourceArn", singletonMap("Fn::Join", List.of("",
List.of(FamilyDirectoryApiGatewayStack.EXECUTE_API_ARN_PREFIX,
singletonMap("Ref", apiId),
FamilyDirectoryApiGatewayStack.getExecuteApiSuffix(
func)))))));
FamilyDirectoryApiGatewayStack.API_GATEWAY_PERMISSION_PRINCIPAL, "SourceArn", singletonMap("Fn::Join", List.of("", lambdaPermissionSourceArnCapture)))));
final List<Object> lambdaPermissionsSourceArn = lambdaPermissionSourceArnCapture.asArray();
final Iterator<Object> lambdaPermissionsSourceArnIterator = lambdaPermissionsSourceArn.iterator();
if (lambdaPermissionsSourceArnIterator.next()
.equals("arn:"))
{
assertEquals(lambdaPermissionsSourceArnIterator.next(), singletonMap("Ref", "AWS::Partition"));
assertEquals(lambdaPermissionsSourceArnIterator.next(), EXECUTE_API_ARN_PRESUFFIX);
} else {
assertEquals(lambdaPermissionsSourceArn.getFirst(), "arn:aws%s".formatted(EXECUTE_API_ARN_PRESUFFIX));
}
assertEquals(lambdaPermissionsSourceArnIterator.next(), singletonMap("Ref", apiId));
assertEquals(lambdaPermissionsSourceArnIterator.next(), getExecuteApiSuffix(func));
assertFalse(lambdaPermissionsSourceArnIterator.hasNext());
}

template.hasResourceProperties("AWS::ApiGatewayV2::Stage", objectLike(
Expand All @@ -157,4 +173,10 @@ FamilyDirectoryDomainStack.HOSTED_ZONE_ID_PARAMETER_NAME, singletonMap("Ref", HO
template.hasResourceProperties("AWS::ApiGatewayV2::ApiMapping", objectLike(
Map.of("ApiId", singletonMap("Ref", apiId), "DomainName", singletonMap("Ref", domainNameId), "Stage", FamilyDirectoryApiGatewayStack.HTTP_API_PUBLIC_STAGE_ID)));
}

@NotNull
private static
String getExecuteApiSuffix (final @NotNull ApiFunction func) {
return "/*/*" + requireNonNull(func).endpoint();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ void testStack () {
entry("WriteAttributes", singletonList("email")))));

final Map<String, Map<String, List<Map<String, String>>>> ssmReaderIamPolicy = singletonMap("PolicyDocument", singletonMap("Statement", singletonList(
Map.of("Action", "ssm:GetParameter", "Effect", "Allow", "Resource", LambdaFunctionConstructUtility.GLOBAL_RESOURCE))));
Map.of("Action", "ssm:GetParameter", "Effect", "Allow", "Resource", FamilyDirectoryCdkApp.GLOBAL_RESOURCE))));
final Map<String, List<Object>> userPoolCloudFrontDomainNamePolicy = singletonMap("Fn::Join", List.of("", List.of("{\"service" + "\":\"CognitoIdentityServiceProvider\"," +
"\"action\":\"describeUserPoolDomain\"," + "\"parameters\":{\"Domain\":\"",
singletonMap("Ref", userPoolDomainNameCapture.asString()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import org.familydirectory.cdk.cognito.FamilyDirectoryCognitoUsEastOneStack;
import org.familydirectory.cdk.customresource.SSMParameterReader;
import org.familydirectory.cdk.domain.FamilyDirectoryDomainStack;
import org.familydirectory.cdk.lambda.construct.utility.LambdaFunctionConstructUtility;
import org.junit.jupiter.api.Test;
import software.amazon.awscdk.App;
import software.amazon.awscdk.StackProps;
Expand Down Expand Up @@ -42,7 +41,7 @@ void testStack () {
final Template template = Template.fromStack(stack);

final Map<String, Map<String, List<Map<String, String>>>> ssmReaderIamPolicy = singletonMap("PolicyDocument", singletonMap("Statement", singletonList(
Map.of("Action", "ssm:GetParameter", "Effect", "Allow", "Resource", LambdaFunctionConstructUtility.GLOBAL_RESOURCE))));
Map.of("Action", "ssm:GetParameter", "Effect", "Allow", "Resource", FamilyDirectoryCdkApp.GLOBAL_RESOURCE))));

if (!FamilyDirectoryCdkApp.DEFAULT_REGION.equals(FamilyDirectoryCognitoUsEastOneStack.REGION)) {
final Capture ssmReaderCreateCapture = new Capture();
Expand Down
Loading

0 comments on commit 6bf4cd3

Please sign in to comment.