serviceaccount

package
v0.30.5 Latest Latest
Warning

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

Go to latest
Published: Nov 2, 2026 License: MIT Imports: 24 Imported by: 0

Documentation

Overview

Package serviceaccount manages service accounts: service principals that belong to one organization, hold application roles there like a member, and authenticate with key pairs through the RFC 7523 JWT-bearer grant (ADR-016).

A service account is a Principal of type service whose organization_id is its organization, with a ServicePrincipal row of service type "service_account" and an active membership in the organization with the role "service_account". Its identifier, "sa_" and 26 random characters, is the issuer and subject of the assertions it signs. SystemAuth stores only its public keys, as key-pair credentials.

Ending access goes through the usual paths and is recorded as an access change (ADR-010): Disable and Delete deactivate the principal (Deactivated), RemoveRole removes an application role (AppRoleChanged), and revoking a usable key records SessionsRevoked.

Index

Constants

View Source
const (
	AlgorithmES256 = "ES256"
	AlgorithmRS256 = "RS256"
	AlgorithmEdDSA = "EdDSA"
)

Key algorithms a service account key may use.

View Source
const (
	// MembershipRole is the membership role of a service account in its
	// organization, shown as "Service account".
	MembershipRole = "service_account"
	// ServiceType is the service type of a service account's
	// ServicePrincipal row.
	ServiceType = "service_account"
	// IdentifierPrefix starts every service account identifier.
	IdentifierPrefix = "sa_"
)
View Source
const EventServiceAccount = "service_account"

EventServiceAccount is the event type of the security events the service records through Config.Audit. The action says what changed: created, disabled, enabled, deleted, key_added, key_revoked, role_granted or role_removed. No event carries key material.

View Source
const MinRSABits = 2048

MinRSABits is the shortest RSA key accepted.

Variables

View Source
var (
	// ErrNotFound means the ID names no service account.
	ErrNotFound = errors.New("serviceaccount: service account not found")
	// ErrKeyNotFound means the account has no key with the key ID.
	ErrKeyNotFound = errors.New("serviceaccount: key not found")
	// ErrOrganizationNotFound means the organization does not exist.
	ErrOrganizationNotFound = errors.New("serviceaccount: organization not found")
	// ErrOrganizationInactive means the organization was deleted.
	ErrOrganizationInactive = errors.New("serviceaccount: organization is not active")
	// ErrPersonalOrganization means the organization is personal, and a
	// personal organization has no service accounts.
	ErrPersonalOrganization = errors.New("serviceaccount: a personal organization cannot have service accounts")
	// ErrNameRequired means CreateInput.Name is empty.
	ErrNameRequired = errors.New("serviceaccount: name is required")
	// ErrInvalidKey means a public key cannot be used: unparsable, of an
	// unsupported type or algorithm, an RSA key shorter than 2048 bits, or
	// an expiry in the past.
	ErrInvalidKey = errors.New("serviceaccount: invalid key")
)

Errors returned by the service.

Functions

func NewIdentifier

func NewIdentifier() string

NewIdentifier returns a fresh service account identifier: "sa_" and 26 random lowercase base32 characters.

func ParsePublicKeyPEM

func ParsePublicKeyPEM(s string) (any, error)

