diff --git a/.gitignore b/.gitignore index 8bccc63..6e726dc 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,9 @@ data/ *.log internal config +# Backup files +*.bak + # Internal files SESSION*.md TODO.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 71d9958..10a6556 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,26 @@ All notable changes to NORA will be documented in this file. --- +## [0.2.28] - 2026-03-13 + +### Fixed / Исправлено +- **docker-compose.yml**: Fixed image reference from `getnora/nora:latest` to `ghcr.io/getnora-io/nora:latest` +- **docker-compose.yml**: Исправлена ссылка на образ с `getnora/nora:latest` на `ghcr.io/getnora-io/nora:latest` + +### Documentation / Документация +- **Authentication Guide**: Added complete auth setup guide in README — htpasswd, API tokens, RBAC roles, curl examples +- **Руководство по аутентификации**: Добавлено полное руководство по настройке auth в README — htpasswd, API-токены, RBAC-роли, примеры curl +- **FSTEC builds**: Documented `Dockerfile.astra` and `Dockerfile.redos` purpose in README +- **Сборки ФСТЭК**: Документировано назначение `Dockerfile.astra` и `Dockerfile.redos` в README +- **TLS / HTTPS**: Added reverse proxy setup guide (Caddy, Nginx) and `insecure-registries` Docker config for internal deployments +- **TLS / HTTPS**: Добавлено руководство по настройке reverse proxy (Caddy, Nginx) и конфигурация `insecure-registries` Docker для внутренних инсталляций + +### Removed / Удалено +- Removed stale `CHANGELOG.md.bak` from repository +- Удалён устаревший `CHANGELOG.md.bak` из репозитория + +--- + ## [0.2.27] - 2026-03-03 ### Added / Добавлено diff --git a/CHANGELOG.md.bak b/CHANGELOG.md.bak deleted file mode 100644 index 02e5119..0000000 --- a/CHANGELOG.md.bak +++ /dev/null @@ -1,414 +0,0 @@ -# Changelog - -All notable changes to NORA will be documented in this file. - ---- - -## [0.2.18] - 2026-01-31 - -### Changed -- Logo styling refinements - ---- - -## [0.2.17] - 2026-01-31 - -### Added -- Copyright headers to all source files (Volkov Pavel | DevITWay) -- SPDX-License-Identifier: MIT in all .rs files - ---- - -## [0.2.16] - 2026-01-31 - -### Changed -- N○RA branding: stylized O logo across dashboard -- Fixed O letter alignment in logo - ---- - -## [0.2.15] - 2026-01-31 - -### Fixed -- Code formatting (cargo fmt) - ---- - -## [0.2.14] - 2026-01-31 - -### Fixed -- Docker dashboard now shows actual image size from manifest layers (config + layers sum) -- Previously showed only manifest file size (~500 B instead of actual image size) - ---- - -## [0.2.13] - 2026-01-31 - -### Fixed -- npm dashboard now shows correct version count and package sizes -- Parses metadata.json for versions, dist.unpackedSize, and time.modified -- Previously showed 0 versions / 0 B for all packages - ---- - -## [0.2.12] - 2026-01-30 - -### Added - -#### Configurable Rate Limiting -- Rate limits now configurable via `config.toml` and environment variables -- New config section `[rate_limit]` with parameters: `auth_rps`, `auth_burst`, `upload_rps`, `upload_burst`, `general_rps`, `general_burst` -- Environment variables: `NORA_RATE_LIMIT_{AUTH|UPLOAD|GENERAL}_{RPS|BURST}` - -#### Secrets Provider Architecture -- Trait-based secrets management (`SecretsProvider` trait) -- ENV provider as default (12-Factor App pattern) -- Protected secrets with `zeroize` (memory zeroed on drop) -- Redacted Debug impl prevents secret leakage in logs -- New config section `[secrets]` with `provider` and `clear_env` options - -#### Docker Image Metadata -- Support for image metadata retrieval - -#### Documentation -- Bilingual onboarding guide (EN/RU) - ---- - -## [0.2.11] - 2026-01-26 - -### Added -- Internationalization (i18n) support -- PyPI registry proxy -- UI improvements - ---- - -## [0.2.10] - 2026-01-26 - -### Changed -- Dark theme applied to all UI pages - ---- - -## [0.2.9] - 2026-01-26 - -### Changed -- Version bump release - ---- - -## [0.2.8] - 2026-01-26 - -### Added -- Dashboard endpoint added to OpenAPI documentation - ---- - -## [0.2.7] - 2026-01-26 - -### Added -- Dynamic version display in UI sidebar - ---- - -## [0.2.6] - 2026-01-26 - -### Added - -#### Dashboard Metrics -- Global stats panel: downloads, uploads, artifacts, cache hit rate, storage -- Extended registry cards with artifact count, size, counters -- Activity log (last 20 events) - -#### UI -- Dark theme (bg: #0f172a, cards: #1e293b) - ---- - -## [0.2.5] - 2026-01-26 - -### Fixed -- Docker push/pull: added PATCH endpoint for chunked uploads - ---- - -## [0.2.4] - 2026-01-26 - -### Fixed -- Rate limiting: health/metrics endpoints now exempt -- Increased upload rate limits for Docker parallel requests - ---- - -## [0.2.0] - 2026-01-25 - -### Added - -#### UI: SVG Brand Icons -- Replaced emoji icons with proper SVG brand icons (Simple Icons style) -- Docker, Maven, npm, Cargo, PyPI icons now render as scalable vector graphics -- Consistent icon styling across dashboard, sidebar, and detail pages - -#### Testing Infrastructure -- Unit tests for LocalStorage (8 tests): put/get, list, stat, health_check -- Unit tests for S3Storage with wiremock HTTP mocking (11 tests) -- Integration tests for auth/htpasswd (7 tests) -- Token lifecycle tests (11 tests) -- Validation tests (21 tests) -- **Total: 75 tests passing** - -#### Security: Input Validation (`validation.rs`) -- Path traversal protection: rejects `../`, `..\\`, null bytes, absolute paths -- Docker image name validation per OCI distribution spec -- Content digest validation (`sha256:[64 hex]`, `sha512:[128 hex]`) -- Docker tag/reference validation -- Storage key length limits (max 1024 chars) - -#### Security: Rate Limiting (`rate_limit.rs`) -- Auth endpoints: 1 req/sec, burst 5 (brute-force protection) -- Upload endpoints: 10 req/sec, burst 20 -- General endpoints: 100 req/sec, burst 200 -- Uses `tower_governor` 0.8 with `PeerIpKeyExtractor` - -#### Observability: Request ID Tracking (`request_id.rs`) -- `X-Request-ID` header added to all responses -- Accepts upstream request ID or generates UUID v4 -- Tracing spans include request_id for log correlation - -#### CLI: Migrate Command (`migrate.rs`) -- `nora migrate --from local --to s3` - migrate between storage backends -- `--dry-run` flag for preview without copying -- Progress bar with indicatif -- Skips existing files in destination -- Summary statistics (migrated, skipped, failed, bytes) - -#### Error Handling (`error.rs`) -- `AppError` enum with `IntoResponse` for Axum -- Automatic conversion from `StorageError` and `ValidationError` -- JSON error responses with request_id support - -### Changed -- `StorageError` now uses `thiserror` derive macro -- `TokenError` now uses `thiserror` derive macro -- Storage wrapper validates keys before delegating to backend -- Docker registry handlers validate name, digest, reference inputs -- Body size limit set to 100MB default via `DefaultBodyLimit` - -### Dependencies Added -- `thiserror = "2"` - typed error handling -- `tower_governor = "0.8"` - rate limiting -- `governor = "0.10"` - rate limiting backend -- `tempfile = "3"` (dev) - temporary directories for tests -- `wiremock = "0.6"` (dev) - HTTP mocking for S3 tests - -### Files Added -- `src/validation.rs` - input validation module -- `src/migrate.rs` - storage migration module -- `src/error.rs` - application error types -- `src/request_id.rs` - request ID middleware -- `src/rate_limit.rs` - rate limiting configuration - ---- - -## [0.1.0] - 2026-01-24 - -### Added -- Multi-protocol support: Docker Registry v2, Maven, npm, Cargo, PyPI -- Web UI dashboard -- Swagger UI (`/api-docs`) -- Storage backends: Local filesystem, S3-compatible -- Smart proxy/cache for Maven and npm -- Health checks (`/health`, `/ready`) -- Basic authentication (htpasswd with bcrypt) -- API tokens (revocable, per-user) -- Prometheus metrics (`/metrics`) -- JSON structured logging -- Environment variable configuration -- Graceful shutdown (SIGTERM/SIGINT) -- Backup/restore commands - ---- - -# Журнал изменений (RU) - -Все значимые изменения NORA документируются в этом файле. - ---- - -## [0.2.12] - 2026-01-30 - -### Добавлено - -#### Настраиваемый Rate Limiting -- Rate limits настраиваются через `config.toml` и переменные окружения -- Новая секция `[rate_limit]` с параметрами: `auth_rps`, `auth_burst`, `upload_rps`, `upload_burst`, `general_rps`, `general_burst` -- Переменные окружения: `NORA_RATE_LIMIT_{AUTH|UPLOAD|GENERAL}_{RPS|BURST}` - -#### Архитектура Secrets Provider -- Trait-based управление секретами (`SecretsProvider` trait) -- ENV provider по умолчанию (12-Factor App паттерн) -- Защищённые секреты с `zeroize` (память обнуляется при drop) -- Redacted Debug impl предотвращает утечку секретов в логи -- Новая секция `[secrets]` с опциями `provider` и `clear_env` - -#### Docker Image Metadata -- Поддержка получения метаданных образов - -#### Документация -- Двуязычный onboarding guide (EN/RU) - ---- - -## [0.2.11] - 2026-01-26 - -### Добавлено -- Поддержка интернационализации (i18n) -- PyPI registry proxy -- Улучшения UI - ---- - -## [0.2.10] - 2026-01-26 - -### Изменено -- Тёмная тема применена ко всем страницам UI - ---- - -## [0.2.9] - 2026-01-26 - -### Изменено -- Релиз с обновлением версии - ---- - -## [0.2.8] - 2026-01-26 - -### Добавлено -- Dashboard endpoint добавлен в OpenAPI документацию - ---- - -## [0.2.7] - 2026-01-26 - -### Добавлено -- Динамическое отображение версии в сайдбаре UI - ---- - -## [0.2.6] - 2026-01-26 - -### Добавлено - -#### Dashboard Metrics -- Глобальная панель статистики: downloads, uploads, artifacts, cache hit rate, storage -- Расширенные карточки реестров с количеством артефактов, размером, счётчиками -- Лог активности (последние 20 событий) - -#### UI -- Тёмная тема (bg: #0f172a, cards: #1e293b) - ---- - -## [0.2.5] - 2026-01-26 - -### Исправлено -- Docker push/pull: добавлен PATCH endpoint для chunked uploads - ---- - -## [0.2.4] - 2026-01-26 - -### Исправлено -- Rate limiting: health/metrics endpoints теперь исключены -- Увеличены лимиты upload для параллельных Docker запросов - ---- - -## [0.2.0] - 2026-01-25 - -### Добавлено - -#### UI: SVG иконки брендов -- Эмоджи заменены на SVG иконки брендов (стиль Simple Icons) -- Docker, Maven, npm, Cargo, PyPI теперь отображаются как векторная графика -- Единый стиль иконок на дашборде, сайдбаре и страницах деталей - -#### Тестовая инфраструктура -- Unit-тесты для LocalStorage (8 тестов): put/get, list, stat, health_check -- Unit-тесты для S3Storage с HTTP-мокированием wiremock (11 тестов) -- Интеграционные тесты auth/htpasswd (7 тестов) -- Тесты жизненного цикла токенов (11 тестов) -- Тесты валидации (21 тест) -- **Всего: 75 тестов проходят** - -#### Безопасность: Валидация ввода (`validation.rs`) -- Защита от path traversal: отклоняет `../`, `..\\`, null-байты, абсолютные пути -- Валидация имён Docker-образов по спецификации OCI distribution -- Валидация дайджестов (`sha256:[64 hex]`, `sha512:[128 hex]`) -- Валидация тегов и ссылок Docker -- Ограничение длины ключей хранилища (макс. 1024 символа) - -#### Безопасность: Rate Limiting (`rate_limit.rs`) -- Auth endpoints: 1 req/sec, burst 5 (защита от брутфорса) -- Upload endpoints: 10 req/sec, burst 20 -- Общие endpoints: 100 req/sec, burst 200 -- Использует `tower_governor` 0.8 с `PeerIpKeyExtractor` - -#### Наблюдаемость: Отслеживание Request ID (`request_id.rs`) -- Заголовок `X-Request-ID` добавляется ко всем ответам -- Принимает upstream request ID или генерирует UUID v4 -- Tracing spans включают request_id для корреляции логов - -#### CLI: Команда миграции (`migrate.rs`) -- `nora migrate --from local --to s3` - миграция между storage backends -- Флаг `--dry-run` для предпросмотра без копирования -- Прогресс-бар с indicatif -- Пропуск существующих файлов в destination -- Итоговая статистика (migrated, skipped, failed, bytes) - -#### Обработка ошибок (`error.rs`) -- Enum `AppError` с `IntoResponse` для Axum -- Автоматическая конверсия из `StorageError` и `ValidationError` -- JSON-ответы об ошибках с поддержкой request_id - -### Изменено -- `StorageError` теперь использует макрос `thiserror` -- `TokenError` теперь использует макрос `thiserror` -- Storage wrapper валидирует ключи перед делегированием backend -- Docker registry handlers валидируют name, digest, reference -- Лимит размера body установлен в 100MB через `DefaultBodyLimit` - -### Добавлены зависимости -- `thiserror = "2"` - типизированная обработка ошибок -- `tower_governor = "0.8"` - rate limiting -- `governor = "0.10"` - backend для rate limiting -- `tempfile = "3"` (dev) - временные директории для тестов -- `wiremock = "0.6"` (dev) - HTTP-мокирование для S3 тестов - -### Добавлены файлы -- `src/validation.rs` - модуль валидации ввода -- `src/migrate.rs` - модуль миграции хранилища -- `src/error.rs` - типы ошибок приложения -- `src/request_id.rs` - middleware для request ID -- `src/rate_limit.rs` - конфигурация rate limiting - ---- - -## [0.1.0] - 2026-01-24 - -### Добавлено -- Мульти-протокольная поддержка: Docker Registry v2, Maven, npm, Cargo, PyPI -- Web UI дашборд -- Swagger UI (`/api-docs`) -- Storage backends: локальная файловая система, S3-совместимое хранилище -- Умный прокси/кэш для Maven и npm -- Health checks (`/health`, `/ready`) -- Базовая аутентификация (htpasswd с bcrypt) -- API токены (отзываемые, per-user) -- Prometheus метрики (`/metrics`) -- JSON структурированное логирование -- Конфигурация через переменные окружения -- Graceful shutdown (SIGTERM/SIGINT) -- Команды backup/restore diff --git a/README.md b/README.md index 32ccdd2..1c9602b 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,62 @@ npm config set registry http://localhost:4000/npm/ npm publish ``` +## Authentication + +NORA supports Basic Auth (htpasswd) and revocable API tokens with RBAC. + +### Quick Setup + +```bash +# 1. Create htpasswd file with bcrypt +htpasswd -cbB users.htpasswd admin yourpassword +# Add more users: +htpasswd -bB users.htpasswd ci-user ci-secret + +# 2. Start NORA with auth enabled +docker run -d -p 4000:4000 \ + -v nora-data:/data \ + -v ./users.htpasswd:/data/users.htpasswd \ + -e NORA_AUTH_ENABLED=true \ + ghcr.io/getnora-io/nora:latest + +# 3. Verify +curl -u admin:yourpassword http://localhost:4000/v2/_catalog +``` + +### API Tokens (RBAC) + +Tokens support three roles: `read`, `write`, `admin`. + +```bash +# Create a write token (30 days TTL) +curl -s -X POST http://localhost:4000/api/tokens \ + -H "Content-Type: application/json" \ + -d '{"username":"admin","password":"yourpassword","role":"write","ttl_days":90,"description":"CI/CD"}' + +# Use token with Docker +docker login localhost:4000 -u token -p nra_ + +# Use token with curl +curl -H "Authorization: Bearer nra_" http://localhost:4000/v2/_catalog + +# List tokens +curl -s -X POST http://localhost:4000/api/tokens/list \ + -H "Content-Type: application/json" \ + -d '{"username":"admin","password":"yourpassword"}' + +# Revoke token by hash prefix +curl -s -X POST http://localhost:4000/api/tokens/revoke \ + -H "Content-Type: application/json" \ + -d '{"username":"admin","password":"yourpassword","hash_prefix":""}' +``` + +| Role | Pull/Read | Push/Write | Delete/Admin | +|------|-----------|------------|--------------| +| `read` | Yes | No | No | +| `write` | Yes | Yes | No | +| `admin` | Yes | Yes | Yes | + ## CLI Commands ```bash @@ -166,6 +222,77 @@ clear_env = false | `/cargo/` | Cargo | | `/simple/` | PyPI | +## TLS / HTTPS + +NORA serves plain HTTP by design. **TLS is intentionally not built into the binary** — this is a deliberate architectural decision: + +- **Single responsibility**: NORA manages artifacts, not certificates. Embedding TLS means bundling Let's Encrypt clients, certificate renewal logic, ACME challenges, and custom CA support — all of which already exist in battle-tested tools. +- **Operational simplicity**: One place for certificates (reverse proxy), not scattered across every service. When a cert expires, you fix it in one config — not in NORA, Grafana, GitLab, and every other service separately. +- **Industry standard**: Docker Hub, GitHub Container Registry, AWS ECR, Harbor, Nexus — none of them terminate TLS in the registry process. A reverse proxy in front is the universal pattern. +- **Zero-config internal use**: On trusted networks (lab, CI/CD), NORA works out of the box without generating self-signed certs or managing keystores. + +### Production (recommended): reverse proxy with auto-TLS + +``` +Client → Caddy/Nginx (HTTPS, port 443) → NORA (HTTP, port 4000) +``` + +Caddy example: + +``` +registry.example.com { + reverse_proxy localhost:4000 +} +``` + +Nginx example: + +```nginx +server { + listen 443 ssl; + server_name registry.example.com; + ssl_certificate /etc/letsencrypt/live/registry.example.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/registry.example.com/privkey.pem; + client_max_body_size 0; # unlimited for large image pushes + location / { + proxy_pass http://127.0.0.1:4000; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} +``` + +### Internal / Lab: insecure registry + +If you run NORA without TLS (e.g., on a private network), configure Docker to trust it: + +```json +// /etc/docker/daemon.json +{ + "insecure-registries": ["192.168.1.100:4000"] +} +``` + +Then restart Docker: + +```bash +sudo systemctl restart docker +``` + +> **Note:** `insecure-registries` disables TLS verification for that host. Use only on trusted networks. + +## FSTEC-Certified OS Builds + +NORA provides dedicated Dockerfiles for Russian FSTEC-certified operating systems: + +- `Dockerfile.astra` — Astra Linux SE (for government and defense sector) +- `Dockerfile.redos` — RED OS (for enterprise and public sector) + +Both use `scratch` base with statically-linked binary for minimal attack surface. Comments in each file show how to switch to official distro base images if required by your security policy. + +These builds are published as `-astra` and `-redos` tagged images in GitHub Releases. + ## Performance | Metric | NORA | Nexus | JFrog | diff --git a/docker-compose.yml b/docker-compose.yml index 621a703..8f51ae3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ services: nora: build: . - image: getnora/nora:latest + image: ghcr.io/getnora-io/nora:latest ports: - "4000:4000" volumes: