|
1 | | -# Sample API |
2 | | - |
3 | | -A minimal HTTP API and custom authorizer designed to run as AWS Lambda functions behind API Gateway. |
4 | | -It includes a mock API with scope-based access control, a token authorizer, and an optional mTLS proxy for testing secure client authentication. |
5 | | - |
6 | | ---- |
7 | | - |
8 | | -## Overview |
9 | | - |
10 | | -### Components |
11 | | -- **Authorizer**: validates OAuth2 tokens and supports mTLS-based client certificate checks. |
12 | | -- **Mock API**: exposes simple domain endpoints (`customer`, `energy`) with scope enforcement. |
13 | | -- **mTLS Proxy**: optional TLS termination layer for local or secure deployments. |
14 | | -- **LocalStack setup script**: provisions IAM roles, Lambdas, and API Gateway locally for testing. |
15 | | - |
16 | | ---- |
17 | | - |
18 | | -## Mutual TLS (mTLS) Server |
19 | | - |
20 | | -Located in `/cmd/mtls`, this service: |
21 | | -- Terminates TLS and enforces client certificate authentication. |
22 | | -- Validates certificates against a trusted CA bundle. |
23 | | -- Uses server and client keys stored in SSM (simulated via LocalStack). |
24 | | - |
25 | | ---- |
26 | | - |
27 | | -## Features |
28 | | - |
29 | | -- AWS Lambda–compatible handlers using `aws-lambda-go-api-proxy`. |
30 | | -- Example endpoints: |
31 | | - - `GET /customer/v1/customer` → requires scope: `customer` |
32 | | - - `GET /energy/v1/energy` → requires scope: `energy` |
33 | | - - `GET /health` → liveness check |
34 | | -- Scope-based authorization via: |
35 | | - - Lambda authorizer context (when deployed) |
36 | | - - Bearer token fallback (for local use) |
37 | | -- `x-fapi-interaction-id` header validation (must be UUIDv4). |
38 | | - |
39 | | ---- |
40 | | - |
41 | | -## Requirements |
42 | | - |
43 | | -- Go 1.24+ |
44 | | -- Docker |
45 | | -- LocalStack (for local AWS simulation) |
46 | | -- Optional AWS account for live testing |
47 | | - |
48 | | ---- |
49 | | - |
50 | | -## Environment Variables |
51 | | - |
52 | | -| Variable | Description | |
53 | | -|-----------|-------------| |
54 | | -| `AWS_LOCAL` | Set to `true` when running under LocalStack | |
55 | | -| `REGION` | AWS region (default `us-east-1`) | |
56 | | -| `CLIENT_CERT_HEADER` | Header name for mTLS client cert (e.g. `TLS-Certificate`) | |
57 | | -| `INTROSPECTION_ENDPOINT` | Token introspection URL *(leave blank locally)* | |
58 | | -| `USER_INFO_ENDPOINT` | User info URL *(leave blank locally)* | |
59 | | -| `CLIENT_ID` | OAuth2 client ID *(leave blank locally)* | |
60 | | -| `SSM_TRANSPORT_CERTIFICATE_NAME` | SSM name for server certificate | |
61 | | -| `SSM_TRANSPORT_KEY_NAME` | SSM name for server private key | |
62 | | -| `SSM_CA_TRUSTED_LIST_NAME` | SSM name for CA certificates | |
63 | | - |
64 | | -When using LocalStack, TLS materials are automatically uploaded to SSM under `/sample-api/...`. |
65 | | - |
66 | | ---- |
67 | | - |
68 | | -## Running locally |
69 | | -Option A: Go build/run |
70 | | -- This Lambda-oriented service is designed for API Gateway/Lambda. For local invocation you typically run with a Lambda runtime emulator (e.g., aws-lambda-rie) or SAM CLI. |
71 | | - |
72 | | -Example with AWS SAM (simplified outline): |
73 | | -- Create a SAM template wiring API Gateway → Lambda (runtime: provided.al2, image-based or binary handler). |
74 | | -- Set env vars (AWS_LOCAL, REGION). |
75 | | -- Run: sam local start-api |
76 | | - |
77 | | -Option B: Docker container |
78 | | -- The provided Dockerfile builds a minimal image suitable for local or image-based Lambda deployment. |
79 | | - |
80 | | -Build: |
81 | | -- docker build -t mockapi:local . |
82 | | - |
83 | | -Run against LocalStack: |
84 | | -- docker network create localstack || true |
85 | | -- docker run --rm -p 443:443 |
86 | | - --network localstack |
87 | | - -e AWS_LOCAL=true |
88 | | - -e REGION=eu-west-1 |
89 | | - --name mockapi |
90 | | - mockapi:local |
91 | | - |
92 | | -Notes: |
93 | | -- The container exposes port 443. |
94 | | -- Ensure LocalStack is reachable on the same Docker network as localstack.local:4566. |
95 | | - |
96 | | -## Authorization and scopes |
97 | | -Each protected endpoint requires specific scopes: |
98 | | -- /sample/protected → sample |
99 | | - |
100 | | -How scopes are resolved: |
101 | | -1. When behind API Gateway, the handler reads them from the custom authorizer context (scope as a space-delimited string). |
102 | | -2. Otherwise, it falls back to parsing the Authorization: Bearer token. |
103 | | - |
104 | | -Accepted token formats for local/dev: |
105 | | -- JWT with a space-delimited scope claim in payload. |
106 | | -- A JSON string token that includes one of: |
107 | | - - scope: "s1 s2" |
108 | | - - scopes: ["s1","s2"] |
109 | | - - permissions: ["s1","s2"] |
110 | | - |
111 | | -Examples: |
112 | | -- JWT payload idea (pseudo): { "sub":"123", "scope":"sample" } |
113 | | -- JSON-string token example for sample: {"active":true,"scopes":["sample"]} |
114 | | - |
115 | | -In practice, set an Authorization header like: |
116 | | -- Authorization: Bearer {"active":true,"scopes":["sample"]} |
117 | | - |
118 | | -Responses on failure: |
119 | | -- 401 if Authorization is missing/invalid or introspection-style JSON cannot be parsed |
120 | | -- 403 if token is valid but lacks required scopes |
121 | | - |
122 | | -## x-fapi-interaction-id |
123 | | -- If the client sets x-fapi-interaction-id, it must be a valid UUIDv4; otherwise the request is rejected with 400. |
124 | | -- If missing, the server generates a UUIDv4 and echoes it in the response header. |
125 | | - |
126 | | -## Data persistence |
127 | | -- This sample is **stateless**. DynamoDB tables and seed data from the original demo were removed. |
128 | | - |
129 | | -## Example requests (local) |
130 | | -Protected endpoint (requires `sample` scope): |
131 | | -- curl -i https://localhost:443/sample/protected \ |
132 | | - -H 'x-fapi-interaction-id: 3fa85f64-5717-4562-b3fc-2c963f66afa6' \ |
133 | | - -H 'Authorization: Bearer {"active":true,"scopes":["sample"]}' |
134 | | - |
135 | | -Missing or invalid x-fapi-interaction-id: |
136 | | -- If you pass x-fapi-interaction-id with an invalid format, you will get 400. |
137 | | -- If you omit it, the response will include a generated x-fapi-interaction-id. |
138 | | - |
139 | | -## Deployment |
140 | | -Container image (typical for Lambda): |
141 | | -- Build and push the image to ECR. |
142 | | -- Create/update a Lambda function using the container image. |
143 | | -- Configure an API Gateway HTTP API or REST API to route to the Lambda. |
144 | | -- Configure a custom authorizer (if applicable) to provide the scope field in the authorizer context. |
145 | | -- Set env vars (REGION, POPULATE_DB as needed; do not set AWS_LOCAL in production). |
146 | | - |
147 | | -IAM and permissions: |
148 | | -- The Lambda role must allow access to DynamoDB (read/write as needed for your tables). |
149 | | - |
150 | | -## Troubleshooting |
151 | | -- 401 Unauthorized: Missing Authorization header, malformed token, or token content cannot be parsed for scopes. |
152 | | -- 403 Forbidden: Token valid but does not include required scope. |
153 | | -- 400 Bad Request: x-fapi-interaction-id provided but not a valid UUIDv4. |
154 | | -- 404 Not Found: No matching data in DynamoDB (ensure POPULATE_DB or seed data). |
155 | | -- DynamoDB local connection issues: Verify Docker network and that LocalStack is reachable at [http://localstack.local:4566](http://localstack.local:4566) with AWS_LOCAL=true. |
| 1 | +# reference_api_resources |
0 commit comments