Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add API Gateway #10

Merged
merged 2 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions .github/workflows/account-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: "[Job] Plan/Deploy to Account"

on:
workflow_call:
inputs:
workspace_name:
description: "The terraform workspace to target for account actions"
required: true
type: string
secrets:
aws_access_key_id:
description: "AWS Access Key ID"
required: true
aws_secret_access_key:
description: "AWS Secret Access Key"
required: true

jobs:
terraform_account_workflow:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- uses: unfor19/install-aws-cli-action@v1
- uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.4.6
terraform_wrapper: false
- name: Configure AWS Credentials For Terraform
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.aws_access_key_id }}
aws-secret-access-key: ${{ secrets.aws_secret_access_key }}
aws-region: eu-west-1
role-duration-seconds: 3600
role-session-name: OPGLpaStoreGithubAction

- name: Lint Terraform
run: terraform fmt -check -recursive
working-directory: ./terraform/account
continue-on-error: true

- name: Terraform Init
run: terraform init -input=false
working-directory: ./terraform/account

- name: Terraform Plan
env:
TF_WORKSPACE: ${{ inputs.workspace_name }}
run: |
terraform workspace show
echo "plan_summary=$(terraform plan -no-color -lock-timeout=300s -input=false -parallelism=30 | grep -ioE 'Plan: [[:digit:]]+ to add, [[:digit:]]+ to change, [[:digit:]]+ to destroy|No changes. Your infrastructure matches the configuration.')" >> $GITHUB_OUTPUT
terraform plan -lock-timeout=300s -input=false -parallelism=30
working-directory: ./terraform/account

- name: Terraform Apply
if: github.ref == 'refs/heads/main'
env:
TF_WORKSPACE: ${{ inputs.workspace_name }}
run: |
terraform apply -lock-timeout=300s -input=false -auto-approve -parallelism=30
working-directory: ./terraform/account
8 changes: 4 additions & 4 deletions .github/workflows/env-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ on:
description: "Github Token"
required: true
outputs:
create_url:
description: "URL of the create endpoint"
base_url:
description: "Base URL of API"
value: ${{ jobs.terraform_environment_workflow.outputs.url }}

jobs:
terraform_environment_workflow:
runs-on: ubuntu-latest
environment:
name: ${{ inputs.workspace_name }} popup environment
name: ${{ inputs.workspace_name }}
url: ${{ steps.terraform_outputs.outputs.url }}
outputs:
url: ${{ steps.terraform_outputs.outputs.url }}
Expand Down Expand Up @@ -85,5 +85,5 @@ jobs:
TF_WORKSPACE: ${{ inputs.workspace_name }}
TF_VAR_app_version: ${{ inputs.version_tag }}
run: |
echo "url=$(terraform output -raw lambda_url)" >> $GITHUB_OUTPUT
echo "url=$(terraform output -raw base_url)" >> $GITHUB_OUTPUT
working-directory: ./terraform/environment
2 changes: 2 additions & 0 deletions .github/workflows/env-destroy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ jobs:
working-directory: ./terraform/environment

- name: Destroy deployment environment
env:
GH_TOKEN: ${{ github.token }}
run: |
gh api \
--method DELETE \
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/env-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ name: "[Job] Test environment"
on:
workflow_call:
inputs:
create_url:
description: "URL of the create endpoint"
base_url:
description: "Base URL of API"
required: true
type: string
secrets:
Expand Down Expand Up @@ -48,5 +48,5 @@ jobs:
role-session-name: GitHubActions
- name: POST to server
env:
URL: ${{ inputs.create_url }}
URL: ${{ inputs.base_url }}
run: make test-api
11 changes: 10 additions & 1 deletion .github/workflows/workflow-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,15 @@ jobs:
aws_access_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

plan-dev-account:
name: TF Plan Dev Account
uses: ./.github/workflows/account-deploy.yml
with:
workspace_name: development
secrets:
aws_access_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

deploy-pr-env:
name: Deploy PR Environment
needs: [build, generate-tags, generate-environment-workspace-name]
Expand All @@ -88,7 +97,7 @@ jobs:
needs: [deploy-pr-env]
uses: ./.github/workflows/env-test.yml
with:
create_url: ${{ needs.deploy-pr-env.outputs.create_url }}
base_url: ${{ needs.deploy-pr-env.outputs.base_url }}
secrets:
aws_access_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ up:
down:
docker compose down

test-api: URL ?= http://localhost:9000/create
test-api: URL ?= http://localhost:9000
test-api:
go build -o ./signer/test-api ./signer && \
chmod +x ./signer/test-api && \
./signer/test-api POST $(URL) '{"uid":"M-AL9A-7EY3-075D","version":"1"}'
./signer/test-api PUT $(URL)/lpas/M-AL9A-7EY3-075D '{"uid":"M-AL9A-7EY3-075D","version":"1"}'

