Build an Auth Endpoint with Go and AWS Lambda

introduce

While I was playing around with my pet project Kyiv Station Walk , I noticed that deleting test data manually was tedious and I needed to come up with a concept for an admin page. This requires some kind of authentication endpoint. Some super lightweight services that check login and password as a pair of superuser credentials.

Serverless is great for this simple nanoservice. This comes with some cost savings as I expect my admin pages for my less popular services to have a lower execution rate, so serverless gives me that almost for free. Also, I think this gives me some architectural benefits, as it allows me to separate my core domain from crosscutting concerns. For my task, I decided to use AWS Lambda. I also decided to use Go because of its minimalistic nature which is useful for Lambda instantiation.

set up

Our lambda function will be called externally via HTTP, so we put the HTTP gateway in front of it so it looks like this in the AWS console.

project structure

To separate our authentication logic from the FaaS internals, our project will have two files: auth.go is where the authentication logic lives, and main.go is where our logic integrates with AWS lambda.

The content of main.go looks like this:

go

For this code to work, we need "github.com/aws/aws-lambda-go/lambda"package.json.

In order to use our endpoint from the outside, because we have to provide a specially formatted response to the API Gateway. For this reason, we also install github.com/aws/aws-lambda-go/eventsthe package.

Let's highlight an example of a successful response that you might have noticed in the snippet above:

go

The error response looks like this:

go
<span style="color:#000000"><span style="background-color:#fbedbb">events.APIGatewayProxyResponse{
    StatusCode: status,
    Body:       http.StatusText(status),
}</span></span>

verify

For our purposes, we'll omit the use of persistent storage, as one pair of credentials will suffice. Still, we need to hash the stored passwords with a hash function, which will allow defenders to verify passwords in acceptable time, but attackers will need a lot of resources to guess passwords from hashes. Argon2 is recommended for such tasks. So to get started, we need "github.com/aws/aws-lambda-go/lambda"packages.

JavaScript
<span style="color:#000000"><span style="background-color:#fbedbb">func main() {
    lambda.Start(HandleRequest)
}</span></span>

Argon2 is implemented "golang.org/x/crypto/argon2"so authentication is very simple.

JavaScript

Notice how we return the same message for wrong logins and wrong passwords to disclose as little information as possible. This allows us to prevent account enumeration attacks.

build it:

<span style="color:#000000"><span style="background-color:#fbedbb">go build -o main main.go
And zipping it
~\Go\Bin\build-lambda-zip.exe -o main.zip main</span></span>

use windows

If you are a Windows user, you will need to set the following environment variables before building:

Using environment variables

We can now see hardcoded credentials in the codebase. This is a bad practice as they fetch credentials automatically .

You can leverage environment variables with the help of package.json os.

JavaScript
<span style="color:#000000"><span style="background-color:#fbedbb">login := os.Getenv(<span style="color:#800080">"</span><span style="color:#800080">LOGIN"</span>)
salt := os.Getenv(<span style="color:#800080">"</span><span style="color:#800080">SALT"</span>)</span></span>

Here's how you set them up in the AWS console.

JWT generation

Once the service verifies that the credentials are valid, it issues a token allowing its holder to act as a superuser. For this, we'll use JWT , which is the de facto standard format for access tokens.

We need the following packages:

<span style="color:#000000"><span style="background-color:#fbedbb">"github.com/dgrijalva/jwt-go"</span></span>

The JWT generation code looks like this:

JavaScript

Since an adversary intercepting such a token could be acting on behalf of a superuser, we do not want this token to be valid indefinitely, as this would grant the adversary unlimited privileges. So we set the token expiration time to one hour.

Test API Gateway

At this point, our API is ready to use. Here's a short snippet in the main service that only deletes a route if the user has sufficient permissions.

F#
shrink ▲   

Minimize attack surface

 

At this point, our function has some bugs, so we have to do some extra work on the API Gateway.

endpoint limit

The default setting is too high for authorization functions that are not expected to be called very often. Let's change that.

Guess you like

Origin blog.csdn.net/wouderw/article/details/127711141#comments_24016279