authtoken

package
v0.8.59 Latest Latest
Warning

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

Go to latest
Published: Aug 11, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package authtoken issues, stores, and resolves the operator bearer tokens that carry the Dejima team-auth model: three built-in roles (owner / operator / viewer) and an optional per-island scope. A token is presented on the operator API surface (the unix socket and the tailnet-pinned TCP listener) via an "Authorization: Bearer <token>" header — it *complements* the tailnet identity, it does not replace it: a request with no token is still the fully-trusted caller, while a request that carries one is attenuated to that token's role + island scope.

This is the exchange-down boundary for the layers *above* the runtime (Scusi, a Slack bot, any control plane): the human authenticates with full authority, then mints a strictly-narrower service token to hand to an automated caller — never its own credential (docs/security-boundary.md). The roles only ever *decrease* authority; there is no token that grants more than the trusted listener already does.

These tokens are distinct from the per-island tokens in internal/porttoken: porttoken authorizes an in-island *brain* on the host-internal autonomy listener (exchange-down into a container); authtoken authorizes an *operator* client on the control-plane listeners. The two stores never cross — a token from one is meaningless to the other's middleware.

At rest (~/.dejima/tokens.json, 0600) only token *metadata* and the SHA-256 of each secret are kept; the raw bearer is shown exactly once, at creation. A leaked store therefore can't be replayed.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Revoke

func Revoke(id string) (bool, error)

Revoke deletes a token by id. Returns ok=false if no such token existed.

func ValidRole

func ValidRole(r Role) bool

ValidRole reports whether r is one of the three built-in roles.

Types

type Identity

type Identity struct {
	// TokenID is the issuing token's id, or "" for the trusted no-token caller.
	TokenID string
	// Subject is a short human label for the actor (the token label, its id, or
	// "local" for the trusted caller) — what an audit record names.
	Subject string
	Role    Role
	// Owner is the tenant this identity acts as (multi-tenant ownership). A
	// non-owner may only touch islands whose owner matches; the host owner
	// (RoleOwner) bypasses via OwnsAll.
	Owner string
	// Islands is the token's island scope; empty means unrestricted (all islands).
	Islands []string
}

Identity is the resolved who/role for an authenticated request. The API layer puts it on the request context so handlers — and Lane 1's audit log — can attribute and authorize. The zero Identity is meaningless; callers get one only from Resolve or by constructing the trusted-owner default explicitly.

func Resolve

func Resolve(secret string) (Identity, bool)

Resolve maps a presented bearer secret to its Identity. It hashes the input and compares against every stored hash in constant time (no early-out timing leak of which token, or how many, exist). ok=false for an empty or unknown token. A present-but-unknown token must be treated as an authentication failure by the caller — never as the trusted no-token caller.

func (Identity) MayTouch

func (i Identity) MayTouch(island string) bool

MayTouch reports whether this identity's island scope permits acting on the named island. An unscoped identity (the common case) may touch any island.

func (Identity) OwnsAll added in v0.8.3

func (i Identity) OwnsAll() bool

OwnsAll reports the host-admin bypass: a RoleOwner identity (the local socket or an owner token) sees and manages every island regardless of its owner.

func (Identity) Scoped

func (i Identity) Scoped() bool

Scoped reports whether this identity is limited to a subset of islands.

type Role

type Role string

Role is one of the three built-in roles. Authority decreases owner → operator → viewer; the middleware (internal/api) maps each route to the minimum role that may reach it.

const (
	// RoleOwner is full authority — the same surface a trusted (no-token) caller
	// has, including destructive ops (purge), credential management, and token
	// administration. Mint sparingly.
	RoleOwner Role = "owner"
	// RoleOperator may drive island lifecycle (create, hibernate/wake, reset,
	// upgrade, clone, exec, attach, Port/capability grants) but NOT purge an
	// island, manage credentials/tokens, or touch daemon administration.
	RoleOperator Role = "operator"
	// RoleViewer is read + observe only: list/status/overview/logs/events/audit.
	// No mutation, no interactive attach.
	RoleViewer Role = "viewer"
)

type Token

type Token struct {
	ID    string `json:"id"`              // short public handle; revoke by this
	Label string `json:"label,omitempty"` // human note ("scusi-prod", "phone")
	Role  Role   `json:"role"`            // owner | operator | viewer
	// Owner is the tenant this token acts as (multi-tenant ownership). An
	// operator/viewer token scoped to owner "amanda" may only see/act on islands
	// amanda owns; a RoleOwner token is the host admin and sees all regardless.
	// Set at mint (defaults to the host owner); server-authoritative, never
	// client-supplied on a request.
	Owner     string    `json:"owner,omitempty"`
	Islands   []string  `json:"islands,omitempty"` // static scope; empty = every island (still bounded by Owner)
	Hash      string    `json:"hash"`              // sha-256 hex of the secret
	CreatedAt time.Time `json:"created_at"`
}

Token is the stored metadata for one issued bearer token. The secret itself is never persisted — only Hash (its SHA-256) — so the store can list and revoke tokens without ever holding a replayable credential.

func Create

func Create(label string, role Role, islands []string, owner string) (secret string, tok Token, err error)

Create mints a fresh token: a 256-bit random secret returned to the caller exactly once, plus persisted metadata (role, scope, the secret's hash). The raw secret is never stored. islands scopes the token to those island names (empty = unrestricted). Returns the secret and the stored Token.

func List

func List() ([]Token, error)

List returns every issued token's metadata (never a secret), newest first.

Jump to

Keyboard shortcuts

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