ParsePublicKeyPEM parses a PEM "PUBLIC KEY" (PKIX) or "RSA PUBLIC KEY" (PKCS #1) block into an *ecdsa.PublicKey, *rsa.PublicKey or ed25519.PublicKey.

Types

type Account

type Account struct {
	ID             uuid.UUID  `json:"id"`
	Identifier     string     `json:"identifier"`
	Name           string     `json:"name"`
	Description    string     `json:"description,omitempty"`
	OrganizationID uuid.UUID  `json:"organization_id"`
	Active         bool       `json:"active"`
	AllowedScopes  []string   `json:"allowed_scopes,omitempty"`
	CreatedBy      *uuid.UUID `json:"created_by,omitempty"`
	LastUsedAt     *time.Time `json:"last_used_at,omitempty"`
	CreatedAt      time.Time  `json:"created_at"`
}

Account is a service account.

type Config

type Config struct {
	// Client is the identity database. Required.
	Client *ent.Client
	// Principals creates, deactivates and reactivates principals. Use the
	// host's principal service so authorization syncing and access-change
	// announcements follow its options. Required; principal.NewService's
	// result implements it.
	Principals principal.Service
	// Credentials stores key-pair credentials. Default:
	// credential.NewService(Client).
	Credentials credential.Service
	// Roles manages application roles. Required for GrantRole, RemoveRole
	// and Delete.
	Roles *approle.Service
	// AccessChangeSink announces the access changes the service itself
	// records (revoking a key) after they commit.
	AccessChangeSink accesschange.Sink
	// Logger records operator actions. Default: slog.Default().
	Logger *slog.Logger
	// Audit records security events (EventServiceAccount) for account,
	// key and role changes. Optional.
	Audit audit.Emitter
}

Config holds the service's dependencies.

type CreateInput

type CreateInput struct {
	OrganizationID uuid.UUID
	Name           string
	Description    string
	// Scopes are the scopes the account may be granted; a token's scopes
	// are the requested ones intersected with these and its key's.
	Scopes []string
	// CreatedBy is the operator's principal ID; uuid.Nil records none.
	CreatedBy uuid.UUID
}

CreateInput describes a new service account.

type Key

type Key struct {
	CredentialID uuid.UUID  `json:"credential_id"`
	KeyID        string     `json:"key_id"`
	Algorithm    string     `json:"algorithm"`
	PublicKeyPEM string     `json:"public_key_pem"`
	Name         string     `json:"name,omitempty"`
	Scopes       []string   `json:"scopes,omitempty"`
	Active       bool       `json:"active"`
	Revoked      bool       `json:"revoked"`
	ExpiresAt    *time.Time `json:"expires_at,omitempty"`
	RevokedAt    *time.Time `json:"revoked_at,omitempty"`
	LastUsedAt   *time.Time `json:"last_used_at,omitempty"`
	LastUsedIP   string     `json:"last_used_ip,omitempty"`
	CreatedAt    time.Time  `json:"created_at"`

	// PrivateKeyPEM is the PKCS #8 private key, set only on the Key AddKey
	// returns for a generated key pair. It is never stored; it is not
	// serialized, so it cannot leak through a JSON listing.
	PrivateKeyPEM string `json:"-"`
}

Key is a service account key.

func (*Key) Usable

func (k *Key) Usable(now time.Time) bool

Usable reports whether the key can authenticate at now: active, unrevoked and unexpired.

type KeyInput

type KeyInput struct {
	// PublicKeyPEM is a PEM "PUBLIC KEY" (PKIX) or "RSA PUBLIC KEY"
	// (PKCS #1) block. Empty generates a key pair.
	PublicKeyPEM string
	// Algorithm is ES256 (P-256), RS256 (RSA, 2048 bits or more) or
	// EdDSA (Ed25519). Empty takes it from the key.
	Algorithm string
	// Name labels the key.
	Name string
	// Scopes limit the key; empty means the account's allowed scopes.
	Scopes []string
	// ExpiresAt is when the key stops working; nil means never.
	ExpiresAt *time.Time
}

KeyInput describes a key to add. With PublicKeyPEM empty, AddKey generates a P-256 key pair and returns the private key once.

type PrincipalService

type PrincipalService interface {
	principal.ServiceTxCreator
	Deactivate(ctx context.Context, id uuid.UUID) error
	Reactivate(ctx context.Context, id uuid.UUID) error
}

PrincipalService is what the service needs of identity/principal. principal.DefaultService implements it.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service manages service accounts.

func New

func New(cfg Config) (*Service, error)

New returns a Service. It fails when Client or Principals is missing, or when Principals cannot create a service principal in a transaction.

func (*Service) AddKey

func (s *Service) AddKey(ctx context.Context, id uuid.UUID, in KeyInput) (*Key, error)

AddKey registers a public key for the account, or generates a P-256 key pair and returns its private key once in Key.PrivateKeyPEM.

func (*Service) Create

func (s *Service) Create(ctx context.Context, in CreateInput) (*Account, error)

Create creates a service account in an active, non-personal organization: the service principal, its ServicePrincipal row recording who created it, and its service_account membership, in one transaction.

The membership is not written to the authorization graph: applications see the account through its application roles and the orgs claim.

func (*Service) Delete

func (s *Service) Delete(ctx context.Context, id, by uuid.UUID) error

Delete deactivates the account (recording Deactivated if it was active), removes its application roles, then deletes its keys, membership and principal.

func (*Service) Disable

func (s *Service) Disable(ctx context.Context, id, by uuid.UUID) error

Disable deactivates the account, which records a Deactivated access change: its tokens stop at once in applications with a revocation cache, and no new token is issued.

func (*Service) Enable

func (s *Service) Enable(ctx context.Context, id, by uuid.UUID) error

Enable reactivates a disabled account.

func (*Service) Get

func (s *Service) Get(ctx context.Context, id uuid.UUID) (*Account, error)

Get returns a service account.

func (*Service) GrantRole

func (s *Service) GrantRole(ctx context.Context, id uuid.UUID, application, role string, by uuid.UUID) error

GrantRole gives the account a role in an application of its organization, replacing the role it held there.

func (*Service) List

func (s *Service) List(ctx context.Context, organizationID uuid.UUID) ([]*Account, error)

List returns the organization's service accounts, oldest first.

func (*Service) ListKeys

func (s *Service) ListKeys(ctx context.Context, id uuid.UUID) ([]*Key, error)

ListKeys returns the account's keys, newest first, including revoked and expired ones.

func (*Service) RemoveRole

func (s *Service) RemoveRole(ctx context.Context, id uuid.UUID, application string, by uuid.UUID) error

RemoveRole removes the account's role in an application, which records an AppRoleChanged access change.

func (*Service) RevokeKey

func (s *Service) RevokeKey(ctx context.Context, id uuid.UUID, keyID, reason string) error

RevokeKey revokes one of the account's keys. When the key was usable, a SessionsRevoked access change is recorded with it, so the account's current tokens, which may have been obtained with it, stop at once in applications with a revocation cache; a workload holding another key gets a new token. Revoking a revoked key does nothing.

Directories

Path Synopsis
Package serviceaccountcmd provides the "service-account" cobra command a host CLI mounts to manage service accounts: create, list, show, disable, enable and delete accounts; add, list and revoke their keys; and grant and remove their application roles.
Package serviceaccountcmd provides the "service-account" cobra command a host CLI mounts to manage service accounts: create, list, show, disable, enable and delete accounts; add, list and revoke their keys; and grant and remove their application roles.

Jump to

Keyboard shortcuts

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