diff --git a/API.md b/API.md index 4aa620e..7ae00d6 100644 --- a/API.md +++ b/API.md @@ -271,6 +271,11 @@ The environment variables to export into the outgoing event once the BashJobRunn ### BillingProvider +Represents a Billing Provider that handles billing-related operations. + +This construct sets up event targets for various billing-related events +and optionally creates an API Gateway resource for a webhook function. + #### Initializers ```typescript @@ -281,9 +286,9 @@ new BillingProvider(scope: Construct, id: string, props: BillingProviderProps) | **Name** | **Type** | **Description** | | --- | --- | --- | -| scope | constructs.Construct | *No description.* | -| id | string | *No description.* | -| props | BillingProviderProps | *No description.* | +| scope | constructs.Construct | The scope in which to define this construct. | +| id | string | The unique ID of this construct. | +| props | BillingProviderProps | The properties for the BillingProvider. | --- @@ -291,18 +296,24 @@ new BillingProvider(scope: Construct, id: string, props: BillingProviderProps) - *Type:* constructs.Construct +The scope in which to define this construct. + --- ##### `id`Required - *Type:* string +The unique ID of this construct. + --- ##### `props`Required - *Type:* BillingProviderProps +The properties for the BillingProvider. + --- #### Methods @@ -387,6 +398,8 @@ Only set when the IBilling webhookFunction is defined. - *Implements:* IAuth +Constructs for setting up Cognito authentication and user management. + #### Initializers ```typescript @@ -468,18 +481,18 @@ Any object. | **Name** | **Type** | **Description** | | --- | --- | --- | | node | constructs.Node | The tree node. | -| authorizationServer | string | Authorization server Url. | -| authorizer | aws-cdk-lib.aws_apigateway.IAuthorizer | Authorizer referenced by the ControlPlaneAPI. | -| clientId | string | The OAuth clientId for the identity provider. | -| controlPlaneIdpDetails | any | Contains any information relevant to the IDP implementation required by the Authorizer and User Function implementations. | -| createUserFunction | aws-cdk-lib.aws_lambda.IFunction | Function referenced by the ControlPlaneAPI -- POST /users. | -| deleteUserFunction | aws-cdk-lib.aws_lambda.IFunction | Function referenced by the ControlPlaneAPI -- DELETE /user/{username}. | -| disableUserFunction | aws-cdk-lib.aws_lambda.IFunction | Function referenced by the ControlPlaneAPI -- PUT /user/{username}/disable. | -| enableUserFunction | aws-cdk-lib.aws_lambda.IFunction | Function referenced by the ControlPlaneAPI -- PUT /user/{username}/enable. | -| fetchAllUsersFunction | aws-cdk-lib.aws_lambda.IFunction | Function referenced by the ControlPlaneAPI -- GET /users. | -| fetchUserFunction | aws-cdk-lib.aws_lambda.IFunction | Function referenced by the ControlPlaneAPI -- GET /user/{username}. | -| updateUserFunction | aws-cdk-lib.aws_lambda.IFunction | Function referenced by the ControlPlaneAPI -- PUT /user/{username}. | -| wellKnownEndpointUrl | string | OpenID configuration Url. | +| authorizationServer | string | The authorization server for the control plane IdP. | +| authorizer | aws-cdk-lib.aws_apigateway.IAuthorizer | The API Gateway authorizer for authenticating requests. | +| clientId | string | The client ID for the control plane IdP. | +| controlPlaneIdpDetails | any | The details of the control plane Identity Provider (IdP). | +| createUserFunction | aws-cdk-lib.aws_lambda.IFunction | The Lambda function for creating a user. | +| deleteUserFunction | aws-cdk-lib.aws_lambda.IFunction | The Lambda function for deleting a user. | +| disableUserFunction | aws-cdk-lib.aws_lambda.IFunction | The Lambda function for disabling a user. | +| enableUserFunction | aws-cdk-lib.aws_lambda.IFunction | The Lambda function for enabling a user. | +| fetchAllUsersFunction | aws-cdk-lib.aws_lambda.IFunction | The Lambda function for fetching all users. | +| fetchUserFunction | aws-cdk-lib.aws_lambda.IFunction | The Lambda function for fetching a user. | +| updateUserFunction | aws-cdk-lib.aws_lambda.IFunction | The Lambda function for updating a user. | +| wellKnownEndpointUrl | string | The well-known endpoint URL for the control plane IdP. | --- @@ -503,7 +516,7 @@ public readonly authorizationServer: string; - *Type:* string -Authorization server Url. +The authorization server for the control plane IdP. --- @@ -515,7 +528,7 @@ public readonly authorizer: IAuthorizer; - *Type:* aws-cdk-lib.aws_apigateway.IAuthorizer -Authorizer referenced by the ControlPlaneAPI. +The API Gateway authorizer for authenticating requests. --- @@ -527,7 +540,7 @@ public readonly clientId: string; - *Type:* string -The OAuth clientId for the identity provider. +The client ID for the control plane IdP. --- @@ -539,7 +552,7 @@ public readonly controlPlaneIdpDetails: any; - *Type:* any -Contains any information relevant to the IDP implementation required by the Authorizer and User Function implementations. +The details of the control plane Identity Provider (IdP). --- @@ -551,7 +564,7 @@ public readonly createUserFunction: IFunction; - *Type:* aws-cdk-lib.aws_lambda.IFunction -Function referenced by the ControlPlaneAPI -- POST /users. +The Lambda function for creating a user. --- @@ -563,7 +576,7 @@ public readonly deleteUserFunction: IFunction; - *Type:* aws-cdk-lib.aws_lambda.IFunction -Function referenced by the ControlPlaneAPI -- DELETE /user/{username}. +The Lambda function for deleting a user. --- @@ -575,7 +588,7 @@ public readonly disableUserFunction: IFunction; - *Type:* aws-cdk-lib.aws_lambda.IFunction -Function referenced by the ControlPlaneAPI -- PUT /user/{username}/disable. +The Lambda function for disabling a user. --- @@ -587,7 +600,7 @@ public readonly enableUserFunction: IFunction; - *Type:* aws-cdk-lib.aws_lambda.IFunction -Function referenced by the ControlPlaneAPI -- PUT /user/{username}/enable. +The Lambda function for enabling a user. --- @@ -599,7 +612,7 @@ public readonly fetchAllUsersFunction: IFunction; - *Type:* aws-cdk-lib.aws_lambda.IFunction -Function referenced by the ControlPlaneAPI -- GET /users. +The Lambda function for fetching all users. --- @@ -611,7 +624,7 @@ public readonly fetchUserFunction: IFunction; - *Type:* aws-cdk-lib.aws_lambda.IFunction -Function referenced by the ControlPlaneAPI -- GET /user/{username}. +The Lambda function for fetching a user. --- @@ -623,7 +636,7 @@ public readonly updateUserFunction: IFunction; - *Type:* aws-cdk-lib.aws_lambda.IFunction -Function referenced by the ControlPlaneAPI -- PUT /user/{username}. +The Lambda function for updating a user. --- @@ -635,7 +648,7 @@ public readonly wellKnownEndpointUrl: string; - *Type:* string -OpenID configuration Url. +The well-known endpoint URL for the control plane IdP. --- @@ -1033,7 +1046,7 @@ public readonly eventManager: EventManager; ### EventManager -Provides an EventManager to help interact with the EventBus shared with the SBT control plane. +Provides an EventManager to interact with the EventBus shared with the SBT control plane. #### Initializers @@ -1098,7 +1111,7 @@ Adds an IRuleTarget to an event. - *Type:* DetailType -The name of the event to add a target to. +The detail type of the event to add a target to. --- @@ -1141,10 +1154,10 @@ Any object. | **Name** | **Type** | **Description** | | --- | --- | --- | | node | constructs.Node | The tree node. | -| applicationPlaneEventSource | string | *No description.* | -| controlPlaneEventSource | string | *No description.* | +| applicationPlaneEventSource | string | The event source used for events emitted by the application plane. | +| controlPlaneEventSource | string | The event source used for events emitted by the control plane. | | eventBus | aws-cdk-lib.aws_events.IEventBus | The event bus to register new rules with. | -| supportedEvents | {[ key: string ]: string} | *No description.* | +| supportedEvents | {[ key: string ]: string} | List of recognized events that are available as triggers. | --- @@ -1168,6 +1181,8 @@ public readonly applicationPlaneEventSource: string; - *Type:* string +The event source used for events emitted by the application plane. + --- ##### `controlPlaneEventSource`Required @@ -1178,6 +1193,8 @@ public readonly controlPlaneEventSource: string; - *Type:* string +The event source used for events emitted by the control plane. + --- ##### `eventBus`Required @@ -1200,6 +1217,8 @@ public readonly supportedEvents: {[ key: string ]: string}; - *Type:* {[ key: string ]: string} +List of recognized events that are available as triggers. + --- @@ -2335,6 +2354,8 @@ An EventManager object to help coordinate events. ### CognitoAuthProps +Properties for the CognitoAuth construct. + #### Initializer ```typescript @@ -2347,10 +2368,10 @@ const cognitoAuthProps: CognitoAuthProps = { ... } | **Name** | **Type** | **Description** | | --- | --- | --- | -| idpName | string | *No description.* | -| systemAdminEmail | string | *No description.* | -| systemAdminRoleName | string | *No description.* | -| controlPlaneCallbackURL | string | *No description.* | +| idpName | string | The name of the Identity Provider (IdP) for the control plane. | +| systemAdminEmail | string | The email address of the system admin. | +| systemAdminRoleName | string | The name of the system admin role. | +| controlPlaneCallbackURL | string | The callback URL for the control plane. | --- @@ -2362,6 +2383,8 @@ public readonly idpName: string; - *Type:* string +The name of the Identity Provider (IdP) for the control plane. + --- ##### `systemAdminEmail`Required @@ -2372,6 +2395,8 @@ public readonly systemAdminEmail: string; - *Type:* string +The email address of the system admin. + --- ##### `systemAdminRoleName`Required @@ -2382,6 +2407,8 @@ public readonly systemAdminRoleName: string; - *Type:* string +The name of the system admin role. + --- ##### `controlPlaneCallbackURL`Optional @@ -2391,6 +2418,11 @@ public readonly controlPlaneCallbackURL: string; ``` - *Type:* string +- *Default:* 'http://localhost' + +The callback URL for the control plane. + +If not provided, defaults to 'http://localhost'. --- @@ -2770,7 +2802,7 @@ The list of JobRunner definitions to create. ### EventManagerProps -Encapsulates the list of properties for an eventManager. +Encapsulates the properties for an EventManager. #### Initializer @@ -3501,40 +3533,74 @@ Encapsulates the list of properties for an IBilling construct. | **Name** | **Type** | **Description** | | --- | --- | --- | -| createUserFunction | aws-cdk-lib.aws_lambda.IFunction | The function to trigger when creating a new billing user. | -| deleteUserFunction | aws-cdk-lib.aws_lambda.IFunction | The function to trigger when deleting a billing user. | +| createCustomerFunction | aws-cdk-lib.aws_lambda.IFunction \| IFunctionTrigger | The function to trigger to create a new customer. | +| deleteCustomerFunction | aws-cdk-lib.aws_lambda.IFunction \| IFunctionTrigger | The function to trigger to delete a customer. | +| createUserFunction | aws-cdk-lib.aws_lambda.IFunction \| IFunctionTrigger | The function to trigger to create a new user. | +| deleteUserFunction | aws-cdk-lib.aws_lambda.IFunction \| IFunctionTrigger | The function to trigger to delete a user. | | ingestor | IDataIngestorAggregator | The IDataIngestorAggregator responsible for accepting and aggregating the raw billing data. | -| putUsageFunction | aws-cdk-lib.aws_lambda.IFunction | The function responsible for taking the aggregated data and pushing that to the billing provider. | +| putUsageFunction | aws-cdk-lib.aws_lambda.IFunction \| IFunctionSchedule | The function responsible for taking the aggregated data and pushing that to the billing provider. | | webhookFunction | aws-cdk-lib.aws_lambda.IFunction | The function to trigger when a webhook request is received. | | webhookPath | string | The path to the webhook resource. | --- -##### `createUserFunction`Required +##### `createCustomerFunction`Required ```typescript -public readonly createUserFunction: IFunction; +public readonly createCustomerFunction: IFunction | IFunctionTrigger; ``` -- *Type:* aws-cdk-lib.aws_lambda.IFunction +- *Type:* aws-cdk-lib.aws_lambda.IFunction | IFunctionTrigger -The function to trigger when creating a new billing user. +The function to trigger to create a new customer. + +(Customer in this context is an entity that has zero or more Users.) --- -##### `deleteUserFunction`Required +##### `deleteCustomerFunction`Required ```typescript -public readonly deleteUserFunction: IFunction; +public readonly deleteCustomerFunction: IFunction | IFunctionTrigger; ``` -- *Type:* aws-cdk-lib.aws_lambda.IFunction +- *Type:* aws-cdk-lib.aws_lambda.IFunction | IFunctionTrigger + +The function to trigger to delete a customer. + +(Customer in this context is an entity that has zero or more Users.) + +--- + +##### `createUserFunction`Optional + +```typescript +public readonly createUserFunction: IFunction | IFunctionTrigger; +``` + +- *Type:* aws-cdk-lib.aws_lambda.IFunction | IFunctionTrigger + +The function to trigger to create a new user. + +(User in this context is an entity that belongs to a Customer.) + +--- + +##### `deleteUserFunction`Optional + +```typescript +public readonly deleteUserFunction: IFunction | IFunctionTrigger; +``` -The function to trigger when deleting a billing user. +- *Type:* aws-cdk-lib.aws_lambda.IFunction | IFunctionTrigger + +The function to trigger to delete a user. + +(User in this context is an entity that belongs to a Customer.) --- -##### `ingestor`Required +##### `ingestor`Optional ```typescript public readonly ingestor: IDataIngestorAggregator; @@ -3546,13 +3612,13 @@ The IDataIngestorAggregator responsible for accepting and aggregating the raw bi --- -##### `putUsageFunction`Required +##### `putUsageFunction`Optional ```typescript -public readonly putUsageFunction: IFunction; +public readonly putUsageFunction: IFunction | IFunctionSchedule; ``` -- *Type:* aws-cdk-lib.aws_lambda.IFunction +- *Type:* aws-cdk-lib.aws_lambda.IFunction | IFunctionSchedule The function responsible for taking the aggregated data and pushing that to the billing provider. @@ -3635,126 +3701,264 @@ The table containing the aggregated data. --- +### IFunctionSchedule + +- *Implemented By:* IFunctionSchedule + +Optional interface that allows specifying both the function to trigger and the schedule by which to trigger it. + + +#### Properties + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| handler | aws-cdk-lib.aws_lambda.IFunction | The function definition. | +| schedule | aws-cdk-lib.aws_events.Schedule | The schedule that will trigger the handler function. | + +--- + +##### `handler`Required + +```typescript +public readonly handler: IFunction; +``` + +- *Type:* aws-cdk-lib.aws_lambda.IFunction + +The function definition. + +--- + +##### `schedule`Required + +```typescript +public readonly schedule: Schedule; +``` + +- *Type:* aws-cdk-lib.aws_events.Schedule + +The schedule that will trigger the handler function. + +--- + +### IFunctionTrigger + +- *Implemented By:* IFunctionTrigger + +Optional interface that allows specifying both the function to trigger and the event that will trigger it. + + +#### Properties + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| handler | aws-cdk-lib.aws_lambda.IFunction | The function definition. | +| trigger | DetailType | The detail-type that will trigger the handler function. | + +--- + +##### `handler`Required + +```typescript +public readonly handler: IFunction; +``` + +- *Type:* aws-cdk-lib.aws_lambda.IFunction + +The function definition. + +--- + +##### `trigger`Required + +```typescript +public readonly trigger: DetailType; +``` + +- *Type:* DetailType + +The detail-type that will trigger the handler function. + +--- + ## Enums ### DetailType -Provides an easy way of accessing event DetailTypes. +Provides an easy way of accessing event detail types. -Note that the string represents the detailTypes used in +The string values represent the "detail-type" used in events sent across the EventBus. #### Members | **Name** | **Description** | | --- | --- | -| ONBOARDING_REQUEST | *No description.* | -| ONBOARDING_SUCCESS | *No description.* | -| ONBOARDING_FAILURE | *No description.* | -| OFFBOARDING_REQUEST | *No description.* | -| OFFBOARDING_SUCCESS | *No description.* | -| OFFBOARDING_FAILURE | *No description.* | -| PROVISION_SUCCESS | *No description.* | -| PROVISION_FAILURE | *No description.* | -| DEPROVISION_SUCCESS | *No description.* | -| DEPROVISION_FAILURE | *No description.* | -| BILLING_SUCCESS | *No description.* | -| BILLING_FAILURE | *No description.* | -| ACTIVATE_REQUEST | *No description.* | -| ACTIVATE_SUCCESS | *No description.* | -| ACTIVATE_FAILURE | *No description.* | -| DEACTIVATE_REQUEST | *No description.* | -| DEACTIVATE_SUCCESS | *No description.* | -| DEACTIVATE_FAILURE | *No description.* | +| ONBOARDING_REQUEST | Event detail type for onboarding request. | +| ONBOARDING_SUCCESS | Event detail type for successful onboarding. | +| ONBOARDING_FAILURE | Event detail type for failed onboarding. | +| OFFBOARDING_REQUEST | Event detail type for offboarding request. | +| OFFBOARDING_SUCCESS | Event detail type for successful offboarding. | +| OFFBOARDING_FAILURE | Event detail type for failed offboarding. | +| PROVISION_SUCCESS | Event detail type for successful provisioning. | +| PROVISION_FAILURE | Event detail type for failed provisioning. | +| DEPROVISION_SUCCESS | Event detail type for successful deprovisioning. | +| DEPROVISION_FAILURE | Event detail type for failed deprovisioning. | +| BILLING_SUCCESS | Event detail type for successful billing configuration. | +| BILLING_FAILURE | Event detail type for failure to configure billing. | +| ACTIVATE_REQUEST | Event detail type for activation request. | +| ACTIVATE_SUCCESS | Event detail type for successful activation. | +| ACTIVATE_FAILURE | Event detail type for failed activation. | +| DEACTIVATE_REQUEST | Event detail type for deactivation request. | +| DEACTIVATE_SUCCESS | Event detail type for successful deactivation. | +| DEACTIVATE_FAILURE | Event detail type for failed deactivation. | +| TENANT_USER_CREATED | Event detail type for user creation on the app-plane side. | +| TENANT_USER_DELETED | Event detail type for user deletion on the app-plane side. | --- ##### `ONBOARDING_REQUEST` +Event detail type for onboarding request. + --- ##### `ONBOARDING_SUCCESS` +Event detail type for successful onboarding. + --- ##### `ONBOARDING_FAILURE` +Event detail type for failed onboarding. + --- ##### `OFFBOARDING_REQUEST` +Event detail type for offboarding request. + --- ##### `OFFBOARDING_SUCCESS` +Event detail type for successful offboarding. + --- ##### `OFFBOARDING_FAILURE` +Event detail type for failed offboarding. + --- ##### `PROVISION_SUCCESS` +Event detail type for successful provisioning. + --- ##### `PROVISION_FAILURE` +Event detail type for failed provisioning. + --- ##### `DEPROVISION_SUCCESS` +Event detail type for successful deprovisioning. + --- ##### `DEPROVISION_FAILURE` +Event detail type for failed deprovisioning. + --- ##### `BILLING_SUCCESS` +Event detail type for successful billing configuration. + --- ##### `BILLING_FAILURE` +Event detail type for failure to configure billing. + --- ##### `ACTIVATE_REQUEST` +Event detail type for activation request. + --- ##### `ACTIVATE_SUCCESS` +Event detail type for successful activation. + --- ##### `ACTIVATE_FAILURE` +Event detail type for failed activation. + --- ##### `DEACTIVATE_REQUEST` +Event detail type for deactivation request. + --- ##### `DEACTIVATE_SUCCESS` +Event detail type for successful deactivation. + --- ##### `DEACTIVATE_FAILURE` +Event detail type for failed deactivation. + +--- + + +##### `TENANT_USER_CREATED` + +Event detail type for user creation on the app-plane side. + +Note that sbt-aws components do not emit this event. This event +should be emitted by the application plane. + +--- + + +##### `TENANT_USER_DELETED` + +Event detail type for user deletion on the app-plane side. + +Note that sbt-aws components do not emit this event. This event +should be emitted by the application plane. + --- diff --git a/docs/public/README.md b/docs/public/README.md index 7749d83..4039d14 100644 --- a/docs/public/README.md +++ b/docs/public/README.md @@ -551,16 +551,15 @@ The control plane emits this event any time it onboards a new tenant. This event ```json { - "Source": "sbt-control-plane-api", - "DetailType": "Onboarding", - "Detail": { + "source": "sbt-control-plane-api", + "detail-type": "Onboarding", + "detail": { "tenantId": "guid string", "tenantStatus": "see notes", "tenantName": "tenant name", "email": "admin@saas.com", "isActive": "boolean" - }, - "EventBusName": "sbt-event-bus" + } } ``` @@ -576,13 +575,12 @@ Upon successful tenant provisioning, the Serverless SaaS reference architecture ```json { - "Source": "sbt-application-plane-api", - "DetailType": "Onboarding", - "Detail": { + "source": "sbt-application-plane-api", + "detail-type": "Onboarding", + "detail": { "tenantConfig": "json string - see notes", "tenantStatus": "Complete", - }, - "EventBusName": "sbt-event-bus" + } } ``` @@ -594,13 +592,12 @@ The control plane emits this event any time it offboards a tenant. At a minimum ```json { - "Source": "sbt-control-plane-api", - "DetailType": "Offboarding", - "Detail": { + "source": "sbt-control-plane-api", + "detail-type": "Offboarding", + "detail": { "tenantId": "string", "tier": "string", - }, - "EventBusName": "sbt-event-bus" + } } ``` @@ -612,12 +609,11 @@ The application plane emits this event upon completion of offboarding. Similar t ```json { - "Source": "sbt-application-plane-api", - "DetailType": "Offboarding", - "Detail": { + "source": "sbt-application-plane-api", + "detail-type": "Offboarding", + "detail": { "tenantStatus": "Deleted", - }, - "EventBusName": "sbt-event-bus" + } } ``` diff --git a/resources/functions/tenant-management/index.py b/resources/functions/tenant-management/index.py index e21a027..4119566 100644 --- a/resources/functions/tenant-management/index.py +++ b/resources/functions/tenant-management/index.py @@ -13,7 +13,6 @@ CORSConfig) from aws_lambda_powertools.logging import correlation_paths from aws_lambda_powertools.event_handler.exceptions import ( - BadRequestError, InternalServerError, NotFoundError, ) diff --git a/src/control-plane/auth/auth-interface.ts b/src/control-plane/auth/auth-interface.ts index e91372f..030e82a 100644 --- a/src/control-plane/auth/auth-interface.ts +++ b/src/control-plane/auth/auth-interface.ts @@ -11,60 +11,60 @@ export interface IAuth { /** * Authorizer referenced by the ControlPlaneAPI */ - authorizer: IAuthorizer; + readonly authorizer: IAuthorizer; /** * Contains any information relevant to the IDP implementation required by the Authorizer and User Function implementations */ - controlPlaneIdpDetails: any; + readonly controlPlaneIdpDetails: any; /** * Authorization server Url */ - authorizationServer: string; + readonly authorizationServer: string; /** * The OAuth clientId for the identity provider */ - clientId: string; + readonly clientId: string; /** * OpenID configuration Url */ - wellKnownEndpointUrl: string; + readonly wellKnownEndpointUrl: string; /** * Function referenced by the ControlPlaneAPI -- POST /users */ - createUserFunction: IFunction; + readonly createUserFunction: IFunction; /** * Function referenced by the ControlPlaneAPI -- GET /users */ - fetchAllUsersFunction: IFunction; // use 'fetch*' instead of 'get*' to avoid error JSII5000 + readonly fetchAllUsersFunction: IFunction; // use 'fetch*' instead of 'get*' to avoid error JSII5000 /** * Function referenced by the ControlPlaneAPI -- GET /user/{username} */ - fetchUserFunction: IFunction; // use 'fetch*' instead of 'get*' to avoid error JSII5000 + readonly fetchUserFunction: IFunction; // use 'fetch*' instead of 'get*' to avoid error JSII5000 /** * Function referenced by the ControlPlaneAPI -- PUT /user/{username} */ - updateUserFunction: IFunction; + readonly updateUserFunction: IFunction; /** * Function referenced by the ControlPlaneAPI -- DELETE /user/{username} */ - deleteUserFunction: IFunction; + readonly deleteUserFunction: IFunction; /** * Function referenced by the ControlPlaneAPI -- PUT /user/{username}/disable */ - disableUserFunction: IFunction; + readonly disableUserFunction: IFunction; /** * Function referenced by the ControlPlaneAPI -- PUT /user/{username}/enable */ - enableUserFunction: IFunction; + readonly enableUserFunction: IFunction; } diff --git a/src/control-plane/auth/cognito-auth.ts b/src/control-plane/auth/cognito-auth.ts index cb9dfcb..a07178d 100644 --- a/src/control-plane/auth/cognito-auth.ts +++ b/src/control-plane/auth/cognito-auth.ts @@ -17,29 +17,99 @@ import { NagSuppressions } from 'cdk-nag'; import { Construct } from 'constructs'; import { IAuth } from './auth-interface'; +/** + * Properties for the CognitoAuth construct. + */ export interface CognitoAuthProps { + /** + * The name of the Identity Provider (IdP) for the control plane. + */ readonly idpName: string; + + /** + * The callback URL for the control plane. If not provided, defaults to 'http://localhost'. + * @default - 'http://localhost' + */ readonly controlPlaneCallbackURL?: string; + + /** + * The name of the system admin role. + */ readonly systemAdminRoleName: string; + + /** + * The email address of the system admin. + */ readonly systemAdminEmail: string; } +/** + * Constructs for setting up Cognito authentication and user management. + */ export class CognitoAuth extends Construct implements IAuth { - authorizer: IAuthorizer; - controlPlaneIdpDetails: any; - authorizationServer: string; - clientId: string; - wellKnownEndpointUrl: string; - createUserFunction: IFunction; - fetchAllUsersFunction: IFunction; - fetchUserFunction: IFunction; - updateUserFunction: IFunction; - deleteUserFunction: IFunction; - disableUserFunction: IFunction; - enableUserFunction: IFunction; + /** + * The API Gateway authorizer for authenticating requests. + */ + public readonly authorizer: IAuthorizer; + + /** + * The details of the control plane Identity Provider (IdP). + */ + public readonly controlPlaneIdpDetails: any; + + /** + * The authorization server for the control plane IdP. + */ + public readonly authorizationServer: string; + + /** + * The client ID for the control plane IdP. + */ + public readonly clientId: string; + + /** + * The well-known endpoint URL for the control plane IdP. + */ + public readonly wellKnownEndpointUrl: string; + + /** + * The Lambda function for creating a user. + */ + public readonly createUserFunction: IFunction; + + /** + * The Lambda function for fetching all users. + */ + public readonly fetchAllUsersFunction: IFunction; + + /** + * The Lambda function for fetching a user. + */ + public readonly fetchUserFunction: IFunction; + + /** + * The Lambda function for updating a user. + */ + public readonly updateUserFunction: IFunction; + + /** + * The Lambda function for deleting a user. + */ + public readonly deleteUserFunction: IFunction; + + /** + * The Lambda function for disabling a user. + */ + public readonly disableUserFunction: IFunction; + + /** + * The Lambda function for enabling a user. + */ + public readonly enableUserFunction: IFunction; constructor(scope: Construct, id: string, props: CognitoAuthProps) { super(scope, id); + const defaultControlPlaneCallbackURL = 'http://localhost'; // https://docs.powertools.aws.dev/lambda/python/2.31.0/#lambda-layer @@ -145,6 +215,7 @@ export class CognitoAuth extends Construct implements IAuth { value: this.controlPlaneIdpDetails, key: 'ControlPlaneIdpDetails', }); + const customAuthorizerFunction = new PythonFunction(this, 'CustomAuthorizerFunction', { entry: path.join(__dirname, '../../../resources/functions/authorizer'), runtime: Runtime.PYTHON_3_12, diff --git a/src/control-plane/billing/billing-interface.ts b/src/control-plane/billing/billing-interface.ts index bda4b03..de16705 100644 --- a/src/control-plane/billing/billing-interface.ts +++ b/src/control-plane/billing/billing-interface.ts @@ -1,34 +1,82 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +import { Schedule } from 'aws-cdk-lib/aws-events'; import { IFunction } from 'aws-cdk-lib/aws-lambda'; +import { DetailType } from '../../utils'; import { IDataIngestorAggregator } from '../ingestor-aggregator/ingestor-aggregator-interface'; +/** + * Optional interface that allows specifying both + * the function to trigger and the event that will trigger it. + */ +export interface IFunctionTrigger { + /** + * The function definition. + */ + readonly handler: IFunction; + + /** + * The detail-type that will trigger the handler function. + */ + readonly trigger: DetailType; +} + +/** + * Optional interface that allows specifying both + * the function to trigger and the schedule by which to trigger it. + */ +export interface IFunctionSchedule { + /** + * The function definition. + */ + readonly handler: IFunction; + + /** + * The schedule that will trigger the handler function. + */ + readonly schedule: Schedule; +} + /** * Encapsulates the list of properties for an IBilling construct. */ export interface IBilling { /** - * The function to trigger when creating a new billing user. + * The function to trigger to create a new customer. + * (Customer in this context is an entity that has zero or more Users.) + */ + createCustomerFunction: IFunction | IFunctionTrigger; + + /** + * The function to trigger to delete a customer. + * (Customer in this context is an entity that has zero or more Users.) + */ + deleteCustomerFunction: IFunction | IFunctionTrigger; + + /** + * The function to trigger to create a new user. + * (User in this context is an entity that belongs to a Customer.) */ - createUserFunction: IFunction; + createUserFunction?: IFunction | IFunctionTrigger; /** - * The function to trigger when deleting a billing user. + * The function to trigger to delete a user. + * (User in this context is an entity that belongs to a Customer.) */ - deleteUserFunction: IFunction; + deleteUserFunction?: IFunction | IFunctionTrigger; /** * The IDataIngestorAggregator responsible for accepting and aggregating * the raw billing data. */ - ingestor: IDataIngestorAggregator; + ingestor?: IDataIngestorAggregator; /** * The function responsible for taking the aggregated data and pushing * that to the billing provider. */ - putUsageFunction: IFunction; + putUsageFunction?: IFunction | IFunctionSchedule; /** * The function to trigger when a webhook request is received. diff --git a/src/control-plane/billing/billing-provider.ts b/src/control-plane/billing/billing-provider.ts index 48f08b0..a6520b0 100644 --- a/src/control-plane/billing/billing-provider.ts +++ b/src/control-plane/billing/billing-provider.ts @@ -5,9 +5,10 @@ import * as cdk from 'aws-cdk-lib'; import { IResource, Resource } from 'aws-cdk-lib/aws-apigateway'; import * as aws_events from 'aws-cdk-lib/aws-events'; import * as event_targets from 'aws-cdk-lib/aws-events-targets'; +import { IFunction } from 'aws-cdk-lib/aws-lambda'; import { NagSuppressions } from 'cdk-nag'; import { Construct } from 'constructs'; -import { IBilling } from './billing-interface'; +import { IBilling, IFunctionTrigger } from './billing-interface'; import { EventManager, DetailType } from '../../utils'; /** @@ -31,29 +32,76 @@ export interface BillingProviderProps { readonly controlPlaneAPIBillingResource: Resource; } +/** + * Represents a Billing Provider that handles billing-related operations. + * + * This construct sets up event targets for various billing-related events + * and optionally creates an API Gateway resource for a webhook function. + */ export class BillingProvider extends Construct { /** * The API Gateway resource containing the billing webhook resource. * Only set when the IBilling webhookFunction is defined. */ public readonly controlPlaneAPIBillingWebhookResource?: IResource; + + /** + * Creates a new instance of the BillingProvider construct. + * + * @param scope The scope in which to define this construct. + * @param id The unique ID of this construct. + * @param props The properties for the BillingProvider. + */ constructor(scope: Construct, id: string, props: BillingProviderProps) { super(scope, id); - props.eventManager.addTargetToEvent( - DetailType.PROVISION_SUCCESS, - new event_targets.LambdaFunction(props.billing.createUserFunction) + this.createEventTarget( + props.eventManager, + DetailType.ONBOARDING_REQUEST, + props.billing.createCustomerFunction ); - props.eventManager.addTargetToEvent( - DetailType.DEPROVISION_SUCCESS, - new event_targets.LambdaFunction(props.billing.deleteUserFunction) + this.createEventTarget( + props.eventManager, + DetailType.OFFBOARDING_REQUEST, + props.billing.deleteCustomerFunction ); - new aws_events.Rule(this, 'BillingPutUsageRule', { - schedule: aws_events.Schedule.rate(cdk.Duration.hours(24)), - targets: [new event_targets.LambdaFunction(props.billing.putUsageFunction)], - }); + this.createEventTarget( + props.eventManager, + DetailType.TENANT_USER_CREATED, + props.billing.createUserFunction + ); + + this.createEventTarget( + props.eventManager, + DetailType.TENANT_USER_DELETED, + props.billing.deleteUserFunction + ); + + if (props.billing.putUsageFunction) { + const schedule = + 'handler' in props.billing.putUsageFunction + ? props.billing.putUsageFunction.schedule + : aws_events.Schedule.rate(cdk.Duration.hours(24)); + + const handler = + 'handler' in props.billing.putUsageFunction + ? props.billing.putUsageFunction.handler + : props.billing.putUsageFunction; + + new aws_events.Rule(this, 'BillingPutUsageRule', { + schedule: schedule, + targets: [new event_targets.LambdaFunction(handler)], + }); + } + + if (props.billing.ingestor) { + new cdk.CfnOutput(this, 'DataIngestorName', { + value: props.billing.ingestor.dataIngestorName, + key: 'dataIngestorName', + }); + } if (props.billing.webhookFunction && props.billing.webhookPath) { this.controlPlaneAPIBillingWebhookResource = props.controlPlaneAPIBillingResource.addResource( @@ -84,4 +132,26 @@ export class BillingProvider extends Construct { ); } } + + private getFunctionProps( + fn: IFunction | IFunctionTrigger, + defaultTrigger: DetailType + ): IFunctionTrigger { + return 'handler' in fn + ? { handler: fn.handler, trigger: fn.trigger } + : { handler: fn, trigger: defaultTrigger }; + } + + private createEventTarget( + eventManager: EventManager, + defaultEvent: DetailType, + fn?: IFunction | IFunctionTrigger + ) { + if (!fn) { + return; + } + + const { handler, trigger } = this.getFunctionProps(fn, defaultEvent); + eventManager.addTargetToEvent(trigger, new event_targets.LambdaFunction(handler)); + } } diff --git a/src/utils/event-manager.ts b/src/utils/event-manager.ts index 256a443..338ba8b 100644 --- a/src/utils/event-manager.ts +++ b/src/utils/event-manager.ts @@ -5,43 +5,115 @@ import { IEventBus, Rule, IRuleTarget } from 'aws-cdk-lib/aws-events'; import { Construct } from 'constructs'; /** - * Provides an easy way of accessing event DetailTypes. - * Note that the string represents the detailTypes used in + * Provides an easy way of accessing event detail types. + * The string values represent the "detail-type" used in * events sent across the EventBus. */ export enum DetailType { + /** + * Event detail type for onboarding request. + */ ONBOARDING_REQUEST = 'onboardingRequest', + /** + * Event detail type for successful onboarding. + */ ONBOARDING_SUCCESS = 'onboardingSuccess', + /** + * Event detail type for failed onboarding. + */ ONBOARDING_FAILURE = 'onboardingFailure', + + /** + * Event detail type for offboarding request. + */ OFFBOARDING_REQUEST = 'offboardingRequest', + /** + * Event detail type for successful offboarding. + */ OFFBOARDING_SUCCESS = 'offboardingSuccess', + /** + * Event detail type for failed offboarding. + */ OFFBOARDING_FAILURE = 'offboardingFailure', + + /** + * Event detail type for successful provisioning. + */ PROVISION_SUCCESS = 'provisionSuccess', + /** + * Event detail type for failed provisioning. + */ PROVISION_FAILURE = 'provisionFailure', + + /** + * Event detail type for successful deprovisioning. + */ DEPROVISION_SUCCESS = 'deprovisionSuccess', + /** + * Event detail type for failed deprovisioning. + */ DEPROVISION_FAILURE = 'deprovisionFailure', + + /** + * Event detail type for successful billing configuration. + */ BILLING_SUCCESS = 'billingSuccess', + /** + * Event detail type for failure to configure billing. + */ BILLING_FAILURE = 'billingFailure', + + /** + * Event detail type for activation request. + */ ACTIVATE_REQUEST = 'activateRequest', + /** + * Event detail type for successful activation. + */ ACTIVATE_SUCCESS = 'activateSuccess', + /** + * Event detail type for failed activation. + */ ACTIVATE_FAILURE = 'activateFailure', + + /** + * Event detail type for deactivation request. + */ DEACTIVATE_REQUEST = 'deactivateRequest', + /** + * Event detail type for successful deactivation. + */ DEACTIVATE_SUCCESS = 'deactivateSuccess', + /** + * Event detail type for failed deactivation. + */ DEACTIVATE_FAILURE = 'deactivateFailure', + + /** + * Event detail type for user creation on the app-plane side. + * Note that sbt-aws components do not emit this event. This event + * should be emitted by the application plane. + */ + TENANT_USER_CREATED = 'tenantUserCreated', + /** + * Event detail type for user deletion on the app-plane side. + * Note that sbt-aws components do not emit this event. This event + * should be emitted by the application plane. + */ + TENANT_USER_DELETED = 'tenantUserDeleted', } /** - * Represents mapping between 'detailType' as key, - * and 'source' as value. + * Represents a mapping between 'detailType' as the key and 'source' as the value. */ export type EventMetadata = { - // key: Event 'detailType' -> val: Event 'source' + // key: Event 'detailType' -> value: Event 'source' [key: string]: string; // [key in DetailType]: string; // Causes this error: Only string-indexed map types are supported }; /** - * Encapsulates the list of properties for an eventManager. + * Encapsulates the properties for an EventManager. */ export interface EventManagerProps { /** @@ -66,37 +138,28 @@ export interface EventManagerProps { } /** - * Provides an EventManager to help interact with the EventBus shared with the SBT control plane. + * Provides an EventManager to interact with the EventBus shared with the SBT control plane. */ export class EventManager extends Construct { + /** + * The event source used for events emitted by the application plane. + * @default + */ public readonly applicationPlaneEventSource: string = 'applicationPlaneEventSource'; + + /** + * The event source used for events emitted by the control plane. + * @default + */ public readonly controlPlaneEventSource: string = 'controlPlaneEventSource'; - // sensible defaults so they are not required when instantiating control plane - - public readonly supportedEvents: EventMetadata = { - onboardingRequest: this.controlPlaneEventSource, - onboardingSuccess: this.applicationPlaneEventSource, - onboardingFailure: this.applicationPlaneEventSource, - offboardingRequest: this.controlPlaneEventSource, - offboardingSuccess: this.applicationPlaneEventSource, - offboardingFailure: this.applicationPlaneEventSource, - provisionSuccess: this.applicationPlaneEventSource, - provisionFailure: this.applicationPlaneEventSource, - deprovisionSuccess: this.applicationPlaneEventSource, - deprovisionFailure: this.applicationPlaneEventSource, - billingSuccess: this.controlPlaneEventSource, - billingFailure: this.controlPlaneEventSource, - activateRequest: this.controlPlaneEventSource, - activateSuccess: this.applicationPlaneEventSource, - activateFailure: this.applicationPlaneEventSource, - deactivateRequest: this.controlPlaneEventSource, - deactivateSuccess: this.applicationPlaneEventSource, - deactivateFailure: this.applicationPlaneEventSource, - }; + + /** + * List of recognized events that are available as triggers. + */ + public readonly supportedEvents: EventMetadata; /** * The event bus to register new rules with. - * @attribute */ public readonly eventBus: IEventBus; @@ -110,6 +173,27 @@ export class EventManager extends Construct { props.applicationPlaneEventSource || this.applicationPlaneEventSource; this.controlPlaneEventSource = props.controlPlaneEventSource || this.controlPlaneEventSource; + this.supportedEvents = { + onboardingRequest: this.controlPlaneEventSource, + onboardingSuccess: this.applicationPlaneEventSource, + onboardingFailure: this.applicationPlaneEventSource, + offboardingRequest: this.controlPlaneEventSource, + offboardingSuccess: this.applicationPlaneEventSource, + offboardingFailure: this.applicationPlaneEventSource, + provisionSuccess: this.applicationPlaneEventSource, + provisionFailure: this.applicationPlaneEventSource, + deprovisionSuccess: this.applicationPlaneEventSource, + deprovisionFailure: this.applicationPlaneEventSource, + billingSuccess: this.controlPlaneEventSource, + billingFailure: this.controlPlaneEventSource, + activateRequest: this.controlPlaneEventSource, + activateSuccess: this.applicationPlaneEventSource, + activateFailure: this.applicationPlaneEventSource, + deactivateRequest: this.controlPlaneEventSource, + deactivateSuccess: this.applicationPlaneEventSource, + deactivateFailure: this.applicationPlaneEventSource, + }; + for (const key in this.supportedEvents) { // update this.eventMetadata with any values passed in via props if (props.eventMetadata && props.eventMetadata[key]) { @@ -121,7 +205,7 @@ export class EventManager extends Construct { /** * Adds an IRuleTarget to an event. * - * @param eventType The name of the event to add a target to. + * @param eventType The detail type of the event to add a target to. * @param target The target that will be added to the event. */ public addTargetToEvent(eventType: DetailType, target: IRuleTarget): void {