Skip to content

Commit

Permalink
Add IAM protection to Lambda function URLs
Browse files Browse the repository at this point in the history
Requires a tool to v4-sign the request to AWS for testing.

Test can be run locally against a deployed function with:
```sh
aws-vault exec identity -- URL=$FUNCTION_URL make test-api
```

#minor
  • Loading branch information
gregtyler committed Oct 11, 2023
1 parent 68c6f45 commit 0acd5dc
Show file tree
Hide file tree
Showing 11 changed files with 176 additions and 11 deletions.
52 changes: 52 additions & 0 deletions .github/workflows/env-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: "[Job] Test environment"

on:
workflow_call:
inputs:
create_url:
description: "URL of the create endpoint"
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

defaults:
run:
shell: bash

permissions:
id-token: write
contents: write
security-events: write
pull-requests: read

jobs:
test:
runs-on: ubuntu-latest
name: Test
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- uses: actions/setup-go@v4
with:
go-version: '1.21'
- uses: unfor19/install-aws-cli-action@v1
- name: Configure AWS
uses: aws-actions/configure-aws-credentials@v4
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-to-assume: arn:aws:iam::311462405659:role/lpa-store-ci
role-duration-seconds: 3600
role-session-name: GitHubActions
- name: POST to server
env:
URL: ${{ inputs.create_url }}
run: make test-api
15 changes: 6 additions & 9 deletions .github/workflows/workflow-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,9 @@ jobs:
test-pr-env:
name: Test PR Environment
needs: [deploy-pr-env]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: "0"
- name: POST to server
env:
URL: ${{ needs.deploy-pr-env.outputs.create_url }}
run: make test-api
uses: ./.github/workflows/env-test.yml
with:
create_url: ${{ needs.deploy-pr-env.outputs.create_url }}
secrets:
aws_access_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ secrets.auto.tfvars
.env
venv/
env/
# built items
signer/test-api
# structurizr
.structurizr
docs/architecture/dsl/**/workspace.json
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ down:

test-api: URL ?= http://localhost:9000/create
test-api:
curl $(URL) -XPOST -H 'Content-type: application/json' -d '{"uid":"M-AL9A-7EY3-075D","version":"1"}' -q
go build -o ./signer/test-api ./signer && \
chmod +x ./signer/test-api && \
./signer/test-api POST $(URL) '{"uid":"M-AL9A-7EY3-075D","version":"1"}'

create-tables:
docker compose run --rm aws dynamodb describe-table --table-name deeds || \
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ services:
AWS_DYNAMODB_ENDPOINT: http://ddb:8000
AWS_ACCESS_KEY_ID: X
AWS_SECRET_ACCESS_KEY: X
DDB_TABLE_NAME_DEEDS: deeds
volumes:
- "./lambda/.aws-lambda-rie:/aws-lambda"
entrypoint: /aws-lambda/aws-lambda-rie /var/task/main
Expand Down
1 change: 1 addition & 0 deletions go.work
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ use (
./lambda/create
./lambda/shared
./mock-apigw
./signer
)
7 changes: 7 additions & 0 deletions signer/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module github.com/ministryofjustice/opg-data-lpa-deed/signer

go 1.20

require github.com/aws/aws-sdk-go v1.45.24

require github.com/jmespath/go-jmespath v0.4.0 // indirect
42 changes: 42 additions & 0 deletions signer/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
github.com/aws/aws-sdk-go v1.45.24 h1:TZx/CizkmCQn8Rtsb11iLYutEQVGK5PK9wAhwouELBo=
github.com/aws/aws-sdk-go v1.45.24/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
47 changes: 47 additions & 0 deletions signer/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package main

import (
"fmt"
"io"
"log"
"net/http"
"os"
"strings"
"time"

v4 "github.com/aws/aws-sdk-go/aws/signer/v4"
"github.com/aws/aws-sdk-go/awstesting/unit"
)

func main() {
creds := unit.Session.Config.Credentials
signer := v4.NewSigner(creds)

method := os.Args[1]
host := os.Args[2]
body := strings.NewReader(os.Args[3])

req, err := http.NewRequest(method, host, body)
if err != nil {
panic(err)
}

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

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

client := http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}

if resp.StatusCode >= 400 {
log.Printf("Response code %d", resp.StatusCode)
buf := new(strings.Builder)
_, _ = io.Copy(buf, resp.Body)
log.Printf("error response: %s", buf.String())

panic(fmt.Sprintf("invalid status code %d", resp.StatusCode))
}
}
14 changes: 14 additions & 0 deletions terraform/modules/lambda/iam.tf
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,17 @@ resource "aws_lambda_permission" "allow_lambda_execution_operator" {
function_name = aws_lambda_function.main.function_name
principal = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/operator"
}

resource "aws_lambda_permission" "allow_lambda_url_execution_operator" {
statement_id = "AllowExecutionOperatorUrl"
action = "lambda:InvokeFunctionUrl"
function_name = aws_lambda_function.main.function_name
principal = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/operator"
}

resource "aws_lambda_permission" "allow_lambda_url_execution_operator" {
statement_id = "AllowExecutionOperatorUrl"
action = "lambda:InvokeFunctionUrl"
function_name = aws_lambda_function.main.function_name
principal = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/lpa-store-ci"
}
2 changes: 1 addition & 1 deletion terraform/modules/lambda/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ resource "aws_lambda_function" "main" {

resource "aws_lambda_function_url" "main" {
function_name = aws_lambda_function.main.function_name
authorization_type = "NONE"
authorization_type = "AWS_IAM"
}

0 comments on commit 0acd5dc

Please sign in to comment.