Skip to content
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 .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"source=${env:HOME}${env:USERPROFILE}/.gitconfig,target=/home/vscode/.gitconfig,type=bind"
],
"features": {
"ghcr.io/devcontainers/features/github-cli:1": {},
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {
"version": "latest",
"moby": "true",
Expand Down
46 changes: 0 additions & 46 deletions .github/scripts/check-sbom-issues-against-ignores.sh

This file was deleted.

30 changes: 29 additions & 1 deletion cdk.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,34 @@
"@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true,
"@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false,
"@aws-cdk/aws-s3:keepNotificationInImportedBucket": false,
"cdk-migrate": true
"@aws-cdk/aws-appsync:appSyncGraphQLAPIScopeLambdaPermission": true,
"@aws-cdk/aws-dynamodb:resourcePolicyPerReplica": true,
"@aws-cdk/aws-dynamodb:retainTableReplica": true,
"@aws-cdk/aws-ec2:bastionHostUseAmazonLinux2023ByDefault": true,
"@aws-cdk/aws-ec2:ec2SumTImeoutEnabled": true,
"@aws-cdk/aws-ec2:requirePrivateSubnetsForEgressOnlyInternetGateway": true,
"@aws-cdk/aws-ecs-patterns:secGroupsDisablesImplicitOpenListener": true,
"@aws-cdk/aws-ecs-patterns:uniqueTargetGroupId": true,
"@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": true,
"@aws-cdk/aws-elasticloadbalancingV2:albDualstackWithoutPublicIpv4SecurityGroupRulesDefault": true,
"@aws-cdk/aws-elasticloadbalancingv2:networkLoadBalancerWithSecurityGroupByDefault": true,
"@aws-cdk/aws-events:requireEventBusPolicySid": true,
"@aws-cdk/aws-iam:oidcRejectUnauthorizedConnections": true,
"@aws-cdk/aws-kms:applyImportedAliasPermissionsToPrincipal": true,
"@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": true,
"@aws-cdk/aws-lambda:useCdkManagedLogGroup": true,
"@aws-cdk/aws-rds:setCorrectValueForDatabaseInstanceReadReplicaInstanceResourceId": true,
"@aws-cdk/aws-route53-patterns:useDistribution": true,
"@aws-cdk/aws-route53-targets:userPoolDomainNameMethodWithoutCustomResource": true,
"@aws-cdk/aws-s3:publicAccessBlockedByDefault": true,
"@aws-cdk/aws-s3:setUniqueReplicationRoleName": true,
"@aws-cdk/aws-signer:signingProfileNamePassedToCfn": true,
"@aws-cdk/aws-stepfunctions-tasks:fixRunEcsTaskPolicy": true,
"@aws-cdk/aws-stepfunctions:useDistributedMapResultWriterV2": true,
"@aws-cdk/core:aspectPrioritiesMutating": true,
"@aws-cdk/core:cfnIncludeRejectComplexResourceUpdateCreatePolicyIntrinsics": true,
"@aws-cdk/core:enableAdditionalMetadataCollection": true,
"@aws-cdk/core:explicitStackTags": true,
"@aws-cdk/s3-notifications:addS3TrustKeyPolicyForSnsSubscriptions": true
}
}
2 changes: 1 addition & 1 deletion packages/cdk/bin/utils/appUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const findResourcesByType = (construct: IConstruct, type: string): Array<CfnReso
/**
* Add/merge cfn-guard suppressions to resources for the given rules.
*/
const addSuppressions = (resources: Array<CfnResource>, rules: Array<string>): void => {
export const addSuppressions = (resources: Array<CfnResource>, rules: Array<string>): void => {
resources.forEach(resource => {
if (!resource.cfnOptions.metadata) {
resource.cfnOptions.metadata = {}
Expand Down
125 changes: 111 additions & 14 deletions packages/cdk/constructs/DelayResource.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
import {Construct} from "constructs"
import {Duration, CustomResource} from "aws-cdk-lib"
import {
Duration,
CustomResource,
Fn,
RemovalPolicy
} from "aws-cdk-lib"
import {Function, Runtime, Code} from "aws-cdk-lib/aws-lambda"
import {Role, ServicePrincipal, ManagedPolicy} from "aws-cdk-lib/aws-iam"
import {
Role,
ServicePrincipal,
ManagedPolicy,
PolicyStatement
} from "aws-cdk-lib/aws-iam"
import {Provider} from "aws-cdk-lib/custom-resources"
import {Key} from "aws-cdk-lib/aws-kms"
import {CfnLogGroup, LogGroup} from "aws-cdk-lib/aws-logs"
import {NagSuppressions} from "cdk-nag"
import {addSuppressions} from "../bin/utils/appUtils"

export interface DelayResourceProps {
/**
Expand All @@ -14,6 +28,11 @@ export interface DelayResourceProps {
* Optional description for the delay resource
*/
readonly description?: string

/**
* Name for the delay resource
*/
readonly name: string
}

/**
Expand All @@ -22,29 +41,72 @@ export interface DelayResourceProps {
*/
export class DelayResource extends Construct {
public readonly customResource: CustomResource
public readonly delaySeconds: number

constructor(scope: Construct, id: string, props: DelayResourceProps = {}) {
constructor(scope: Construct, id: string, props: DelayResourceProps) {
super(scope, id)
const {
delaySeconds = 30,
description = `Delay resource for ${delaySeconds} seconds`,
name
} = props
const cloudWatchLogsKmsKey = Key.fromKeyArn(
scope, `${name}delayResourceCloudWatchLogsKmsKey`, Fn.importValue("account-resources:CloudwatchLogsKmsKeyArn"))

const cloudwatchEncryptionKMSPolicy = ManagedPolicy.fromManagedPolicyArn(
scope, `${name}delayResourceCloudwatchEncryptionKMSPolicyArn`,
Fn.importValue("account-resources:CloudwatchEncryptionKMSPolicyArn"))

const logGroup = new LogGroup(scope, `${name}LambdaLogGroup`, {
encryptionKey: cloudWatchLogsKmsKey,
logGroupName: `/aws/lambda/${name}`,
retention: 30,
removalPolicy: RemovalPolicy.DESTROY
})

const cfnlogGroup = logGroup.node.defaultChild as CfnLogGroup
addSuppressions([cfnlogGroup], ["CW_LOGGROUP_RETENTION_PERIOD_CHECK"])
const putLogsManagedPolicy = new ManagedPolicy(scope, `${name}LambdaPutLogsManagedPolicy`, {
description: `write to ${name} logs`,
statements: [
new PolicyStatement({
actions: [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
resources: [
logGroup.logGroupArn,
`${logGroup.logGroupArn}:log-stream:*`
]
})
]
})

this.delaySeconds = props.delaySeconds || 30
NagSuppressions.addResourceSuppressions(putLogsManagedPolicy, [
{
id: "AwsSolutions-IAM5",
// eslint-disable-next-line max-len
reason: "Suppress error for not having wildcards in permissions. This is a fine as we need to have permissions on all log streams under path"
}
])

// create IAM role for the delay Lambda function
const lambdaExecutionRole = new Role(this, "LambdaExecutionRole", {
const lambdaExecutionRole = new Role(this, `${name}LambdaExecutionRole`, {
assumedBy: new ServicePrincipal("lambda.amazonaws.com"),
description: "Execution role for delay custom resource Lambda function",
managedPolicies: [
ManagedPolicy.fromAwsManagedPolicyName("service-role/AWSLambdaBasicExecutionRole")
putLogsManagedPolicy,
cloudwatchEncryptionKMSPolicy
]
})

// create the delay Lambda function with inline Python code
const delayFunction = new Function(this, "DelayFunction", {
const delayFunction = new Function(this, `${name}DelayFunction`, {
runtime: Runtime.PYTHON_3_12,
logGroup: logGroup,
handler: "index.handler",
role: lambdaExecutionRole,
timeout: Duration.minutes(15), // max Lambda timeout to handle long delays
description: props.description || `Delay resource for ${this.delaySeconds} seconds`,
description: description,
code: Code.fromInline(`
from time import sleep
import json
Expand Down Expand Up @@ -78,17 +140,52 @@ def handler(event, context):
`)
})

const frameworkInvokeDelayFunctionPolicy = new ManagedPolicy(this,
`${name}DelayProviderInvokeDelayFunctionPolicy`, {
description: `Allow provider framework to invoke ${name} delay function`,
statements: [
new PolicyStatement({
actions: [
"lambda:InvokeFunction",
"lambda:GetFunction"
],
resources: [
delayFunction.functionArn
]
})
]
})

const frameworkOnEventRole = new Role(this, `${name}DelayProviderFrameworkOnEventRole`, {
assumedBy: new ServicePrincipal("lambda.amazonaws.com"),
description: "Execution role for delay provider framework onEvent Lambda function",
managedPolicies: [
putLogsManagedPolicy,
cloudwatchEncryptionKMSPolicy,
frameworkInvokeDelayFunctionPolicy
]
})

const frameworkOnEventRoleRef = Role.fromRoleArn(
this,
`${name}DelayProviderFrameworkOnEventRoleRef`,
frameworkOnEventRole.roleArn,
{mutable: false}
)

// create the custom resource provider
const provider = new Provider(this, "DelayProvider", {
onEventHandler: delayFunction
const provider = new Provider(this, `${name}DelayProvider`, {
onEventHandler: delayFunction,
logGroup: logGroup,
frameworkOnEventRole: frameworkOnEventRoleRef
})

// create the custom resource that triggers the delay
this.customResource = new CustomResource(this, "DelayCustomResource", {
this.customResource = new CustomResource(this, `${name}DelayCustomResource`, {
serviceToken: provider.serviceToken,
properties: {
WaitSeconds: this.delaySeconds,
Description: props.description || `Delay for ${this.delaySeconds} seconds`,
WaitSeconds: delaySeconds,
Description: description,
// timestamp to ensure updates trigger when properties change
Timestamp: Date.now()
}
Expand Down
5 changes: 4 additions & 1 deletion packages/cdk/constructs/SecretWithParameter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import {Construct} from "constructs"
import {SecretValue} from "aws-cdk-lib"
import {StringParameter, ParameterTier} from "aws-cdk-lib/aws-ssm"
import {Secret} from "aws-cdk-lib/aws-secretsmanager"
import {IKey} from "aws-cdk-lib/aws-kms"

export interface SecretWithParameterProps {
readonly secretName: string
readonly parameterName: string
readonly description: string
readonly secretValue: string
readonly kmsKey: IKey
}

export class SecretWithParameter extends Construct {
Expand All @@ -21,7 +23,8 @@ export class SecretWithParameter extends Construct {
const secret = new Secret(this, "Secret", {
secretName: props.secretName,
description: props.description,
secretStringValue: SecretValue.unsafePlainText(props.secretValue)
secretStringValue: SecretValue.unsafePlainText(props.secretValue),
encryptionKey: props.kmsKey
})

// Create SSM parameter that references the secret
Expand Down
Loading
Loading