Documentation
¶
Overview ¶
Package token makes and reads the tokens a client presents to a daemon's TCP listener, and manages the daemon's record of them.
A token is Prefix and a secret, usually followed by an underscore and the daemon's fingerprint:
dicer_<secret>_<fingerprint>
The daemon checks the secret, and keeps only its SHA-256. The client checks the fingerprint, the SHA-256 of the daemon's public key, so that it never sends the secret to anyone else. A token has no fingerprint when the daemon's certificate is one clients verify for themselves. A token holds no address: the client says where the daemon is.
Index ¶
- Constants
- Variables
- func Fingerprint(cert *x509.Certificate) string
- func Format(secret, fingerprint string) string
- func NewSecret() string
- func Parse(s string) (secret, fingerprint string, err error)
- func SecretSHA256(secret string) string
- func ValidateSecret(s string) error
- type Config
- type Manager
- func (m *Manager) Create(name, secret string, scopes []Scope) (Token, string, error)
- func (m *Manager) Delete(nameOrID string) error
- func (m *Manager) RecordUse(nameOrID string, at time.Time) error
- func (m *Manager) Rotate(nameOrID, secret string) (Token, string, error)
- func (m *Manager) Token(nameOrID string) (Token, error)
- func (m *Manager) TokenBySecret(secret string) (Token, error)
- func (m *Manager) Tokens() []Token
- type Scope
- type Store
- type Token
Constants ¶
const (
// MinSecretLength is the fewest characters a secret may have.
MinSecretLength = 32
)
const Prefix = "dicer_"
Prefix starts every token, so that a token is recognised for what it is, by a person or by a secret scanner.
Variables ¶
var ErrInvalid = errors.New("invalid token")
ErrInvalid is a string that is not a token, or a secret that cannot be one's.
Functions ¶
func Fingerprint ¶
func Fingerprint(cert *x509.Certificate) string
Fingerprint returns the fingerprint of the public key cert holds: its SHA-256, hex-encoded. A certificate renewed with the same key keeps it.
func Format ¶
Format returns the token for a secret and the daemon's fingerprint. An empty fingerprint leaves it out.
func Parse ¶
Parse returns a token's secret and the fingerprint it holds, if any. It returns an error wrapping ErrInvalid if s is not a token.
func SecretSHA256 ¶
SecretSHA256 returns the SHA-256 of a secret, hex-encoded: what the daemon keeps in its place.
func ValidateSecret ¶
ValidateSecret returns an error wrapping ErrInvalid unless s can be a token's secret: at least MinSecretLength letters and digits.
Types ¶
type Config ¶
type Config struct {
// Store keeps the tokens. It is required.
Store Store
}
Config configures a Manager.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager creates, rotates and deletes tokens, and finds the token a secret belongs to. It keeps only each secret's SHA-256. It is safe for concurrent use.
func (*Manager) Create ¶
Create records a token named name with scopes, and returns it with its secret, the only time the secret is returned. An empty secret is replaced by a new one. A secret another token has is refused with an errdefs.ErrExists error.
func (*Manager) Rotate ¶
Rotate gives a token a new secret, and returns it with that secret. An empty secret is replaced by a new one. The old secret no longer works.
func (*Manager) TokenBySecret ¶
TokenBySecret returns the token whose secret is secret, or an errdefs.ErrNotFound error if there is none.
type Scope ¶
type Scope string
Scope is what a token allows: ScopeAll, or an action on a kind of resource, written RESOURCE:ACTION. A read scope allows the calls that only look at its resource. A write scope also allows those that change it.
const ( ScopeInstancesRead Scope = "instances:read" ScopeInstancesWrite Scope = "instances:write" ScopeSnapshotsRead Scope = "snapshots:read" ScopeSnapshotsWrite Scope = "snapshots:write" ScopeNetworksRead Scope = "networks:read" ScopeNetworksWrite Scope = "networks:write" ScopeVolumesRead Scope = "volumes:read" ScopeVolumesWrite Scope = "volumes:write" ScopeImagesRead Scope = "images:read" ScopeImagesWrite Scope = "images:write" ScopeKernelsRead Scope = "kernels:read" ScopeKernelsWrite Scope = "kernels:write" ScopeTokensRead Scope = "tokens:read" ScopeTokensWrite Scope = "tokens:write" ScopeEventsRead Scope = "events:read" )
The scopes of each kind of resource. Events, the log of what happens to every other resource, can only be read.
const ScopeAll Scope = "*"
ScopeAll allows everything, now and as the API grows.
type Store ¶
type Store interface {
CreateToken(t Token) error
Token(nameOrID string) (Token, error)
TokenBySecretSHA256(secretSHA256 string) (Token, error)
Tokens() []Token
UpdateToken(t Token) error
RecordTokenUse(nameOrID string, at time.Time) error
DeleteToken(nameOrID string) error
}
Store keeps the tokens.
type Token ¶
type Token struct {
ID string `yaml:"id"`
Name string `yaml:"name"`
// SecretSHA256 is the SHA-256 of the token's secret, hex-encoded.
SecretSHA256 string `yaml:"secret_sha256"`
// Scopes are what the token allows.
Scopes []Scope `yaml:"scopes"`
CreatedAt time.Time `yaml:"created_at"`
UpdatedAt time.Time `yaml:"updated_at"`
// LastUsedAt is when the token last made a call, to the minute. It is
// zero for a token never used.
LastUsedAt time.Time `yaml:"last_used_at,omitempty"`
}
Token is a credential a client presents to the daemon's TCP listener. The daemon keeps the SHA-256 of its secret, never the secret itself.
func (Token) Allows ¶
Allows reports whether the token's scopes allow scope: it has ScopeAll, scope itself, or, for a read scope, the write scope of the same resource.