create-tables:
docker compose run --rm aws dynamodb describe-table --table-name deeds || \
Expand Down
112 changes: 111 additions & 1 deletion docs/openapi/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,114 @@ servers:
description: Development
security:
- {}
paths: {}
paths:
/lpas/{uid}:
parameters:
- name: uid
in: path
required: true
description: The UID of the complaint
schema:
type: string
pattern: "M-([A-Z0-9]{4})-([A-Z0-9]{4})-([A-Z0-9]{4})"
example: M-789Q-P4DF-4UX3
put:
operationId: putLpa
summary: Store an LPA
requestBody:
content:
application/json:
schema:
type: object
additionalProperties: false
responses:
"201":
description: Case created
"400":
description: Invalid request
content:
application/json:
schema:
$ref: "#/components/schemas/BadRequestError"
x-amazon-apigateway-auth:
type: "AWS_IAM"
x-amazon-apigateway-integration:
uri: ${lambda_create_invoke_arn}
httpMethod: "POST"
type: "aws_proxy"
contentHandling: "CONVERT_TO_TEXT"
/health:
get:
operationId: healthCheck
summary: Health check endpoint for external services to consume
responses:
200:
description: Healthy
content:
application/json:
schema:
type: object
properties:
status:
type: string
example: OK
additionalProperties: false
503:
description: Service unavailable
content:
application/json:
schema:
type: object
properties:
status:
type: string
example: Unhealthy
additionalProperties: false
x-amazon-apigateway-auth:
type: "AWS_IAM"
x-amazon-apigateway-integration:
type: "mock"
responses:
default:
statusCode: 200
responseTemplates:
application/json: '{"status":"ok", "statusCode":200}'
requestTemplates:
application/json: '{"statusCode": 200}'
passthroughBehavior: "when_no_templates"

components:
schemas:
AbstractError:
type: object
required:
- code
- detail
properties:
code:
type: string
detail:
type: string
BadRequestError:
allOf:
- $ref: "#/components/schemas/AbstractError"
- type: object
properties:
code:
enum: ["INVALID_REQUEST"]
errors:
type: array
items:
type: object
required:
- source
- detail
properties:
source:
type: string
format: jsonpointer
detail:
type: string
example:
- source: "/uid"
detail: "invalid uid format"
4 changes: 2 additions & 2 deletions lambda/create/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ type Lambda struct {
logger Logger
}

func (l *Lambda) HandleEvent(ctx context.Context, event events.LambdaFunctionURLRequest) (events.LambdaFunctionURLResponse, error) {
func (l *Lambda) HandleEvent(ctx context.Context, event events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
var data shared.Case
response := events.LambdaFunctionURLResponse{
response := events.APIGatewayProxyResponse{
StatusCode: 500,
Body: "{\"code\":\"INTERNAL_SERVER_ERROR\",\"detail\":\"Internal server error\"}",
}
Expand Down
4 changes: 2 additions & 2 deletions lambda/shared/problem.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ var ProblemInvalidRequest Problem = Problem{
Detail: "Invalid request",
}

func (problem Problem) Respond() (events.LambdaFunctionURLResponse, error) {
func (problem Problem) Respond() (events.APIGatewayProxyResponse, error) {
var errorString = ""
for _, ve := range problem.Errors {
errorString += fmt.Sprintf("%s %s, ", ve.Source, ve.Detail)
Expand All @@ -64,7 +64,7 @@ func (problem Problem) Respond() (events.LambdaFunctionURLResponse, error) {
body = []byte("{\"code\":\"INTERNAL_SERVER_ERROR\",\"detail\":\"Internal server error\"}")
}

return events.LambdaFunctionURLResponse{
return events.APIGatewayProxyResponse{
StatusCode: code,
Body: string(body),
}, nil
Expand Down
5 changes: 4 additions & 1 deletion mock-apigw/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@ import (
"io"
"log"
"net/http"
"regexp"
"strings"

"github.com/aws/aws-lambda-go/events"
)

var LPAPath = regexp.MustCompile("/lpas/M(-[0-9A-Z]{4}){3}")

func delegateHandler(w http.ResponseWriter, r *http.Request) {
lambdaName := ""

if r.URL.Path == "/create" && r.Method == http.MethodPost {
if LPAPath.MatchString(r.URL.Path) && r.Method == http.MethodPut {
lambdaName = "create"
}

Expand Down
2 changes: 1 addition & 1 deletion signer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func main() {

req.Header.Add("Content-type", "application/json")

signer.Sign(req, body, "lambda", "eu-west-1", time.Now())
signer.Sign(req, body, "execute-api", "eu-west-1", time.Now())

client := http.Client{}
resp, err := client.Do(req)
Expand Down
6 changes: 6 additions & 0 deletions terraform/account/.envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Terraform
export TF_WORKSPACE=development
export TF_VAR_default_role=operator
export TF_VAR_management_role=operator

export TF_CLI_ARGS_init="-backend-config=role_arn=arn:aws:iam::311462405659:role/operator"
25 changes: 25 additions & 0 deletions terraform/account/.terraform.lock.hcl

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

20 changes: 20 additions & 0 deletions terraform/account/apigateway.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
resource "aws_iam_role" "api_gateway_cloudwatch" {
name = "api-gateway-cloudwatch-global"
assume_role_policy = data.aws_iam_policy_document.api_gateway_assume_role.json
}

data "aws_iam_policy_document" "api_gateway_assume_role" {
statement {
actions = ["sts:AssumeRole"]

principals {
type = "Service"
identifiers = ["apigateway.amazonaws.com"]
}
}
}

resource "aws_iam_role_policy_attachment" "api_gateway_log_to_cloudwatch" {
role = aws_iam_role.api_gateway_cloudwatch.id
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs"
}
Loading
Loading