Skip to content

Commit

Permalink
feat: support wildcards and improve error response logging (#158)
Browse files Browse the repository at this point in the history
* improve logging

* add wildcard matching support

* update README.md
  • Loading branch information
danadajian authored Feb 23, 2024
1 parent 835e84f commit b859e5c
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 8 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ aws s3 cp "${file}" "${s3_destination}/${file}"
```

Optionally, you may create a Lambda layer which optionally contains the following files:
* `allowed-destination-hosts.json`: An array of destination hosts that the proxy can forward to. If omitted, all destinations will be allowed.
* `allowed-destination-hosts.json`: An array of destination hosts that the proxy can forward to. If omitted, all destinations will be allowed. Wildcard matching is supported via [micromatch](https://github.com/micromatch/micromatch)
* `ca.pem`: A root CA certificate for forwarding to internal destinations with self-signed certs
* `cert.pem`: A chain certificate for forwarding to internal destinations with self-signed certs

Expand Down
8 changes: 7 additions & 1 deletion lambda/destination-host-is-allowed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,18 @@ limitations under the License.
*/

import { readFileFromLayer } from './file-readers';
import { isMatch } from 'micromatch';

export function destinationHostIsAllowed(url: string) {
const allowedDestinationHostsContents = readFileFromLayer('allowed-destination-hosts.json');
if (!allowedDestinationHostsContents) {
return true;
}
const allowedDestinationHosts: string[] = JSON.parse(allowedDestinationHostsContents);
return allowedDestinationHosts.includes(new URL(url).host);
const host = new URL(url).host;
const destinationHostIsAllowed = allowedDestinationHosts.includes(host) || isMatch(host, allowedDestinationHosts);
if (!destinationHostIsAllowed) {
console.error(`Destination host ${host} does not match allowlist ${allowedDestinationHosts}`);
}
return destinationHostIsAllowed;
}
15 changes: 14 additions & 1 deletion lambda/proxy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const baseEvent: APIGatewayProxyWithLambdaAuthorizerEvent<any> = {
resource: ''
};
const fileMap: Record<string, string> = {
'allowed-destination-hosts.json': JSON.stringify(['approved.host', 'another.approved.host'])
'allowed-destination-hosts.json': JSON.stringify(['approved.host', 'another.approved.host', 'a.wildcard.*.host'])
};
(readFileFromLayer as jest.Mock).mockImplementation((fileName: string) => fileMap[fileName]);

Expand Down Expand Up @@ -170,6 +170,19 @@ describe('proxy', () => {
expect(axios.post).not.toHaveBeenCalled();
});

it('should forward a request that has an approved host which matches a wildcard', async () => {
const destinationUrl = 'https://a.wildcard.test.host/github-webhook/';
const endpointId = encodeURIComponent(destinationUrl);
const event: APIGatewayProxyWithLambdaAuthorizerEvent<any> = {
...baseEvent,
pathParameters: {
endpointId
}
};
const result = await handler(event);
expect(result).toEqual(expectedResponseObject);
});

it('should forward a request from an enterprise and github org without supplied certs', async () => {
const destinationUrl = 'https://approved.host/github-webhook/';
const endpointId = encodeURIComponent(destinationUrl);
Expand Down
1 change: 1 addition & 0 deletions lambda/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export async function handler(event: APIGatewayProxyWithLambdaAuthorizerEvent<an
const endpointId = pathParameters?.endpointId;

if (!endpointId || !body) {
console.error(`EndpointId or body is missing. endpointId: ${endpointId}, body: ${body}`);
return { statusCode: 404, body: 'Not found' };
}

Expand Down
20 changes: 16 additions & 4 deletions lambda/request-payload-is-valid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,24 @@ export function requestPayloadIsValid({ sender, enterprise }: EnterpriseProxyEve
}

function requestCameFromValidEnterprise(enterprise?: EnterpriseProxyEvent['enterprise']) {
return process.env.ENTERPRISE_SLUG && enterprise?.slug === process.env.ENTERPRISE_SLUG;
const requestCameFromValidEnterprise =
process.env.ENTERPRISE_SLUG && enterprise?.slug === process.env.ENTERPRISE_SLUG;
if (!requestCameFromValidEnterprise) {
console.error(
`ENTERPRISE_SLUG environment variable ${process.env.ENTERPRISE_SLUG} does not equal enterprise slug ${enterprise?.slug}`
);
}
return requestCameFromValidEnterprise;
}

function senderLoginEndsWithUserSuffix(senderLogin?: string) {
return (
const senderLoginEndsWithUserSuffix =
process.env.ENTERPRISE_MANAGED_USER_SUFFIX &&
senderLogin?.endsWith(`_${process.env.ENTERPRISE_MANAGED_USER_SUFFIX}`)
);
senderLogin?.endsWith(`_${process.env.ENTERPRISE_MANAGED_USER_SUFFIX}`);
if (!senderLoginEndsWithUserSuffix) {
console.error(
`Sender login ${senderLogin} does not end with ENTERPRISE_MANAGED_USER_SUFFIX environment variable ${process.env.ENTERPRISE_MANAGED_USER_SUFFIX}`
);
}
return senderLoginEndsWithUserSuffix;
}
6 changes: 5 additions & 1 deletion lambda/url-is-valid.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { urlSchema } from './schema';

export function urlIsValid(url: string) {
return urlSchema.safeParse(url).success;
const urlIsValid = urlSchema.safeParse(url).success;
if (!urlIsValid) {
console.error('Invalid URL:', url);
}
return urlIsValid;
}
16 changes: 16 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@types/aws-lambda": "8.10.107",
"@types/jest": "29.5.12",
"@types/lodash.mapkeys": "4.6.9",
"@types/micromatch": "4.0.6",
"jest": "29.7.0",
"prettier": "3.2.5"
},
Expand Down

0 comments on commit b859e5c

Please sign in to comment.