Skip to content

Commit a3e916e

Browse files
committed
docs: readme
1 parent 0d5f940 commit a3e916e

File tree

2 files changed

+101
-69
lines changed

2 files changed

+101
-69
lines changed

README.md

Lines changed: 101 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,50 @@
11
# Tailscale Lambda Extension Proxy
22

3-
[![npm version](https://badge.fury.io/js/tailscale-lambda-proxy.svg)](https://badge.fury.io/js/tailscale-lambda-proxy)
3+
[![npm version](https://badge.fury.io/js/tailscale-lambda-proxy.svg)](https://badge.fury.io/js/tailscale-lambda-proxy)
44
[![PyPI version](https://badge.fury.io/py/tailscale-lambda-proxy.svg)](https://badge.fury.io/py/tailscale-lambda-proxy)
55

6-
A CDK construct that creates an AWS Lambda Function that acts as a proxy to your Tailscale network.
6+
A CDK construct that creates an AWS Lambda Function acting as a transparent proxy to your Tailscale network.
77

8-
Available in CDK as a TypeScript NPM Package and Python PyPi Package:
8+
Available as both a TypeScript NPM Package and a Python PyPi Package:
99
- [TypeScript NPM Package](https://www.npmjs.com/package/tailscale-lambda-proxy)
1010
- [Python PyPi Package](https://pypi.org/project/tailscale-lambda-proxy/)
1111

12-
## Why use a proxy?
12+
## Why use a proxy?
1313

14-
The Proxy Lambda uses the [Tailscale Lambda Extension](https://github.com/rehanvdm/tailscale-lambda-extension) CDK
15-
construct.
14+
The Proxy Lambda leverages the [Tailscale Lambda Extension](https://github.com/rehanvdm/tailscale-lambda-extension) CDK
15+
construct.
1616

1717
It is recommended to use the Proxy Lambda to simplify connecting to your Tailscale network and reduces cold starts
1818
by reusing the same Lambda function for all your Tailscale connected traffic.
1919

2020
Use the extension directly if:
21-
- You only have **a single Lambda**/service that needs to connect to your Tailscale network.
22-
- You are okay with accepting that this Lambda will have mixed responsibilities (i.e. connecting to Tailscale and your
23-
business logic).
24-
25-
Use the Proxy Lambda (recommended) construct if:
26-
- You have **multiple Lambdas**/services that need to connect to your Tailscale network. The proxy Lambda will
27-
effectively create a "pool" of warm connections to your Tailscale network, ready to be used by any other Lambda
28-
that calls it.
29-
- You want to separate concerns and have a dedicated Lambda function that only connects to your Tailscale network.
30-
- Authentication to your Tailscale network (through the proxy) is then moved to an IAM level. Access is granted to
31-
the Proxy Lambda Function URL (FURL), and not to the Tailscale API Secret Manager directly.
21+
- You have **a single Lambda** or service that needs to connect to your Tailscale network.
22+
- You are comfortable with this Lambda having mixed responsibilities, such as connecting to Tailscale and running
23+
business logic.
24+
25+
Use the Proxy Lambda (recommended) if:
26+
- You have **multiple Lambdas** or services requiring connection to your Tailscale network. The Proxy Lambda *eventually*
27+
creates a "pool of warm connections" to the Tailscale network, ready for use by other Lambdas.
28+
- You want to separate responsibilities by having a dedicated Lambda for Tailscale connectivity.
29+
- Authentication to the Tailscale network is handled at the IAM level, where access is granted to the Proxy Lambda's
30+
Function URL (FURL), instead of directly to the Tailscale API Secret Manager.
3231

3332
## Usage
3433

3534
> [!TIP]
36-
> See the complete example in the [tailscale-lambda-proxy-example](https://github.com/rehanvdm/tailscale-lambda-proxy-example)
37-
> repository.
35+
> Refer to the [tailscale-lambda-proxy-example](https://github.com/rehanvdm/tailscale-lambda-proxy-example) repository
36+
> for a complete example.
37+
38+
### Installation
3839

39-
Install the package:
40+
Install the package:
4041
```bash
4142
npm install tailscale-lambda-proxy
4243
```
4344

44-
The Lambda Proxy requires the following:
45-
- `tsSecretApiKey` - The AWS Secrets Manager secret that contains the pure text Tailscale API Key.
46-
- `tsHostname` - The "Machine" name as shown in the Tailscale admin console that identifies this Lambda(s) function.
45+
The Proxy Lambda requires the following:
46+
- `tsSecretApiKey`: The AWS Secrets Manager secret containing the Tailscale API Key as plain text.
47+
- `tsHostname`: The "Machine" name as shown in the Tailscale admin console, which identifies the Lambda function(s).
4748

4849
```typescript
4950
import * as cdk from 'aws-cdk-lib';
@@ -90,70 +91,101 @@ export class MyStack extends cdk.Stack {
9091

9192
## Accessing your Tailscale Network through the Proxy
9293

93-
The code below can be found in the
94-
[tailscale-lambda-proxy-example](https://github.com/rehanvdm/tailscale-lambda-proxy-example) repository.
94+
The [tailscale-lambda-proxy-example](https://github.com/rehanvdm/tailscale-lambda-proxy-example) repository contains
95+
the following example.
9596

96-
**The Tailscale Lambda Proxy is transparent**. It does not modify the request or response that is sent to the machine in
97-
any way. It simply forwards the request (path, method, headers, and body) to the machine and returns the response.
97+
The Tailscale Lambda Proxy is fully transparent. It forwards requests (path, method, headers, and body) to the machine
98+
and returns the response without modification.
9899

99-
There are 2 important components when interacting with the Tailscale Lambda Proxy:
100+
Key considerations when using the Proxy:
100101
1. All requests must be signed with the IAM Signature V4 algorithm.
101-
2. The IP address and port of your Tailscale connected machine/device should be placed in the
102-
headers when making the call to the proxy.
103-
104-
### Signing Requests
102+
2. The target machine's IP address and port must be included in the headers when making requests to the Proxy.
105103

106-
The Lambda Proxy exposes a Function URL secured with IAM Authentication. The caller Lambda only needs this URL and IAM
107-
permissions to call it. Then it needs to sign all requests with the IAM Signature V4 algorithm. For Typescript users,
108-
you can use the [aws4](https://www.npmjs.com/package/aws4) package to sign requests.
104+
#### Signing Requests
109105

110-
### Including the correct headers
106+
The Proxy Lambda exposes a Function URL secured with IAM Authentication. The caller Lambda requires this URL and
107+
IAM permissions to make requests. These requests must be signed with the IAM Signature V4 algorithm. For TypeScript,
108+
use the [aws4](https://www.npmjs.com/package/aws4) package to sign requests.
111109

112-
When making a request to the Proxy, you need to include the IP address and port of the Tailscale connected machine/device
113-
that you are targeting in the headers.
110+
#### Including Target Headers
114111

115-
The `ts-` headers below will be removed before forwarding the request to the Tailscale machine/device, they are only
116-
used for routing and internal logic to the proxy.
112+
When calling the Proxy, include the following headers to specify the target machine:
113+
- `ts-target-ip`: The IP address of the Tailscale-connected machine/device.
114+
- `ts-target-port`: The port of the Tailscale-connected machine/device.
117115

118-
- `ts-target-ip` - The IP address of the Tailscale connected machine/device.
119-
- `ts-target-port` - The port of the Tailscale connected machine/device.
116+
These `ts-` headers are removed before the request is forwarded to the target machine.
120117

121-
### Create CloudWatch Tracking Metrics
118+
### Creating CloudWatch Tracking Metrics
122119

123-
These metrics are optional and are used to track the success and failure of requests made through the proxy.
124-
125-
To enable the optional tracking metrics, you can include the following headers as well:
126-
- `ts-metric-service` - The name of the service or API making the request.
127-
- `ts-metric-dimension-name` - The name of the dimension to track (e.g., client name).
128-
- `ts-metric-dimension-value` - The value associated with the dimension.
120+
To enable optional tracking metrics, add the following headers to your request:
121+
- `ts-metric-service`: The name of the service or API making the request.
122+
- `ts-metric-dimension-name`: The dimension name for tracking (such as client name).
123+
- `ts-metric-dimension-value`: The value associated with the dimension.
129124

130-
For each request, one of the following CloudWatch metrics is created:
131-
- `success`: Recorded when the request is successfully delivered to the target server. Note that this does not depend on
132-
the HTTP status code of the API response.
133-
- `failure`: Recorded when the request fails to reach the target server. Possible reasons include network issues or the
134-
target server being unavailable.
125+
Metrics generated in CloudWatch:
126+
- `success`: Logged when a request reaches the target server, regardless of the API response status.
127+
- `failure`: Logged when a request fails to reach the target server, typically due to network issues or server
128+
unavailability.
135129

136-
Here is an example of headers for a request:
137-
- `ts-metric-service`: `gallagher` the name of the calling service or API being targeted.
138-
- `ts-metric-dimension-name`: `client` tracks the client name to be used for monitoring or alerts.
139-
- `ts-metric-dimension-value`: `rehan-test-client` the specific client name.
130+
Example headers for a request:
131+
- `ts-metric-service`: `gallagher`, indicating the service or API making the request.
132+
- `ts-metric-dimension-name`: `client`, used for monitoring or alerts.
133+
- `ts-metric-dimension-value`: `rehan-test-client`, identifying the specific client.
140134

141-
This setup generates a CloudWatch metric similar to the one below:
135+
This configuration generates CloudWatch metrics similar to the screenshot below:
142136
![tailscale-cloudwatch-metric.png](_imgs/tailscale-cloudwatch-metric.png)
143137

144138
### Error Handling
145139

146-
In efforts to keep the Proxy Lambda transparent, all traffic, including errors are passed back to the caller. This makes
147-
it difficult to determine if the error was due to the Proxy Lambda or if it originated from the Tailscale connected
148-
machine/device.
140+
To maintain transparency, the Proxy Lambda passes all traffic, including errors, back to the caller. This approach
141+
makes it difficult to determine whether an error originated from the Proxy Lambda or the Tailscale-connected machine.
142+
143+
A Proxy Lambda error can be identified by the following headers in the response:
144+
- `ts-error-name`: The error name.
145+
- `ts-error-message`: The error message.
146+
147+
### Code Examples
148+
149+
Refer to the [tailscale-lambda-proxy-example](https://github.com/rehanvdm/tailscale-lambda-proxy-example) repository
150+
for the complete example. The partial snippet below shows a Lambda function accessing an express server running
151+
on a Tailscale-connected machine. The [TailscaleProxyApi](https://github.com/rehanvdm/tailscale-lambda-proxy-example/blob/f5e95c9b2294bd185bbe5b372a24dafcafc17297/lib/lambda/tailscale-caller/tailscale-proxy-api.ts)
152+
class implements the above-mentioned usage specifications.
153+
154+
```typescript
155+
import {TailscaleProxyApi} from "./tailscale-proxy-api";
156+
157+
export const handler = async (event: any) => {
158+
console.log(JSON.stringify(event, null, 2));
149159

150-
A Lambda Proxy error can be identified by the presence of the following response headers:
151-
- `ts-error-name` - The name of the error.
152-
- `ts-error-message` - The error message.
160+
// Connect to the tailscale network with your laptop, get your tailscale IP, then start the express server in
161+
// `express-local-api` with `npm run start` and then run the lambda function to test the connection.
162+
const targetIp = "100.91.164.93";
163+
const targetPort = 3000;
164+
165+
const api = new TailscaleProxyApi(process.env.TS_PROXY_URL!, process.env.AWS_REGION!,
166+
targetIp, targetPort,
167+
"express-local-api", "client", "client-a"
168+
);
169+
170+
const resp = await api.request("/ping", "GET");
171+
172+
if(resp.proxyError) {
173+
throw new Error(`PROXY ERROR: ${resp.proxyError}`);
174+
}
175+
else if(resp.response.statusCode !== 200) {
176+
throw new Error(`API ERROR: ${resp.response.statusCode} with body: ${resp.response.body}`);
177+
}
178+
179+
console.log('');
180+
console.log('API SUCCESS: ', resp.response.body);
181+
182+
return true;
183+
};
184+
```
153185

154186
## Additional Information
155187

156-
See the [Tailscale Lambda Extension](https://github.com/rehanvdm/tailscale-lambda-extension) for more information on:
157-
- How to configure Tailscale
158-
- Limitations like cold start times, package sizes and the lack of DNS resolution.
159-
- Implementation Details
188+
Refer to the [Tailscale Lambda Extension](https://github.com/rehanvdm/tailscale-lambda-extension) documentation for:
189+
- Configuring Tailscale.
190+
- Understanding limitations such as cold start times, package sizes, and the lack of DNS resolution.
191+
- Additional implementation details.
76.9 KB
Loading

0 commit comments

Comments
 (0)