Documentation
¶
Index ¶
Constants ¶
const IdentityTokenPrefix = "aocrwrap:"
IdentityTokenPrefix is the sentinel AOCR's auth service uses to route `aocrwrap:<blob>` strings through the wrap-validation path rather than the static-PAT or cluster-PAT paths. Anything starting with this prefix is treated as a wrapped upstream credential.
Variables ¶
This section is empty.
Functions ¶
func WrapUpstreamCreds ¶
func WrapUpstreamCreds(ring *UpstreamWrapKeyRing, creds UpstreamCredentials) (string, error)
WrapUpstreamCreds seals `creds` with the current key in `ring` and returns a Docker `identitytoken` value of the form `aocrwrap:<base64url>`. AOCR's auth service unwraps and probes the upstream registry with the embedded credentials.
The blob layout is AES-256-GCM `nonce(12) || ciphertext || tag(16)`, then base64url. AOCR's `unwrap` reads exactly this format.
Types ¶
type Cipher ¶
type Cipher struct {
// contains filtered or unexported fields
}
Cipher seals and opens user-supplied secrets (cloud credentials for sandbox mounts) using AES-256-GCM. The seal format is `nonce(12) || ciphertext+tag`. The key never leaves this package; sealed bytes are what crosses other trust boundaries (DB, logs, error messages).
func NewCipher ¶
NewCipher constructs a Cipher from either an explicit key (base64-encoded, must decode to 32 bytes) or a fallback file path. If the explicit key is empty and the fallback path does not exist, a fresh 32-byte key is generated and persisted at the path with mode 0600.
func (*Cipher) Decrypt ¶
Decrypt opens a sealed blob produced by Encrypt. Tampering, truncation, or using a different key all return an error.
func (*Cipher) DecryptWithAAD ¶
type UpstreamCredentials ¶
type UpstreamCredentials struct {
UpstreamHost string `json:"upstreamHost"`
Username string `json:"username"`
Password string `json:"password"`
Scope string `json:"scope"`
}
UpstreamCredentials is the plaintext shape AOCR's auth service expects inside a wrapped blob. Field names are JSON-serialized as-is; they must match `auth/src/upstreamAuth/wrap.ts` exactly or the round-trip breaks.
`Scope` pins the wrap to a specific Distribution token-server scope string (e.g. `repository:aocr/ghcr/org/repo:pull`). AOCR cross-checks the scope inside the blob against the scope on the `/v2/token` request, so a leaked blob cannot be reused for a different repo.
type UpstreamWrapKey ¶
UpstreamWrapKey is one key in the rotation ring. `ID` is a short, human- readable identifier surfaced in metrics and logs; the cryptographic material is `Bytes`. The wire format on AOCR's side and ours must agree exactly: 32-byte AES-256 keys, base64 (standard alphabet), optionally prefixed with `<id>:`.
type UpstreamWrapKeyRing ¶
type UpstreamWrapKeyRing struct {
Keys []UpstreamWrapKey
}
UpstreamWrapKeyRing holds the ordered list of wrap keys. The first entry is the *current* key used for wrapping new tokens; all entries are kept available for unwrap (here only as a future-proofing detail — sandboxd only wraps, never unwraps — but matching AOCR's structure keeps the two sides interchangeable).
Rotation policy: prepend a new key (`new:<b64>,old:<b64>`) on every node, wait one full token lifetime so any in-flight wrapped credentials have expired on the AOCR side, then drop the old entry. See the `rotate-upstream-wrap-key.yml` playbook for the operator flow.
func LoadUpstreamWrapKeyRing ¶
func LoadUpstreamWrapKeyRing(path string) (*UpstreamWrapKeyRing, error)
LoadUpstreamWrapKeyRing reads the wrap key file at `path` and parses it into a key ring. The file must be mode 0400 (owner-readable only); any looser mode is refused at load time to prevent operator-mistake leaks via world-readable home directories or `cp -p` from a wide-mode source.
The file body is a comma-separated list of `<b64>` or `<id>:<b64>` entries — same format as the AOCR side's `UPSTREAM_AUTH_WRAP_KEYS` env var. Whitespace around commas is tolerated. Malformed entries are silently dropped (matching AOCR behavior) so a partial-bad rotation does not break the node entirely, but the final ring must have at least one valid key or LoadUpstreamWrapKeyRing returns an error.
If the file does not exist, LoadUpstreamWrapKeyRing returns `os.ErrNotExist` wrapped so callers can fall through to "wrap keys not configured" without treating it as fatal — the daemon may still run for public images.
func ParseUpstreamWrapKeyRing ¶
func ParseUpstreamWrapKeyRing(raw string) *UpstreamWrapKeyRing
ParseUpstreamWrapKeyRing parses the comma-separated wrap-key format. Public so callers (tests, config validators) can validate a string without writing it to disk.
func (*UpstreamWrapKeyRing) Current ¶
func (r *UpstreamWrapKeyRing) Current() (UpstreamWrapKey, bool)
Current returns the active wrap key. Callers should not cache the returned key across reloads.