Skip to content

Latest commit

 

History

8 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

age-mtls

Regulators in the EU and UK are starting to require age checks before people can use large parts of the internet. The usual way to comply is to collect a government ID or a face scan, which means handing your identity to every service that wants to confirm one fact about you: whether you're old enough. That trades privacy for compliance, and it's becoming the default.

age-mtls takes a different route. You verify your age once with a trusted authority and receive a client certificate that proves a single attribute (over 18, human, or automated) without revealing who you are. Sites check the certificate instead of your ID. The certificate carries the claim, and nobody downstream learns your name, your birth date, or anything else about you.

The goal is to make this an operating-system primitive rather than a per-website feature. If age proof lives in the OS, any app or browser can request it through one trusted path, the user approves it once, and no individual site ever touches an identity document. That's what separates a privacy-preserving platform capability from yet another login wall, and it's why the OS-level work matters.

Status

This is early. The cryptographic flow already works: a certificate authority issues certificates that carry an access level, a verifier tracks them, and a TLS-protected service grants access based on the level. Today the three services run on Kubernetes and use a mock authentication step in place of a real identity provider. Moving the verification flow down to the OS level is the active work.

How it works

There are three services, each in its own directory under mtls-project-microservices/:

CA Service (port 8080)

Issues and signs client certificates. It loads the CA certificate and key (mounted from a Kubernetes secret at /etc/ca), generates a client certificate with rcgen, assigns it a serial number, and registers that serial with the verifier before returning the certificate and private key to the caller.

  • POST /issue: issue a new certificate
  • GET /health: health check

Verifier Service (port 8081)

Stores certificate records in Redis and answers verification queries. Each record holds the user ID, access level, issue and expiry timestamps, and a revoked flag. Records are keyed by cert:{serial} and expire automatically when the certificate does.

  • POST /register: register a certificate
  • GET /verify/:serial: verify a certificate and return its access level
  • POST /revoke/:serial: revoke a certificate
  • GET /health: health check

Protected Website (port 8443)

Serves over HTTPS using rustls, with the server certificate and key mounted at /etc/tls. It hands out certificates through a mock authentication page and exposes the protected routes.

  • /: public landing page
  • /auth: request a certificate (mock BankID flow)
  • /protected: protected area
  • /admin: admin area (intended for the highest access level)
  • /health: health check

Access levels

Certificates carry one of three levels, which stand in for different verified attributes:

Level Name Meaning
1 Bot Automated systems and APIs
2 Human A verified human user
3 Adult An age-verified user (18+)

This mirrors real situations like proving you're a real person, proving you're over 18, or proving a specific attribute without handing over your full identity.

Request flow

1. A user visits the website and goes to /auth
2. They pick an access level and authenticate (mock BankID)
3. The CA Service issues a certificate, signs it, and registers the serial
   with the Verifier (serial -> access level)
4. The user receives the certificate and private key
5. They reconnect with the certificate; the mTLS handshake runs and the
   Verifier confirms the certificate is valid and reports its level

Tech stack

  • Language: Rust, on the Tokio async runtime
  • Web framework: Axum
  • TLS: rustls (via axum-server)
  • Certificate generation: rcgen
  • Storage: Redis, for certificate records
  • Containers: Docker, multi-stage builds
  • Orchestration: Kubernetes

Project layout

mtls-project-microservices/
├── ca-service/             # Certificate authority
├── verifier-service/       # Certificate verification + Redis
├── protected-website/      # mTLS-protected website
├── infrastructure/         # Namespace and Redis manifests
├── scripts/                # generate-ca, deploy, cleanup, test
├── config/                 # Environment configuration
└── docs/                   # Architecture and deployment notes

Each service is self-contained: its own Cargo workspace, Dockerfile, Kubernetes manifests, and values.yaml. There's also a mtls-project-monolith/ variant that keeps the same three services in a single combined project.

Getting started

You'll need Docker, a Kubernetes cluster (minikube, kind, or self-hosted), kubectl, and Rust for local development.

cd mtls-project-microservices

# Generate the CA and server certificates
make setup

# Deploy everything to Kubernetes
make deploy

# Run the integration test
make test

To deploy the services individually instead:

kubectl apply -f infrastructure/k8s/
kubectl apply -f ca-service/k8s/
kubectl apply -f verifier-service/k8s/
kubectl apply -f protected-website/k8s/

Local development

Run a single service:

cd ca-service
cargo run

Issue a certificate against a running CA Service:

curl -X POST http://localhost:8080/issue \
  -H 'Content-Type: application/json' \
  -d '{"user_id": "test", "access_level": 3, "validity_days": 30}'

Or build all three at once with make build-local. The Makefile also has shortcuts for issuing certificates at each level (make issue-bot, make issue-human, make issue-adult), tailing logs, and opening a Redis CLI.

License

MIT licensed. Early-stage project with a working proof of concept.

About

Certificate-based tiered access control over mTLS — prove you're human or 18+ without handing over your identity. Rust microservices on Kubernetes.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages