Skip to content
Merged
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
18 changes: 11 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 31 additions & 0 deletions packages/cdk/nagSuppressions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,37 @@ export const nagSuppressions = (stack: Stack) => {
]
)

safeAddNagSuppression(
stack,
"/StatelessStack/SharedSecrets/ApigeeApiKey/Resource",
[
{
id: "AwsSolutions-SMG4",
reason: "Suppress error for not rotating secret. This is by design."
}
]
)
safeAddNagSuppression(
stack,
"/StatelessStack/SharedSecrets/ApigeeApiSecret/Resource",
[
{
id: "AwsSolutions-SMG4",
reason: "Suppress error for not rotating secret. This is by design."
}
]
)
safeAddNagSuppression(
stack,
"/StatelessStack/SharedSecrets/ApigeeDoHSApiKey/Resource",
[
{
id: "AwsSolutions-SMG4",
reason: "Suppress error for not rotating secret. This is by design."
}
]
)

}

}
Expand Down
67 changes: 67 additions & 0 deletions packages/cdk/resources/SharedSecrets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ export interface SharedSecretsProps {
readonly stackName: string
readonly deploymentRole: IRole
readonly useMockOidc?: boolean
readonly apigeeApiKey: string
readonly apigeeApiSecret: string
readonly apigeeDoHSApiKey: string
}

// Construct for managing shared secrets and associated resources
Expand All @@ -26,6 +29,11 @@ export class SharedSecrets extends Construct {
public readonly useJwtKmsKeyPolicy: ManagedPolicy
public readonly getPrimaryJwtPrivateKeyPolicy: ManagedPolicy
public readonly getMockJwtPrivateKeyPolicy: ManagedPolicy
public readonly apigeeSecretsKmsKey: IKey
public readonly apigeeApiKey: Secret
public readonly apigeeApiSecret: Secret
public readonly apigeeDoHSApiKey: Secret
public readonly getApigeeSecretsPolicy: ManagedPolicy

constructor(scope: Construct, id: string, props: SharedSecretsProps) {
super(scope, id)
Expand Down Expand Up @@ -57,6 +65,65 @@ export class SharedSecrets extends Construct {
})
})

this.apigeeSecretsKmsKey = new Key(this, "ApigeeSecretsKmsKey", {
description: `${props.stackName}-apigeeSecretsKmsKey`,
enableKeyRotation: true,
removalPolicy: RemovalPolicy.DESTROY,
pendingWindow: Duration.days(7),
policy: new PolicyDocument({
statements: [
// Allow full IAM permissions for account root
new PolicyStatement({
sid: "EnableIAMUserPermissions",
effect: Effect.ALLOW,
actions: ["kms:*"],
principals: [new AccountRootPrincipal()],
resources: ["*"]
}),
// Allow the deployment role to encrypt and generate data keys
new PolicyStatement({
effect: Effect.ALLOW,
principals: [props.deploymentRole],
actions: ["kms:Encrypt", "kms:GenerateDataKey*"],
resources: ["*"]
})
]
})
})
this.apigeeApiKey = new Secret(this, "ApigeeApiKey", {
secretName: `${props.stackName}-apigeeApiKey`,
secretStringValue: SecretValue.unsafePlainText(props.apigeeApiKey),
encryptionKey: this.apigeeSecretsKmsKey
})
this.apigeeApiSecret = new Secret(this, "ApigeeApiSecret", {
secretName: `${props.stackName}-apigeeApiSecret`,
secretStringValue: SecretValue.unsafePlainText(props.apigeeApiSecret),
encryptionKey: this.apigeeSecretsKmsKey
})
this.apigeeDoHSApiKey = new Secret(this, "ApigeeDoHSApiKey", {
secretName: `${props.stackName}-apigeeDoHSApiKey`,
secretStringValue: SecretValue.unsafePlainText(props.apigeeDoHSApiKey),
encryptionKey: this.apigeeSecretsKmsKey
})

// Create a managed policy to allow getting the primary JWT private key secret
this.getApigeeSecretsPolicy = new ManagedPolicy(this, "GetApigeeSecretsPolicy", {
statements: [
new PolicyStatement({
actions: ["secretsmanager:GetSecretValue"],
resources: [
this.apigeeApiKey.secretArn,
this.apigeeApiSecret.secretArn,
this.apigeeDoHSApiKey.secretArn]
}),
new PolicyStatement({
actions: ["kms:DescribeKey", "kms:Decrypt"],
effect: Effect.ALLOW,
resources: [this.apigeeSecretsKmsKey.keyArn]
})
]
})

