Skip to content
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
21 changes: 12 additions & 9 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,23 @@ on:
branches:
- master

permissions:
contents: read

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
go-version: [1.21.x]
go-version: [ 1.25.x ]
steps:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
- name: Setup Go
uses: actions/setup-go@v6
with:
go-version: ${{ matrix.go-version }}

- name: Checkout code
uses: actions/checkout@v4
- name: Checkout code
uses: actions/checkout@v6

- name: Test
run: go test ./...
- name: Test
run: go test ./...
17 changes: 12 additions & 5 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,32 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to the Container registry
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

- name: Build and push Docker image
uses: docker/build-push-action@v4
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
labels: ${{ steps.meta.outputs.labels }}
22 changes: 13 additions & 9 deletions .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: golangci-lint
on:
push:
branches:
- master
- '**'
pull_request:

permissions:
Expand All @@ -15,14 +15,18 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v6

- uses: actions/setup-go@v5
- name: Get go version from go.mod
run: |
echo "GO_VERSION=$(grep '^go ' go.mod | cut -d " " -f 2)" >> $GITHUB_ENV

- name: Setup-go
uses: actions/setup-go@v6
with:
go-version: '1.22'
cache: false

- name: golangci-lint
uses: golangci/golangci-lint-action@v4
go-version: ${{ env.GO_VERSION }}

- name: Run golangci-lint
uses: golangci/golangci-lint-action@v9
with:
version: v1.56
version: v2.7.2
58 changes: 43 additions & 15 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,34 +1,62 @@
version: "2"
run:
timeout: 2m
linters:
disable-all: true
default: none
enable:
- dupl
- errcheck
- errorlint
- exportloopref
- funlen
- gci
- goconst
- gocritic
- gocyclo
- gofmt
- goimports
- gosimple
- gosec
- govet
- ineffassign
- lll
- misspell
- nolintlint
- prealloc
- revive
- staticcheck
- stylecheck
- typecheck
- thelper
- tparallel
- unconvert
- unparam
- unused

issues:
exclude-rules:
- path: _test\.go
linters:
- unparam
- funlen
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
rules:
- linters:
- funlen
- unparam
path: _test\.go
- linters:
- revive
path: internal/http/
text: "var-naming.*package names"
- linters:
- revive
path: internal/util/hash/
text: "var-naming.*package names"
paths:
- third_party$
- builtin$
- examples$
formatters:
enable:
- gci
- gofmt
- goimports
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
17 changes: 10 additions & 7 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
# syntax=docker/dockerfile:1.2
FROM golang:alpine3.19 AS build
# syntax=docker/dockerfile:1.4
FROM golang:1.25-alpine AS build
RUN apk --no-cache add gcc g++ make git
WORKDIR /go/src/app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go get ./...
WORKDIR /go/src/app/cmd/auth
RUN GOOS=linux go build -ldflags="-s -w" -o ./bin/auth
RUN GOOS=linux go build -ldflags="-s -w" -o ./bin/auth ./cmd/auth

FROM alpine:3.19.1
FROM alpine:3.23
RUN addgroup -g 1000 appgroup && adduser -u 1000 -G appgroup -D appuser
WORKDIR /app
COPY --from=build /go/src/app/cmd/auth/bin /app
COPY --from=build /go/src/app/bin/auth /app
COPY --from=build /go/src/app/config /app/
COPY ./secrets ./secrets
RUN chown -R appuser:appgroup /app
ENV AUTH_SERVER_LOCAL_CONFIG_PATH=local_repository_config.yml
USER appuser

EXPOSE 8081
ENTRYPOINT ["/app/auth", "-c", "service_config.yml"]
49 changes: 42 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,19 @@ The `auth-server` project aims to address these concerns by serving as a transpa

2. The proxy server routes this request to `auth-server` to issue a token.
Response body:
`{"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1ODg5MzMyNTIsImlhdCI6MTU4ODkyOTY1MiwidXNlciI6ImFkbWluIiwicm9sZSI6MX0.LUx9EYsfBZGwbEsofBTT_5Lo3Y_3lk7T8pWLv3bw-XKVOqb_GhaRkVE90QR_sI-bWTkYCFIG9cPYmMXzmPLyjbofgsqTOzH6OaXi3IqxwZRtRGFtuqMoqXkakX5n38mvI3XkIOwFkNosHrpMtIq-HdqB3tfiDJc3YMsYfPbqyRBnBYJu2K51NslGQSiqKSnS_4KeLeaqqdpC7Zdb9Fo-r7EMn3FFuyPEab1iBsrcUYG3qnsKkvDhaq_jEGHflao7dEPEWaiGvJywXWaKR6XyyGtVx0H-OPfgvh1vUCLUUci2K3xE-IxjfRrHx3dSzdqFgJq_n4bVXpO9iNVYOZLccQ","token_type":"Bearer","expires_in":3600000}`
`{"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...","token_type":"Bearer","expires_in":3600000}`

