summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Dockerfile33
-rw-r--r--Makefile43
-rw-r--r--Procfile2
-rw-r--r--bin/.keep0
-rwxr-xr-xbin/envoy3
-rw-r--r--etc/envoy/envoy.yaml97
-rw-r--r--mise.toml1
8 files changed, 140 insertions, 40 deletions
diff --git a/.gitignore b/.gitignore
index 4ea11ebf..2d67c87d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+bin
target
# Explicitly include vendor directory
diff --git a/Dockerfile b/Dockerfile
index 02079de5..cbb0692f 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,14 +1,35 @@
# syntax=docker/dockerfile:1
-FROM rust:alpine AS builder
+# Build stage for authzd
+FROM rust:alpine AS authzd-builder
RUN apk add --no-cache musl-dev
WORKDIR /app
COPY . ./
RUN cargo build --release --target x86_64-unknown-linux-musl --offline
RUN strip /app/target/x86_64-unknown-linux-musl/release/authzd
-FROM gcr.io/distroless/static-debian12:nonroot
+# Build stage for getting Envoy binary
+FROM envoyproxy/envoy:v1.34-latest AS envoy-binary
+
+# Build stage for goreman (Procfile supervisor)
+FROM golang:1.23-alpine AS goreman-builder
+RUN go install github.com/mattn/goreman@latest
+
+# Final stage
+FROM gcr.io/distroless/base-debian12:nonroot
EXPOSE 9901 10000 50051
-WORKDIR /var/www
-COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/authzd /bin/authzd
-COPY --from=builder /app/etc/authzd /etc/authzd
-ENTRYPOINT ["/bin/authzd"]
+WORKDIR /
+
+# Copy binaries
+COPY --from=authzd-builder /app/target/x86_64-unknown-linux-musl/release/authzd /bin/authzd
+COPY --from=envoy-binary /usr/local/bin/envoy /bin/envoy
+COPY --from=goreman-builder /go/bin/goreman /bin/goreman
+
+# Copy configurations
+COPY --from=authzd-builder /app/etc/authzd /etc/authzd
+COPY --from=authzd-builder /app/etc/envoy /etc/envoy
+
+# Copy Procfile and goreman config
+COPY --from=authzd-builder /app/Procfile /Procfile
+
+ENTRYPOINT ["/bin/goreman"]
+CMD ["start"]
diff --git a/Makefile b/Makefile
index ca1a93db..2ab437eb 100644
--- a/Makefile
+++ b/Makefile
@@ -1,15 +1,17 @@
-PROJECT_NAME := $(shell basename $(shell pwd))
+PROJECT_NAME := $(shell basename $(shell pwd))# {{{}}}
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD | sed 's/\//_/g')
IMAGE_TAG := $(PROJECT_NAME):$(GIT_BRANCH)
.PHONY: build check test run clean fmt lint doc vendor
-.PHONY: build-image run-image health-check list-services test-grpc
+.PHONY: build-image run-image health-check list-services test-image
setup:
- @rustup component add clippy rustfmt
+ mise install
+ mise exec go -- go install github.com/mattn/goreman@latest
+ mise exec rustup -- rustup component add clippy rustfmt
# Cargo targets
-build: vendor
+build:
@cargo build --offline
check:
@@ -18,8 +20,9 @@ check:
test:
@cargo test
-run:
- @cargo run --offline
+run: build
+ @cp target/debug/authzd bin/authzd
+ @goreman -set-ports=false -rpc-server=false -f ./Procfile -exit-on-error=true start
clean:
@cargo clean
@@ -37,18 +40,36 @@ vendor:
@cargo vendor
# Docker targets
-build-image: vendor
+build-image:
@docker build --tag $(IMAGE_TAG) .
build-image-clean:
- @docker build --no-cache --tag $(IMAGE_TAG) .
+ @docker build --tag $(IMAGE_TAG) .
run-image: build-image
- @docker run --rm -p 50051:50051 --init -it $(IMAGE_TAG)
+ @docker run --rm -p 10000:10000 -p 9901:9901 --init -it $(IMAGE_TAG)
-# gRPC testing targets
+# HTTP and gRPC testing targets
health-check:
- @grpcurl -plaintext localhost:50051 grpc.health.v1.Health/Check
+ @curl -s http://localhost:10000/health || echo "Service not running"
+
+envoy-admin:
+ @curl -s http://localhost:9901/stats/prometheus | head -20
list-services:
@grpcurl -plaintext localhost:50051 list
+
+test-image: build-image
+ @echo "Starting container..."
+ @docker run -d --name authzd-test -p 10000:10000 -p 9901:9901 $(IMAGE_TAG)
+ @echo "Waiting for services to start..."
+ @sleep 5
+ @echo "Testing Envoy admin endpoint..."
+ @curl -s http://localhost:9901/stats/prometheus | grep -q "envoy_" && echo "✓ Envoy admin is accessible" || echo "✗ Envoy admin failed"
+ @echo "Testing health endpoint..."
+ @curl -s -o /dev/null -w "%{http_code}" http://localhost:10000/health | grep -q "200" && echo "✓ Health check passed" || echo "✗ Health check failed"
+ @echo "Testing authorization flow..."
+ @curl -s -H "Authorization: Bearer valid-token" http://localhost:10000/ -w "\n%{http_code}" | grep -q "200" && echo "✓ Auth with valid token passed" || echo "✗ Auth with valid token failed"
+ @curl -s http://localhost:10000/ -w "\n%{http_code}" | grep -q "401" && echo "✓ Auth without token correctly rejected" || echo "✗ Auth without token failed"
+ @echo "Cleaning up..."
+ @docker stop authzd-test && docker rm authzd-test
diff --git a/Procfile b/Procfile
new file mode 100644
index 00000000..6646bcf9
--- /dev/null
+++ b/Procfile
@@ -0,0 +1,2 @@
+authzd: ./bin/authzd
+envoy: ./bin/envoy -c ./etc/envoy/envoy.yaml --service-cluster authzd --service-node authzd
diff --git a/bin/.keep b/bin/.keep
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/bin/.keep
diff --git a/bin/envoy b/bin/envoy
new file mode 100755
index 00000000..ede6290c
--- /dev/null
+++ b/bin/envoy
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+exec envoy $@
diff --git a/etc/envoy/envoy.yaml b/etc/envoy/envoy.yaml
index e050a49e..31b29c80 100644
--- a/etc/envoy/envoy.yaml
+++ b/etc/envoy/envoy.yaml
@@ -6,21 +6,23 @@ admin:
application_log_config:
log_format:
json_format:
- Timestamp: "%Y-%m-%dT%T.%F"
- ThreadId: "%t"
- SourceLine: "%s:%#"
- Level: "%l"
- Message: "%j"
+ timestamp: "%Y-%m-%dT%T.%FZ"
+ thread_id: "%t"
+ level: "%l"
+ logger: "%n"
+ message: "%j"
overload_manager:
resource_monitors:
- name: "envoy.resource_monitors.global_downstream_max_connections"
typed_config:
"@type": type.googleapis.com/envoy.extensions.resource_monitors.downstream_connections.v3.DownstreamConnectionsConfig
- max_active_downstream_connections: 1024
+ max_active_downstream_connections: 10240
static_resources:
clusters:
- name: authzd
connect_timeout: 5s
+ type: STATIC
+ lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: authzd
endpoints:
@@ -35,8 +37,21 @@ static_resources:
"@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
explicit_http_config:
http2_protocol_options: {}
+ health_checks:
+ - timeout: 3s
+ interval: 5s
+ unhealthy_threshold: 2
+ healthy_threshold: 2
+ grpc_health_check: {}
+ circuit_breakers:
+ thresholds:
+ - priority: DEFAULT
+ max_connections: 1024
+ max_pending_requests: 1024
+ max_requests: 1024
+ max_retries: 3
listeners:
- - name: listener_0
+ - name: main_listener
address:
socket_address:
protocol: TCP
@@ -49,25 +64,30 @@ static_resources:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
access_log:
- name: envoy.access_loggers.stdout
+ filter:
+ not_health_check_filter: {}
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
log_format:
json_format:
- app: "envoy"
- authority: "%REQ(:AUTHORITY)%"
- bytes_received: "%BYTES_RECEIVED%"
- bytes_sent: "%BYTES_SENT%"
- client_ip: "%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%"
- duration: "%DURATION%"
- forwarded_for: "%REQ(X-FORWARDED-FOR)%"
+ timestamp: "%START_TIME(%FT%T.%3fZ)%"
method: "%REQ(:METHOD)%"
path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"
protocol: "%PROTOCOL%"
- request_id: "%REQ(X-REQUEST-ID)%"
response_code: "%RESPONSE_CODE%"
- timestamp: "%START_TIME%"
+ response_flags: "%RESPONSE_FLAGS%"
+ bytes_received: "%BYTES_RECEIVED%"
+ bytes_sent: "%BYTES_SENT%"
+ duration_ms: "%DURATION%"
+ upstream_service_time: "%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%"
+ x_forwarded_for: "%REQ(X-FORWARDED-FOR)%"
user_agent: "%REQ(USER-AGENT)%"
+ request_id: "%REQ(X-REQUEST-ID)%"
+ authority: "%REQ(:AUTHORITY)%"
+ upstream_host: "%UPSTREAM_HOST%"
codec_type: AUTO
+ request_timeout: 30s
+ stream_idle_timeout: 300s
http_filters:
- name: envoy.filters.http.health_check
typed_config:
@@ -80,30 +100,61 @@ static_resources:
- name: envoy.filters.http.ext_authz
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
+ transport_api_version: V3
grpc_service:
envoy_grpc:
cluster_name: authzd
- timeout: 30s
+ timeout: 5s
failure_mode_allow: false
+ include_peer_certificate: true
+ clear_route_cache: true
+ status_on_error:
+ code: 503
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
suppress_envoy_headers: true
route_config:
+ name: local_route
request_headers_to_remove:
- authorization
- cookie
- - user-agent
+ response_headers_to_add:
+ - header:
+ key: "x-content-type-options"
+ value: "nosniff"
+ - header:
+ key: "x-frame-options"
+ value: "DENY"
+ - header:
+ key: "x-xss-protection"
+ value: "1; mode=block"
virtual_hosts:
- - name: local
+ - name: backend
domains: ["*"]
routes:
- match:
prefix: "/"
route:
cluster: authzd
- timeout: 5s
- retry_policy:
- retry_on: "5xx"
- num_retries: 3
+ timeout: 30s
+ retry_policy:
+ retry_on: "5xx,reset,connect-failure,retriable-status-codes"
+ num_retries: 3
+ per_try_timeout: 10s
+ retriable_status_codes: [503]
+ request_headers_to_add:
+ - header:
+ key: "x-real-ip"
+ value: "%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%"
+ - header:
+ key: "x-forwarded-proto"
+ value: "%REQ(X-FORWARDED-PROTO)%"
stat_prefix: ingress_http
+ common_http_protocol_options:
+ idle_timeout: 300s
+ headers_with_underscores_action: REJECT_REQUEST
+ http2_protocol_options:
+ max_concurrent_streams: 100
+ initial_stream_window_size: 65536
+ server_header_transformation: PASS_THROUGH
diff --git a/mise.toml b/mise.toml
index 276d2e72..21f7cb80 100644
--- a/mise.toml
+++ b/mise.toml
@@ -1,4 +1,5 @@
[tools]
+go = "latest"
grpcurl = "latest"
make = "latest"
rust = "latest"