Skip to content

Commit 22ed274

Browse files
authored
pulumi/aws: update dependencies and runtime to nodejs24 (#53)
1 parent a95fae5 commit 22ed274

10 files changed

Lines changed: 2296 additions & 4397 deletions

File tree

‎.gitignore‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
**/.claude
2+
13
# Terraform-related files
24
*.tfstate
35
*.tfstate.*

‎pulumi/aws/aws-lambda-device-approval-handler/README.md‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,20 @@ This example creates the following:
44

55
- a API Gateway REST API
66
- a Lambda function to receive [Tailscale webhooks](https://tailscale.com/kb/1213/webhooks) and approve devices based on device details and attributes
7+
- a Tailscale [webhook](https://tailscale.com/kb/1213/webhooks) that sends `nodeNeedsApproval` events to the deployed Lambda's API Gateway URL
78

89
## To use
910

11+
### Configure
12+
1013
Follow the documentation to configure the Pulumi providers:
1114

1215
- [AWS](https://www.pulumi.com/registry/packages/aws/installation-configuration/)
16+
- [Tailscale](https://www.pulumi.com/registry/packages/tailscale/installation-configuration/) — set the `TAILSCALE_OAUTH_CLIENT_ID` / `TAILSCALE_OAUTH_CLIENT_SECRET` environment variables before you run `pulumi up`. Pulumi uses these to authenticate the Tailscale provider that manages the webhook.
1317

1418
### Deploy
1519

16-
Create a [Tailscale OAuth Client](https://tailscale.com/kb/1215/oauth-clients#setting-up-an-oauth-client) with scope `all` and provide the client ID and client secret with `pulumi config set ...` as shown below.
20+
Create a [Tailscale OAuth Client](https://tailscale.com/kb/1215/oauth-clients#setting-up-an-oauth-client) with scope `all`. Set the client ID and client secret for the Lambda function with `pulumi config set ...` as shown below. Also export them as the `TAILSCALE_OAUTH_CLIENT_ID` / `TAILSCALE_OAUTH_CLIENT_SECRET` environment variables, for the Tailscale provider.
1721

1822
```shell
1923
pulumi stack init
@@ -22,6 +26,16 @@ pulumi config set tailscaleOauthClientSecret --secret
2226
pulumi up
2327
```
2428

29+
`pulumi up` creates the Lambda function and API Gateway, then registers the Tailscale webhook that points at the API Gateway URL.
30+
31+
### Outputs
32+
33+
| Output | Description |
34+
| --- | --- |
35+
| `url` | The API Gateway invoke URL. This is also the endpoint the Tailscale webhook is configured to call. |
36+
| `lambdaFunctionName` | The name of the deployed Lambda function, for finding it in the AWS console or `aws logs`. |
37+
| `webhookSecret` | The secret Tailscale generates when the webhook is created, for verifying the `Tailscale-Webhook-Signature` header as described in [Verifying an event signature](https://tailscale.com/kb/1213/webhooks#verifying-an-event-signature) (see the `TODO` in [`handler.ts`](./handler.ts)). This output is marked secret, so use `pulumi stack output webhookSecret --show-secrets` to view it. |
38+
2539
## To destroy
2640

2741
```shell
Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,48 @@
11
import * as pulumi from "@pulumi/pulumi";
22
import * as aws from "@pulumi/aws";
33
import * as apigateway from "@pulumi/aws-apigateway";
4+
import * as tailscale from "@pulumi/tailscale";
45
import * as path from "path";
56

67
import * as handler from "./handler";
78

89
const name = `example-${path.basename(process.cwd())}`;
910
const pulumiConfig = new pulumi.Config();
11+
const tailscaleOauthClientId = pulumiConfig.require("tailscaleOauthClientId");
12+
const tailscaleOauthClientSecret = pulumiConfig.requireSecret("tailscaleOauthClientSecret");
13+
14+
const fn = new aws.lambda.CallbackFunction(`${name}-fn`, {
15+
environment: {
16+
variables: {
17+
[handler.ENV_TAILSCALE_OAUTH_CLIENT_ID]: tailscaleOauthClientId,
18+
[handler.ENV_TAILSCALE_OAUTH_CLIENT_SECRET]: tailscaleOauthClientSecret,
19+
},
20+
},
21+
runtime: "nodejs24.x",
22+
callback: async (ev: any, ctx) => {
23+
return handler.lambdaHandler(ev);
24+
},
25+
});
1026

1127
const api = new apigateway.RestAPI(name, {
12-
stageName: "tailscale-device-approval",
28+
stageName: `${name}`,
1329
binaryMediaTypes: ["application/json"],
1430
routes: [
1531
{
1632
path: "/",
1733
method: "POST",
18-
eventHandler: new aws.lambda.CallbackFunction(`${name}-fn`, {
19-
environment: {
20-
variables: {
21-
[handler.ENV_TAILSCALE_OAUTH_CLIENT_ID]: pulumiConfig.require("tailscaleOauthClientId"),
22-
[handler.ENV_TAILSCALE_OAUTH_CLIENT_SECRET]: pulumiConfig.requireSecret("tailscaleOauthClientSecret"),
23-
},
24-
},
25-
runtime: "nodejs20.x",
26-
callback: async (ev: any, ctx) => {
27-
return handler.lambdaHandler(ev);
28-
},
29-
}),
34+
eventHandler: fn,
3035
},
3136
],
3237
});
3338

3439
export const url = api.url;
40+
export const lambdaFunctionName = fn.name;
41+
42+
const webhook = new tailscale.Webhook(`${name}-webhook`, {
43+
endpointUrl: api.url,
44+
subscriptions: ["nodeNeedsApproval"],
45+
});
46+
47+
// Only set at creation. Store it if you plan to verify webhook signatures in the handler.
48+
export const webhookSecret = pulumi.secret(webhook.secret);

0 commit comments

Comments
 (0)