3. The user sends an authenticated request to the proxy server:
```
GET /foo HTTP/1.1
Host: localhost:8081
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1ODg5MzMyNTIsImlhdCI6MTU4ODkyOTY1MiwidXNlciI6ImFkbWluIiwicm9sZSI6MX0.LUx9EYsfBZGwbEsofBTT_5Lo3Y_3lk7T8pWLv3bw-XKVOqb_GhaRkVE90QR_sI-bWTkYCFIG9cPYmMXzmPLyjbofgsqTOzH6OaXi3IqxwZRtRGFtuqMoqXkakX5n38mvI3XkIOwFkNosHrpMtIq-HdqB3tfiDJc3YMsYfPbqyRBnBYJu2K51NslGQSiqKSnS_4KeLeaqqdpC7Zdb9Fo-r7EMn3FFuyPEab1iBsrcUYG3qnsKkvDhaq_jEGHflao7dEPEWaiGvJywXWaKR6XyyGtVx0H-OPfgvh1vUCLUUci2K3xE-IxjfRrHx3dSzdqFgJq_n4bVXpO9iNVYOZLccQ
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
```

4. Proxy invokes `auth-server` as an authentication/authorization middleware. In case the token was successfully authenticated/authorized, the request will be routed to the target service. Otherwise, an auth error code will be returned to the client.

## Installation and Prerequisites
* `auth-server` is written in Golang.
* `auth-server` is written in Go (1.24+).
To install the latest stable version of Go, visit the [releases page](https://golang.org/dl/).

* Read the following [instructions](./secrets/README.md) to generate keys required to sign the token. Specify the location of the generated certificates in the service configuration file. An example of the configuration file can be found [here](config/service_config.yml).
Expand All @@ -60,15 +60,50 @@ To install the latest stable version of Go, visit the [releases page](https://go

* To run the project using Docker, visit their [page](https://www.docker.com/get-started) to get started. Docker images are available under the [GitHub Packages](https://github.com/reugn/auth-server/packages).

* Install `docker-compose` to get started with the examples.
* Install Docker to get started with the examples.

## Configuration

### Proxy Providers

The `proxy` setting in your configuration determines how `auth-server` parses incoming requests to extract the original method and URI. This is important when running behind a reverse proxy that may modify or forward request details via headers.

| Provider | Description | Headers Used |
|----------|-------------|--------------|
| `direct` | No proxy, use actual request values | None |
| `nginx` | Nginx with `auth_request` module | `X-Forwarded-Method`, `X-Forwarded-Uri` |
| `traefik` | Traefik with ForwardAuth middleware | `X-Forwarded-Method`, `X-Forwarded-Uri`, `X-Forwarded-Prefix` |
| `envoy` | Envoy with ext_authz filter | `X-Original-*`, `X-Envoy-Original-*`, `X-Forwarded-*` (priority order) |
| `haproxy` | HAProxy with external auth | `X-Forwarded-Method`, `X-Forwarded-Uri`, `X-Original-URI` |
| `kong` | Kong API Gateway | `X-Forwarded-Method`, `X-Forwarded-Path`, `X-Forwarded-Prefix` |

Example configuration:
```yaml
proxy: direct # or nginx, traefik, envoy, haproxy, kong
```

## Examples
Examples are available under the [examples](examples) folder.

To run `auth-server` as a [Traefik](https://docs.traefik.io/) middleware:
```
### Traefik
Run `auth-server` as a [Traefik](https://docs.traefik.io/) ForwardAuth middleware:
```sh
cd examples/traefik
docker-compose up -d
docker compose up -d
```

### Nginx
Run `auth-server` with [Nginx](https://nginx.org/) using the `auth_request` module:
```sh
cd examples/nginx
docker compose up -d
```

### Envoy
Run `auth-server` with [Envoy](https://www.envoyproxy.io/) using the `ext_authz` filter:
```sh
cd examples/envoy
docker compose up -d
```

## License
Expand Down
24 changes: 18 additions & 6 deletions cmd/auth/main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"fmt"
"log/slog"
"os"

Expand All @@ -12,7 +13,7 @@ import (
)

const (
version = "0.4.0"
version = "0.5.0"
)

func run() int {
Expand Down Expand Up @@ -50,21 +51,32 @@ func run() int {
return server.Start()
}

err := rootCmd.Execute()
if err != nil {
if err := rootCmd.Execute(); err != nil {
return 1
}
return 0
}

// readConfiguration reads the configuration file and returns the configuration.
func readConfiguration(path string) (*config.Service, error) {
// read the configuration file
data, err := os.ReadFile(path)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to read configuration file %s: %w", path, err)
}

// unmarshal the configuration data
config := config.NewServiceDefault()
err = yaml.Unmarshal(data, config)
return config, err
if err := yaml.Unmarshal(data, config); err != nil {
return nil, fmt.Errorf("failed to unmarshal configuration data: %w", err)
}

// validate the configuration
if err := config.Validate(); err != nil {
return nil, fmt.Errorf("invalid configuration: %w", err)
}

return config, nil
}

func main() {
Expand Down
34 changes: 23 additions & 11 deletions config/service_config.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
---
# Supported signing methods: RS256, RS384, RS512
signing-method: RS256
proxy: traefik

# Supported proxy providers: direct, nginx, traefik, envoy, haproxy, kong
# Use 'direct' when accessing auth-server without a reverse proxy.
proxy: direct

# Supported repository providers: local, aerospike, vault
repository: local

# HTTP server configuration
http:
host: 0.0.0.0
port: 8081
rate:
tps: 1024
size: 1024
white-list: []
host: 0.0.0.0
port: 8081
rate:
tps: 1024
size: 1024
white-list: [ ]

# Secret configuration
secret:
private-path: secrets/privkey.pem
public-path: secrets/cert.pem
private-path: secrets/privkey.pem
public-path: secrets/cert.pem

# Logger configuration
logger:
level: INFO
format: PLAIN
level: INFO
format: PLAIN
Loading
Loading