@mstuercke/pulumi-modules 0.0.1
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 +33 -0
- package/src/auth0/Auth0.ts +162 -0
- package/src/auth0/index.ts +7 -0
- package/src/domain/getDomain.ts +32 -0
- package/src/domain/index.ts +7 -0
- package/src/iam/SimpleIamRolePolicy.ts +165 -0
- package/src/iam/SimpleIamRolePolicyConfig.ts +75 -0
- package/src/iam/index.ts +8 -0
- package/src/index.ts +31 -0
- package/src/lambda/NodeLambdaFunction.ts +120 -0
- package/src/lambda/WithInputs.ts +5 -0
- package/src/lambda/index.ts +7 -0
- package/src/mongodb/MongoDB.ts +86 -0
- package/src/mongodb/index.ts +9 -0
- package/src/rest/RestApi.ts +226 -0
- package/src/rest/index.ts +7 -0
- package/src/s3/PublicS3Bucket.ts +92 -0
- package/src/s3/index.ts +7 -0
- package/src/website/StaticWebsite.ts +159 -0
- package/src/website/index.ts +7 -0
- package/src/website/readFilesRecursive.ts +33 -0
- package/src/websocket/WebsocketApi.ts +219 -0
- package/src/websocket/index.ts +7 -0
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mstuercke/pulumi-modules",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"files": [
|
|
5
|
+
"src/**/!(*.test|*.fixture).ts",
|
|
6
|
+
"README.md"
|
|
7
|
+
],
|
|
8
|
+
"main": "src/index.ts",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"typeCheck": "tsc --noEmit",
|
|
11
|
+
"bump:major": "npm version major --git-tag-version false",
|
|
12
|
+
"bump:minor": "npm version minor --git-tag-version false",
|
|
13
|
+
"bump:patch": "npm version patch --git-tag-version false",
|
|
14
|
+
"release": "bun run --tsconfig-override ./tsconfig.scripts.json scripts/release.ts"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@pulumi/archive": "^0.2.2",
|
|
18
|
+
"@pulumi/auth0": "^3.8.1",
|
|
19
|
+
"@pulumi/aws": "^6.56.1",
|
|
20
|
+
"@pulumi/mongodbatlas": "^3.20.2",
|
|
21
|
+
"@pulumi/pulumi": "^3.137.0",
|
|
22
|
+
"@pulumi/random": "^4.16.7",
|
|
23
|
+
"@pulumiverse/sentry": "^0.0.8",
|
|
24
|
+
"@types/mime": "^3.0.4",
|
|
25
|
+
"glob": "^11.0.0",
|
|
26
|
+
"mime": "^3.0.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@mstuercke/bun-utils": "7.0.6",
|
|
30
|
+
"@types/bun": "1.1.12",
|
|
31
|
+
"typescript": "5.6.3"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import {type CustomResourceOptions, type Output, Resource} from '@pulumi/pulumi'
|
|
2
|
+
import {Client, ClientCredentials, Connection, ConnectionClient, Provider, Tenant, User} from '@pulumi/auth0'
|
|
3
|
+
|
|
4
|
+
export type Auth0Domain = `${string}.auth0.com`
|
|
5
|
+
export type Auth0URL = `http://${string}` | `https://${string}`
|
|
6
|
+
|
|
7
|
+
export interface Auth0User {
|
|
8
|
+
name: string
|
|
9
|
+
email: string
|
|
10
|
+
password: string
|
|
11
|
+
emailVerified: boolean
|
|
12
|
+
appMetadata?: Record<string, unknown>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface Auth0Args {
|
|
16
|
+
projectId: string
|
|
17
|
+
environmentName: string
|
|
18
|
+
tenantDisplayName: string
|
|
19
|
+
clientDisplayName: string
|
|
20
|
+
domain: Auth0Domain
|
|
21
|
+
m2mClientId: string
|
|
22
|
+
allowedUrls: Auth0URL[]
|
|
23
|
+
allowedLoginCallbackUrls?: Auth0URL[]
|
|
24
|
+
allowedLogoutCallbackUrls?: Auth0URL[]
|
|
25
|
+
nativeAppId?: `com.${string}`
|
|
26
|
+
defaultUsers?: Auth0User[]
|
|
27
|
+
disableSignup?: boolean
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export class Auth0 extends Resource {
|
|
31
|
+
domain: string
|
|
32
|
+
clientId: Output<string>
|
|
33
|
+
|
|
34
|
+
constructor(id: string, args: Auth0Args, opts?: CustomResourceOptions) {
|
|
35
|
+
super('mstuercke:auth0:Auth0', id, false, undefined, opts)
|
|
36
|
+
|
|
37
|
+
const {
|
|
38
|
+
projectId,
|
|
39
|
+
environmentName,
|
|
40
|
+
tenantDisplayName,
|
|
41
|
+
clientDisplayName,
|
|
42
|
+
domain,
|
|
43
|
+
m2mClientId,
|
|
44
|
+
allowedUrls,
|
|
45
|
+
allowedLoginCallbackUrls,
|
|
46
|
+
allowedLogoutCallbackUrls,
|
|
47
|
+
nativeAppId,
|
|
48
|
+
defaultUsers = [],
|
|
49
|
+
disableSignup = false,
|
|
50
|
+
} = args
|
|
51
|
+
|
|
52
|
+
new Provider('provider', {}, {parent: this})
|
|
53
|
+
|
|
54
|
+
new Tenant(
|
|
55
|
+
'tenant',
|
|
56
|
+
{
|
|
57
|
+
friendlyName: tenantDisplayName,
|
|
58
|
+
flags: {
|
|
59
|
+
enableClientConnections: false,
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
{parent: this},
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
const nativeAppCallbackUrls = nativeAppId
|
|
66
|
+
? [
|
|
67
|
+
`${nativeAppId}.auth0://${domain}/ios/${nativeAppId}/callback`,
|
|
68
|
+
`${nativeAppId}.auth0://${domain}/android/${nativeAppId}/callback`,
|
|
69
|
+
]
|
|
70
|
+
: []
|
|
71
|
+
const client = new Client(
|
|
72
|
+
'client',
|
|
73
|
+
{
|
|
74
|
+
name: clientDisplayName,
|
|
75
|
+
appType: 'spa',
|
|
76
|
+
callbacks: [...(allowedLoginCallbackUrls || allowedUrls), ...nativeAppCallbackUrls],
|
|
77
|
+
webOrigins: allowedUrls,
|
|
78
|
+
allowedLogoutUrls: [...(allowedLogoutCallbackUrls || allowedUrls), ...nativeAppCallbackUrls],
|
|
79
|
+
jwtConfiguration: {
|
|
80
|
+
alg: 'RS256',
|
|
81
|
+
},
|
|
82
|
+
addons: {},
|
|
83
|
+
},
|
|
84
|
+
{parent: this},
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
const connection = new Connection(
|
|
88
|
+
'password-authentication',
|
|
89
|
+
{
|
|
90
|
+
name: `${projectId}-${environmentName}`,
|
|
91
|
+
strategy: 'auth0',
|
|
92
|
+
options: {
|
|
93
|
+
disableSignup: disableSignup,
|
|
94
|
+
bruteForceProtection: true,
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
{parent: this},
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
const m2mClientConnection = new ConnectionClient(
|
|
101
|
+
'password-authentication-m2m-client',
|
|
102
|
+
{
|
|
103
|
+
clientId: m2mClientId,
|
|
104
|
+
connectionId: connection.id,
|
|
105
|
+
},
|
|
106
|
+
{parent: client},
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
const clientConnection = new ConnectionClient(
|
|
110
|
+
'password-authentication-client',
|
|
111
|
+
{
|
|
112
|
+
clientId: client.id,
|
|
113
|
+
connectionId: connection.id,
|
|
114
|
+
},
|
|
115
|
+
{parent: client},
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
// TODO: Implement disabling of google-oauth2 (If possible, also disable "Username-Password-Authentication")
|
|
119
|
+
// // disable google-oauth2 on all clients
|
|
120
|
+
// const googleOauth2Connection = output(getConnection({name: 'google-oauth2'}))
|
|
121
|
+
// new ConnectionClients(
|
|
122
|
+
// 'google-oauth2-clients',
|
|
123
|
+
// {
|
|
124
|
+
// connectionId: googleOauth2Connection.id,
|
|
125
|
+
// enabledClients: [],
|
|
126
|
+
// },
|
|
127
|
+
// {parent: client, dependsOn: [client]},
|
|
128
|
+
// )
|
|
129
|
+
|
|
130
|
+
new ClientCredentials(
|
|
131
|
+
'credentials',
|
|
132
|
+
{
|
|
133
|
+
clientId: client.id,
|
|
134
|
+
authenticationMethod: 'none',
|
|
135
|
+
},
|
|
136
|
+
{parent: this},
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
for (const defaultUser of defaultUsers) {
|
|
140
|
+
const {name, email, emailVerified, password, appMetadata} = defaultUser
|
|
141
|
+
|
|
142
|
+
new User(
|
|
143
|
+
`default-user-${defaultUser.email}`,
|
|
144
|
+
{
|
|
145
|
+
connectionName: connection.name,
|
|
146
|
+
name: name,
|
|
147
|
+
email: email,
|
|
148
|
+
emailVerified: emailVerified,
|
|
149
|
+
password: password,
|
|
150
|
+
appMetadata: appMetadata ? JSON.stringify(appMetadata) : undefined,
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
dependsOn: [m2mClientConnection, clientConnection],
|
|
154
|
+
parent: connection,
|
|
155
|
+
},
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
this.domain = domain
|
|
160
|
+
this.clientId = client.id
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import {acm, type Provider, route53} from '@pulumi/aws'
|
|
2
|
+
|
|
3
|
+
export interface DataDomainOptions {
|
|
4
|
+
usEast1Provider: Provider
|
|
5
|
+
name: `${string}.${string}`
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type DomainResult = {
|
|
9
|
+
name: string
|
|
10
|
+
zoneId: string
|
|
11
|
+
nameServers: string[]
|
|
12
|
+
usEast1CertificateArn: string
|
|
13
|
+
euCentral1CertificateArn: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const getDomain = async (options: DataDomainOptions): Promise<DomainResult> => {
|
|
17
|
+
const {usEast1Provider, name} = options
|
|
18
|
+
|
|
19
|
+
const zone = await route53.getZone({name})
|
|
20
|
+
|
|
21
|
+
const euCentral1Certificate = await acm.getCertificate({domain: name})
|
|
22
|
+
|
|
23
|
+
const usEast1Certificate = await acm.getCertificate({domain: name}, {provider: usEast1Provider})
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
name: zone.name,
|
|
27
|
+
zoneId: zone.zoneId,
|
|
28
|
+
nameServers: zone.nameServers,
|
|
29
|
+
usEast1CertificateArn: usEast1Certificate.arn,
|
|
30
|
+
euCentral1CertificateArn: euCentral1Certificate.arn,
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import {iam} from '@pulumi/aws'
|
|
2
|
+
import type {SimpleIamRolePolicyConfig} from './SimpleIamRolePolicyConfig'
|
|
3
|
+
import type {CustomResourceOptions, Input} from '@pulumi/pulumi'
|
|
4
|
+
import type {RolePolicyArgs} from '@pulumi/aws/iam'
|
|
5
|
+
import type {PolicyStatement} from '@pulumi/aws/iam/documents'
|
|
6
|
+
|
|
7
|
+
export class SimpleIamRolePolicy extends iam.RolePolicy {
|
|
8
|
+
constructor(iamRoleId: string, config: SimpleIamRolePolicyConfig, opts?: CustomResourceOptions) {
|
|
9
|
+
switch (config.type) {
|
|
10
|
+
case 'custom':
|
|
11
|
+
super(config.name, mapIamRolePolicyConfig(iamRoleId, config.name, config.statements), opts)
|
|
12
|
+
break
|
|
13
|
+
|
|
14
|
+
case 'dynamodb':
|
|
15
|
+
if (config.level !== 'full-access') throw mapError(config)
|
|
16
|
+
super(
|
|
17
|
+
config.name,
|
|
18
|
+
mapIamRolePolicyConfig(iamRoleId, config.name, [
|
|
19
|
+
{
|
|
20
|
+
Action: ['dynamodb:*'],
|
|
21
|
+
Effect: 'Allow',
|
|
22
|
+
Resource: [`${config.tableArn}`, `${config.tableArn}/*`],
|
|
23
|
+
},
|
|
24
|
+
]),
|
|
25
|
+
opts,
|
|
26
|
+
)
|
|
27
|
+
break
|
|
28
|
+
|
|
29
|
+
case 'timestream':
|
|
30
|
+
if (config.level !== 'full-access') throw mapError(config)
|
|
31
|
+
|
|
32
|
+
super(
|
|
33
|
+
config.name,
|
|
34
|
+
mapIamRolePolicyConfig(iamRoleId, config.name, [
|
|
35
|
+
{
|
|
36
|
+
Action: ['timestream:*'],
|
|
37
|
+
Effect: 'Allow',
|
|
38
|
+
Resource: [config.dbArn, config.tableArn],
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
Action: ['timestream:DescribeEndpoints'],
|
|
42
|
+
Effect: 'Allow',
|
|
43
|
+
Resource: ['*'],
|
|
44
|
+
},
|
|
45
|
+
]),
|
|
46
|
+
opts,
|
|
47
|
+
)
|
|
48
|
+
break
|
|
49
|
+
|
|
50
|
+
case 's3':
|
|
51
|
+
if (config.level !== 'full-access') throw mapError(config)
|
|
52
|
+
|
|
53
|
+
super(
|
|
54
|
+
config.name,
|
|
55
|
+
mapIamRolePolicyConfig(iamRoleId, config.name, [
|
|
56
|
+
{
|
|
57
|
+
Action: ['s3:*'],
|
|
58
|
+
Effect: 'Allow',
|
|
59
|
+
Resource: [`${config.bucketArn}`, `${config.bucketArn}/*`],
|
|
60
|
+
},
|
|
61
|
+
]),
|
|
62
|
+
opts,
|
|
63
|
+
)
|
|
64
|
+
break
|
|
65
|
+
|
|
66
|
+
case 'cognito':
|
|
67
|
+
if (config.level !== 'full-access') throw mapError(config)
|
|
68
|
+
|
|
69
|
+
super(
|
|
70
|
+
config.name,
|
|
71
|
+
mapIamRolePolicyConfig(iamRoleId, config.name, [
|
|
72
|
+
{
|
|
73
|
+
Action: ['cognito-idp:*'],
|
|
74
|
+
Effect: 'Allow',
|
|
75
|
+
Resource: [config.userPoolArn],
|
|
76
|
+
},
|
|
77
|
+
]),
|
|
78
|
+
opts,
|
|
79
|
+
)
|
|
80
|
+
break
|
|
81
|
+
|
|
82
|
+
case 'websocket':
|
|
83
|
+
if (config.level !== 'full-access') throw mapError(config)
|
|
84
|
+
|
|
85
|
+
super(
|
|
86
|
+
config.name,
|
|
87
|
+
mapIamRolePolicyConfig(iamRoleId, config.name, [
|
|
88
|
+
{
|
|
89
|
+
Effect: 'Allow',
|
|
90
|
+
Action: 'execute-api:*',
|
|
91
|
+
Resource: config.apiArn,
|
|
92
|
+
},
|
|
93
|
+
]),
|
|
94
|
+
opts,
|
|
95
|
+
)
|
|
96
|
+
break
|
|
97
|
+
|
|
98
|
+
case 'sns':
|
|
99
|
+
if (config.level !== 'publish-message') throw mapError(config)
|
|
100
|
+
|
|
101
|
+
super(
|
|
102
|
+
config.name,
|
|
103
|
+
mapIamRolePolicyConfig(iamRoleId, config.name, [
|
|
104
|
+
{
|
|
105
|
+
Effect: 'Allow',
|
|
106
|
+
Action: 'sns:Publish',
|
|
107
|
+
Resource: config.snsTopicArn,
|
|
108
|
+
},
|
|
109
|
+
]),
|
|
110
|
+
opts,
|
|
111
|
+
)
|
|
112
|
+
break
|
|
113
|
+
|
|
114
|
+
case 'execute-lambda':
|
|
115
|
+
super(
|
|
116
|
+
config.name,
|
|
117
|
+
mapIamRolePolicyConfig(iamRoleId, config.name, [
|
|
118
|
+
{
|
|
119
|
+
Effect: 'Allow',
|
|
120
|
+
Action: 'lambda:InvokeFunction',
|
|
121
|
+
Resource: config.lambdaArn,
|
|
122
|
+
},
|
|
123
|
+
]),
|
|
124
|
+
opts,
|
|
125
|
+
)
|
|
126
|
+
break
|
|
127
|
+
|
|
128
|
+
case 'event-bridge':
|
|
129
|
+
super(
|
|
130
|
+
config.name,
|
|
131
|
+
mapIamRolePolicyConfig(iamRoleId, config.name, [
|
|
132
|
+
{
|
|
133
|
+
Effect: 'Allow',
|
|
134
|
+
Action: ['events:DescribeRule', 'events:DisableRule', 'events:EnableRule'],
|
|
135
|
+
Resource: config.ruleArn,
|
|
136
|
+
},
|
|
137
|
+
]),
|
|
138
|
+
opts,
|
|
139
|
+
)
|
|
140
|
+
break
|
|
141
|
+
|
|
142
|
+
default:
|
|
143
|
+
throw mapError(config)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function mapIamRolePolicyConfig(
|
|
149
|
+
iamRoleId: Input<string>,
|
|
150
|
+
name: string,
|
|
151
|
+
statements: Input<Input<PolicyStatement>[]>,
|
|
152
|
+
): RolePolicyArgs {
|
|
153
|
+
return {
|
|
154
|
+
role: iamRoleId,
|
|
155
|
+
name: name,
|
|
156
|
+
policy: {
|
|
157
|
+
Version: '2012-10-17',
|
|
158
|
+
Statement: statements,
|
|
159
|
+
},
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function mapError(config: SimpleIamRolePolicyConfig): Error {
|
|
164
|
+
return new Error(`Unable to create policy with config: ${JSON.stringify(config)}`)
|
|
165
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type {Input} from '@pulumi/pulumi'
|
|
2
|
+
import type {PolicyStatement} from '@pulumi/aws/iam/documents'
|
|
3
|
+
|
|
4
|
+
export type SimpleIamRolePolicyConfig =
|
|
5
|
+
| CustomPolicyConfig
|
|
6
|
+
| DynamoDbPolicyConfig
|
|
7
|
+
| TimestreamPolicyConfig
|
|
8
|
+
| S3PolicyConfig
|
|
9
|
+
| CognitoPolicyConfig
|
|
10
|
+
| WebsocketPolicyConfig
|
|
11
|
+
| ExecuteLambdaConfig
|
|
12
|
+
| SnsPolicyConfig
|
|
13
|
+
| EventBridgeConfig
|
|
14
|
+
|
|
15
|
+
interface CustomPolicyConfig {
|
|
16
|
+
type: 'custom'
|
|
17
|
+
name: string
|
|
18
|
+
statements: PolicyStatement[]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface DynamoDbPolicyConfig {
|
|
22
|
+
type: 'dynamodb'
|
|
23
|
+
level: 'full-access'
|
|
24
|
+
name: string
|
|
25
|
+
tableArn: Input<string>
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface TimestreamPolicyConfig {
|
|
29
|
+
type: 'timestream'
|
|
30
|
+
level: 'full-access'
|
|
31
|
+
name: string
|
|
32
|
+
dbArn: Input<string>
|
|
33
|
+
tableArn: Input<string>
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface S3PolicyConfig {
|
|
37
|
+
type: 's3'
|
|
38
|
+
level: 'full-access'
|
|
39
|
+
name: string
|
|
40
|
+
bucketArn: Input<string>
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface CognitoPolicyConfig {
|
|
44
|
+
type: 'cognito'
|
|
45
|
+
level: 'full-access'
|
|
46
|
+
name: string
|
|
47
|
+
userPoolArn: Input<string>
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface WebsocketPolicyConfig {
|
|
51
|
+
type: 'websocket'
|
|
52
|
+
level: 'full-access'
|
|
53
|
+
name: string
|
|
54
|
+
apiArn: '*'
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface SnsPolicyConfig {
|
|
58
|
+
type: 'sns'
|
|
59
|
+
level: 'publish-message'
|
|
60
|
+
name: string
|
|
61
|
+
snsTopicArn: Input<string>
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
interface ExecuteLambdaConfig {
|
|
65
|
+
type: 'execute-lambda'
|
|
66
|
+
name: string
|
|
67
|
+
lambdaArn: Input<string>
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface EventBridgeConfig {
|
|
71
|
+
type: 'event-bridge'
|
|
72
|
+
level: 'enable-disable-rule'
|
|
73
|
+
name: string
|
|
74
|
+
ruleArn: Input<string>
|
|
75
|
+
}
|
package/src/iam/index.ts
ADDED
package/src/index.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {auth0} from './auth0'
|
|
2
|
+
import {domain} from './domain'
|
|
3
|
+
import {iam} from './iam'
|
|
4
|
+
import {rest} from './rest'
|
|
5
|
+
import {lambda} from './lambda'
|
|
6
|
+
import {mongodb} from './mongodb'
|
|
7
|
+
import {s3} from './s3'
|
|
8
|
+
import {website} from './website'
|
|
9
|
+
import {websocket} from './websocket'
|
|
10
|
+
|
|
11
|
+
export * from './auth0'
|
|
12
|
+
export * from './domain'
|
|
13
|
+
export * from './iam'
|
|
14
|
+
export * from './lambda'
|
|
15
|
+
export * from './mongodb'
|
|
16
|
+
export * from './rest'
|
|
17
|
+
export * from './s3'
|
|
18
|
+
export * from './website'
|
|
19
|
+
export * from './websocket'
|
|
20
|
+
|
|
21
|
+
export const mstuercke = {
|
|
22
|
+
auth0,
|
|
23
|
+
domain,
|
|
24
|
+
iam,
|
|
25
|
+
lambda,
|
|
26
|
+
mongodb,
|
|
27
|
+
rest,
|
|
28
|
+
s3,
|
|
29
|
+
website,
|
|
30
|
+
websocket,
|
|
31
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import {iam, lambda} from '@pulumi/aws'
|
|
2
|
+
import {getFile} from '@pulumi/archive'
|
|
3
|
+
import {asset, type CustomResourceOptions, type Output, Resource} from '@pulumi/pulumi'
|
|
4
|
+
|
|
5
|
+
import type {SimpleIamRolePolicyConfig} from '../iam'
|
|
6
|
+
import type {WithInputs} from './WithInputs'
|
|
7
|
+
import {mstuercke} from '../index'
|
|
8
|
+
|
|
9
|
+
export type NodeLambdaFunctionArgs<EnvironmentVariables> = {
|
|
10
|
+
name: string
|
|
11
|
+
runtime?: string
|
|
12
|
+
functionHandler?: string
|
|
13
|
+
memorySize?: number
|
|
14
|
+
timeoutSeconds?: number
|
|
15
|
+
lambdaPath: string
|
|
16
|
+
additionalIamRolePolicies?: SimpleIamRolePolicyConfig[]
|
|
17
|
+
environmentVariables?: WithInputs<EnvironmentVariables>
|
|
18
|
+
projectId: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class NodeLambdaFunction<
|
|
22
|
+
EnvironmentVariables extends Record<string, string> = Record<string, string>,
|
|
23
|
+
> extends Resource {
|
|
24
|
+
name: string
|
|
25
|
+
arn: Output<string>
|
|
26
|
+
invokeArn: Output<string>
|
|
27
|
+
|
|
28
|
+
constructor(args: NodeLambdaFunctionArgs<EnvironmentVariables>, opts?: CustomResourceOptions) {
|
|
29
|
+
super('mstuercke:lambda:NodeLambdaFunction', args.name, false, undefined, opts)
|
|
30
|
+
const {
|
|
31
|
+
name,
|
|
32
|
+
additionalIamRolePolicies = [],
|
|
33
|
+
environmentVariables = undefined,
|
|
34
|
+
runtime = 'nodejs20.x',
|
|
35
|
+
functionHandler = 'lambdaFunction.lambdaHandler',
|
|
36
|
+
memorySize = 128,
|
|
37
|
+
timeoutSeconds = 30,
|
|
38
|
+
projectId,
|
|
39
|
+
} = args
|
|
40
|
+
|
|
41
|
+
const role = new iam.Role(
|
|
42
|
+
name,
|
|
43
|
+
{
|
|
44
|
+
name: `${name}-lambda`,
|
|
45
|
+
assumeRolePolicy: JSON.stringify({
|
|
46
|
+
Version: '2012-10-17',
|
|
47
|
+
Statement: [
|
|
48
|
+
{
|
|
49
|
+
Action: 'sts:AssumeRole',
|
|
50
|
+
Principal: {Service: 'lambda.amazonaws.com'},
|
|
51
|
+
Effect: 'Allow',
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
}),
|
|
55
|
+
tags: {
|
|
56
|
+
project: projectId,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
{parent: this},
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
role.id.apply((roleId) => {
|
|
63
|
+
new mstuercke.iam.SimpleIamRolePolicy(
|
|
64
|
+
roleId,
|
|
65
|
+
{
|
|
66
|
+
type: 'custom',
|
|
67
|
+
name: 'logging',
|
|
68
|
+
statements: [
|
|
69
|
+
{
|
|
70
|
+
Effect: 'Allow',
|
|
71
|
+
Action: ['logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents'],
|
|
72
|
+
Resource: '*',
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
{parent: this},
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
for (const config of additionalIamRolePolicies) {
|
|
80
|
+
new mstuercke.iam.SimpleIamRolePolicy(roleId, config, {parent: this})
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
const lambdaZip = getFile({
|
|
85
|
+
type: 'zip',
|
|
86
|
+
sourceDir: args.lambdaPath,
|
|
87
|
+
outputPath: `dist/lambda/${name}.zip`,
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
const lambdaFunction = new lambda.Function(
|
|
91
|
+
name,
|
|
92
|
+
{
|
|
93
|
+
name: name,
|
|
94
|
+
handler: functionHandler,
|
|
95
|
+
runtime: runtime,
|
|
96
|
+
memorySize: memorySize,
|
|
97
|
+
timeout: timeoutSeconds,
|
|
98
|
+
|
|
99
|
+
code: new asset.FileArchive(lambdaZip.then((lambdaZip) => lambdaZip.outputPath)),
|
|
100
|
+
sourceCodeHash: lambdaZip.then((lambdaZip) => lambdaZip.outputBase64sha256),
|
|
101
|
+
|
|
102
|
+
role: role.arn,
|
|
103
|
+
|
|
104
|
+
environment: {
|
|
105
|
+
variables: {
|
|
106
|
+
...environmentVariables,
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
tags: {
|
|
110
|
+
project: projectId,
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
{parent: this},
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
this.name = name
|
|
117
|
+
this.arn = lambdaFunction.arn
|
|
118
|
+
this.invokeArn = lambdaFunction.invokeArn
|
|
119
|
+
}
|
|
120
|
+
}
|