@gradientedge/cdk-utils-azure 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/LICENSE +21 -0
  2. package/dist/src/common/constants.d.ts +83 -0
  3. package/dist/src/common/constants.js +87 -0
  4. package/dist/src/common/construct.d.ts +80 -0
  5. package/dist/src/common/construct.js +128 -0
  6. package/dist/src/common/index.d.ts +6 -0
  7. package/dist/src/common/index.js +6 -0
  8. package/dist/src/common/resource-name-formatter.d.ts +18 -0
  9. package/dist/src/common/resource-name-formatter.js +34 -0
  10. package/dist/src/common/stack.d.ts +46 -0
  11. package/dist/src/common/stack.js +120 -0
  12. package/dist/src/common/tagging.d.ts +29 -0
  13. package/dist/src/common/tagging.js +78 -0
  14. package/dist/src/common/types.d.ts +57 -0
  15. package/dist/src/common/types.js +1 -0
  16. package/dist/src/construct/event-handler/index.d.ts +2 -0
  17. package/dist/src/construct/event-handler/index.js +2 -0
  18. package/dist/src/construct/event-handler/main.d.ts +61 -0
  19. package/dist/src/construct/event-handler/main.js +180 -0
  20. package/dist/src/construct/event-handler/types.d.ts +35 -0
  21. package/dist/src/construct/event-handler/types.js +1 -0
  22. package/dist/src/construct/function-app/index.d.ts +2 -0
  23. package/dist/src/construct/function-app/index.js +2 -0
  24. package/dist/src/construct/function-app/main.d.ts +128 -0
  25. package/dist/src/construct/function-app/main.js +374 -0
  26. package/dist/src/construct/function-app/types.d.ts +33 -0
  27. package/dist/src/construct/function-app/types.js +1 -0
  28. package/dist/src/construct/index.d.ts +6 -0
  29. package/dist/src/construct/index.js +6 -0
  30. package/dist/src/construct/rest-api/index.d.ts +2 -0
  31. package/dist/src/construct/rest-api/index.js +2 -0
  32. package/dist/src/construct/rest-api/main.d.ts +64 -0
  33. package/dist/src/construct/rest-api/main.js +216 -0
  34. package/dist/src/construct/rest-api/types.d.ts +25 -0
  35. package/dist/src/construct/rest-api/types.js +1 -0
  36. package/dist/src/construct/rest-api-function/index.d.ts +2 -0
  37. package/dist/src/construct/rest-api-function/index.js +2 -0
  38. package/dist/src/construct/rest-api-function/main.d.ts +66 -0
  39. package/dist/src/construct/rest-api-function/main.js +302 -0
  40. package/dist/src/construct/rest-api-function/types.d.ts +29 -0
  41. package/dist/src/construct/rest-api-function/types.js +1 -0
  42. package/dist/src/construct/rest-api-with-cache/index.d.ts +2 -0
  43. package/dist/src/construct/rest-api-with-cache/index.js +2 -0
  44. package/dist/src/construct/rest-api-with-cache/main.d.ts +41 -0
  45. package/dist/src/construct/rest-api-with-cache/main.js +85 -0
  46. package/dist/src/construct/rest-api-with-cache/types.d.ts +13 -0
  47. package/dist/src/construct/rest-api-with-cache/types.js +1 -0
  48. package/dist/src/construct/site-with-webapp/index.d.ts +2 -0
  49. package/dist/src/construct/site-with-webapp/index.js +2 -0
  50. package/dist/src/construct/site-with-webapp/main.d.ts +60 -0
  51. package/dist/src/construct/site-with-webapp/main.js +176 -0
  52. package/dist/src/construct/site-with-webapp/types.d.ts +30 -0
  53. package/dist/src/construct/site-with-webapp/types.js +1 -0
  54. package/dist/src/index.d.ts +4 -0
  55. package/dist/src/index.js +4 -0
  56. package/dist/src/services/api-management/index.d.ts +2 -0
  57. package/dist/src/services/api-management/index.js +2 -0
  58. package/dist/src/services/api-management/main.d.ts +143 -0
  59. package/dist/src/services/api-management/main.js +244 -0
  60. package/dist/src/services/api-management/types.d.ts +72 -0
  61. package/dist/src/services/api-management/types.js +1 -0
  62. package/dist/src/services/app-configuration/index.d.ts +2 -0
  63. package/dist/src/services/app-configuration/index.js +2 -0
  64. package/dist/src/services/app-configuration/main.d.ts +41 -0
  65. package/dist/src/services/app-configuration/main.js +71 -0
  66. package/dist/src/services/app-configuration/types.d.ts +3 -0
  67. package/dist/src/services/app-configuration/types.js +1 -0
  68. package/dist/src/services/app-service/index.d.ts +2 -0
  69. package/dist/src/services/app-service/index.js +2 -0
  70. package/dist/src/services/app-service/main.d.ts +40 -0
  71. package/dist/src/services/app-service/main.js +90 -0
  72. package/dist/src/services/app-service/types.d.ts +6 -0
  73. package/dist/src/services/app-service/types.js +1 -0
  74. package/dist/src/services/application-insights/index.d.ts +2 -0
  75. package/dist/src/services/application-insights/index.js +2 -0
  76. package/dist/src/services/application-insights/main.d.ts +40 -0
  77. package/dist/src/services/application-insights/main.js +68 -0
  78. package/dist/src/services/application-insights/types.d.ts +6 -0
  79. package/dist/src/services/application-insights/types.js +1 -0
  80. package/dist/src/services/authorisation/constants.d.ts +13 -0
  81. package/dist/src/services/authorisation/constants.js +14 -0
  82. package/dist/src/services/authorisation/index.d.ts +3 -0
  83. package/dist/src/services/authorisation/index.js +3 -0
  84. package/dist/src/services/authorisation/main.d.ts +84 -0
  85. package/dist/src/services/authorisation/main.js +120 -0
  86. package/dist/src/services/authorisation/types.d.ts +3 -0
  87. package/dist/src/services/authorisation/types.js +1 -0
  88. package/dist/src/services/cosmosdb/constants.d.ts +8 -0
  89. package/dist/src/services/cosmosdb/constants.js +10 -0
  90. package/dist/src/services/cosmosdb/index.d.ts +3 -0
  91. package/dist/src/services/cosmosdb/index.js +3 -0
  92. package/dist/src/services/cosmosdb/main.d.ts +87 -0
  93. package/dist/src/services/cosmosdb/main.js +162 -0
  94. package/dist/src/services/cosmosdb/types.d.ts +9 -0
  95. package/dist/src/services/cosmosdb/types.js +1 -0
  96. package/dist/src/services/dns/index.d.ts +2 -0
  97. package/dist/src/services/dns/index.js +2 -0
  98. package/dist/src/services/dns/main.d.ts +58 -0
  99. package/dist/src/services/dns/main.js +107 -0
  100. package/dist/src/services/dns/types.d.ts +9 -0
  101. package/dist/src/services/dns/types.js +1 -0
  102. package/dist/src/services/eventgrid/index.d.ts +2 -0
  103. package/dist/src/services/eventgrid/index.js +2 -0
  104. package/dist/src/services/eventgrid/main.d.ts +69 -0
  105. package/dist/src/services/eventgrid/main.js +136 -0
  106. package/dist/src/services/eventgrid/types.d.ts +11 -0
  107. package/dist/src/services/eventgrid/types.js +1 -0
  108. package/dist/src/services/function/index.d.ts +2 -0
  109. package/dist/src/services/function/index.js +2 -0
  110. package/dist/src/services/function/main.d.ts +60 -0
  111. package/dist/src/services/function/main.js +223 -0
  112. package/dist/src/services/function/types.d.ts +20 -0
  113. package/dist/src/services/function/types.js +1 -0
  114. package/dist/src/services/index.d.ts +18 -0
  115. package/dist/src/services/index.js +18 -0
  116. package/dist/src/services/key-vault/index.d.ts +2 -0
  117. package/dist/src/services/key-vault/index.js +2 -0
  118. package/dist/src/services/key-vault/main.d.ts +49 -0
  119. package/dist/src/services/key-vault/main.js +83 -0
  120. package/dist/src/services/key-vault/types.d.ts +5 -0
  121. package/dist/src/services/key-vault/types.js +1 -0
  122. package/dist/src/services/monitor/index.d.ts +2 -0
  123. package/dist/src/services/monitor/index.js +2 -0
  124. package/dist/src/services/monitor/main.d.ts +31 -0
  125. package/dist/src/services/monitor/main.js +36 -0
  126. package/dist/src/services/monitor/types.d.ts +3 -0
  127. package/dist/src/services/monitor/types.js +1 -0
  128. package/dist/src/services/operational-insights/index.d.ts +2 -0
  129. package/dist/src/services/operational-insights/index.js +2 -0
  130. package/dist/src/services/operational-insights/main.d.ts +40 -0
  131. package/dist/src/services/operational-insights/main.js +64 -0
  132. package/dist/src/services/operational-insights/types.d.ts +5 -0
  133. package/dist/src/services/operational-insights/types.js +1 -0
  134. package/dist/src/services/portal/error.d.ts +5 -0
  135. package/dist/src/services/portal/error.js +10 -0
  136. package/dist/src/services/portal/index.d.ts +4 -0
  137. package/dist/src/services/portal/index.js +4 -0
  138. package/dist/src/services/portal/main.d.ts +33 -0
  139. package/dist/src/services/portal/main.js +51 -0
  140. package/dist/src/services/portal/renderer.d.ts +11 -0
  141. package/dist/src/services/portal/renderer.js +156 -0
  142. package/dist/src/services/portal/types.d.ts +40 -0
  143. package/dist/src/services/portal/types.js +1 -0
  144. package/dist/src/services/redis/index.d.ts +2 -0
  145. package/dist/src/services/redis/index.js +2 -0
  146. package/dist/src/services/redis/main.d.ts +31 -0
  147. package/dist/src/services/redis/main.js +52 -0
  148. package/dist/src/services/redis/types.d.ts +3 -0
  149. package/dist/src/services/redis/types.js +1 -0
  150. package/dist/src/services/resource-group/index.d.ts +2 -0
  151. package/dist/src/services/resource-group/index.js +2 -0
  152. package/dist/src/services/resource-group/main.d.ts +38 -0
  153. package/dist/src/services/resource-group/main.js +53 -0
  154. package/dist/src/services/resource-group/types.d.ts +3 -0
  155. package/dist/src/services/resource-group/types.js +1 -0
  156. package/dist/src/services/security-center/index.d.ts +2 -0
  157. package/dist/src/services/security-center/index.js +2 -0
  158. package/dist/src/services/security-center/main.d.ts +31 -0
  159. package/dist/src/services/security-center/main.js +33 -0
  160. package/dist/src/services/security-center/types.d.ts +3 -0
  161. package/dist/src/services/security-center/types.js +1 -0
  162. package/dist/src/services/servicebus/index.d.ts +2 -0
  163. package/dist/src/services/servicebus/index.js +2 -0
  164. package/dist/src/services/servicebus/main.d.ts +67 -0
  165. package/dist/src/services/servicebus/main.js +127 -0
  166. package/dist/src/services/servicebus/types.d.ts +11 -0
  167. package/dist/src/services/servicebus/types.js +1 -0
  168. package/dist/src/services/storage/index.d.ts +2 -0
  169. package/dist/src/services/storage/index.js +2 -0
  170. package/dist/src/services/storage/main.d.ts +88 -0
  171. package/dist/src/services/storage/main.js +173 -0
  172. package/dist/src/services/storage/types.d.ts +20 -0
  173. package/dist/src/services/storage/types.js +1 -0
  174. package/dist/src/types/index.d.ts +4 -0
  175. package/dist/src/types/index.js +1 -0
  176. package/package.json +41 -0
