Skip to main content

GNY server

Project description

GNY

This is currently ALPHA software - lots of bits and pieces are missing.

GNY is a FastAPI-based server that manages DNS TXT records for ACME dns-01 certificate challenges. It is designed to be used as a hook target for certbot (or any ACME client) when automating TLS certificate issuance and renewal.

Overview

GNY exposes a small REST API (documented in openapi.yaml) that lets enrolled servers add and remove _acme-challenge.* DNS TXT records. Access is controlled by:

  1. Enrollment — a server registers its IP address and administrator email, receiving a Bearer token.
  2. Email confirmation — an administrator with access_level >= 1 confirms the enrollment via OIDC login (Google, Azure AD, or any standard OIDC provider), activating the token.
  3. PTR-based authorization — an enrolled server may only manage TXT records for its own hostname (as resolved by reverse-DNS lookup of its IP address).

Requirements

  • Python 3.11+
  • MariaDB or MySQL database
  • An OIDC client (Google Cloud OAuth2, Azure AD/Entra ID app registration, or any standard OIDC provider) for enrollment confirmation
  • The enrolling server must have a valid PTR (reverse-DNS) record

Installation

pip install .

For development (editable install with test/lint extras):

pip install -e ".[test,lint]"

Configuration

Copy .env and adjust values:

Variable Description
APP_URL Public base URL of this server (e.g. https://dns.example.com)
DB_HOST MariaDB/MySQL hostname
DB_DATABASE Database name
DB_USERNAME Database user
DB_PASSWORD Database password
OIDCProviderMetadataURL OIDC Discovery document URL (see below)
OIDCClientID OIDC client ID
OIDCClientSecret OIDC client secret
OIDCRedirectURI OIDC redirect path (default /.well-known/sso)
LOG_LEVEL Logging level: debug, info, warning, error
DISPLAY_ERRORS Show error details in responses (true / false)

The redirect URI registered with the OIDC provider must be {APP_URL}{OIDCRedirectURI}, e.g. https://dns.example.com/.well-known/sso.

OIDC provider examples

Google:

OIDCProviderMetadataURL=https://accounts.google.com/.well-known/openid-configuration

Azure AD / Entra ID (replace {tenant_id} with your directory tenant ID):

OIDCProviderMetadataURL=https://login.microsoftonline.com/{tenant_id}/v2.0/.well-known/openid-configuration

Running

uvicorn gny.main:app --host 0.0.0.0 --port 8000

For development with auto-reload:

uvicorn gny.main:app --reload

The database tables are created automatically on startup.

Interactive API docs are available at http://localhost:8000/docs.

API

All endpoints are under /api. Full spec: openapi.yaml.

Enrollment workflow

1. Enroll

POST /api/enroll
Content-Type: application/json

{ "mail": "admin@example.com" }

Returns a Bearer token, e.g., gny-ab3df26e48b2467bf705156d4c8914f2. The server's IP must resolve to a PTR record or the request is rejected with 409.

2. Confirm enrollment

Open the following URL in a browser as an administrator (a user with access_level >= 1):

GET /api/enroll/start?token={token}

This redirects to the configured OIDC provider (Google, Azure AD, etc.). After authenticating, the provider redirects back to /.well-known/sso, which upserts the user record and activates the enrollment token.

On first login, every user is created with access_level = 0. An existing administrator must grant access before a new user can confirm enrollments:

UPDATE users SET access_level = 1 WHERE mail = 'admin@example.com';

Alternatively, the /api/enroll/confirm endpoint accepts an OIDC Bearer token directly and confirms the enrollment programmatically (still requires access_level >= 1).

Managing TXT records

All requests below require Authorization: Bearer {enrollment_token}.

Add a record

POST /api/txt?name=_acme-challenge.example.com&text=<validation_token>

Delete a record

DELETE /api/txt?name=_acme-challenge.example.com&text=<validation_token>

Test authorization

GET /api/txt/test?name=_acme-challenge.example.com

Returns {"status": "ok"} if the authenticated server is allowed to manage that name, or 403 otherwise.

Authorization rules

A server enrolled from IP 1.2.3.4 whose PTR record resolves to server.example.com may manage any TXT record whose domain component (after stripping a leading _acme-challenge.) equals or is a subdomain of server.example.com.

Project structure

gny/
├── main.py            # FastAPI application entry point
├── config.py          # Pydantic settings (reads .env)
├── database.py        # Async SQLAlchemy engine and session
├── models.py          # ORM models: Enrollment, TxtRecord, User
├── auth.py            # Bearer token validation, user upsert
├── oidc_provider.py   # OIDC Discovery, UserInfo fetch
├── dns_utils.py       # PTR lookup and domain authorization check
└── routes/
    ├── enroll.py      # POST /api/enroll, POST /api/enroll/confirm
    ├── txt.py         # POST/DELETE /api/txt, GET /api/txt/test
    └── oidc.py        # GET /api/enroll/start, GET /.well-known/sso
requirements.txt
openapi.yaml

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gny-0.0.1.tar.gz (4.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gny-0.0.1-py3-none-any.whl (4.2 kB view details)

Uploaded Python 3

File details

Details for the file gny-0.0.1.tar.gz.

File metadata

  • Download URL: gny-0.0.1.tar.gz
  • Upload date:
  • Size: 4.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for gny-0.0.1.tar.gz
Algorithm Hash digest
SHA256 4caa1a1ad91853348bf3948cd7b93d1a1f8e5f9be9b47c0bb9f28ee57396dc70
MD5 f4c02f66361f72a3ee23497ef766d99e
BLAKE2b-256 6f5bdcc080d320992d34bc945b9734cf3f94a1e6e72c1fc87e7dae5c6f0a2de5

See more details on using hashes here.

Provenance

The following attestation bundles were made for gny-0.0.1.tar.gz:

Publisher: release.yml on svalgaard/gny

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file gny-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: gny-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 4.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for gny-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 7391ecc9572d417434d7e37d207b10422fcc3191e8d6a3b1439504c9d959e632
MD5 df56d96b6c73146ae3376e9fca6087f2
BLAKE2b-256 b6915b8305ea9cd65d4c4ba787056945231559304bf046ca9d9863b1ec17f7a9

See more details on using hashes here.

Provenance

The following attestation bundles were made for gny-0.0.1-py3-none-any.whl:

Publisher: release.yml on svalgaard/gny

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page