Skip to main content

Security Model

Angos implements defense-in-depth security with multiple layers of protection.

Security Layers​


Trust Boundaries​

External Boundary​

Between clients and registry:

  • TLS encryption (required for production)
  • Authentication credentials
  • Rate limiting via concurrency control

Internal Boundary​

Between registry and storage:

  • Separate credentials for S3
  • Redis authentication for the cache
  • Network isolation recommended

Upstream Boundary​

Between registry and upstream registries:

  • Credential management
  • Certificate validation
  • Content verification

Fail-Closed Design​

Angos implements fail-closed authorization for critical security decisions:

ScenarioBehavior
No policies definedAccess denied (fail-closed)
No authentication providedProceeds as anonymous identity
Webhook timeout or unreachableAccess denied (fail-closed)
Webhook 429 / 5xxAccess denied (fail-closed)
Webhook not configuredNot evaluated, access continues
Invalid mTLS certificateTLS handshake fails
No client cert, client_auth = "required"TLS handshake fails
Invalid OIDC token401 Unauthorized (fail-closed)
Invalid Basic Auth password401 Unauthorized (fail-closed)
CEL evaluation errorAccess denied (fail-closed)
CEL non-boolean result (any mode)Access denied (fail-closed)

Important: Without authentication, requests proceed with an anonymous identity. Without access policies, the default behavior is to deny access (default = "deny"). To allow anonymous reads, you must explicitly configure access policies with appropriate rules.

Policy Defaults​

# Recommended: explicit allow
[global.access_policy]
default = "deny"
rules = ["identity.username != null"]

Without any policies, all access is denied.


No Unsafe Code​

#![forbid(unsafe_code)]

The entire codebase forbids unsafe Rust, eliminating memory safety vulnerabilities:

  • No buffer overflows
  • No use-after-free
  • No null pointer dereferences
  • No data races

Cryptographic Security​

Password Storage​

Argon2id with strong parameters:

  • Memory-hard (resists GPU attacks)
  • Time-cost balanced for security/performance
  • Salt per-password
./angos argon
# Generates: $argon2id$v=19$m=19456,t=2,p=1$...

A rejected credential is held to a one-second floor whatever made it fail, and an unknown username is verified against a configured hash rather than discarded. Response timing therefore separates neither an unknown username from a wrong password nor one identity's hash cost from another's, and a guessing loop gets one attempt a second per connection.

JWT Validation​

OIDC tokens are fully verified:

  • Signature against provider's JWKS
  • Per-provider algorithm allowlist before signature verification, defaulting to RS256
  • One cache-bypassing JWKS refresh when a cached key set misses a token kid
  • An issuer that does not answer is remembered for a minute, so an outage costs one connection attempt per minute rather than one per request; a refusal is not remembered, since two provider entries can share an issuer
  • Issuer claim required and must match
  • Audience claim required and must match when required_audience is set, unvalidated otherwise
  • Expiration enforced
  • Clock skew tolerance configurable

Registry Tokens​

Tokens the token service issues are HMAC-signed with a key of at least 32 bytes and their algorithm is pinned, so a token claiming another algorithm is never verified with the signing key. They carry the identity but never the client certificate or IP, which keeps a certificate-bound identity from becoming a replayable bearer credential.

A token cannot be revoked before it expires: ttl_secs, capped at a day, is the window a stolen one stays usable. Nor can it be exchanged for a fresh one at /token, so that window never extends itself past the credential the token was minted from. Rotating secret_key, or removing the credential a token names, invalidates outstanding tokens: the OIDC provider for a token minted from one, the [auth.identity] entry for a token minted from basic auth. Authorization is unaffected, since policies are evaluated per request against live configuration rather than frozen into the token.

The token is not scope-bound either. Where the registry v2 model narrows a token to one repository and a set of actions through an access claim, angos puts the identity in the token, so a stolen one reaches everything that identity reaches. What bounds it is the per-request policy evaluation above: the token grants no more than the credential it replaced, just over a wider surface than a scoped token would.

That spec's claim set (iss, sub, aud, nbf, jti, access) and its kid header exist so a registry can verify tokens minted by a separate authorization server. Angos is both issuer and verifier, so its token is opaque to clients and carries only the identity it restores.

TLS Configuration​

Server TLS with modern defaults:

  • TLS 1.2+ only
  • Strong cipher suites
  • Certificate chain validation

Input Validation​

OCI Compliance​

All inputs validated against OCI specification:

  • Digest format validation
  • Reference format validation
  • Media type validation
  • Manifest structure validation

Request Validation​

  • Path traversal prevention
  • Size limits on uploads
  • Timeout enforcement
  • Content-type validation

Content Integrity​

Content Addressing​

All content addressed by cryptographic hash:

  • SHA-256 (default)
  • SHA-512 (supported)
  • No mutable references to content

Verification Flow​

Immutable Content​

Once stored, blobs are immutable:

  • Same digest = same content
  • Prevents tampering
  • Enables caching

Authorization Security​

CEL Sandboxing​

CEL expressions run in a sandboxed environment:

  • No file system access
  • No network access
  • No code execution
  • Deterministic evaluation

Webhook Security​

Webhook calls are secured:

  • HTTPS recommended
  • Authentication (Bearer, Basic, mTLS)
  • Timeout enforcement
  • Certificate validation

Secrets Management​

Configuration​

Sensitive values in configuration:

  • Stored on disk (protect with file permissions)
  • Not logged
  • Automatically cleared from memory when dropped (zeroize)

Recommendations​

  1. Keep credentials in a separate configuration file and pass both with -c, so the file your deployment tooling renders holds no secrets
  2. Use Kubernetes Secrets or similar for that file
  3. Restrict file permissions on config
  4. Rotate credentials regularly

Angos reads no credentials from environment variables. An environment is fixed when the process starts, so a rotated secret would need a restart, and it is readable through /proc/<pid>/environ and core dumps. A credentials file is watched like any other configuration file, so rotating it applies without a restart.


Audit Trail​

Logging​

Security-relevant events are logged:

  • Authentication attempts (success/failure)
  • Authorization decisions
  • Configuration changes

Metrics​

Security metrics exposed:

  • auth_attempts_total{method, result}
  • webhook_authorization_requests_total{webhook, result}

Network Security​

Recommendations​

  1. TLS everywhere: Always enable TLS in production
  2. Network isolation: Separate registry network from public
  3. Firewall rules: Restrict access to necessary ports
  4. Private endpoints: Use VPC endpoints for S3

Internal Services​

Redis and S3 should be:

  • On private network
  • Authenticated
  • Encrypted in transit

Operational Security​

Configuration Reloading​

  • Configuration changes logged
  • Invalid configurations rejected
  • Certificates reload without restart

Storage Maintenance​

  • Run scrub with least privilege
  • Audit what's deleted
  • Use dry-run first

Monitoring​

Detect anomalies:

  • Unusual authentication failures
  • Unexpected webhook denials
  • High error rates

Security Checklist​

Deployment​

  • TLS enabled with valid certificates
  • Strong passwords for basic auth (use argon)
  • Access policies configured
  • Webhook authentication configured
  • Redis authentication enabled (if used)
  • S3 credentials properly secured

Operations​

  • Logs monitored for security events
  • Metrics alerting configured
  • Certificate rotation automated
  • Regular security updates applied
  • Backup and recovery tested

Policies​

  • default = "deny"
  • Minimum necessary access granted
  • Production/development separated
  • Delete operations restricted

Vulnerability Reporting​

Report security issues to: https://github.com/project-angos/angos/security

Do not open public issues for security vulnerabilities.