Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Update API Gateway Configuration #531

Merged
merged 4 commits into from
Sep 4, 2024
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
39 changes: 29 additions & 10 deletions config/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { RemovalPolicy } from 'aws-cdk-lib';
import { VpcLookupOptions } from 'aws-cdk-lib/aws-ec2';
import { RetentionDays } from 'aws-cdk-lib/aws-logs';
import path from 'path';

export enum AppStage {
Expand Down Expand Up @@ -35,15 +37,35 @@ export const vpcProps: VpcLookupOptions = {
};

// upstream infra: cognito
export const cognitoUserPoolIdParameterName = '/data_portal/client/cog_user_pool_id';
export const cognitoPortalAppClientIdParameterName =
'/data_portal/client/data2/cog_app_client_id_stage';
export const cognitoStatusPageAppClientIdParameterName =
'/data_portal/status_page/cog_app_client_id_stage';
export const cognitoApiGatewayProps = {
cognitoUserPoolIdParameterName: cognitoUserPoolIdParameterName,
cognitoPortalAppClientIdParameterName: cognitoPortalAppClientIdParameterName,
cognitoStatusPageAppClientIdParameterName: cognitoStatusPageAppClientIdParameterName,
export const cognitoUserPoolIdParameterName = '/data_portal/client/cog_user_pool_id';
export const logsApiGatewayConfig = {
[AppStage.BETA]: {
retention: RetentionDays.TWO_WEEKS,
removalPolicy: RemovalPolicy.DESTROY,
},
[AppStage.GAMMA]: {
retention: RetentionDays.TWO_WEEKS,
removalPolicy: RemovalPolicy.DESTROY,
},
[AppStage.PROD]: {
retention: RetentionDays.TWO_YEARS,
removalPolicy: RemovalPolicy.RETAIN,
},
};
export const corsAllowOrigins = {
[AppStage.BETA]: ['https://orcaui.dev.umccr.org'],
[AppStage.GAMMA]: ['https://orcaui.stg.umccr.org'],
[AppStage.PROD]: ['https://orcaui.prod.umccr.org', 'https://orcaui.umccr.org'],
};
export const cognitoApiGatewayConfig = {
region,
cognitoUserPoolIdParameterName,
cognitoClientIdParameterNameArray: [
cognitoPortalAppClientIdParameterName, // portal - TokenServiceStack
'/orcaui/cog_app_client_id_stage', // orcaui - https://github.com/umccr/orca-ui
],
};

export const oncoanalyserBucket: Record<AppStage, string> = {
Expand Down Expand Up @@ -153,9 +175,6 @@ export const bclconvertInteropQcDynamoDbTableSSMArn = path.join(
);

// Stateless

export const corsAllowOrigins = ['*'];

export const bclconvertInteropQcIcav2PipelineWorkflowName = 'bclconvert-interop-qc';
export const bclconvertInteropQcIcav2PipelineWorkflowTypeVersion = '1.3.1--1.21';
export const bclconvertInteropQcIcav2ServiceVersion = '2024.07.01';
Expand Down
24 changes: 9 additions & 15 deletions config/stacks/fileManager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { RetentionDays } from 'aws-cdk-lib/aws-logs';
import { FilemanagerConfig } from '../../lib/workload/stateless/stacks/filemanager/deploy/stack';
import {
AppStage,
Expand All @@ -7,36 +6,31 @@ import {
dbClusterEndpointHostParameterName,
eventSourceQueueName,
vpcProps,
cognitoPortalAppClientIdParameterName,
cognitoStatusPageAppClientIdParameterName,
cognitoUserPoolIdParameterName,
oncoanalyserBucket,
icav2PipelineCacheBucket,
fileManagerIngestRoleName,
logsApiGatewayConfig,
cognitoApiGatewayConfig,
corsAllowOrigins,
} from '../constants';
import { RemovalPolicy } from 'aws-cdk-lib';

export const getFileManagerStackProps = (stage: AppStage): FilemanagerConfig => {
const logsConfig = {
retention: stage === AppStage.PROD ? RetentionDays.TWO_YEARS : RetentionDays.TWO_WEEKS,
removalPolicy: stage === AppStage.PROD ? RemovalPolicy.RETAIN : RemovalPolicy.DESTROY,
};

return {
securityGroupName: computeSecurityGroupName,
vpcProps,
eventSourceQueueName: eventSourceQueueName,
databaseClusterEndpointHostParameter: dbClusterEndpointHostParameterName,
port: databasePort,
migrateDatabase: true,
cognitoPortalAppClientIdParameterName: cognitoPortalAppClientIdParameterName,
cognitoStatusPageAppClientIdParameterName: cognitoStatusPageAppClientIdParameterName,
cognitoUserPoolIdParameterName: cognitoUserPoolIdParameterName,
apiGwLogsConfig: logsConfig,
inventorySourceBuckets: ['filemanager-inventory-test'],
eventSourceBuckets: [oncoanalyserBucket[stage], icav2PipelineCacheBucket[stage]],
fileManagerIngestRoleName: fileManagerIngestRoleName,
corsAllowOrigins,
apiGatewayCognitoProps: {
...cognitoApiGatewayConfig,
corsAllowOrigins: corsAllowOrigins[stage],
apiGwLogsConfig: logsApiGatewayConfig[stage],
apiName: 'FileManager',
customDomainNamePrefix: 'file',
},
};
};
19 changes: 9 additions & 10 deletions config/stacks/metadataManager.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
import {
AppStage,
cognitoApiGatewayProps,
cognitoApiGatewayConfig,
computeSecurityGroupName,
corsAllowOrigins,
logsApiGatewayConfig,
vpcProps,
} from '../constants';
import { MetadataManagerStackProps } from '../../lib/workload/stateless/stacks/metadata-manager/deploy/stack';
import { RemovalPolicy } from 'aws-cdk-lib';
import { RetentionDays } from 'aws-cdk-lib/aws-logs';

export const getMetadataManagerStackProps = (stage: AppStage): MetadataManagerStackProps => {
const logsConfig = {
retention: stage === AppStage.PROD ? RetentionDays.TWO_YEARS : RetentionDays.TWO_WEEKS,
removalPolicy: stage === AppStage.PROD ? RemovalPolicy.RETAIN : RemovalPolicy.DESTROY,
};

const isDailySync = stage == AppStage.PROD ? true : false;

return {
vpcProps,
isDailySync: isDailySync,
lambdaSecurityGroupName: computeSecurityGroupName,
apiGatewayCognitoProps: { ...cognitoApiGatewayProps, apiGwLogsConfig: logsConfig },
corsAllowOrigins,
apiGatewayCognitoProps: {
...cognitoApiGatewayConfig,
corsAllowOrigins: corsAllowOrigins[stage],
apiGwLogsConfig: logsApiGatewayConfig[stage],
apiName: 'MetadataManager',
customDomainNamePrefix: 'metadata',
},
};
};
24 changes: 9 additions & 15 deletions config/stacks/sequenceRunManager.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,25 @@
import {
AppStage,
cognitoPortalAppClientIdParameterName,
cognitoStatusPageAppClientIdParameterName,
cognitoUserPoolIdParameterName,
cognitoApiGatewayConfig,
computeSecurityGroupName,
corsAllowOrigins,
eventBusName,
logsApiGatewayConfig,
vpcProps,
} from '../constants';
import { SequenceRunManagerStackProps } from '../../lib/workload/stateless/stacks/sequence-run-manager/deploy/stack';
import { RetentionDays } from 'aws-cdk-lib/aws-logs';
import { RemovalPolicy } from 'aws-cdk-lib';

export const getSequenceRunManagerStackProps = (stage: AppStage): SequenceRunManagerStackProps => {
const logsConfig = {
retention: stage === AppStage.PROD ? RetentionDays.TWO_YEARS : RetentionDays.TWO_WEEKS,
removalPolicy: stage === AppStage.PROD ? RemovalPolicy.RETAIN : RemovalPolicy.DESTROY,
};

return {
vpcProps,
lambdaSecurityGroupName: computeSecurityGroupName,
mainBusName: eventBusName,
cognitoUserPoolIdParameterName: cognitoUserPoolIdParameterName,
cognitoPortalAppClientIdParameterName: cognitoPortalAppClientIdParameterName,
cognitoStatusPageAppClientIdParameterName: cognitoStatusPageAppClientIdParameterName,
apiGwLogsConfig: logsConfig,
corsAllowOrigins,
apiGatewayCognitoProps: {
...cognitoApiGatewayConfig,
corsAllowOrigins: corsAllowOrigins[stage],
apiGwLogsConfig: logsApiGatewayConfig[stage],
apiName: 'SequenceRunManager',
customDomainNamePrefix: 'sequence',
},
};
};
24 changes: 9 additions & 15 deletions config/stacks/workflowRunManager.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,25 @@
import { RetentionDays } from 'aws-cdk-lib/aws-logs';
import { WorkflowManagerStackProps } from '../../lib/workload/stateless/stacks/workflow-manager/deploy/stack';
import {
vpcProps,
computeSecurityGroupName,
eventBusName,
cognitoUserPoolIdParameterName,
cognitoPortalAppClientIdParameterName,
cognitoStatusPageAppClientIdParameterName,
AppStage,
cognitoApiGatewayConfig,
logsApiGatewayConfig,
corsAllowOrigins,
} from '../constants';
import { RemovalPolicy } from 'aws-cdk-lib';

export const getWorkflowManagerStackProps = (stage: AppStage): WorkflowManagerStackProps => {
const logsConfig = {
retention: stage === AppStage.PROD ? RetentionDays.TWO_YEARS : RetentionDays.TWO_WEEKS,
removalPolicy: stage === AppStage.PROD ? RemovalPolicy.RETAIN : RemovalPolicy.DESTROY,
};

return {
vpcProps,
lambdaSecurityGroupName: computeSecurityGroupName,
mainBusName: eventBusName,
cognitoUserPoolIdParameterName: cognitoUserPoolIdParameterName,
cognitoPortalAppClientIdParameterName: cognitoPortalAppClientIdParameterName,
cognitoStatusPageAppClientIdParameterName: cognitoStatusPageAppClientIdParameterName,
apiGwLogsConfig: logsConfig,
corsAllowOrigins,
apiGatewayCognitoProps: {
...cognitoApiGatewayConfig,
corsAllowOrigins: corsAllowOrigins[stage],
apiGwLogsConfig: logsApiGatewayConfig[stage],
apiName: 'WorkflowManager',
customDomainNamePrefix: 'workflow',
},
};
};
10 changes: 10 additions & 0 deletions docs/developer/MICROSERVICE.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ Either tasks _(developing an app and/or cdk deployment constructs)_; we promote
_Mac user: Option + M for the µ symbol_


### Using API as backend

When integrating the microservice with a client, you might create a new Cognito app client ID. If this is the case, you
will need to add the new client ID to the AWS API Gateway setup to ensure the token generated by that Cognito app is
valid for use with the microservice API Gateway. Store this Cognito app ID in an SSM Parameter and pass the SSM
Parameter name in the `cognitoApiGatewayConfig` constant file (`./config/constants.ts`). Additionally, you may need to set
the appropriate CORS origin in the `corsAllowOrigins` constant file to prevent any CORS errors in your client.

Reference on creating new Cognito App: <https://github.com/umccr/infrastructure/tree/master/terraform/stacks/cognito_aai>

### Native Bootstrap

You may also just simply use "native toolchain bootstrap" method. This could be the typical "getting started" of respective tool or framework. Some examples as follows.
Expand Down
57 changes: 36 additions & 21 deletions lib/workload/components/api-gateway/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,36 @@ export interface ApiGwLogsConfig {
}

export interface ApiGatewayConstructProps {
/**
* The AWS region.
*/
region: string;
apiName: string | undefined;
cognitoUserPoolIdParameterName: string;
cognitoPortalAppClientIdParameterName: string;
cognitoStatusPageAppClientIdParameterName: string;
/**
* The name of the API.
*/
apiName: string;
/**
* The prefix for the custom domain name
*/
customDomainNamePrefix: string;
/**
*The cognito user pool id parameter name.
*/
cognitoUserPoolIdParameterName: string;
/**
* The parameter name for the cognito client id in array.
* In order API Gateway to validate the JWT token, it needs to know the client id which usually
* stored in SSM Parameter. This will accept multiple parameter name in an array.
*/
cognitoClientIdParameterNameArray: string[];
/**
* The configuration for aws cloudwatch logs
*/
apiGwLogsConfig: ApiGwLogsConfig;
/**
* Allowed CORS origins.
*/
corsAllowOrigins?: string[];
corsAllowOrigins: string[];
}

export class ApiGatewayConstruct extends Construct {
Expand All @@ -64,7 +77,15 @@ export class ApiGatewayConstruct extends Construct {
this._httpApi = new HttpApi(this, 'HttpApi', {
apiName: 'OrcaBusAPI-' + props.apiName,
corsPreflight: {
allowHeaders: ['Authorization'],
allowHeaders: [
'content-type',
'content-disposition',
'authorization',
'x-amz-date',
'x-api-key',
'x-amz-security-token',
'x-amz-user-agent',
],
allowMethods: [
CorsHttpMethod.GET,
CorsHttpMethod.HEAD,
Expand Down Expand Up @@ -144,34 +165,28 @@ export class ApiGatewayConstruct extends Construct {
* FIXME One fine day in future when we have proper Cognito AAI setup.
* For the moment, we leverage Portal and established Cognito infrastructure.
* See https://github.com/umccr/orcabus/issues/102
*
* UI clients:
* https://portal.[dev|stg|prod].umccr.org
* https://status.[dev|stg|prod].umccr.org
*/

const userPoolIdParam: IStringParameter = aws_ssm.StringParameter.fromStringParameterName(
this,
'CognitoUserPoolIdParameter',
props.cognitoUserPoolIdParameterName
);
const portalClientIdParam: IStringParameter = aws_ssm.StringParameter.fromStringParameterName(
this,
'CognitoPortalClientIdParameter',
props.cognitoPortalAppClientIdParameterName

const clientIdParamsArray: IStringParameter[] = props.cognitoClientIdParameterNameArray.map(
(name) =>
aws_ssm.StringParameter.fromStringParameterName(
this,
`CognitoClientId${name}Parameter`,
name
)
);
const statusPageClientIdParam: IStringParameter =
aws_ssm.StringParameter.fromStringParameterName(
this,
'CognitoStatusPageClientIdParameter',
props.cognitoStatusPageAppClientIdParameterName
);

const issuer =
'https://cognito-idp.' + props.region + '.amazonaws.com/' + userPoolIdParam.stringValue;

return new HttpJwtAuthorizer('PortalAuthorizer', issuer, {
jwtAudience: [portalClientIdParam.stringValue, statusPageClientIdParam.stringValue],
jwtAudience: clientIdParamsArray.map((param) => param.stringValue),
});
}

Expand Down
Loading