@appliance.sh/api-server 1.13.0 → 1.14.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appliance.sh/api-server",
3
- "version": "1.13.0",
3
+ "version": "1.14.0",
4
4
  "description": "",
5
5
  "author": "Eliot Lim",
6
6
  "repository": "https://github.com/appliance-sh/appliance.sh",
@@ -1,13 +1,18 @@
1
1
  import * as pulumi from '@pulumi/pulumi';
2
2
  import * as aws from '@pulumi/aws';
3
+ import * as awsNative from '@pulumi/aws-native';
4
+ import { ApplianceBaseConfig } from '@appliance.sh/sdk';
3
5
 
4
6
  export interface ApplianceStackArgs {
5
7
  tags?: Record<string, string>;
8
+ config: ApplianceBaseConfig;
6
9
  }
7
10
 
8
11
  export interface ApplianceStackOpts extends pulumi.ComponentResourceOptions {
9
12
  globalProvider: aws.Provider;
10
13
  provider: aws.Provider;
14
+ nativeProvider: awsNative.Provider;
15
+ nativeGlobalProvider: awsNative.Provider;
11
16
  }
12
17
 
13
18
  export class ApplianceStack extends pulumi.ComponentResource {
@@ -15,11 +20,13 @@ export class ApplianceStack extends pulumi.ComponentResource {
15
20
  lambdaRolePolicy: aws.iam.Policy;
16
21
  lambda: aws.lambda.Function;
17
22
  lambdaUrl: aws.lambda.FunctionUrl;
23
+ dnsRecord: pulumi.Output<string>;
18
24
 
19
25
  constructor(name: string, args: ApplianceStackArgs, opts: ApplianceStackOpts) {
20
26
  super('appliance:aws:ApplianceStack', name, args, opts);
21
27
 
22
28
  const defaultOpts = { parent: this, provider: opts.provider };
29
+ const defaultNativeOpts = { parent: this, provider: opts.nativeProvider };
23
30
  const defaultTags = { stack: name, managed: 'appliance', ...args.tags };
24
31
 
25
32
  this.lambdaRole = new aws.iam.Role(`${name}-role`, {
@@ -58,25 +65,96 @@ export class ApplianceStack extends pulumi.ComponentResource {
58
65
  `${name}-url`,
59
66
  {
60
67
  functionName: this.lambda.name,
61
- authorizationType: 'NONE',
68
+ authorizationType: args.config.aws.cloudfrontDistributionId ? 'AWS_IAM' : 'NONE',
62
69
  },
63
70
  defaultOpts
64
71
  );
65
72
 
66
- new aws.lambda.Permission(`${name}-url-invoke-url-permission`, {
67
- function: this.lambda.name,
68
- action: 'lambda:InvokeFunctionUrl',
69
- principal: '*',
70
- functionUrlAuthType: 'NONE',
71
- statementId: 'FunctionURLAllowPublicAccess',
72
- });
73
+ this.dnsRecord = pulumi.interpolate`${name}.${args.config.domainName ?? ''}`;
73
74
 
74
- new aws.lambda.Permission(`${name}-url-invoke-lambda-permission`, {
75
- function: this.lambda.name,
76
- action: 'lambda:InvokeFunction',
77
- principal: '*',
78
- statementId: 'FunctionURLAllowInvokeAction',
79
- });
75
+ if (args.config.aws.cloudfrontDistributionId) {
76
+ new aws.lambda.Permission(`${name}-url-invoke-url-permission`, {
77
+ function: this.lambda.name,
78
+ action: 'lambda:InvokeFunctionUrl',
79
+ principal: 'cloudfront.amazonaws.com',
80
+ functionUrlAuthType: 'AWS_IAM',
81
+ sourceArn: pulumi.interpolate`arn:aws:cloudfront::${
82
+ aws.getCallerIdentityOutput({}, { provider: opts.provider }).accountId
83
+ }:distribution/${args.config.aws.cloudfrontDistributionId}`,
84
+ statementId: 'FunctionURLAllowCloudFrontAccess',
85
+ });
86
+
87
+ // Grant the edge router role permission to invoke the Lambda Function URL
88
+ // The edge router role is the execution role of the Lambda@Edge function that signs requests
89
+ if (args.config.aws.edgeRouterRoleArn) {
90
+ new aws.lambda.Permission(`${name}-invoke-url-edge-router-permission`, {
91
+ function: this.lambda.name,
92
+ action: 'lambda:InvokeFunctionUrl',
93
+ principal: args.config.aws.edgeRouterRoleArn,
94
+ functionUrlAuthType: 'AWS_IAM',
95
+ statementId: 'FunctionURLAllowEdgeRouterRoleAccess',
96
+ });
97
+
98
+ new awsNative.lambda.Permission(
99
+ `${name}-invoke-edge-router-permission`,
100
+ {
101
+ action: 'lambda:InvokeFunction',
102
+ principal: args.config.aws.edgeRouterRoleArn,
103
+ functionName: this.lambda.name,
104
+ invokedViaFunctionUrl: true,
105
+ },
106
+ defaultNativeOpts
107
+ );
108
+ }
109
+ } else {
110
+ new aws.lambda.Permission(`${name}-url-invoke-url-permission`, {
111
+ function: this.lambda.name,
112
+ action: 'lambda:InvokeFunctionUrl',
113
+ principal: '*',
114
+ functionUrlAuthType: 'NONE',
115
+ statementId: 'FunctionURLAllowPublicAccess',
116
+ });
117
+ }
118
+
119
+ if (args.config.aws.cloudfrontDistributionId && args.config.aws.cloudfrontDistributionDomainName) {
120
+ new awsNative.lambda.Permission(
121
+ `${name}-url-invoke-lambda-native-permission`,
122
+ {
123
+ action: 'lambda:InvokeFunction',
124
+ principal: 'cloudfront.amazonaws.com',
125
+ sourceArn: pulumi.interpolate`arn:aws:cloudfront::${
126
+ aws.getCallerIdentityOutput({}, { provider: opts.provider }).accountId
127
+ }:distribution/${args.config.aws.cloudfrontDistributionId}`,
128
+ functionName: this.lambda.name,
129
+ invokedViaFunctionUrl: true,
130
+ },
131
+ defaultNativeOpts
132
+ );
133
+
134
+ new aws.route53.Record(
135
+ `${name}-cname-record`,
136
+ {
137
+ zoneId: args.config.aws.zoneId,
138
+ name: pulumi.interpolate`${name}.${args.config.domainName ?? ''}`,
139
+ type: 'CNAME',
140
+ ttl: 60,
141
+ records: [args.config.aws.cloudfrontDistributionDomainName],
142
+ },
143
+ { parent: this, provider: opts.globalProvider }
144
+ );
145
+
146
+ new aws.route53.Record(
147
+ `${name}-txt-record`,
148
+ {
149
+ zoneId: args.config.aws.zoneId,
150
+ name: pulumi.interpolate`origin.${name}.${args.config.domainName ?? ''}`,
151
+ type: 'TXT',
152
+ ttl: 60,
153
+ records: [this.lambdaUrl.functionUrl],
154
+ },
155
+ { parent: this, provider: opts.globalProvider }
156
+ );
157
+ }
80
158
 
81
159
  this.registerOutputs({
82
160
  lambda: this.lambda,
@@ -1,6 +1,7 @@
1
1
  import { Injectable, Logger } from '@nestjs/common';
2
2
  import * as auto from '@pulumi/pulumi/automation';
3
3
  import * as aws from '@pulumi/aws';
4
+ import * as awsNative from '@pulumi/aws-native';
4
5
  import { ApplianceStack } from './ApplianceStack';
5
6
  import { applianceBaseConfig } from '@appliance.sh/sdk';
6
7
 
@@ -17,31 +18,46 @@ export interface PulumiResult {
17
18
  @Injectable()
18
19
  export class PulumiService {
19
20
  private readonly logger = new Logger(PulumiService.name);
20
- private readonly region = process.env.AWS_REGION || 'us-east-1';
21
21
  private readonly projectName = 'appliance-api-managed-proj';
22
22
 
23
23
  private readonly baseConfig = process.env.APPLIANCE_BASE_CONFIG
24
24
  ? applianceBaseConfig.parse(JSON.parse(process.env.APPLIANCE_BASE_CONFIG))
25
25
  : undefined;
26
+ private readonly region = this.baseConfig?.aws.region || 'us-east-1';
26
27
 
27
28
  private inlineProgram() {
28
29
  return async () => {
29
30
  const name = 'appliance';
31
+
32
+ if (!this.baseConfig) {
33
+ throw new Error('Missing base config');
34
+ }
35
+
30
36
  const regionalProvider = new aws.Provider(`${name}-regional`, {
31
- region: this.baseConfig?.region ?? 'ap-southeast-1',
37
+ region: (this.baseConfig?.aws.region as aws.Region) ?? 'ap-southeast-1',
32
38
  });
33
39
  const globalProvider = new aws.Provider(`${name}-global`, {
34
40
  region: 'us-east-1',
35
41
  });
42
+ const nativeRegionalProvider = new awsNative.Provider(`${name}-native-regional`, {
43
+ region: (this.baseConfig?.aws.region as awsNative.Region) ?? 'ap-southeast-1',
44
+ });
45
+
46
+ const nativeGlobalProvider = new awsNative.Provider(`${name}-native-global`, {
47
+ region: 'us-east-1',
48
+ });
36
49
 
37
50
  const applianceStack = new ApplianceStack(
38
51
  `${name}-stack`,
39
52
  {
40
53
  tags: { project: name },
54
+ config: this.baseConfig,
41
55
  },
42
56
  {
43
57
  globalProvider,
44
58
  provider: regionalProvider,
59
+ nativeProvider: nativeRegionalProvider,
60
+ nativeGlobalProvider: nativeGlobalProvider,
45
61
  }
46
62
  );
47
63
 
@@ -67,7 +83,7 @@ export class PulumiService {
67
83
  { projectName: this.projectName, stackName, program },
68
84
  { envVars }
69
85
  );
70
- await stack.setConfig('aws:region', { value: this.region });
86
+ await stack.setConfig('aws:region', { value: this.baseConfig.aws.region });
71
87
  return stack;
72
88
  }
73
89