Documentation
¶
Overview ¶
Package ocitoken mints the bearer tokens an OCI registry (CNCF Distribution, "token" auth) accepts: a short-lived JWT whose `access` claim names exact repositories and the actions allowed on each. The registry verifies a token by itself, against a certificate it was started with — it never calls back.
The chassis admin plane is the token service: a signed admin request already says who is asking and for which tenant, so the handler (chassis/server/admin/registry_token.go) decides WHAT may be granted and this package only parses the request's scopes and signs the answer.
Tokens are ES256 with the signer's certificate in the `x5c` header. A registry accepts an x5c leaf that is byte-identical to an entry of its rootcertbundle, so one self-signed certificate is the whole trust relationship, and the same token verifies on Distribution 2.8 and 3.x (which stopped matching the older `kid` form).
Index ¶
Constants ¶
const ( DefaultTTL = 300 * time.Second MinTTL = 60 * time.Second MaxTTL = 900 * time.Second )
TTL bounds. A token is a bearer credential for a push: long enough for a large upload to start, short enough that a leaked one is worth little.
const MaxRepositoryLen = 255
MaxRepositoryLen is the longest repository name a registry takes.
Variables ¶
This section is empty.
Functions ¶
func LoadPEM ¶
LoadPEM returns the PEM for a caller holding either a file's bytes or its base64 (a secret store that keeps values, not files). The base64, when given, wins.
func Namespace ¶
Namespace splits a repository name at its FIRST slash: the namespace, and the package's name within it (which may itself be a path).
func ValidateRepository ¶
ValidateRepository checks a repository name against the OCI grammar and requires a namespace: at least `<namespace>/<name>`.
Types ¶
type Access ¶
type Access struct {
Type string `json:"type"`
Name string `json:"name"`
Actions []string `json:"actions"`
}
Access is one entry of a token's `access` claim: a resource and what may be done to it.
func ParseScope ¶
ParseScope reads one scope as a registry challenge states it, `<type>:<name>:<action>[,<action>…]` (`repository:acme/tool:pull,push`). The type is what precedes the first colon and the actions what follows the last, so a name may itself hold one. Actions come back sorted and de-duplicated. It checks the shape only: which types, names and actions may be granted is the caller's decision.
type Config ¶
type Config struct {
// KeyPEM is an ECDSA P-256 private key, PKCS#8 ("PRIVATE KEY") or SEC1
// ("EC PRIVATE KEY"). An "EC PARAMETERS" block, as `openssl ecparam
// -genkey` writes, is skipped.
KeyPEM []byte
// CertPEM is the key's certificate: exactly one CERTIFICATE block, the
// same bytes the registry holds as its rootcertbundle.
CertPEM []byte
// Issuer is the `iss` claim (the registry's auth.token.issuer).
Issuer string
// Service is the `aud` claim (the registry's auth.token.service).
Service string
// TTL is a token's lifetime; zero is DefaultTTL, and it is clamped to
// [MinTTL, MaxTTL].
TTL time.Duration
}
Config is what a Signer is loaded from.
type Signer ¶
type Signer struct {
// Fingerprint is the hex SHA-256 of the certificate's DER: what an
// operator compares against the registry's bundle.
Fingerprint string
// NotAfter is when the certificate, and so every token, stops verifying.
NotAfter time.Time
// contains filtered or unexported fields
}
Signer mints tokens. Safe for concurrent use.
func Load ¶
Load builds a Signer, refusing anything a registry would later refuse a token for: a key that is not P-256, a certificate that is not this key's, or one outside its validity at `now`.
func (*Signer) Mint ¶
Mint signs a token granting `access` to `sub`. tenantID is carried for the registry's log and a later audit; the registry does not read it.