Skip to content

Commit

Permalink
pulumi: add aws-lambda-device-lookup-table (#28)
Browse files Browse the repository at this point in the history
* pulumi: add aws-lambda-device-lookup-table

* pulumi: update aws-lambda-device-lookup-table

replicates similar changes from aws-lambda-device-lookup-table
  • Loading branch information
clstokes authored Oct 18, 2024
1 parent bfdaefc commit 63fd22c
Show file tree
Hide file tree
Showing 14 changed files with 4,058 additions and 242 deletions.
2 changes: 1 addition & 1 deletion pulumi/aws/aws-lambda-device-approval-handler/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This example creates the following:

## To use

Follow the documentation to configure the Terraform providers:
Follow the documentation to configure the Pulumi providers:

- [AWS](https://www.pulumi.com/registry/packages/aws/installation-configuration/)

Expand Down
25 changes: 12 additions & 13 deletions pulumi/aws/aws-lambda-device-approval-handler/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import { APIGatewayProxyEvent, APIGatewayProxyResult } from "aws-lambda";

export async function lambdaHandler(ev: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> {
// TODO: https://tailscale.com/kb/1213/webhooks#verifying-an-event-signature
// console.log(`Received event: ${JSON.stringify(ev)}`); // TODO: add verbose logging flag?
// console.log(`Received event: ${JSON.stringify(ev)}`);

let processedCount = 0;
let ignoredCount = 0;
let erroredCount = 0;
try {
let decodedBody = ev.body;
if (ev.isBase64Encoded) {
decodedBody = Buffer.from(ev.body!, 'base64').toString('utf8');
decodedBody = Buffer.from(ev.body!, "base64").toString("utf8");
}
const tailnetEvents: TailnetEvent[] = JSON.parse(decodedBody!);
const results: ProcessingResult[] = [];
Expand Down Expand Up @@ -56,7 +56,6 @@ function generateResponseBody(statusCode: number, ev: APIGatewayProxyEvent, proc
statusCode: statusCode,
body: JSON.stringify({
message: (statusCode == 200 ? "ok" : "An error occurred."),
// requestId: ev.requestContext.requestId, // TODO: This requestId doesn't match what's in the lambda logs.
eventResults: {
processed: processedCount,
errored: erroredCount,
Expand Down Expand Up @@ -103,11 +102,11 @@ async function nodeNeedsApprovalHandler(event: TailnetEvent): Promise<Processing
["windows", "macos", "linux"].includes(attributesResponseJson["attributes"]["node:os"])
&& attributesResponseJson["attributes"]["node:tsReleaseTrack"] == "stable"
) {
// approve device
await approveDevice(eventData);
// authorize device
await authorizeDevice(eventData);
}
else {
console.log(`NOT approving device [${eventData.nodeID}:${eventData.deviceName}] with attributes [${JSON.stringify(attributesResponseJson)}]`);
console.log(`NOT authorizing device [${eventData.nodeID}:${eventData.deviceName}] with attributes [${JSON.stringify(attributesResponseJson)}]`);
}

return { event: event, result: "SUCCESS", } as ProcessingResult;
Expand All @@ -120,7 +119,7 @@ export const ENV_TAILSCALE_OAUTH_CLIENT_ID = "OAUTH_CLIENT_ID";
export const ENV_TAILSCALE_OAUTH_CLIENT_SECRET = "OAUTH_CLIENT_SECRET";
const TAILSCALE_CONTROL_URL = "https://login.tailscale.com";

// https://github.com/tailscale/tailscale/blob/main/publicapi/device.md#get-device-posture-attributes
// https://tailscale.com/api#tag/devices/GET/device/{deviceId}/attributes
async function getDeviceAttributes(event: TailnetEventDeviceData): Promise<Response> {
console.log(`Getting device attributes [${event.nodeID}]`);
const data = await makeAuthenticatedRequest("GET", `${TAILSCALE_CONTROL_URL}/api/v2/device/${event.nodeID}/attributes`);
Expand All @@ -130,7 +129,7 @@ async function getDeviceAttributes(event: TailnetEventDeviceData): Promise<Respo
return data;
}

// https://github.com/tailscale/tailscale/blob/main/publicapi/device.md#get-device
// https://tailscale.com/api#tag/devices/GET/device/{deviceId}
async function getDevice(event: TailnetEventDeviceData): Promise<Response> {
console.log(`Getting device [${event.nodeID}]`);
const data = await makeAuthenticatedRequest("GET", `${TAILSCALE_CONTROL_URL}/api/v2/device/${event.nodeID}`);
Expand All @@ -140,12 +139,12 @@ async function getDevice(event: TailnetEventDeviceData): Promise<Response> {
return data;
}

// https://github.com/tailscale/tailscale/blob/main/publicapi/device.md#authorize-device
async function approveDevice(device: TailnetEventDeviceData) {
console.log(`Approving device [${device.nodeID}:${device.deviceName}]`);
// https://tailscale.com/api#tag/devices/POST/device/{deviceId}/authorized
async function authorizeDevice(device: TailnetEventDeviceData) {
console.log(`Authorizing device [${device.nodeID}:${device.deviceName}]`);
const data = await makeAuthenticatedRequest("POST", `${TAILSCALE_CONTROL_URL}/api/v2/device/${device.nodeID}/authorized`, JSON.stringify({ "authorized": true }));
if (!data.ok) {
throw new Error(`Failed to approve device [${device.nodeID}:${device.deviceName}]`);
throw new Error(`Failed to authorize device [${device.nodeID}:${device.deviceName}]`);
}
}

Expand Down Expand Up @@ -185,7 +184,7 @@ const makeAuthenticatedRequest = async function (method: "GET" | "POST", url: st
}

async function httpsRequest(url: string, options: any): Promise<Response> {
// console.log(`Making HTTP request to [${url}] with options [${JSON.stringify(options)}]`); // TODO: add verbose logging flag?
// console.log(`Making HTTP request to [${url}] with options [${JSON.stringify(options)}]`);
return await fetch(url, options);
}

Expand Down
21 changes: 0 additions & 21 deletions pulumi/aws/aws-lambda-device-approval-handler/handlerPulumi.ts

This file was deleted.

21 changes: 18 additions & 3 deletions pulumi/aws/aws-lambda-device-approval-handler/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as apigateway from "@pulumi/aws-apigateway";
import * as path from 'path';
import * as handler from "./handlerPulumi";
import * as path from "path";

import * as handler from "./handler";

const name = `example-${path.basename(process.cwd())}`;
const pulumiConfig = new pulumi.Config();

const api = new apigateway.RestAPI(name, {
stageName: "tailscale-device-approval",
Expand All @@ -11,7 +15,18 @@ const api = new apigateway.RestAPI(name, {
{
path: "/",
method: "POST",
eventHandler: handler.getPulumiHandler(`${name}-fn`),
eventHandler: new aws.lambda.CallbackFunction(`${name}-fn`, {
environment: {
variables: {
[handler.ENV_TAILSCALE_OAUTH_CLIENT_ID]: pulumiConfig.require("tailscaleOauthClientId"),
[handler.ENV_TAILSCALE_OAUTH_CLIENT_SECRET]: pulumiConfig.requireSecret("tailscaleOauthClientSecret"),
},
},
runtime: "nodejs20.x",
callback: async (ev: any, ctx) => {
return handler.lambdaHandler(ev);
},
}),
},
],
});
Expand Down
Loading

0 comments on commit 63fd22c

Please sign in to comment.