Skip to main content

Service accounts and the API

A service account is how a CI pipeline or a script calls G8's API with a token instead of a person's session. A service account holds roles the way a person does, and each of its tokens acts with those roles. A token makes the same calls the console makes, under the same access rules and into the same audit log.

Who may open it​

Service accounts sit on the Service accounts tab under Users & access, which belongs to the Platform administrator. On the server, everything about service accounts needs the permission to manage service accounts (service_accounts.manage). It is a platform permission, which only the Platform administrator holds.

Create a service account​

  1. On the Service accounts tab, select New service account.
  2. Under General, enter a Name: 2 to 64 lowercase letters, digits, dots or hyphens. The name appears in the audit log and cannot change later.
  3. Optional: enter a Description, what the account is for.
  4. Under Access, pick the first role and the environment it applies in. A service account carries environment roles only, built-in or custom, so the platform roles are refused.
  5. Select Create service account.

The account's page then shows its tokens and its access. To change the description later, select Edit on that page. The form says what it leaves out: The name cannot change; tokens and access are managed on the account's page.

Add access gives the account a role in another environment, and Remove access takes a role away. The confirmation reads: ci-deploy loses Editor in Production on its next request. The server reads an account's roles again on every call, so the next call of any of its tokens is made without that role. A custom role suits a pipeline that needs exactly one kind of change; see Custom roles.

The Service accounts tab with one account listed: its name, description, roles, tokens, last use and status.

Tokens​

On the account's page, select New token, name the token and choose when it expires: 30 days, 90 days, 180 days or 1 year. The dialog notes: Tokens carry the account's environment roles. Each account can have up to 5 active tokens.

  • Shown once. The token appears once, in the dialog that confirms it. It starts with g8sa_, and the server keeps only a SHA-256 hash of it, so no page can show it again.
  • At most 5 active. A sixth is refused until one is revoked or expires. Expired and revoked tokens stay listed with their state.
  • Before it expires. In the last 14 days of a token, its row shows the days left, as in Expires in 14 days. G8 sends no notification about it.
  • Revoke. Revoke ends one token. The confirmation says: Requests with this token fail from now on. This cannot be undone.
  • Disable. Disable revokes every token of the account, and a disabled account cannot be issued new ones. Enabling it again does not bring the old tokens back; issue new ones.
  • Delete. The confirmation says: Every token of the account stops working now. The name can be used again. Its roles are removed with it.
  • Last used. Each token records when it was last used, at most once a minute, and so does the account.

To replace a token, create the new one first, give it to the pipeline, and then revoke the old one. That needs a free place among the 5 active tokens. When all 5 are taken, the button is unavailable and its tip says: Revoke a token first (5 active)

How a service account is audited​

Every change a token makes leaves audit rows exactly as a person's change does, in the log of the environment it changed and in the platform log. The row's Actor is the service account, by name, with the actor type Service account. The row's detail also shows the Token, the ID of the token that made the call, so one leaked token can be traced.

The life of the account is audited in the platform log too.

Row in the consoleWhat happened
Service account created (service_account.created)The account was created, together with an Access granted row for its first role.
Service account updated (service_account.updated)Its description was changed with Edit. The name cannot change, so the description is all an update holds.
Service account disabled (service_account.disabled) and Service account enabled (service_account.enabled)The account was disabled, which revoked its tokens, or enabled again.
Service account deleted (service_account.deleted)The account was deleted, with an Access revoked row for each role it held.
Access granted (assignment.granted) and Access revoked (assignment.revoked)A role was given or taken away.
Token created (service_account.token_created)A token was created. The row names the account and the token's expiry.
Token revoked (service_account.token_revoked)A token was revoked.

No row carries the token itself.

Using the API​

Send a token​

The dialog that shows the new token says how to send it: Send it as Authorization: Bearer …. Tokens in URLs are rejected. The server reads the token from the Authorization header with the Bearer scheme.

What the request doesWhat the server answers
Carries a valid token of an active accountThe route's own answer, with the account's roles applied.
Carries a token that is unknown, expired or revoked, or one of a disabled account401 unauthenticated.
Carries access_token or token in the query string401 with the reason token_in_url, whatever else it carries.
Exceeds the token's rate429 too_many_requests. Each token may make 300 requests a minute unless the server sets G8_TOKEN_RATE_PER_MINUTE otherwise.
Calls a route meant for a person's own session, a password change or a sign-out403 with the reason session_required.
Lacks the permission the route declares403 forbidden, naming the permission. A refused change also leaves an Access denied row (access.denied) in the audit log.

A token is not a browser session, so the server does not apply the same-origin check to its writes that it applies to the console's.

An example request​

A pipeline that lists the routes of the environment dev sends this request.

curl -sS \
-H "Authorization: Bearer $G8_TOKEN" \
"$G8_URL/api/environments/dev/gateway/routes?page_size=100"

The first variable holds the token, the second the address where your users open the console. Reading the routes (/api/environments/{id}/gateway/routes) needs the view permission of Routes (routes.view), so the account needs a role in dev that carries it.

The answer is a JSON object with items, total, unfiltered_total, page and page_size. The page size is 25, 50 or 100. Each item carries the route's id, its name and its value, the route as the gateway stores it. A role without the manage permission of routes gets secret values masked, as Custom roles explains.

Writes​

A write goes to the same address with PUT, POST or DELETE. Each read of a single object answers with an ETag. Send it back as If-Match on the write, and the server refuses the write with a conflict when the object changed in the meantime. In a protected environment, a delete also needs the confirm query parameter set to the object's ID or its name. The server takes either. The console's delete dialog sends what it asked you to type, as Environment settings describes.

The API description​

The whole API is described by an OpenAPI 3.1 document that the server itself serves (GET /api/openapi.yaml). Fetching it needs no token and no session.

Every route the server mounts under /api is in that document, and nothing else is. The server compares the two when it starts and refuses to start when they differ. The console's own API types are generated from the same document. Each operation lists the answers it can give. A change to a gateway object lists 503 audit_unavailable, the answer when its audit row could not be written before the gateway was called.

G8 dev