@@ -0,0 +1,216 @@
1
+ import { HostnameType, LoggerType } from '@pulumi/azure-native/apimanagement/index.js';
2
+ import { getComponentOutput } from '@pulumi/azure-native/applicationinsights/index.js';
3
+ import { getVaultOutput } from '@pulumi/azure-native/keyvault/index.js';
4
+ import * as pulumi from '@pulumi/pulumi';
5
+ import { CommonAzureConstruct } from '../../common/index.js';
6
+ import { RoleDefinitionId } from '../../services/index.js';
7
+ /**
8
+ * @classdesc Provides a construct to create and deploy an Azure API Management service with diagnostics and logging
9
+ * @example
10
+ * import { AzureRestApi, AzureRestApiProps } from '@gradientedge/cdk-utils'
11
+ *
12
+ * class CustomConstruct extends AzureRestApi {
13
+ * constructor(id: string, props: AzureRestApiProps) {
14
+ * super(id, props)
15
+ * this.props = props
16
+ * this.id = id
17
+ * this.initResources()
18
+ * }
19
+ * }
20
+ */
21
+ export class AzureRestApi extends CommonAzureConstruct {
22
+ props;
23
+ api;
24
+ applicationInsights;
25
+ constructor(id, props) {
26
+ super(id, props);
27
+ this.props = props;
28
+ this.id = id;
29
+ }
30
+ /**
31
+ * @summary Initialise and provision resources
32
+ */
33
+ initResources() {
34
+ this.createResourceGroup();
35
+ this.resolveApiKeyVault();
36
+ this.resolveCommonLogAnalyticsWorkspace();
37
+ this.resolveApplicationInsights();
38
+ this.createApiManagement();
39
+ this.createNamespaceSecretRole();
40
+ this.createNamespaceSecret();
41
+ this.createSubscriptionKeySecret();
42
+ this.createApiManagementLogger();
43
+ this.createApiDiagnostic();
44
+ this.createDiagnosticLog();
45
+ }
46
+ /**
47
+ * @summary Method to resolve the API authentication Key Vault
48
+ */
49
+ resolveApiKeyVault() {
50
+ this.api.authKeyVault = getVaultOutput({
51
+ vaultName: this.props.apiAuthKeyVault.name,
52
+ resourceGroupName: this.props.apiAuthKeyVault.resourceGroupName,
53
+ });
54
+ }
55
+ /**
56
+ * @summary Method to resolve the Application Insights instance
57
+ */
58
+ resolveApplicationInsights() {
59
+ if (!this.props.commonApplicationInsights || !this.props.commonApplicationInsights.resourceName)
60
+ return;
61
+ this.applicationInsights = getComponentOutput({
62
+ resourceName: this.props.commonApplicationInsights.resourceName,
63
+ resourceGroupName: this.props.commonApplicationInsights.resourceGroupName,
64
+ });
65
+ }
66
+ /**
67
+ * @summary Method to create or resolve an existing API Management service
68
+ */
69
+ createApiManagement() {
70
+ if (this.props.apiManagement.useExistingApiManagement) {
71
+ if (this.props.apiManagement.apiStackName) {
72
+ const apiStack = new pulumi.StackReference(this.props.apiManagement.apiStackName);
73
+ this.api.id = apiStack.getOutput('apiId');
74
+ this.api.name = apiStack.getOutput('apiName');
75
+ this.api.resourceGroupName = apiStack.getOutput('apiResourceGroupName');
76
+ }
77
+ }
78
+ else {
79
+ let hostnameConfigurations;
80
+ if (this.props.apiManagement.certificateKeyVaultId) {
81
+ hostnameConfigurations = [
82
+ {
83
+ hostName: `api-${this.props.locationConfig?.[this.props.location].name}.${this.props.domainName}`,
84
+ keyVaultId: this.props.apiManagement.certificateKeyVaultId,
85
+ type: HostnameType.Management,
86
+ },
87
+ ];
88
+ }
89
+ this.api.apim = this.apiManagementManager.createApiManagementService(this.id, this, {
90
+ ...this.props.apiManagement,
91
+ serviceName: this.props.stackName,
92
+ location: this.resourceGroup.location,
93
+ resourceGroupName: this.resourceGroup.name,
94
+ hostnameConfigurations,
95
+ }, undefined, undefined, { protect: true });
96
+ this.api.id = this.api.apim.id;
97
+ this.api.name = this.api.apim.name;
98
+ this.api.resourceGroupName = this.resourceGroup.name;
99
+ if (this.props.apiManagement.certificateKeyVaultId) {
100
+ this.authorisationManager.createRoleAssignment(`${this.id}-kv-role`, this, {
101
+ principalId: this.api.apim.identity.apply(identity => identity?.principalId ?? ''),
102
+ roleDefinitionId: RoleDefinitionId.KEY_VAULT_CERTIFICATE_USER,
103
+ scope: this.props.apiManagement.certificateKeyVaultId,
104
+ });
105
+ }
106
+ }
107
+ this.registerOutputs({
108
+ apiId: this.api.id,
109
+ apiName: this.api.name,
110
+ apiResourceGroupName: this.api.resourceGroupName,
111
+ });
112
+ }
113
+ /**
114
+ * @summary Method to create the Key Vault role assignment for the API Management identity
115
+ */
116
+ createNamespaceSecretRole() {
117
+ if (this.props.apiManagement.useExistingApiManagement)
118
+ return;
119
+ this.api.namedValueRoleAssignment = this.authorisationManager.createRoleAssignment(`${this.id}-key-vault-role-api-namespace`, this, {
120
+ principalId: this.api.apim.identity.apply(identity => identity?.principalId ?? ''),
121
+ roleDefinitionId: `/subscriptions/${this.props.subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/4633458b-17de-408a-b874-0445c86b69e6`,
122
+ scope: this.api.authKeyVault.id,
123
+ });
124
+ }
125
+ /**
126
+ * @summary Method to create the namespace secret in Key Vault for Application Insights
127
+ */
128
+ createNamespaceSecret() {
129
+ if (this.props.apiManagement.useExistingApiManagement)
130
+ return;
131
+ this.api.namedValueSecret = this.keyVaultManager.createKeyVaultSecret(`${this.id}-key-vault-api-namespace-secret`, this, {
132
+ vaultName: this.api.authKeyVault.name,
133
+ secretName: `${this.applicationInsights.name}-${this.props.stackName}-key`,
134
+ resourceGroupName: this.resourceGroup.name,
135
+ properties: {
136
+ value: this.applicationInsights.instrumentationKey,
137
+ },
138
+ });
139
+ }
140
+ /**
141
+ * @summary Method to create the API Management subscription and store the key in Key Vault
142
+ */
143
+ createSubscriptionKeySecret() {
144
+ if (this.props.apiManagement.useExistingApiManagement)
145
+ return;
146
+ const apiManagementSubscription = this.apiManagementManager.createSubscription(this.id, this, {
147
+ serviceName: this.api.apim.name,
148
+ resourceGroupName: this.resourceGroup.name,
149
+ displayName: 'all-apis',
150
+ state: 'active',
151
+ allowTracing: false,
152
+ scope: '', // todo
153
+ });
154
+ this.keyVaultManager.createKeyVaultSecret(`${this.id}-key-vault-api-subscription-key-secret`, this, {
155
+ vaultName: this.api.authKeyVault.name,
156
+ secretName: `${this.props.stackName}-subscription-key`,
157
+ resourceGroupName: this.resourceGroup.name,
158
+ properties: {
159
+ value: apiManagementSubscription.primaryKey.apply(key => key ?? ''),
160
+ },
161
+ });
162
+ }
163
+ /**
164
+ * @summary Method to create the API Management logger with Application Insights integration
165
+ */
166
+ createApiManagementLogger() {
167
+ if (this.props.apiManagement.useExistingApiManagement)
168
+ return;
169
+ const apiAppNamedValue = this.apiManagementManager.createNamedValue(`${this.id}-am-nv`, this, {
170
+ displayName: this.applicationInsights.name,
171
+ resourceGroupName: this.resourceGroup.name,
172
+ serviceName: this.api.apim.name,
173
+ namedValueId: `${this.applicationInsights.name}-key`,
174
+ secret: true,
175
+ keyVault: {
176
+ secretIdentifier: this.api.namedValueSecret.id,
177
+ },
178
+ });
179
+ this.api.logger = this.apiManagementManager.createLogger(`${this.id}-am-logger`, this, {
180
+ resourceGroupName: this.resourceGroup.name,
181
+ serviceName: this.api.apim.name,
182
+ resourceId: this.applicationInsights.id,
183
+ loggerType: LoggerType.ApplicationInsights,
184
+ credentials: {
185
+ instrumentationKey: `{{${apiAppNamedValue.displayName}}}`,
186
+ },
187
+ });
188
+ }
189
+ /**
190
+ * @summary Method to create the API diagnostic settings for API Management
191
+ */
192
+ createApiDiagnostic() {
193
+ if (this.props.apiManagement.useExistingApiManagement)
194
+ return;
195
+ this.apiManagementManager.createApiDiagnostic(`${this.id}-all-apis`, this, {
196
+ ...this.props.apiManagementDiagnostic,
197
+ apiId: this.api.apim.id,
198
+ resourceGroupName: this.resourceGroup.name,
199
+ serviceName: this.api.apim.name,
200
+ loggerId: this.api.logger.id,
201
+ });
202
+ }
203
+ /**
204
+ * @summary Method to create the Monitor diagnostic log settings for API Management
205
+ */
206
+ createDiagnosticLog() {
207
+ if (this.props.apiManagement.useExistingApiManagement)
208
+ return;
209
+ this.monitorManager.createMonitorDiagnosticSettings(`${this.id}-apim-diagnostic`, this, {
210
+ ...this.props.apiManagementDiagnosticSettings,
211
+ name: `${this.props.stackName}-api-management`,
212
+ resourceUri: this.api.apim.id,
213
+ workspaceId: this.commonLogAnalyticsWorkspace.id,
214
+ });
215
+ }
216
+ }
@@ -0,0 +1,25 @@
1
+ import { ApiManagementService, Logger } from '@pulumi/azure-native/apimanagement/index.js';
2
+ import { RoleAssignment } from '@pulumi/azure-native/authorization/index.js';
3
+ import { GetVaultResult, Secret } from '@pulumi/azure-native/keyvault/index.js';
4
+ import { Input, Output } from '@pulumi/pulumi';
5
+ import { ApiDiagnosticProps, ApiManagementProps, CommonAzureStackProps, MonitorDiagnosticSettingProps } from '../../index.js';
6
+ export interface ApiAuthKeyVault {
7
+ name: string;
8
+ resourceGroupName: string;
9
+ }
10
+ export interface AzureRestApiProps extends CommonAzureStackProps {
11
+ apiAuthKeyVault: ApiAuthKeyVault;
12
+ apiManagement: ApiManagementProps;
13
+ apiManagementDiagnostic: ApiDiagnosticProps;
14
+ apiManagementDiagnosticSettings: MonitorDiagnosticSettingProps;
15
+ }
16
+ export interface AzureApi {
17
+ id: Input<string>;
18
+ name: Input<string>;
19
+ resourceGroupName: Input<string>;
20
+ authKeyVault: Output<GetVaultResult>;
21
+ apim: ApiManagementService;
22
+ namedValueSecret: Secret;
23
+ namedValueRoleAssignment: RoleAssignment;
24
+ logger: Logger;
25
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from './main.js';
2
+ export * from './types.js';
@@ -0,0 +1,2 @@
1
+ export * from './main.js';
2
+ export * from './types.js';
@@ -0,0 +1,66 @@
1
+ import { ApiManagementApiOperationProps } from '../../services/index.js';
2
+ import { AzureFunctionApp } from '../function-app/index.js';
3
+ import { AzureApiFunction, AzureRestApiFunctionProps } from './types.js';
4
+ /**
5
+ * @classdesc Provides a construct to create and deploy an Azure Function App with API Management integration
6
+ * @example
7
+ * import { AzureRestApiFunction, AzureRestApiFunctionProps } from '@gradientedge/cdk-utils'
8
+ *
9
+ * class CustomConstruct extends AzureRestApiFunction {
10
+ * constructor(id: string, props: AzureRestApiFunctionProps) {
11
+ * super(id, props)
12
+ * this.props = props
13
+ * this.id = id
14
+ * this.initResources()
15
+ * }
16
+ * }
17
+ */
18
+ export declare class AzureRestApiFunction extends AzureFunctionApp {
19
+ props: AzureRestApiFunctionProps;
20
+ api: AzureApiFunction;
21
+ constructor(id: string, props: AzureRestApiFunctionProps);
22
+ /**
23
+ * @summary Initialise and provision resources
24
+ */
25
+ initResources(): void;
26
+ /**
27
+ * @summary Method to resolve the API authentication Key Vault
28
+ */
29
+ protected resolveApiKeyVault(): void;
30
+ /**
31
+ * @summary Method to create the namespace secret in Key Vault for the function app host key
32
+ */
33
+ protected createNamespaceSecret(): void;
34
+ /**
35
+ * @summary Method to create or resolve an existing API Management service
36
+ */
37
+ protected createApiManagement(): void;
38
+ /**
39
+ * @summary Method to create the API Management named value and backend for the function app
40
+ */
41
+ protected createApiManagementNamespace(): void;
42
+ /**
43
+ * @summary Method to create the API Management API and operation routes
44
+ */
45
+ protected createApiManagementRoutes(): void;
46
+ /**
47
+ * @summary Method to create an API Management API operation
48
+ */
49
+ protected createApiOperation(operation: ApiManagementApiOperationProps): void;
50
+ /**
51
+ * @summary Method to create a cache policy for an API Management API operation
52
+ */
53
+ protected createApiOperationCachePolicy(operation: ApiManagementApiOperationProps): void;
54
+ /**
55
+ * @summary Method to create the CORS policy for API Management
56
+ */
57
+ protected createCorsPolicy(): void;
58
+ /**
59
+ * @summary Method to create the API-level policy for API Management with backend routing and tracing
60
+ */
61
+ protected createApiPolicy(): void;
62
+ /**
63
+ * @summary Method to get the dashboard template variables including API Management name
64
+ */
65
+ protected dashboardVariables(): Record<string, any>;
66
+ }
@@ -0,0 +1,302 @@
1
+ import { HostnameType, NamedValue } from '@pulumi/azure-native/apimanagement/index.js';
2
+ import { getVaultOutput } from '@pulumi/azure-native/keyvault/index.js';
3
+ import { listWebAppHostKeysOutput } from '@pulumi/azure-native/web/index.js';
4
+ import * as pulumi from '@pulumi/pulumi';
5
+ import _ from 'lodash';
6
+ import { RoleDefinitionId } from '../../services/index.js';
7
+ import { AzureFunctionApp } from '../function-app/index.js';
8
+ /**
9
+ * @classdesc Provides a construct to create and deploy an Azure Function App with API Management integration
10
+ * @example
11
+ * import { AzureRestApiFunction, AzureRestApiFunctionProps } from '@gradientedge/cdk-utils'
12
+ *
13
+ * class CustomConstruct extends AzureRestApiFunction {
14
+ * constructor(id: string, props: AzureRestApiFunctionProps) {
15
+ * super(id, props)
16
+ * this.props = props
17
+ * this.id = id
18
+ * this.initResources()
19
+ * }
20
+ * }
21
+ */
22
+ export class AzureRestApiFunction extends AzureFunctionApp {
23
+ props;
24
+ api;
25
+ constructor(id, props) {
26
+ super(id, props);
27
+ this.props = props;
28
+ this.id = id;
29
+ }
30
+ /**
31
+ * @summary Initialise and provision resources
32
+ */
33
+ initResources() {
34
+ this.createResourceGroup();
35
+ this.resolveCommonLogAnalyticsWorkspace();
36
+ this.resolveApplicationInsights();
37
+ this.createAppServicePlan();
38
+ this.createdParsedAppConfigurations();
39
+ this.createAppConfiguration();
40
+ this.createAppConfigurations();
41
+ this.createStorageAccount();
42
+ this.createStorageDeploymentContainer();
43
+ this.createStorageContainer();
44
+ this.createDataStorageAccount();
45
+ this.createDataStorageContainer();
46
+ this.generateStorageContainerSas();
47
+ this.createFunctionHosts();
48
+ this.createCodePackage();
49
+ this.createFunctionAppSiteConfig();
50
+ this.createFunctionApp();
51
+ this.createRoleAssignments();
52
+ this.resolveApiKeyVault();
53
+ this.createNamespaceSecret();
54
+ this.createApiManagement();
55
+ this.createApiManagementNamespace();
56
+ this.createApiManagementRoutes();
57
+ this.createCorsPolicy();
58
+ this.createFunctionDashboard();
59
+ }
60
+ /**
61
+ * @summary Method to resolve the API authentication Key Vault
62
+ */
63
+ resolveApiKeyVault() {
64
+ this.api.authKeyVault = getVaultOutput({
65
+ vaultName: this.props.apiAuthKeyVault.name,
66
+ resourceGroupName: this.props.apiAuthKeyVault.resourceGroupName,
67
+ });
68
+ }
69
+ /**
70
+ * @summary Method to create the namespace secret in Key Vault for the function app host key
71
+ */
72
+ createNamespaceSecret() {
73
+ if (!this.props.apiManagement.useExistingApiManagement)
74
+ return;
75
+ const functionDefaultKey = listWebAppHostKeysOutput({
76
+ name: this.app.name,
77
+ resourceGroupName: this.resourceGroup.name,
78
+ });
79
+ this.api.namedValueSecret = this.keyVaultManager.createKeyVaultSecret(`${this.id}-key-vault-api-namespace-secret`, this, {
80
+ vaultName: this.api.authKeyVault.name,
81
+ secretName: pulumi.interpolate `${this.app.name}key`,
82
+ resourceGroupName: this.resourceGroup.name,
83
+ properties: {
84
+ value: functionDefaultKey.functionKeys?.apply(keys => keys?.['default'] ?? ''),
85
+ },
86
+ });
87
+ }
88
+ /**
89
+ * @summary Method to create or resolve an existing API Management service
90
+ */
91
+ createApiManagement() {
92
+ if (this.props.apiManagement.useExistingApiManagement) {
93
+ if (this.props.apiManagement.apiStackName) {
94
+ const apiStack = new pulumi.StackReference(this.props.apiManagement.apiStackName);
95
+ this.api.id = apiStack.getOutput('apiId');
96
+ this.api.name = apiStack.getOutput('apiName');
97
+ this.api.resourceGroupName = apiStack.getOutput('apiResourceGroupName');
98
+ }
99
+ }
100
+ else {
101
+ let hostnameConfigurations;
102
+ if (this.props.apiManagement.certificateKeyVaultId) {
103
+ hostnameConfigurations = [
104
+ {
105
+ hostName: `api-${this.props.locationConfig?.[this.props.location].name}.${this.props.domainName}`,
106
+ keyVaultId: this.props.apiManagement.certificateKeyVaultId,
107
+ type: HostnameType.Management,
108
+ },
109
+ ];
110
+ }
111
+ this.api.apim = this.apiManagementManager.createApiManagementService(this.id, this, {
112
+ ...this.props.apiManagement,
113
+ serviceName: this.props.stackName,
114
+ location: this.resourceGroup.location,
115
+ resourceGroupName: this.resourceGroup.name,
116
+ hostnameConfigurations,
117
+ }, undefined, undefined, { protect: true });
118
+ this.api.id = this.api.apim.id;
119
+ this.api.name = this.api.apim.name;
120
+ this.api.resourceGroupName = this.resourceGroup.name;
121
+ if (this.props.apiManagement.certificateKeyVaultId) {
122
+ this.authorisationManager.createRoleAssignment(`${this.id}-kv-role`, this, {
123
+ principalId: this.api.apim.identity.apply(identity => identity?.principalId ?? ''),
124
+ roleDefinitionId: RoleDefinitionId.KEY_VAULT_CERTIFICATE_USER,
125
+ scope: this.props.apiManagement.certificateKeyVaultId,
126
+ });
127
+ }
128
+ }
129
+ }
130
+ /**
131
+ * @summary Method to create the API Management named value and backend for the function app
132
+ */
133
+ createApiManagementNamespace() {
134
+ this.api.namedValue = new NamedValue(`${this.id}-am-nv`, {
135
+ displayName: this.app.name,
136
+ keyVault: {
137
+ secretIdentifier: this.api.namedValueSecret.id,
138
+ },
139
+ resourceGroupName: this.api.resourceGroupName,
140
+ secret: true,
141
+ serviceName: this.api.name,
142
+ });
143
+ this.api.backend = this.apiManagementManager.createBackend(this.id, this, {
144
+ ...this.props.apiManagementBackend,
145
+ title: this.props.stackName,
146
+ resourceGroupName: this.api.resourceGroupName,
147
+ serviceName: this.api.name,
148
+ url: pulumi.interpolate `https://${this.app.name}.azurewebsites.net/${this.props.apiManagementBackend.backendUrlPath}`,
149
+ resourceId: pulumi.interpolate `https://management.azure.com/subscriptions/${this.props.subscriptionId}/resourceGroups/${this.resourceGroup.name}/providers/Microsoft.Web/sites/${this.app.name}`,
150
+ credentials: {
151
+ header: {
152
+ 'x-functions-key': [`{{${this.api.namedValue.name}}}`],
153
+ },
154
+ },
155
+ });
156
+ }
157
+ /**
158
+ * @summary Method to create the API Management API and operation routes
159
+ */
160
+ createApiManagementRoutes() {
161
+ this.api.managementApi = this.apiManagementManager.createApi(`${this.id}-apim-api`, this, {
162
+ ...this.props.apiManagementApi,
163
+ displayName: this.props.apiManagementApi.displayName ?? this.props.stackName,
164
+ serviceName: this.api.name,
165
+ resourceGroupName: this.api.resourceGroupName,
166
+ isCurrent: this.props.apiManagementApi.isCurrent ?? true,
167
+ protocols: this.props.apiManagementApi.protocols ?? ['https'],
168
+ });
169
+ _.forEach(this.props.apiManagementApi.operations, operation => {
170
+ this.createApiOperation(operation);
171
+ this.createApiOperationCachePolicy(operation);
172
+ });
173
+ }
174
+ /**
175
+ * @summary Method to create an API Management API operation
176
+ */
177
+ createApiOperation(operation) {
178
+ this.api.apiOperations[operation.displayName.toString()] = this.apiManagementManager.createOperation(`${this.id}-apim-api-apim-api-operation-${operation.displayName}-${operation.method}`, this, {
179
+ operationId: `${operation.displayName}-${operation.method}`,
180
+ method: operation.method.toString().toUpperCase(),
181
+ serviceName: this.api.name,
182
+ resourceGroupName: this.api.resourceGroupName,
183
+ apiId: this.api.id,
184
+ displayName: operation.displayName,
185
+ urlTemplate: operation.urlTemplate,
186
+ templateParameters: operation.templateParameters,
187
+ });
188
+ }
189
+ /**
190
+ * @summary Method to create a cache policy for an API Management API operation
191
+ */
192
+ createApiOperationCachePolicy(operation) {
193
+ if (!operation.caching || !operation.caching.enableCacheSet)
194
+ return;
195
+ this.apiManagementManager.createOperationPolicy(`${this.id}-apim-api-operation-policy-${operation.displayName}-${operation.method}`, this, {
196
+ apiId: this.api.id,
197
+ resourceGroupName: this.api.resourceGroupName,
198
+ serviceName: this.api.name,
199
+ operationId: `${operation.displayName}-${operation.method}`,
200
+ value: `
201
+ <policies>
202
+ <policies>
203
+ <inbound>
204
+ <base />
205
+ ${this.props.apiManagementApi.cacheSetInboundPolicy}
206
+ </inbound>
207
+ <backend>
208
+ <base />
209
+ </backend>
210
+ <outbound>
211
+ <base />
212
+ ${this.props.apiManagementApi.cacheSetOutboundPolicy}
213
+ </outbound>
214
+ <on-error>
215
+ <base />
216
+ </on-error>
217
+ </policies>`.replace(/\n[ \t]*\n/g, '\n'), // move to utils
218
+ });
219
+ }
220
+ /**
221
+ * @summary Method to create the CORS policy for API Management
222
+ */
223
+ createCorsPolicy() {
224
+ if (!this.props.apiManagementCors?.enableCors)
225
+ return;
226
+ const allowedOrigins = [];
227
+ if (this.props.apiManagementCors.allowedOrigins) {
228
+ _.forEach(this.props.apiManagementCors.allowedOrigins, (origin) => {
229
+ allowedOrigins.push(`<origin>${origin}</origin>`);
230
+ });
231
+ }
232
+ else if (this.props.apiManagementCors.originSubdomain) {
233
+ _.forEach(this.props.locales, (locale) => {
234
+ allowedOrigins.push(`<origin>https://${this.props.apiManagementCors?.originSubdomain}-${locale}.${this.props.domainName}</origin>`);
235
+ });
236
+ }
237
+ const allowedHeaders = [];
238
+ _.forEach(this.props.apiManagementCors.allowedHeaders, (header) => {
239
+ allowedHeaders.push(`<header>${header}</header>`);
240
+ });
241
+ const allowedMethods = [];
242
+ _.forEach(this.props.apiManagementCors.allowedMethods, (method) => {
243
+ allowedMethods.push(`<method>${method}</method>`);
244
+ });
245
+ this.api.corsPolicyXmlContent = `
246
+ <cors allow-credentials="${this.props.apiManagementCors.allowCredentials}">
247
+ <allowed-origins>
248
+ ${allowedOrigins.toString().replaceAll(',', '')}
249
+ </allowed-origins>
250
+ <allowed-methods>
251
+ ${allowedMethods.toString().replaceAll(',', '')}
252
+ </allowed-methods>
253
+ <allowed-headers>
254
+ ${allowedHeaders.toString().replaceAll(',', '')}
255
+ </allowed-headers>
256
+ </cors>`.replace(/\n[ \t]*\n/g, '\n'); // move to utils
257
+ }
258
+ /**
259
+ * @summary Method to create the API-level policy for API Management with backend routing and tracing
260
+ */
261
+ createApiPolicy() {
262
+ const policyXmlContent = pulumi.interpolate `
263
+ <policies>
264
+ <inbound>
265
+ <base />
266
+ ${this.api.corsPolicyXmlContent ?? ''}
267
+ <set-backend-service backend-id="${this.api.backend.name}" />
268
+ <set-header name="traceparent" exists-action="override">
269
+ <value>@(context.Request.Headers.GetValueOrDefault("traceparent", ""))</value>
270
+ </set-header>
271
+ </inbound>
272
+ <backend>
273
+ <base />
274
+ </backend>
275
+ <outbound>
276
+ <base />
277
+ <set-header name="traceparent" exists-action="override">
278
+ <value>@(context.Request.Headers.GetValueOrDefault("traceparent", ""))</value>
279
+ </set-header>
280
+ </outbound>
281
+ <on-error>
282
+ <base />
283
+ </on-error>
284
+ </policies>`;
285
+ this.apiManagementManager.createPolicy(`${this.id}-apim-api-policy`, this, {
286
+ serviceName: this.api.name,
287
+ apiId: this.api.id,
288
+ resourceGroupName: this.api.resourceGroupName,
289
+ value: policyXmlContent.apply(xml => xml.replace(/\n[ \t]*\n/g, '\n')),
290
+ });
291
+ }
292
+ /**
293
+ * @summary Method to get the dashboard template variables including API Management name
294
+ */
295
+ dashboardVariables() {
296
+ const variables = super.dashboardVariables();
297
+ return {
298
+ ...variables,
299
+ apimName: this.api.name,
300
+ };
301
+ }
302
+ }
@@ -0,0 +1,29 @@
1
+ import { Api, ApiOperation, Backend, NamedValue } from '@pulumi/azure-native/apimanagement/index.js';
2
+ import { ApiManagementApiProps, ApiManagementBackendProps, ApiManagementProps, ApplicationInsightsProps, AzureApi, AzureFunctionAppProps, AzureRestApiProps } from '../../index.js';
3
+ export interface ApiManagementRestApiProps extends ApiManagementProps {
4
+ useExistingApiManagement: boolean;
5
+ }
6
+ export interface ApiManagementCors {
7
+ enableCors: boolean;
8
+ allowCredentials: boolean;
9
+ allowedMethods: string[];
10
+ allowedHeaders: string[];
11
+ allowedOrigins?: string[];
12
+ originSubdomain?: string;
13
+ }
14
+ export interface AzureRestApiFunctionProps extends AzureRestApiProps, AzureFunctionAppProps {
15
+ apiManagementBackend: ApiManagementBackendProps;
16
+ apiManagementApi: ApiManagementApiProps;
17
+ apiManagementApplicationInsights?: ApplicationInsightsProps;
18
+ apiManagement: ApiManagementRestApiProps;
19
+ apiManagementCors?: ApiManagementCors;
20
+ }
21
+ export interface AzureApiFunction extends AzureApi {
22
+ corsPolicyXmlContent?: string;
23
+ apiOperations: {
24
+ [operation: string]: ApiOperation;
25
+ };
26
+ managementApi: Api;
27
+ backend: Backend;
28
+ namedValue: NamedValue;
29
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from './main.js';
2
+ export * from './types.js';
@@ -0,0 +1,2 @@
1
+ export * from './main.js';
2
+ export * from './types.js';