mirror of
https://github.com/hanzoai/o11y.git
synced 2026-10-15 12:58:33 +00:00
An op learns its address from zip.OpOf and zip.AddressOf, so the claim table, the five declaring verbs and the address bookkeeping are gone. A host that declares one of these addresses itself now gets a Build conflict from zip. Co-authored-by: Hanzo Dev <[email protected]>
649 lines
26 KiB
Go
649 lines
26 KiB
Go
package o11y
|
|
|
|
// The ACCESS-CONTROL face — roles, service accounts, service-account keys and
|
|
// the authorization probe — as TYPED ops.
|
|
//
|
|
// These twenty routes reached traffic only through the delegation wildcard, and
|
|
// a route behind a wildcard is in no document: no SDK method, no CLI command,
|
|
// no agent tool, no reference page. An operator could not grant a role or mint
|
|
// a service-account key from anything but a hand-written HTTP call. Typing them
|
|
// is what puts the twenty operations in the document and therefore in every
|
|
// projection built from it.
|
|
//
|
|
// THE WIRE DOES NOT MOVE, and the way it does not move is that these ops do not
|
|
// re-implement access control. Each hands the call to the SAME runtime handler
|
|
// the wildcard delegates to (see relay.go), so identity resolution, the org gate,
|
|
// the CheckResources/OpenAccess gate on every route, the FGA resource checks,
|
|
// the audit record and the success envelope are all still the runtime's,
|
|
// executed in the order they always were. What is new here is the TYPE — the In
|
|
// the caller may send and the Out they get back — and the prose that goes with
|
|
// it.
|
|
//
|
|
// Statuses are the RUNTIME's, not the old swaggest annotations': granting a
|
|
// role to a service account renders 204 (the annotation claimed 201, the
|
|
// handler never did), and every update/delete answers 204 with no content, the
|
|
// same bytes a caller has always received through the wildcard.
|
|
//
|
|
// TWO DISPATCHES, ONE IMPLEMENTATION: the mux registrations in
|
|
// pkg/apiserver/o11yapiserver/{role,serviceaccount,authz}.go stay — the
|
|
// standalone server has no native router to register an op on — and both
|
|
// dispatches end in the same handler.
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/zap-proto/zip"
|
|
)
|
|
|
|
// mountAccess registers the twenty typed access-control ops on the native
|
|
// router. The literal /service_accounts/me routes register ahead of the
|
|
// parameterised ones so an id can never shadow them — the same defence
|
|
// telemetry.go gives its collection routes.
|
|
func mountAccess(app *zip.App) {
|
|
g := app.Group(o11yRoot)
|
|
|
|
g.Post("/roles", createRole, op("CreateRole"), zip.WithStatus(http.StatusCreated))
|
|
g.Get("/roles", listRoles, op("ListRoles"))
|
|
g.Get("/roles/:id", getRole, op("GetRole"))
|
|
g.Put("/roles/:id", updateRole, op("UpdateRole"), zip.WithStatus(http.StatusNoContent))
|
|
g.Delete("/roles/:id", deleteRole, op("DeleteRole"), zip.WithStatus(http.StatusNoContent))
|
|
|
|
g.Post("/service_accounts", createServiceAccount, op("CreateServiceAccount"), zip.WithStatus(http.StatusCreated))
|
|
g.Get("/service_accounts", listServiceAccounts, op("ListServiceAccounts"))
|
|
g.Get("/service_accounts/me", getMyServiceAccount, op("GetMyServiceAccount"))
|
|
g.Put("/service_accounts/me", updateMyServiceAccount, op("UpdateMyServiceAccount"), zip.WithStatus(http.StatusNoContent))
|
|
g.Get("/service_accounts/:id", getServiceAccount, op("GetServiceAccount"))
|
|
g.Put("/service_accounts/:id", updateServiceAccount, op("UpdateServiceAccount"), zip.WithStatus(http.StatusNoContent))
|
|
g.Delete("/service_accounts/:id", deleteServiceAccount, op("DeleteServiceAccount"), zip.WithStatus(http.StatusNoContent))
|
|
g.Get("/service_accounts/:id/roles", listServiceAccountRoles, op("GetServiceAccountRoles"))
|
|
g.Post("/service_accounts/:id/roles", grantServiceAccountRole, op("CreateServiceAccountRole"), zip.WithStatus(http.StatusNoContent))
|
|
g.Delete("/service_accounts/:id/roles/:rid", revokeServiceAccountRole, op("DeleteServiceAccountRole"), zip.WithStatus(http.StatusNoContent))
|
|
g.Post("/service_accounts/:id/keys", createServiceAccountKey, op("CreateServiceAccountKey"), zip.WithStatus(http.StatusCreated))
|
|
g.Get("/service_accounts/:id/keys", listServiceAccountKeys, op("ListServiceAccountKeys"))
|
|
g.Put("/service_accounts/:id/keys/:fid", updateServiceAccountKey, op("UpdateServiceAccountKey"), zip.WithStatus(http.StatusNoContent))
|
|
g.Delete("/service_accounts/:id/keys/:fid", revokeServiceAccountKey, op("RevokeServiceAccountKey"), zip.WithStatus(http.StatusNoContent))
|
|
|
|
g.Post("/authz/check", checkAccess, op("AuthzCheck"))
|
|
}
|
|
|
|
// ── roles ─────────────────────────────────────────────────────────────────────
|
|
|
|
// createRole creates a custom role in the caller's org from a name, an optional
|
|
// description and the transaction groups it grants, answering the new role's id.
|
|
//
|
|
// Names are lowercase letters and hyphens only, and may not start with the
|
|
// reserved managed-role prefix; the runtime refuses anything else.
|
|
func createRole(ctx context.Context, in *O11yRoleCreateIn) (*O11yRoleCreateOut, error) {
|
|
out := new(O11yRoleCreateOut)
|
|
return out, relay(ctx, nil, in, out)
|
|
}
|
|
|
|
// listRoles lists every role in the caller's org — the managed ones the
|
|
// platform seeds and the custom ones its admins created.
|
|
func listRoles(ctx context.Context, in *O11yRolesIn) (*O11yRolesOut, error) {
|
|
out := new(O11yRolesOut)
|
|
return out, relay(ctx, nil, nil, out)
|
|
}
|
|
|
|
// getRole returns one role with the transaction groups it grants.
|
|
func getRole(ctx context.Context, in *O11yRoleGetIn) (*O11yRoleOut, error) {
|
|
out := new(O11yRoleOut)
|
|
return out, relay(ctx, nil, nil, out)
|
|
}
|
|
|
|
// updateRole replaces a custom role's description and transaction groups.
|
|
// Both fields are mandatory — send an empty string or an empty array to clear
|
|
// one — and managed roles cannot be edited.
|
|
func updateRole(ctx context.Context, in *O11yRoleUpdateIn) (*struct{}, error) {
|
|
return nil, relay(ctx, nil, in, nil)
|
|
}
|
|
|
|
// deleteRole deletes a custom role. A role that still has user or
|
|
// service-account assignees, or an auth-domain mapping, is refused; managed
|
|
// roles cannot be deleted.
|
|
func deleteRole(ctx context.Context, in *O11yRoleDeleteIn) (*struct{}, error) {
|
|
return nil, relay(ctx, nil, nil, nil)
|
|
}
|
|
|
|
// ── service accounts ──────────────────────────────────────────────────────────
|
|
|
|
// createServiceAccount creates a service account in the caller's org,
|
|
// answering its id. The name — a lowercase letter followed by lowercase
|
|
// letters, digits or hyphens — becomes the account's email local part.
|
|
func createServiceAccount(ctx context.Context, in *O11yServiceAccountCreateIn) (*O11yServiceAccountCreateOut, error) {
|
|
out := new(O11yServiceAccountCreateOut)
|
|
return out, relay(ctx, nil, in, out)
|
|
}
|
|
|
|
// listServiceAccounts lists the caller's org's service accounts.
|
|
func listServiceAccounts(ctx context.Context, in *O11yServiceAccountsIn) (*O11yServiceAccountsOut, error) {
|
|
out := new(O11yServiceAccountsOut)
|
|
return out, relay(ctx, nil, nil, out)
|
|
}
|
|
|
|
// getMyServiceAccount returns the calling service account itself, with the
|
|
// roles it holds — the self-inspection read for a key-authenticated caller.
|
|
func getMyServiceAccount(ctx context.Context, in *O11yMyServiceAccountIn) (*O11yServiceAccountOut, error) {
|
|
out := new(O11yServiceAccountOut)
|
|
return out, relay(ctx, nil, nil, out)
|
|
}
|
|
|
|
// updateMyServiceAccount renames the calling service account.
|
|
func updateMyServiceAccount(ctx context.Context, in *O11yMyServiceAccountUpdateIn) (*struct{}, error) {
|
|
return nil, relay(ctx, nil, in, nil)
|
|
}
|
|
|
|
// getServiceAccount returns one service account with the roles it holds.
|
|
func getServiceAccount(ctx context.Context, in *O11yServiceAccountGetIn) (*O11yServiceAccountOut, error) {
|
|
out := new(O11yServiceAccountOut)
|
|
return out, relay(ctx, nil, nil, out)
|
|
}
|
|
|
|
// updateServiceAccount renames a service account.
|
|
func updateServiceAccount(ctx context.Context, in *O11yServiceAccountUpdateIn) (*struct{}, error) {
|
|
return nil, relay(ctx, nil, in, nil)
|
|
}
|
|
|
|
// deleteServiceAccount deletes a service account and revokes every key it
|
|
// holds.
|
|
func deleteServiceAccount(ctx context.Context, in *O11yServiceAccountDeleteIn) (*struct{}, error) {
|
|
return nil, relay(ctx, nil, nil, nil)
|
|
}
|
|
|
|
// listServiceAccountRoles lists the roles a service account holds.
|
|
func listServiceAccountRoles(ctx context.Context, in *O11yServiceAccountRolesIn) (*O11yServiceAccountRolesOut, error) {
|
|
out := new(O11yServiceAccountRolesOut)
|
|
return out, relay(ctx, nil, nil, out)
|
|
}
|
|
|
|
// grantServiceAccountRole assigns a role, named by its id, to a service
|
|
// account.
|
|
func grantServiceAccountRole(ctx context.Context, in *O11yServiceAccountRoleGrantIn) (*struct{}, error) {
|
|
return nil, relay(ctx, nil, in, nil)
|
|
}
|
|
|
|
// revokeServiceAccountRole removes a role from a service account.
|
|
func revokeServiceAccountRole(ctx context.Context, in *O11yServiceAccountRoleRevokeIn) (*struct{}, error) {
|
|
return nil, relay(ctx, nil, nil, nil)
|
|
}
|
|
|
|
// ── service-account keys ──────────────────────────────────────────────────────
|
|
|
|
// createServiceAccountKey mints an API key for a service account and answers
|
|
// the key's id and its secret — the one time the secret is ever shown.
|
|
//
|
|
// ExpiresAt is a unix timestamp in seconds; zero means the key never expires,
|
|
// and a timestamp in the past is refused.
|
|
func createServiceAccountKey(ctx context.Context, in *O11yAPIKeyCreateIn) (*O11yAPIKeyCreateOut, error) {
|
|
out := new(O11yAPIKeyCreateOut)
|
|
return out, relay(ctx, nil, in, out)
|
|
}
|
|
|
|
// listServiceAccountKeys lists a service account's API keys — metadata only,
|
|
// never the secrets.
|
|
func listServiceAccountKeys(ctx context.Context, in *O11yAPIKeysIn) (*O11yAPIKeysOut, error) {
|
|
out := new(O11yAPIKeysOut)
|
|
return out, relay(ctx, nil, nil, out)
|
|
}
|
|
|
|
// updateServiceAccountKey renames an API key or moves its expiry.
|
|
func updateServiceAccountKey(ctx context.Context, in *O11yAPIKeyUpdateIn) (*struct{}, error) {
|
|
return nil, relay(ctx, nil, in, nil)
|
|
}
|
|
|
|
// revokeServiceAccountKey revokes an API key. Revocation is immediate and
|
|
// permanent.
|
|
func revokeServiceAccountKey(ctx context.Context, in *O11yAPIKeyRevokeIn) (*struct{}, error) {
|
|
return nil, relay(ctx, nil, nil, nil)
|
|
}
|
|
|
|
// ── authorization probe ───────────────────────────────────────────────────────
|
|
|
|
// checkAccess evaluates a batch of transactions — relation plus object — for
|
|
// the authenticated caller and answers each with its authorization verdict, in
|
|
// the order they were asked. It is the read a UI uses to decide which controls
|
|
// to show.
|
|
func checkAccess(ctx context.Context, in *O11yCheckIn) (*O11yCheckOut, error) {
|
|
out := new(O11yCheckOut)
|
|
return out, relay(ctx, nil, in, out)
|
|
}
|
|
|
|
// ── inputs ────────────────────────────────────────────────────────────────────
|
|
//
|
|
// Every type carries the O11y qualifier because these names enter a fleet-wide
|
|
// document, where one name may have exactly one shape. Path-bound fields are
|
|
// `json:"-" url:"…"` so they never leak into a relayed body; body fields whose
|
|
// PRESENCE the runtime tests (the update bodies' nil checks) are pointers with
|
|
// omitempty, so an absent field stays absent and an intentionally empty one
|
|
// stays empty.
|
|
|
|
// O11yRoleCreateIn describes the role to create.
|
|
type O11yRoleCreateIn struct {
|
|
// Name is the role's name: lowercase letters and hyphens, at most 50
|
|
// characters, not starting with the reserved managed-role prefix. Required.
|
|
Name string `json:"name"`
|
|
// Description says what the role is for.
|
|
Description string `json:"description,omitempty"`
|
|
// TransactionGroups are the grants the role carries.
|
|
TransactionGroups []O11yTransactionGroup `json:"transactionGroups,omitempty"`
|
|
}
|
|
|
|
// O11yRolesIn has no inputs; the org is the caller's own.
|
|
type O11yRolesIn struct{}
|
|
|
|
// O11yRoleGetIn names one role.
|
|
type O11yRoleGetIn struct {
|
|
// ID is the role id.
|
|
ID string `json:"-" url:"id"`
|
|
}
|
|
|
|
// O11yRoleUpdateIn replaces a role's description and grants.
|
|
type O11yRoleUpdateIn struct {
|
|
// ID is the role id.
|
|
ID string `json:"-" url:"id"`
|
|
// Description says what the role is for. Required — send an empty string to
|
|
// clear it.
|
|
Description *string `json:"description,omitempty"`
|
|
// TransactionGroups are the grants the role carries. Required — send an
|
|
// empty array to clear them.
|
|
TransactionGroups *[]O11yTransactionGroup `json:"transactionGroups,omitempty"`
|
|
}
|
|
|
|
// O11yRoleDeleteIn names the role to delete.
|
|
type O11yRoleDeleteIn struct {
|
|
// ID is the role id.
|
|
ID string `json:"-" url:"id"`
|
|
}
|
|
|
|
// O11yServiceAccountCreateIn describes the service account to create.
|
|
type O11yServiceAccountCreateIn struct {
|
|
// Name is the account's name: a lowercase letter followed by lowercase
|
|
// letters, digits or hyphens, at most 50 characters. Required.
|
|
Name string `json:"name"`
|
|
}
|
|
|
|
// O11yServiceAccountsIn has no inputs; the org is the caller's own.
|
|
type O11yServiceAccountsIn struct{}
|
|
|
|
// O11yMyServiceAccountIn has no inputs; the account is the caller itself.
|
|
type O11yMyServiceAccountIn struct{}
|
|
|
|
// O11yMyServiceAccountUpdateIn renames the calling service account.
|
|
type O11yMyServiceAccountUpdateIn struct {
|
|
// Name is the account's new name, under the same rules it was created with.
|
|
// Required.
|
|
Name string `json:"name"`
|
|
}
|
|
|
|
// O11yServiceAccountGetIn names one service account.
|
|
type O11yServiceAccountGetIn struct {
|
|
// ID is the service account id.
|
|
ID string `json:"-" url:"id"`
|
|
}
|
|
|
|
// O11yServiceAccountUpdateIn renames a service account.
|
|
type O11yServiceAccountUpdateIn struct {
|
|
// ID is the service account id.
|
|
ID string `json:"-" url:"id"`
|
|
// Name is the account's new name, under the same rules it was created with.
|
|
// Required.
|
|
Name string `json:"name"`
|
|
}
|
|
|
|
// O11yServiceAccountDeleteIn names the service account to delete.
|
|
type O11yServiceAccountDeleteIn struct {
|
|
// ID is the service account id.
|
|
ID string `json:"-" url:"id"`
|
|
}
|
|
|
|
// O11yServiceAccountRolesIn names the service account whose roles to list.
|
|
type O11yServiceAccountRolesIn struct {
|
|
// ID is the service account id.
|
|
ID string `json:"-" url:"id"`
|
|
}
|
|
|
|
// O11yServiceAccountRoleGrantIn assigns a role to a service account. The path
|
|
// names the account; the body names the role — two different ids both spelled
|
|
// "id" on the wire, kept apart by the url/json split.
|
|
type O11yServiceAccountRoleGrantIn struct {
|
|
// ServiceAccountID is the service account id.
|
|
ServiceAccountID string `json:"-" url:"id"`
|
|
// RoleID is the id of the role to assign. Required.
|
|
RoleID string `json:"id" url:"-"`
|
|
}
|
|
|
|
// O11yServiceAccountRoleRevokeIn removes a role from a service account.
|
|
type O11yServiceAccountRoleRevokeIn struct {
|
|
// ID is the service account id.
|
|
ID string `json:"-" url:"id"`
|
|
// RoleID is the id of the role to remove.
|
|
RoleID string `json:"-" url:"rid"`
|
|
}
|
|
|
|
// O11yAPIKeyCreateIn describes the API key to mint.
|
|
type O11yAPIKeyCreateIn struct {
|
|
// ServiceAccountID is the service account the key belongs to.
|
|
ServiceAccountID string `json:"-" url:"id"`
|
|
// Name is the key's name: a lowercase letter followed by lowercase letters,
|
|
// digits or hyphens, at most 80 characters. Required.
|
|
Name string `json:"name"`
|
|
// ExpiresAt is when the key stops working, as a unix timestamp in seconds.
|
|
// Zero means it never expires; a past timestamp is refused.
|
|
ExpiresAt uint64 `json:"expiresAt"`
|
|
}
|
|
|
|
// O11yAPIKeysIn names the service account whose keys to list.
|
|
type O11yAPIKeysIn struct {
|
|
// ID is the service account id.
|
|
ID string `json:"-" url:"id"`
|
|
}
|
|
|
|
// O11yAPIKeyUpdateIn renames an API key or moves its expiry.
|
|
type O11yAPIKeyUpdateIn struct {
|
|
// ServiceAccountID is the service account the key belongs to.
|
|
ServiceAccountID string `json:"-" url:"id"`
|
|
// KeyID is the key id.
|
|
KeyID string `json:"-" url:"fid"`
|
|
// Name is the key's new name, under the same rules it was created with.
|
|
// Required.
|
|
Name string `json:"name"`
|
|
// ExpiresAt is when the key stops working, as a unix timestamp in seconds.
|
|
// Zero means it never expires; a past timestamp is refused.
|
|
ExpiresAt uint64 `json:"expiresAt"`
|
|
}
|
|
|
|
// O11yAPIKeyRevokeIn names the API key to revoke.
|
|
type O11yAPIKeyRevokeIn struct {
|
|
// ID is the service account id.
|
|
ID string `json:"-" url:"id"`
|
|
// KeyID is the key id.
|
|
KeyID string `json:"-" url:"fid"`
|
|
}
|
|
|
|
// O11yCheckIn is a batch of transactions to evaluate for the caller. The wire
|
|
// body is the bare array itself — the shape this route has always taken.
|
|
type O11yCheckIn []O11yTransaction
|
|
|
|
// O11yTransaction is one authorization question: may the caller do RELATION to
|
|
// OBJECT.
|
|
type O11yTransaction struct {
|
|
// Relation is the verb being asked about, e.g. read, create, update, delete.
|
|
Relation string `json:"relation"`
|
|
// Object is the resource the verb would act on.
|
|
Object O11yObject `json:"object"`
|
|
}
|
|
|
|
// O11yObject is one addressable resource: what kind of thing it is, and which
|
|
// one.
|
|
type O11yObject struct {
|
|
// Resource is the resource's type and kind.
|
|
Resource O11yResourceRef `json:"resource"`
|
|
// Selector picks the instance — an FGA object string, wildcard allowed.
|
|
Selector string `json:"selector"`
|
|
}
|
|
|
|
// O11yResourceRef names a resource type.
|
|
type O11yResourceRef struct {
|
|
// Type is the resource type, e.g. role, dashboard, serviceaccount.
|
|
Type string `json:"type"`
|
|
// Kind is the resource kind the type belongs to.
|
|
Kind string `json:"kind"`
|
|
}
|
|
|
|
// O11yTransactionGroup is one grant a role carries: a relation over a group of
|
|
// objects.
|
|
type O11yTransactionGroup struct {
|
|
// Relation is the verb the grant allows.
|
|
Relation string `json:"relation"`
|
|
// ObjectGroup is the set of objects it allows the verb on.
|
|
ObjectGroup O11yObjectGroup `json:"objectGroup"`
|
|
}
|
|
|
|
// O11yObjectGroup is a set of same-typed objects, named by selectors.
|
|
type O11yObjectGroup struct {
|
|
// Resource is the objects' type and kind.
|
|
Resource O11yResourceRef `json:"resource"`
|
|
// Selectors pick the instances; a wildcard selects them all.
|
|
Selectors []string `json:"selectors"`
|
|
}
|
|
|
|
// ── outputs ───────────────────────────────────────────────────────────────────
|
|
//
|
|
// Each Out is the runtime's answer NAMED, field for field, tag for tag —
|
|
// including the status/data envelope every read on this face has always
|
|
// answered with. Written flat (nothing embeds), so the document and the bytes
|
|
// agree; access_test.go re-encodes each Out and compares it byte for byte with
|
|
// what the runtime wrote. The 204 operations answer no content at all, which is
|
|
// what their callers have always received.
|
|
|
|
// O11yRoleCreateOut answers a role creation with the new role's id.
|
|
type O11yRoleCreateOut struct {
|
|
// Status is "success".
|
|
Status string `json:"status"`
|
|
// Data carries the new role's id.
|
|
Data O11yCreated `json:"data"`
|
|
}
|
|
|
|
// O11yRoleOut is one role with its grants.
|
|
type O11yRoleOut struct {
|
|
// Status is "success".
|
|
Status string `json:"status"`
|
|
// Data holds the role and its transaction groups.
|
|
Data O11yRoleDetail `json:"data"`
|
|
}
|
|
|
|
// O11yRoleDetail is one role together with the grants it carries.
|
|
type O11yRoleDetail struct {
|
|
// ID is the role id.
|
|
ID string `json:"id"`
|
|
// CreatedAt is when the role was created.
|
|
CreatedAt time.Time `json:"createdAt"`
|
|
// UpdatedAt is when it last changed.
|
|
UpdatedAt time.Time `json:"updatedAt"`
|
|
// Name is the role's name.
|
|
Name string `json:"name"`
|
|
// Description says what the role is for.
|
|
Description string `json:"description"`
|
|
// Type is custom or managed.
|
|
Type string `json:"type"`
|
|
// OrgID is the org the role belongs to.
|
|
OrgID string `json:"orgId"`
|
|
// TransactionGroups are the grants the role carries.
|
|
TransactionGroups []O11yTransactionGroup `json:"transactionGroups"`
|
|
}
|
|
|
|
// O11yServiceAccountCreateOut answers a service-account creation with the new
|
|
// account's id.
|
|
type O11yServiceAccountCreateOut struct {
|
|
// Status is "success".
|
|
Status string `json:"status"`
|
|
// Data carries the new account's id.
|
|
Data O11yCreated `json:"data"`
|
|
}
|
|
|
|
// O11yServiceAccountsOut is every service account in the org.
|
|
type O11yServiceAccountsOut struct {
|
|
// Status is "success".
|
|
Status string `json:"status"`
|
|
// Data holds the service accounts.
|
|
Data []O11yServiceAccount `json:"data"`
|
|
}
|
|
|
|
// O11yServiceAccountOut is one service account with the roles it holds.
|
|
type O11yServiceAccountOut struct {
|
|
// Status is "success".
|
|
Status string `json:"status"`
|
|
// Data holds the account and its role assignments.
|
|
Data O11yServiceAccountDetail `json:"data"`
|
|
}
|
|
|
|
// O11yServiceAccount is one service account.
|
|
type O11yServiceAccount struct {
|
|
// ID is the service account id.
|
|
ID string `json:"id"`
|
|
// CreatedAt is when the account was created.
|
|
CreatedAt time.Time `json:"createdAt"`
|
|
// UpdatedAt is when it last changed.
|
|
UpdatedAt time.Time `json:"updatedAt"`
|
|
// Name is the account's name.
|
|
Name string `json:"name"`
|
|
// Email is the address the account authenticates as.
|
|
Email string `json:"email"`
|
|
// Status is active or deleted.
|
|
Status string `json:"status"`
|
|
// OrgID is the org the account belongs to.
|
|
OrgID string `json:"orgId"`
|
|
}
|
|
|
|
// O11yServiceAccountDetail is one service account together with its role
|
|
// assignments.
|
|
type O11yServiceAccountDetail struct {
|
|
// ID is the service account id.
|
|
ID string `json:"id"`
|
|
// CreatedAt is when the account was created.
|
|
CreatedAt time.Time `json:"createdAt"`
|
|
// UpdatedAt is when it last changed.
|
|
UpdatedAt time.Time `json:"updatedAt"`
|
|
// Name is the account's name.
|
|
Name string `json:"name"`
|
|
// Email is the address the account authenticates as.
|
|
Email string `json:"email"`
|
|
// Status is active or deleted.
|
|
Status string `json:"status"`
|
|
// OrgID is the org the account belongs to.
|
|
OrgID string `json:"orgId"`
|
|
// ServiceAccountRoles are the account's role assignments.
|
|
ServiceAccountRoles []O11yServiceAccountRole `json:"serviceAccountRoles"`
|
|
}
|
|
|
|
// O11yServiceAccountRole is one role assignment on a service account.
|
|
type O11yServiceAccountRole struct {
|
|
// ID is the assignment's own id.
|
|
ID string `json:"id"`
|
|
// CreatedAt is when the role was assigned.
|
|
CreatedAt time.Time `json:"createdAt"`
|
|
// UpdatedAt is when the assignment last changed.
|
|
UpdatedAt time.Time `json:"updatedAt"`
|
|
// ServiceAccountID is the account holding the role.
|
|
ServiceAccountID string `json:"serviceAccountId"`
|
|
// RoleID is the role held.
|
|
RoleID string `json:"roleId"`
|
|
// Role is the role itself.
|
|
Role *O11yRole `json:"role"`
|
|
}
|
|
|
|
// O11yServiceAccountRolesOut is the roles a service account holds.
|
|
type O11yServiceAccountRolesOut struct {
|
|
// Status is "success".
|
|
Status string `json:"status"`
|
|
// Data holds the roles.
|
|
Data []O11yRole `json:"data"`
|
|
}
|
|
|
|
// O11yAPIKeyCreateOut answers a key mint with the key's id and its secret —
|
|
// shown here and never again.
|
|
type O11yAPIKeyCreateOut struct {
|
|
// Status is "success".
|
|
Status string `json:"status"`
|
|
// Data carries the key's id and secret.
|
|
Data O11yAPIKeySecret `json:"data"`
|
|
}
|
|
|
|
// O11yAPIKeySecret is a freshly minted key: its id and its secret.
|
|
type O11yAPIKeySecret struct {
|
|
// ID is the key id.
|
|
ID string `json:"id"`
|
|
// Key is the secret the service account authenticates with.
|
|
Key string `json:"key"`
|
|
}
|
|
|
|
// O11yAPIKeysOut is a service account's keys, metadata only.
|
|
type O11yAPIKeysOut struct {
|
|
// Status is "success".
|
|
Status string `json:"status"`
|
|
// Data holds the keys.
|
|
Data []O11yAPIKey `json:"data"`
|
|
}
|
|
|
|
// O11yAPIKey is one API key's metadata; the secret is never listed.
|
|
type O11yAPIKey struct {
|
|
// ID is the key id.
|
|
ID string `json:"id"`
|
|
// CreatedAt is when the key was minted.
|
|
CreatedAt time.Time `json:"createdAt"`
|
|
// UpdatedAt is when it last changed.
|
|
UpdatedAt time.Time `json:"updatedAt"`
|
|
// Name is the key's name.
|
|
Name string `json:"name"`
|
|
// ExpiresAt is when the key stops working, as a unix timestamp in seconds;
|
|
// zero means never.
|
|
ExpiresAt uint64 `json:"expiresAt"`
|
|
// LastObservedAt is when the key was last seen authenticating.
|
|
LastObservedAt time.Time `json:"lastObservedAt"`
|
|
// ServiceAccountID is the account the key belongs to.
|
|
ServiceAccountID string `json:"serviceAccountId"`
|
|
}
|
|
|
|
// O11yCheckOut answers an authorization probe, one verdict per transaction
|
|
// asked, in the order they were asked.
|
|
type O11yCheckOut struct {
|
|
// Status is "success".
|
|
Status string `json:"status"`
|
|
// Data holds the verdicts.
|
|
Data []O11yTransactionResult `json:"data"`
|
|
}
|
|
|
|
// O11yTransactionResult is one evaluated transaction.
|
|
type O11yTransactionResult struct {
|
|
// Relation is the verb that was asked about.
|
|
Relation string `json:"relation"`
|
|
// Object is the resource it would act on.
|
|
Object O11yObject `json:"object"`
|
|
// Authorized says whether the caller may do it.
|
|
Authorized bool `json:"authorized"`
|
|
}
|
|
|
|
// ── the seam ──────────────────────────────────────────────────────────────────
|
|
|
|
// ── role records ──────────────────────────────────────────────────────────────
|
|
//
|
|
// These lived in identity.go while the identity face still administered members
|
|
// and the roles they held. That face is gone — Hanzo IAM administers members —
|
|
// but ROLES themselves are not identity: they are o11y's own vocabulary for what
|
|
// may be done to o11y's own dashboards, alerts and views, which is this file's
|
|
// subject. So the records moved to the face that uses them.
|
|
|
|
// O11yRolesOut is a list of roles.
|
|
type O11yRolesOut struct {
|
|
// Status is "success".
|
|
Status string `json:"status"`
|
|
// Data holds the roles.
|
|
Data []O11yRole `json:"data"`
|
|
}
|
|
|
|
// O11yRole is one role.
|
|
type O11yRole struct {
|
|
// ID is the role id.
|
|
ID string `json:"id"`
|
|
// CreatedAt is when the role was created.
|
|
CreatedAt time.Time `json:"createdAt"`
|
|
// UpdatedAt is when it last changed.
|
|
UpdatedAt time.Time `json:"updatedAt"`
|
|
// Name is the role's name.
|
|
Name string `json:"name"`
|
|
// Description says what the role is for.
|
|
Description string `json:"description"`
|
|
// Type is how the role came to be — managed by the platform or custom.
|
|
Type string `json:"type"`
|
|
// OrgID is the org the role belongs to.
|
|
OrgID string `json:"orgId"`
|
|
}
|
|
|
|
// O11yCreated is a newly created record, named by id.
|
|
type O11yCreated struct {
|
|
// ID is the new record's id.
|
|
ID string `json:"id"`
|
|
}
|