// Create a managed policy to allow using the KMS key for decryption
this.useJwtKmsKeyPolicy = new ManagedPolicy(this, "UseJwtKmsKeyPolicy", {
description: "Policy to allow using the JWT KMS key",
Expand Down
28 changes: 9 additions & 19 deletions packages/cdk/resources/api/apiFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import {SharedSecrets} from "../SharedSecrets"
import {ITableV2} from "aws-cdk-lib/aws-dynamodb"
import {IManagedPolicy} from "aws-cdk-lib/aws-iam"
import {NodejsFunction} from "aws-cdk-lib/aws-lambda-nodejs"
import {Secret} from "aws-cdk-lib/aws-secretsmanager"
import {NagSuppressions} from "cdk-nag"
import {ISecret, Secret} from "aws-cdk-lib/aws-secretsmanager"

// Interface for properties needed to create API functions
export interface ApiFunctionsProps {
Expand Down Expand Up @@ -39,9 +38,9 @@ export interface ApiFunctionsProps {
readonly apigeeDoHSEndpoint: string
readonly apigeePrescriptionsEndpoint: string
readonly apigeePersonalDemographicsEndpoint: string
readonly apigeeApiKey: string
readonly apigeeApiSecret: string
readonly apigeeDoHSApiKey: string
readonly apigeeApiKey: ISecret
readonly apigeeApiSecret: ISecret
readonly apigeeDoHSApiKey: ISecret
readonly jwtKid: string
readonly logLevel: string
readonly roleId: string
Expand Down Expand Up @@ -78,7 +77,8 @@ export class ApiFunctions extends Construct {
props.sessionManagementTableReadPolicy,
props.useSessionManagementKmsKeyPolicy,
props.sharedSecrets.useJwtKmsKeyPolicy,
props.sharedSecrets.getPrimaryJwtPrivateKeyPolicy
props.sharedSecrets.getPrimaryJwtPrivateKeyPolicy,
props.sharedSecrets.getApigeeSecretsPolicy
]

if (props.useMockOidc && props.sharedSecrets.getMockJwtPrivateKeyPolicy) {
Expand All @@ -101,10 +101,9 @@ export class ApiFunctions extends Construct {
// Indicate if mock mode is available
MOCK_MODE_ENABLED: props.useMockOidc ? "true" : "false",

APIGEE_API_SECRET: props.apigeeApiSecret,
APIGEE_API_KEY: props.apigeeApiKey,
APIGEE_API_SECRET_ARN: props.apigeeApiSecret.secretArn,
APIGEE_API_KEY_ARN: props.apigeeApiKey.secretArn,
FULL_CLOUDFRONT_DOMAIN: props.fullCloudfrontDomain

}

// If mock OIDC is enabled, add mock environment variables
Expand Down Expand Up @@ -240,14 +239,6 @@ export class ApiFunctions extends Construct {
// Add the policy to apiFunctionsPolicies
apiFunctionsPolicies.push(patientSearchLambda.executeLambdaManagedPolicy)

// Suppress the AwsSolutions-L1 rule for the prescription list Lambda function
NagSuppressions.addResourceSuppressions(prescriptionListLambda.lambda, [
{
id: "AwsSolutions-L1",
reason: "The Lambda function uses the latest runtime version supported at the time of implementation."
}
])

// Prescription Details Lambda Function
const prescriptionDetailsLambda = new LambdaFunction(this, "PrescriptionDetails", {
serviceName: props.serviceName,
Expand All @@ -266,10 +257,9 @@ export class ApiFunctions extends Construct {
apigeePrescriptionsEndpoint: props.apigeePrescriptionsEndpoint,
apigeeDoHSEndpoint: props.apigeeDoHSEndpoint,
apigeePersonalDemographicsEndpoint: props.apigeePersonalDemographicsEndpoint,
apigeeApiKey: props.apigeeApiKey,
jwtKid: props.jwtKid,
roleId: props.roleId,
APIGEE_DOHS_API_KEY: props.apigeeDoHSApiKey
APIGEE_DOHS_API_KEY_ARN: props.apigeeDoHSApiKey.secretArn
}
})

Expand Down
30 changes: 18 additions & 12 deletions packages/cdk/resources/api/oauth2Functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {Construct} from "constructs"
import {LambdaFunction} from "../LambdaFunction"
import {ITableV2} from "aws-cdk-lib/aws-dynamodb"
import {IManagedPolicy} from "aws-cdk-lib/aws-iam"
import {Secret} from "aws-cdk-lib/aws-secretsmanager"
import {ISecret, Secret} from "aws-cdk-lib/aws-secretsmanager"
import {NodejsFunction} from "aws-cdk-lib/aws-lambda-nodejs"
import {SharedSecrets} from "../SharedSecrets"

Expand Down Expand Up @@ -57,8 +57,8 @@ export interface OAuth2FunctionsProps {
readonly logRetentionInDays: number
readonly logLevel: string
readonly jwtKid: string
readonly apigeeApiKey: string
readonly apigeeApiSecret: string
readonly apigeeApiKey: ISecret
readonly apigeeApiSecret: ISecret
}

/**
Expand Down Expand Up @@ -103,7 +103,8 @@ export class OAuth2Functions extends Construct {
props.sharedSecrets.getPrimaryJwtPrivateKeyPolicy,
props.sessionManagementTableWritePolicy,
props.sessionManagementTableReadPolicy,
props.useSessionManagementKmsKeyPolicy
props.useSessionManagementKmsKeyPolicy,
props.sharedSecrets.getApigeeSecretsPolicy
],
logRetentionInDays: props.logRetentionInDays,
logLevel: props.logLevel,
Expand Down Expand Up @@ -131,7 +132,8 @@ export class OAuth2Functions extends Construct {
additionalPolicies: [
props.stateMappingTableWritePolicy,
props.stateMappingTableReadPolicy,
props.useStateMappingKmsKeyPolicy
props.useStateMappingKmsKeyPolicy,
props.sharedSecrets.getApigeeSecretsPolicy
],
logRetentionInDays: props.logRetentionInDays,
logLevel: props.logLevel,
Expand All @@ -154,7 +156,8 @@ export class OAuth2Functions extends Construct {
additionalPolicies: [
props.stateMappingTableWritePolicy,
props.stateMappingTableReadPolicy,
props.useStateMappingKmsKeyPolicy
props.useStateMappingKmsKeyPolicy,
props.sharedSecrets.getApigeeSecretsPolicy
],
logRetentionInDays: props.logRetentionInDays,
logLevel: props.logLevel,
Expand Down Expand Up @@ -199,7 +202,8 @@ export class OAuth2Functions extends Construct {
props.useStateMappingKmsKeyPolicy,
props.sessionStateMappingTableWritePolicy,
props.sessionStateMappingTableReadPolicy,
props.useSessionStateMappingKmsKeyPolicy
props.useSessionStateMappingKmsKeyPolicy,
props.sharedSecrets.getApigeeSecretsPolicy
],
logRetentionInDays: props.logRetentionInDays,
logLevel: props.logLevel,
Expand All @@ -212,7 +216,7 @@ export class OAuth2Functions extends Construct {
FULL_CLOUDFRONT_DOMAIN: props.fullCloudfrontDomain,
StateMappingTableName: props.stateMappingTable.tableName,
SessionStateMappingTableName: props.sessionStateMappingTable.tableName,
APIGEE_API_KEY: props.apigeeApiKey
APIGEE_API_KEY_ARN: props.apigeeApiKey.secretArn
}
})

Expand All @@ -238,7 +242,8 @@ export class OAuth2Functions extends Construct {
props.sessionStateMappingTableWritePolicy,
props.useSessionStateMappingKmsKeyPolicy,
props.sharedSecrets.useJwtKmsKeyPolicy,
props.sharedSecrets.getMockJwtPrivateKeyPolicy
props.sharedSecrets.getMockJwtPrivateKeyPolicy,
props.sharedSecrets.getApigeeSecretsPolicy
],
logRetentionInDays: props.logRetentionInDays,
logLevel: props.logLevel,
Expand All @@ -259,8 +264,8 @@ export class OAuth2Functions extends Construct {
MOCK_OIDC_ISSUER: props.mockOidcIssuer,
FULL_CLOUDFRONT_DOMAIN: props.fullCloudfrontDomain,
jwtKid: props.jwtKid,
APIGEE_API_KEY: props.apigeeApiKey,
APIGEE_API_SECRET: props.apigeeApiSecret
APIGEE_API_KEY_ARN: props.apigeeApiKey.secretArn,
APIGEE_API_SECRET_ARN: props.apigeeApiSecret.secretArn
}
})

Expand All @@ -278,7 +283,8 @@ export class OAuth2Functions extends Construct {
props.useStateMappingKmsKeyPolicy,
props.sessionStateMappingTableReadPolicy,
props.sessionStateMappingTableWritePolicy,
props.useSessionStateMappingKmsKeyPolicy
props.useSessionStateMappingKmsKeyPolicy,
props.sharedSecrets.getApigeeSecretsPolicy
],
logRetentionInDays: props.logRetentionInDays,
logLevel: props.logLevel,
Expand Down
Loading