Help us shape the future of Go! Take the 2026 Go Developer Survey

serviceaccount

package
v0.27.0 Latest Latest
Warning

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

Go to latest
Published: Oct 29, 2026 License: MIT Imports: 23 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 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
}

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