secrets

package
v0.7.21 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 21, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Index

Constants

View Source
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

func NewCipher(keyB64, fallbackPath string) (*Cipher, error)

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

func (c *Cipher) Decrypt(sealed []byte) ([]byte, error)

Decrypt opens a sealed blob produced by Encrypt. Tampering, truncation, or using a different key all return an error.

func (*Cipher) DecryptWithAAD

func (c *Cipher) DecryptWithAAD(sealed []byte, aad []byte) ([]byte, error)

func (*Cipher) Encrypt

func (c *Cipher) Encrypt(plain []byte) ([]byte, error)

Encrypt seals plaintext. Empty input is allowed and produces a non-empty sealed blob (the nonce alone authenticates that no plaintext was sealed).

func (*Cipher) EncryptWithAAD

func (c *Cipher) EncryptWithAAD(plain []byte, aad []byte) ([]byte, error)

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

type UpstreamWrapKey struct {
	ID    string
	Bytes []byte
}

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL