Last active
May 3, 2024 12:39
-
-
Save razor-x/44c1c572a8c9e4cb723b1945a4d75bdb to your computer and use it in GitHub Desktop.
Sentry.io CloudFront Lambda@Edge tunnel
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# TODO: Setup https://github.com/silvermine/serverless-plugin-cloudfront-lambda-edge | |
sentryOriginReq: | |
handler: handlers/handler.default | |
lambdaAtEdge: | |
distribution: AppDistribution | |
eventType: origin-request | |
includeBody: true | |
pathPattern: /_tunnel # TODO: Choose tunnel path. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const options = { | |
sentryDsn: 'https://public_key@public_host.ingest.sentry.io/project_id' // TODO: Set DSN. | |
} | |
module.exports.default = (event, context, callback) => { | |
const request = event.Records[0].cf.request | |
if (!willHandleSentryRequest(request, options)) { | |
return callback(null, { | |
status: 404, | |
statusDescription: 'Not Found', | |
}) | |
} | |
const { body } = request | |
if (body.inputTruncated) { | |
return callback(null, { | |
status: 413, | |
statusDescription: 'Payload Too Large and truncated by CloudFront', | |
}) | |
} | |
const envelope = | |
body.encoding === 'base64' | |
? Buffer.from(body.data, 'base64').toString('utf-8') | |
: body.data | |
const { host, projectId } = parseEnvelope(envelope) | |
const { host: allowedHost, projectId: allowedProjectId } = parseDsn( | |
options.sentryDsn | |
) | |
if (projectId !== allowedProjectId) { | |
return callback(null, { | |
status: 403, | |
statusDescription: `Forbidden Sentry project id: ${projectId}`, | |
}) | |
} | |
if (host !== allowedHost) { | |
return callback(null, { | |
status: 403, | |
statusDescription: `Forbidden Sentry host: ${host}`, | |
}) | |
} | |
request.uri = `/api/${projectId}/envelope/` | |
callback(null, request) | |
} | |
const willHandleSentryRequest = (request, options) => { | |
if (!options.sentryDsn) return false | |
if (request.method === 'POST') return false | |
return true | |
} | |
const parseDsn = (dsn) => { | |
const url = new URL(dsn) | |
const path = url.pathname | |
const host = url.hostname | |
const projectId = path.split('/')[1] | |
return { host, projectId } | |
} | |
const parseEnvelope = (envelope) => { | |
const [headerJson] = envelope.split('\n') | |
const header = JSON.parse(headerJson) | |
const { host, projectId } = parseDsn(header.dsn) | |
return { host, projectId } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"Records": [ | |
{ | |
"cf": { | |
"config": { | |
"distributionDomainName": "d111111abcdef8.cloudfront.net", | |
"distributionId": "EDFDVBD6EXAMPLE", | |
"eventType": "origin-request", | |
"requestId": "4TyzHTaYWb1GX1qTfsHhEqV6HUDd_BzoBZnwfnvQc_1oF26ClkoUSEQ==" | |
}, | |
"request": { | |
"clientIp": "203.0.113.178", | |
"headers": { | |
"x-forwarded-for": [ | |
{ | |
"key": "X-Forwarded-For", | |
"value": "203.0.113.178" | |
} | |
], | |
"user-agent": [ | |
{ | |
"key": "User-Agent", | |
"value": "Amazon CloudFront" | |
} | |
], | |
"via": [ | |
{ | |
"key": "Via", | |
"value": "2.0 2afae0d44e2540f472c0635ab62c232b.cloudfront.net (CloudFront)" | |
} | |
], | |
"host": [ | |
{ | |
"key": "Host", | |
"value": "example.org" | |
} | |
], | |
"cache-control": [ | |
{ | |
"key": "Cache-Control", | |
"value": "no-cache, cf-no-cache" | |
} | |
] | |
}, | |
"method": "GET", | |
"body": { | |
"data": "eyJkc24iOiJodHRwczovL3B1YmxpY19rZXlAcHVibGljX2hvc3QuaW5nZXN0LnNlbnRyeS5pby9wcm9qZWN0X2lkIn0Ke30Ke30=", | |
"inputTruncated": false, | |
"encoding": "base64" | |
}, | |
"origin": { | |
"custom": { | |
"customHeaders": {}, | |
"domainName": "example.org", | |
"keepaliveTimeout": 5, | |
"path": "", | |
"port": 443, | |
"protocol": "https", | |
"readTimeout": 30, | |
"sslProtocols": ["TLSv1", "TLSv1.1", "TLSv1.2"] | |
} | |
}, | |
"querystring": "", | |
"uri": "/_tunnel" | |
} | |
} | |
} | |
] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
AppDistribution: | |
Type: AWS::CloudFront::Distribution | |
Properties: | |
DistributionConfig: | |
# TODO: Put in the rest of your CloudFront config. | |
CacheBehaviors: | |
- TargetOriginId: SentryOrigin | |
PathPattern: /_tunnel # TODO: Choose tunnel path. | |
ViewerProtocolPolicy: redirect-to-https | |
AllowedMethods: | |
- DELETE | |
- GET | |
- HEAD | |
- OPTIONS | |
- PATCH | |
- POST | |
- PUT | |
CachedMethods: | |
- GET | |
- HEAD | |
ForwardedValues: | |
QueryString: false | |
Cookies: | |
Forward: 'none' | |
Headers: | |
- Origin | |
Origins: | |
- Id: SentryOrigin | |
DomainName: project_id.sentry.io # TODO: Set project id. | |
CustomOriginConfig: | |
OriginProtocolPolicy: https-only | |
OriginSSLProtocols: | |
- TLSv1.2 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment