From 6e8791eab36f15b42c3c1a45dd678a3f1be0010f Mon Sep 17 00:00:00 2001 From: Daniel Lemos Simoes Date: Fri, 14 Nov 2025 11:05:12 -0300 Subject: [PATCH 1/2] small refactors --- authorizer/Makefile | 31 +++++++++------ cmd/mockapi/Makefile | 38 +++++++++---------- docker-compose.yml | 7 +--- go.mod | 11 +----- go.sum | 75 +++++++++++++++++++++++++++++-------- scripts/setup-localstack.sh | 16 ++++---- 6 files changed, 108 insertions(+), 70 deletions(-) diff --git a/authorizer/Makefile b/authorizer/Makefile index 682be73..55bc375 100644 --- a/authorizer/Makefile +++ b/authorizer/Makefile @@ -1,35 +1,44 @@ # Makefile # -include ../version.properties -VER=${VERSION} +ROOT ?= .. +-include $(ROOT)/version.properties # don't error if the file isn't there +VERSION ?= 1.0.0 ifdef CHANGE_ID VER=PR-${CHANGE_ID}-SNAPSHOT -else +else ifdef BUILD_NUMBER VER=${VERSION}.${BUILD_NUMBER} +else +VER=${VERSION} endif PKG=github.com/example/sample-api/authorizer REPO_INFO=$(shell git config --get remote.origin.url) DATE=$(shell date) - GOARCH=arm64 - LDFLAGS=-X "$(PKG).Version=$(VER)" -X "$(PKG).BuildDate=$(DATE)" -X "$(PKG).RepoUrl=$(REPO_INFO)" -X "$(PKG).BuildUrl=$(BUILD_URL)" -.PHONY: build build-local build-debug-local +.PHONY: build build-local build-debug-local clean + +clean: + @rm -f bootstrap app sample-api-$(VER).authorizer-function.zip build: - @rm -f bootstrap sample-api-${VER}-authorizer-function.zip - @(GOARCH=arm64 GOOS=linux go build -ldflags '-s -w $(LDFLAGS)' -gcflags "all=-trimpath=$$GOPATH" -o bootstrap && zip sample-api-${VER}-authorizer-function.zip bootstrap) + @rm -f bootstrap sample-api-$(VER).authorizer-function.zip + @(GOARCH=$(GOARCH) GOOS=linux go build -ldflags '-s -w $(LDFLAGS)' -gcflags "all=-trimpath=$$GOPATH" -o bootstrap && zip sample-api-$(VER).authorizer-function.zip bootstrap) build-local: - @(rm -f bootstrap sample-api-${VER}-authorizer-function.zip && GOARCH=arm64 GOOS=linux go build -ldflags '-s -w $(LDFLAGS)' -gcflags "all=-trimpath=$$GOPATH" -o bootstrap && zip sample-api-${VER}-authorizer-function.zip bootstrap) + @(rm -f bootstrap sample-api-$(VER).authorizer-function.zip && GOARCH=$(GOARCH) GOOS=linux go build -ldflags '-s -w $(LDFLAGS)' -gcflags "all=-trimpath=$$GOPATH" -o bootstrap && zip sample-api-$(VER).authorizer-function.zip bootstrap) build-debug-local: - @rm -f app sample-api-${VER}-authorizer-function.zip bootstrap + @rm -f app sample-api-$(VER).authorizer-function.zip bootstrap @echo "#!/bin/bash" > bootstrap @echo "dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient exec ./app" >> bootstrap @chmod +x bootstrap - @(go build -ldflags '$(LDFLAGS)' -gcflags "all=-N -l -trimpath=$$GOPATH" -o app && zip sample-api-${VER}-authorizer-function.zip bootstrap app) \ No newline at end of file + @(go build -ldflags '$(LDFLAGS)' -gcflags "all=-N -l -trimpath=$$GOPATH" -o app && zip sample-api-$(VER).authorizer-function.zip bootstrap app) +print-ver: + @echo "VERSION='${VERSION}'" + @echo "BUILD_NUMBER='${BUILD_NUMBER}'" + @echo "CHANGE_ID='${CHANGE_ID}'" + @echo "VER='${VER}'" \ No newline at end of file diff --git a/cmd/mockapi/Makefile b/cmd/mockapi/Makefile index 993c744..9644677 100644 --- a/cmd/mockapi/Makefile +++ b/cmd/mockapi/Makefile @@ -1,41 +1,37 @@ # Makefile # -include ../../version.properties -VER=${VERSION} +ROOT ?= ../.. +-include $(ROOT)/version.properties +VERSION ?= 1.0.0 ifdef CHANGE_ID VER=PR-${CHANGE_ID}-SNAPSHOT -else +else ifdef BUILD_NUMBER VER=${VERSION}.${BUILD_NUMBER} +else +VER=${VERSION} endif -# Update to your module path -PKG=github.com/example/sample-api/cmd/mockapi +PKG=github.com/example/sample-api/mock-api REPO_INFO=$(shell git config --get remote.origin.url) DATE=$(shell date) - LDFLAGS=-X "$(PKG).Version=$(VER)" -X "$(PKG).BuildDate=$(DATE)" -X "$(PKG).RepoUrl=$(REPO_INFO)" -X "$(PKG).BuildUrl=$(BUILD_URL)" -.PHONY: checks clean build build-local test test-and-report - -checks: - @staticcheck ./... - @gosec ./... - @go fmt ./... +.PHONY: checks clean build test test-and-report build-local clean: - @rm -f bootstrap sample-api-${VER}-mock-api-function.zip + @( rm -f main bootstrap sample-api-$(VER).mock-api-function.zip ) build: - @rm -f bootstrap sample-api-${VER}-mock-api-function.zip - @(GOARCH=arm64 GOOS=linux go build -ldflags '-s -w $(LDFLAGS)' -gcflags "all=-trimpath=$$GOPATH" -o bootstrap && zip sample-api-${VER}-mock-api-function.zip bootstrap) + @rm -f bootstrap sample-api-$(VER).mock-api-function.zip + @(GOARCH=arm64 GOOS=linux go build -ldflags '-s -w $(LDFLAGS)' -gcflags "all=-trimpath=$$GOPATH" -o bootstrap && zip sample-api-$(VER).mock-api-function.zip bootstrap) build-local: - @(rm -f bootstrap sample-api-${VER}-mock-api-function.zip && GOARCH=arm64 GOOS=linux go build -ldflags '-s -w $(LDFLAGS)' -gcflags "all=-trimpath=$$GOPATH" -o bootstrap && zip sample-api-${VER}-mock-api-function.zip bootstrap) - -test: - @(go test -v -coverprofile=coverage.out && go tool cover -func=coverage.out) + @(rm -f bootstrap sample-api-$(VER).mock-api-function.zip && GOARCH=arm64 GOOS=linux go build -ldflags '-s -w $(LDFLAGS)' -gcflags "all=-trimpath=$$GOPATH" -o bootstrap && zip sample-api-$(VER).mock-api-function.zip bootstrap) -test-and-report: - @(go test -v -coverprofile=coverage.out -json > report.json && go tool cover -func=coverage.out) \ No newline at end of file +print-ver: + @echo "VERSION='${VERSION}'" + @echo "BUILD_NUMBER='${BUILD_NUMBER}'" + @echo "CHANGE_ID='${CHANGE_ID}'" + @echo "VER='${VER}'" \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 097937b..b2eb9e9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,6 +5,8 @@ services: build: context: . dockerfile: cmd/mtls/Dockerfile + volumes: + - ./keys:/keys:ro environment: - API_URI=http://mockapi:3000 - SSM_TRANSPORT_CERTIFICATE_NAME=/sample-api/server-crt @@ -19,11 +21,6 @@ services: depends_on: localstack: condition: service_healthy - networks: - default: - aliases: - - matls-api.local - - matls-directory.local localstack: image: localstack/localstack diff --git a/go.mod b/go.mod index 47a6de3..afcf728 100644 --- a/go.mod +++ b/go.mod @@ -30,21 +30,12 @@ require ( github.com/aws/aws-sdk-go-v2/service/ssooidc v1.34.0 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.38.0 // indirect github.com/aws/smithy-go v1.22.5 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect - github.com/goccy/go-json v0.10.5 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/klauspost/compress v1.17.6 // indirect - github.com/lestrrat-go/blackmagic v1.0.4 // indirect - github.com/lestrrat-go/httpcc v1.0.1 // indirect - github.com/lestrrat-go/httprc/v3 v3.0.1 // indirect - github.com/lestrrat-go/option v1.0.1 // indirect - github.com/lestrrat-go/option/v2 v2.0.0 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/segmentio/asm v1.2.0 // indirect + github.com/stretchr/testify v1.10.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.52.0 // indirect - github.com/valyala/fastjson v1.6.4 // indirect - golang.org/x/crypto v0.41.0 // indirect golang.org/x/net v0.42.0 // indirect golang.org/x/sys v0.35.0 // indirect golang.org/x/text v0.28.0 // indirect diff --git a/go.sum b/go.sum index 29e0ce3..25bd939 100644 --- a/go.sum +++ b/go.sum @@ -1,56 +1,101 @@ +github.com/DATA-DOG/go-sqlmock v1.5.1 h1:FK6RCIUSfmbnI/imIICmboyQBkOckutaa6R5YYlLZyo= +github.com/DATA-DOG/go-sqlmock v1.5.1/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/aws/aws-lambda-go v1.49.0 h1:z4VhTqkFZPM3xpEtTqWqRqsRH4TZBMJqTkRiBPYLqIQ= github.com/aws/aws-lambda-go v1.49.0/go.mod h1:dpMpZgvWx5vuQJfBt0zqBha60q7Dd7RfgJv23DymV8A= +github.com/aws/aws-sdk-go v1.47.9 h1:rarTsos0mA16q+huicGx0e560aYRtOucV5z2Mw23JRY= github.com/aws/aws-sdk-go v1.47.9/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go-v2 v1.38.1 h1:j7sc33amE74Rz0M/PoCpsZQ6OunLqys/m5antM0J+Z8= github.com/aws/aws-sdk-go-v2 v1.38.1/go.mod h1:9Q0OoGQoboYIAJyslFyF1f5K1Ryddop8gqMhWx/n4Wg= +github.com/aws/aws-sdk-go-v2/config v1.31.3 h1:RIb3yr/+PZ18YYNe6MDiG/3jVoJrPmdoCARwNkMGvco= github.com/aws/aws-sdk-go-v2/config v1.31.3/go.mod h1:jjgx1n7x0FAKl6TnakqrpkHWWKcX3xfWtdnIJs5K9CE= +github.com/aws/aws-sdk-go-v2/credentials v1.18.7 h1:zqg4OMrKj+t5HlswDApgvAHjxKtlduKS7KicXB+7RLg= github.com/aws/aws-sdk-go-v2/credentials v1.18.7/go.mod h1:/4M5OidTskkgkv+nCIfC9/tbiQ/c8qTox9QcUDV0cgc= +github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.20.6 h1:QR3/KSpHmOhQD1XPn8SVbYdklWPB9TwM9VebUsisRm4= github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.20.6/go.mod h1:sMmWNSeevbQ/2lFMdm7go2WZuCMaJO4HrGHlCSN60WQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.4 h1:lpdMwTzmuDLkgW7086jE94HweHCqG+uOJwHf3LZs7T0= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.4/go.mod h1:9xzb8/SV62W6gHQGC/8rrvgNXU6ZoYM3sAIJCIrXJxY= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.4 h1:IdCLsiiIj5YJ3AFevsewURCPV+YWUlOW8JiPhoAy8vg= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.4/go.mod h1:l4bdfCD7XyyZA9BolKBo1eLqgaJxl0/x91PL4Yqe0ao= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.4 h1:j7vjtr1YIssWQOMeOWRbh3z8g2oY/xPjnZH2gLY4sGw= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.4/go.mod h1:yDmJgqOiH4EA8Hndnv4KwAo8jCGTSnM5ASG1nBI+toA= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.49.1 h1:0RqS5X7EodJzOenoY4V3LUSp9PirELO2ZOpOZbMldco= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.49.1/go.mod h1:VRp/OeQolnQD9GfNgdSf3kU5vbg708PF6oPHh2bq3hc= +github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.30.0 h1:SkUalAKtprOV5y77RsO3k76cEBPhacLIo0sGL3MKjuE= github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.30.0/go.mod h1:fuh7P1XXoWryEkCQVxTwoaOQ/GdI3ripI9UFmHaPo0o= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 h1:6+lZi2JeGKtCraAj1rpoZfKqnQ9SptseRZioejfUOLM= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0/go.mod h1:eb3gfbVIxIoGgJsi9pGne19dhCBpK6opTYpQqAmdy44= +github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.4 h1:upi++G3fQCAUBXQe58TbjXmdVPwrqMnRQMThOAIz7KM= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.4/go.mod h1:swb+GqWXTZMOyVV9rVePAUu5L80+X5a+Lui1RNOyUFo= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4 h1:ueB2Te0NacDMnaC+68za9jLwkjzxGWm0KB5HTUHjLTI= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4/go.mod h1:nLEfLnVMmLvyIG58/6gsSA03F1voKGaCfHV7+lR8S7s= +github.com/aws/aws-sdk-go-v2/service/ssm v1.64.0 h1:P0B6+TCK7bHi+MQPnakYOVrYENtEpVkaoVGeNCWjOV4= github.com/aws/aws-sdk-go-v2/service/ssm v1.64.0/go.mod h1:NMCzIcmGKoLNNkZ3/8SZzmp1+jvcU32vyUk5j7BwWI4= +github.com/aws/aws-sdk-go-v2/service/sso v1.28.2 h1:ve9dYBB8CfJGTFqcQ3ZLAAb/KXWgYlgu/2R2TZL2Ko0= github.com/aws/aws-sdk-go-v2/service/sso v1.28.2/go.mod h1:n9bTZFZcBa9hGGqVz3i/a6+NG0zmZgtkB9qVVFDqPA8= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.34.0 h1:Bnr+fXrlrPEoR1MAFrHVsge3M/WoK4n23VNhRM7TPHI= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.34.0/go.mod h1:eknndR9rU8UpE/OmFpqU78V1EcXPKFTTm5l/buZYgvM= +github.com/aws/aws-sdk-go-v2/service/sts v1.38.0 h1:iV1Ko4Em/lkJIsoKyGfc0nQySi+v0Udxr6Igq+y9JZc= github.com/aws/aws-sdk-go-v2/service/sts v1.38.0/go.mod h1:bEPcjW7IbolPfK67G1nilqWyoxYMSPrDiIQ3RdIdKgo= +github.com/aws/aws-xray-sdk-go v1.8.5 h1:A/Gc733PHvARkjcAk+fw+0k2RT3O4VSZ+x/3YvAREfc= github.com/aws/aws-xray-sdk-go v1.8.5/go.mod h1:tDkyLXjXQ+9j49uUrFXhO9cPnpH7qp7PWkEON+KbbKs= +github.com/aws/smithy-go v1.22.5 h1:P9ATCXPMb2mPjYBgueqJNCA5S9UfktsW0tTxi+a7eqw= github.com/aws/smithy-go v1.22.5/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= +github.com/awslabs/aws-lambda-go-api-proxy v0.16.2 h1:CJyGEyO1CIwOnXTU40urf0mchf6t3voxpvUDikOU9LY= github.com/awslabs/aws-lambda-go-api-proxy v0.16.2/go.mod h1:vxxjwBHe/KbgFeNlAP/Tvp4SsVRL3WQamcWRxqVh0z0= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= -github.com/go-jose/go-jose/v4 v4.1.2/go.mod h1:22cg9HWM1pOlnRiY+9cQYJ9XHmya1bYW8OeDM6Ku6Oo= -github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI= github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= -github.com/lestrrat-go/blackmagic v1.0.4/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw= -github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= -github.com/lestrrat-go/httprc/v3 v3.0.1/go.mod h1:2uAvmbXE4Xq8kAUjVrZOq1tZVYYYs5iP62Cmtru00xk= -github.com/lestrrat-go/jwx/v3 v3.0.10/go.mod h1:kNMedLgTpHvPJkK5EMVa1JFz+UVyY2dMmZKu3qjl/Pk= -github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= -github.com/lestrrat-go/option/v2 v2.0.0/go.mod h1:oSySsmzMoR0iRzCDCaUfsCzxQHUEuhOViQObyy7S6Vg= +github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= +github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= +github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.52.0 h1:wqBQpxH71XW0e2g+Og4dzQM8pk34aFYlA1Ga8db7gU0= github.com/valyala/fasthttp v1.52.0/go.mod h1:hf5C4QnVMkNXMspnsUlfM3WitlgYflyhHYoKol/szxQ= -github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= -golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/scripts/setup-localstack.sh b/scripts/setup-localstack.sh index 6a4196a..84670da 100755 --- a/scripts/setup-localstack.sh +++ b/scripts/setup-localstack.sh @@ -15,21 +15,21 @@ set -e ######################################## awslocal ssm put-parameter \ - --name "/sample-api/ca-crt" \ - --type "SecureString" \ - --value "$(cat /keys/ca.crt)" \ + --name /sample-api/server-crt \ + --type SecureString \ + --value "$(cat /keys/server.crt)" \ --overwrite awslocal ssm put-parameter \ - --name "/sample-api/server-key" \ - --type "SecureString" \ + --name /sample-api/server-key \ + --type SecureString \ --value "$(cat /keys/server.key)" \ --overwrite awslocal ssm put-parameter \ - --name "/sample-api/server-crt" \ - --type "SecureString" \ - --value "$(cat /keys/server.crt)" \ + --name /sample-api/ca-crt \ + --type SecureString \ + --value "$(cat /keys/ca.crt)" \ --overwrite ######################################## From b104ece23be42d18ffa97edfc2cb798635da015d Mon Sep 17 00:00:00 2001 From: Daniel Lemos Simoes Date: Wed, 10 Dec 2025 11:04:51 -0300 Subject: [PATCH 2/2] update readme --- README.md | 395 ++++++++++++++++++++++++++++++--------------- docker-compose.yml | 3 +- 2 files changed, 267 insertions(+), 131 deletions(-) diff --git a/README.md b/README.md index e376d5f..3cd2ef1 100644 --- a/README.md +++ b/README.md @@ -1,155 +1,292 @@ -# Sample API +# Sample API (reference_api_resources) -A minimal HTTP API and custom authorizer designed to run as AWS Lambda functions behind API Gateway. -It includes a mock API with scope-based access control, a token authorizer, and an optional mTLS proxy for testing secure client authentication. +A minimal **reference implementation** of an HTTP API, custom token authorizer, and optional mTLS proxy designed to run as AWS Lambda functions behind API Gateway. + +The repository is intended as a **forkable, production-inspired template** for teams experimenting with: + +- Secure API patterns (OAuth2 scopes, custom authorizers, mTLS, API Gateway flows) +- Local AWS-like environments using LocalStack +- Infrastructure validation, integration testing, and client onboarding flows + +This project mirrors the design standards used in the Recco repositories, but is generalized for any domain. --- -## Overview +# Table of Contents +1. [Overview](#overview) +2. [Architecture](#architecture) +3. [Folder Structure](#folder-structure) +4. [Requirements](#requirements) +5. [Getting Started (Local)](#getting-started-local) +6. [Environment Variables](#environment-variables) +7. [Running the Stack](#running-the-stack) +8. [Testing the API](#testing-the-api) +9. [Example Flows](#example-flows) +10. [Deployment](#deployment) +11. [Troubleshooting](#troubleshooting) + +--- + +# Overview + +This repository contains: + +- **Mock API Lambda** – A simple, scope-protected endpoint (`/sample/protected`). +- **Custom Authorizer Lambda** – Validates tokens and resolves scopes. +- **mTLS Proxy** – Terminates TLS, validates client certificates, and forwards traffic to API Gateway. +- **LocalStack automation** – Fully provisions IAM roles, Lambdas, API Gateway, and SSM. +- **Local development CA + certificates** – Used exclusively for local testing. + +The goal is to be: + +- Simple +- Understandable +- Easily forkable +- Close to real AWS behaviour + +--- + +# Architecture + +## High-level Flow + +``` +Client + │ (HTTPS + optional mTLS) + ▼ +mTLS Proxy (port 443) + │ forwards → execute-api + ▼ +API Gateway (LocalStack or AWS) + ├── Custom Authorizer Lambda + └── Mock API Lambda +``` ### Components -- **Authorizer**: validates OAuth2 tokens and supports mTLS-based client certificate checks. -- **Mock API**: exposes simple domain endpoints (`customer`, `energy`) with scope enforcement. -- **mTLS Proxy**: optional TLS termination layer for local or secure deployments. -- **LocalStack setup script**: provisions IAM roles, Lambdas, and API Gateway locally for testing. + +| Component | Purpose | +|----------|---------| +| **Mock API** | Implements `/sample/protected`; enforces the `sample` scope. | +| **Authorizer** | Reads OAuth2-style tokens, extracts scopes, returns IAM-style policy results. | +| **mTLS proxy** | Loads certs from SSM, terminates TLS, enforces client certs, forwards to the API. | +| **LocalStack** | Provides Lambda, SSM, IAM, and API Gateway locally. | +| **Key materials** | Self-signed CA, server keypair, and client cert for testing. | --- -## Mutual TLS (mTLS) Server +# Folder Structure + +``` +reference_api_resources/ +│ +├── cmd/ +│ └── mtls/ # mTLS proxy (TLS termination, SSM cert loading) +│ +├── authorizer/ # Custom authorizer Lambda +│ +├── mockapi/ # Sample mock API Lambda +│ +├── infra/ # LocalStack provisioning scripts (API Gateway, IAM, Lambdas) +│ +├── keys/ # Local CA, server certs, client certs +│ +├── docker-compose.yml # Entire local runtime stack +└── README.md # This documentation +``` -Located in `/cmd/mtls`, this service: -- Terminates TLS and enforces client certificate authentication. -- Validates certificates against a trusted CA bundle. -- Uses server and client keys stored in SSM (simulated via LocalStack). +--- + +# Requirements + +## Core Tools +- Go **1.24+** +- Docker **20+** +- Docker Compose +- Make (optional) + +## Local AWS Simulation +- LocalStack (managed through docker-compose) +- AWS CLI v2 + - Credentials may be dummy (`test/test`) + +## TLS Tooling +- OpenSSL (or mkcert) + +## Optional for AWS deployment +- AWS Account +- ECR, Lambda, API Gateway, SSM permissions --- -## Features +# Getting Started (Local) + +The project includes a fully automated LocalStack environment. The only required command is: + +``` +docker compose up --build +``` + +This launches: -- AWS Lambda–compatible handlers using `aws-lambda-go-api-proxy`. -- Example endpoints: - - `GET /customer/v1/customer` → requires scope: `customer` - - `GET /energy/v1/energy` → requires scope: `energy` - - `GET /health` → liveness check -- Scope-based authorization via: - - Lambda authorizer context (when deployed) - - Bearer token fallback (for local use) -- `x-fapi-interaction-id` header validation (must be UUIDv4). +- mTLS proxy on **https://localhost** +- Authorizer Lambda +- Mock API Lambda +- API Gateway REST API +- SSM with uploaded certificates --- -## Requirements +## 1. Generate Local TLS Certificates -- Go 1.24+ -- Docker -- LocalStack (for local AWS simulation) -- Optional AWS account for live testing +Inside `keys/`: + +``` +openssl genrsa -out ca.key 4096 +openssl req -x509 -new -nodes -key ca.key -sha256 -days 365 \ + -subj "/CN=Local CA" \ + -out ca.crt + +openssl genrsa -out server.key 2048 +openssl req -new -key server.key -subj "/CN=mtls-api.local" -out server.csr + +openssl x509 -req -in server.csr \ + -CA ca.crt -CAkey ca.key -CAcreateserial \ + -out server.crt -days 365 -sha256 + +openssl genrsa -out client.key 2048 +openssl req -new -key client.key -subj "/CN=mtls-client" -out client.csr + +openssl x509 -req -in client.csr \ + -CA ca.crt -CAkey ca.key -CAcreateserial \ + -out client.crt -days 365 -sha256 +``` + +These are automatically uploaded to SSM by LocalStack at startup. --- -## Environment Variables +# Environment Variables | Variable | Description | -|-----------|-------------| -| `AWS_LOCAL` | Set to `true` when running under LocalStack | -| `REGION` | AWS region (default `us-east-1`) | -| `CLIENT_CERT_HEADER` | Header name for mTLS client cert (e.g. `TLS-Certificate`) | -| `INTROSPECTION_ENDPOINT` | Token introspection URL *(leave blank locally)* | -| `USER_INFO_ENDPOINT` | User info URL *(leave blank locally)* | -| `CLIENT_ID` | OAuth2 client ID *(leave blank locally)* | -| `SSM_TRANSPORT_CERTIFICATE_NAME` | SSM name for server certificate | -| `SSM_TRANSPORT_KEY_NAME` | SSM name for server private key | -| `SSM_CA_TRUSTED_LIST_NAME` | SSM name for CA certificates | - -When using LocalStack, TLS materials are automatically uploaded to SSM under `/sample-api/...`. +|----------|-------------| +| `AWS_LOCAL` | Whether to use LocalStack (`true`) | +| `REGION` | AWS region (default: `us-east-1`) | +| `CLIENT_CERT_HEADER` | Header containing forwarded client cert | +| `INTROSPECTION_ENDPOINT` | Token introspection URL *(unused locally)* | +| `USER_INFO_ENDPOINT` | User-info endpoint *(unused locally)* | +| `CLIENT_ID` | OAuth2 client ID *(unused locally)* | +| `SSM_TRANSPORT_CERTIFICATE_NAME` | Path to server cert in SSM | +| `SSM_TRANSPORT_KEY_NAME` | Path to server key | +| `SSM_CA_TRUSTED_LIST_NAME` | Path to CA bundle | + +Defaults point to: + +``` +/sample-api/server-crt +/sample-api/server-key +/sample-api/ca-crt +``` + +--- + +# Running the Stack + +``` +docker compose up --build +``` + +This will: + +- Deploy Lambdas +- Deploy API Gateway +- Load certificates to SSM +- Start the mTLS proxy on port **443** --- -## Running locally -Option A: Go build/run -- 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. - -Example with AWS SAM (simplified outline): -- Create a SAM template wiring API Gateway → Lambda (runtime: provided.al2, image-based or binary handler). -- Set env vars (AWS_LOCAL, REGION). -- Run: sam local start-api - -Option B: Docker container -- The provided Dockerfile builds a minimal image suitable for local or image-based Lambda deployment. - -Build: -- docker build -t mockapi:local . - -Run against LocalStack: -- docker network create localstack || true -- docker run --rm -p 443:443 - --network localstack - -e AWS_LOCAL=true - -e REGION=eu-west-1 - --name mockapi - mockapi:local - -Notes: -- The container exposes port 443. -- Ensure LocalStack is reachable on the same Docker network as localstack.local:4566. - -## Authorization and scopes -Each protected endpoint requires specific scopes: -- /sample/protected → sample - -How scopes are resolved: -1. When behind API Gateway, the handler reads them from the custom authorizer context (scope as a space-delimited string). -2. Otherwise, it falls back to parsing the Authorization: Bearer token. - -Accepted token formats for local/dev: -- JWT with a space-delimited scope claim in payload. -- A JSON string token that includes one of: - - scope: "s1 s2" - - scopes: ["s1","s2"] - - permissions: ["s1","s2"] - -Examples: -- JWT payload idea (pseudo): { "sub":"123", "scope":"sample" } -- JSON-string token example for sample: {"active":true,"scopes":["sample"]} - -In practice, set an Authorization header like: -- Authorization: Bearer {"active":true,"scopes":["sample"]} - -Responses on failure: -- 401 if Authorization is missing/invalid or introspection-style JSON cannot be parsed -- 403 if token is valid but lacks required scopes - -## x-fapi-interaction-id -- If the client sets x-fapi-interaction-id, it must be a valid UUIDv4; otherwise the request is rejected with 400. -- If missing, the server generates a UUIDv4 and echoes it in the response header. - -## Data persistence -- This sample is **stateless**. DynamoDB tables and seed data from the original demo were removed. - -## Example requests (local) -Protected endpoint (requires `sample` scope): -- curl -i https://localhost:443/sample/protected \ - -H 'x-fapi-interaction-id: 3fa85f64-5717-4562-b3fc-2c963f66afa6' \ - -H 'Authorization: Bearer {"active":true,"scopes":["sample"]}' - -Missing or invalid x-fapi-interaction-id: -- If you pass x-fapi-interaction-id with an invalid format, you will get 400. -- If you omit it, the response will include a generated x-fapi-interaction-id. - -## Deployment -Container image (typical for Lambda): -- Build and push the image to ECR. -- Create/update a Lambda function using the container image. -- Configure an API Gateway HTTP API or REST API to route to the Lambda. -- Configure a custom authorizer (if applicable) to provide the scope field in the authorizer context. -- Set env vars (REGION, POPULATE_DB as needed; do not set AWS_LOCAL in production). - -IAM and permissions: -- The Lambda role must allow access to DynamoDB (read/write as needed for your tables). - -## Troubleshooting -- 401 Unauthorized: Missing Authorization header, malformed token, or token content cannot be parsed for scopes. -- 403 Forbidden: Token valid but does not include required scope. -- 400 Bad Request: x-fapi-interaction-id provided but not a valid UUIDv4. -- 404 Not Found: No matching data in DynamoDB (ensure POPULATE_DB or seed data). -- 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. +# Testing the API + +## 1. Test health endpoint (HTTPS + client cert) + +Using Postman: + +- CA cert: `keys/ca.crt` +- Client cert: `keys/client.crt` +- Client key: `keys/client.key` + +Send: + +``` +GET https://localhost/health +``` + +Expected response: + +``` +{"status":"ok"} +``` + +--- + +## 2. Test protected endpoint (scope required) + +``` +GET https://localhost/sample/protected +Authorization: Bearer {"active":true,"scopes":["sample"]} +x-fapi-interaction-id: +``` + +Expected: + +``` +200 OK +``` + +If missing the scope `"sample"`: + +``` +403 Forbidden +``` + +If missing Authorization header: + +``` +401 Unauthorized +``` + +If invalid UUID: + +``` +400 Bad Request +``` + +--- + +# Example Flows + +## Token + Authorizer flow +1. Client sends Authorization header +2. API Gateway invokes custom authorizer +3. Authorizer returns IAM-style policy +4. API Lambda executes with scope context + +## mTLS flow +1. Client presents certificate +2. Proxy validates against CA from SSM +3. Proxy forwards request to execute-api +4. API Gateway + Lambdas run as normal + +--- + +# Troubleshooting + +| Problem | Likely Cause | +|--------|--------------| +| 308 redirect | Wrong execute-api path (double slash); check proxy logs | +| 401 | Missing/invalid Authorization header | +| 403 | Token valid but missing required scope | +| 400 | Invalid UUID in `x-fapi-interaction-id` | +| mTLS handshake failure | Wrong CA, wrong key, unsupported key format on macOS | +| LocalStack not provisioning | Run `docker compose logs localstack` | + +--- \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index b2eb9e9..5bea448 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,7 @@ services: volumes: - ./keys:/keys:ro environment: - - API_URI=http://mockapi:3000 + - API_NAME=mockapi - SSM_TRANSPORT_CERTIFICATE_NAME=/sample-api/server-crt - SSM_TRANSPORT_KEY_NAME=/sample-api/server-key - SSM_CA_TRUSTED_LIST_NAME=/sample-api/ca-crt @@ -27,7 +27,6 @@ services: ports: - "4566:4566" environment: - # DynamoDB is not required anymore; keep only what we need. - SERVICES=iam,ssm,lambda,kms,vpc,apigateway - AWS_ACCESS_KEY_ID=test - AWS_SECRET_ACCESS_KEY=test