Entitlements & token security
This page is the reference for how StrataBI Enterprise authorizes a licensed install: how your entitlement is proven, how the install runner knows it is permitted to deploy, where secrets live, and what the trust boundaries are. It is written for the security and DevSecOps reviewers who need to sign off before StrataBI runs in your account.
The short version: Shaleio never holds credentials in your account, and the control plane never receives yours. Every deploy runs in your AWS account, under your own IAM identity, against state in your own S3 bucket. The control plane (StrataHQ) is a request/response entitlement service — it answers "is this account licensed for this version?" and, if so, hands back a short-lived, signed pointer to the artifact. Nothing more.
The actors
| Actor | Where it runs | Credentials it holds |
|---|---|---|
| Operator (you) | Your workstation / CI | Your own AWS identity; the license token |
| StrataCTL | Same as the operator | None of its own — uses the operator's identity |
| StrataCI runner | Ephemeral compute in your account | A CodeBuild service role in your account (or your CI's role) |
| StrataHQ | Shaleio's control-plane account | None in your account; cannot assume into it |
StrataHQ is reachable only over HTTPS at the entitlement endpoint. It is the only Shaleio component in the picture, and it is contacted twice at most per install: once to check the entitlement, once to download the artifact over the presigned URL it returns.
Two independent gates
A licensed install (install-stratabi, update, fetch-runtime) calls POST /entitlement on StrataHQ. The request passes two checks that both have to succeed.
1. Caller-account proof (SigV4 / IAM)
The entitlement endpoint is IAM-authorized. StrataCTL signs the request with SigV4 using your AWS credentials, and API Gateway verifies that signature before the Lambda ever runs. The handler then reads the caller's AWS account id from the verified request context (requestContext.identity.accountId) — not from anything the client puts in the body.
The practical consequence: the account identity is cryptographic, not asserted. If the request body claims a customer_id that disagrees with the SigV4-verified account, the request is denied. A license token is therefore only redeemable from the AWS account it was issued for — copying it to another account gets you a 403, because that account's signature won't match the licensed one.
Note. The signing uses botocore's own HTTP path so the exact bytes and headers that were signed are what travel on the wire; the license token rides in theX-Strata-Tokenheader specifically so theAuthorizationheader is left free for the SigV4 signature.
2. License-token gate
The token is checked against the entitlement store for the verified account. StrataHQ stores only the SHA-256 of your token, never the token itself; the handler hashes the presented token and compares it to the stored token_sha256, and requires the record's status to be active. A missing, unknown, revoked, or inactive token yields the same uniform denial as any other failure.
Only after both gates pass does the entitlement check proceed to resolve the version.
What a denial looks like
Every failure path returns a uniform 403 with no detail about why. This is deliberate: the response never reveals whether a module or version exists, so an unlicensed caller cannot probe the catalog. install/update require an active, unexpired grant. destroy is treated specially — see below.
What an allow returns
On success StrataHQ returns a small JSON document:
| Field | Meaning |
|---|---|
artifact_url | A short-lived presigned GET URL for the exact artifact (default TTL 900s / 15 min) |
sha256 | The expected SHA-256 of the bundle |
signature | A KMS signature over that SHA-256 (base64) |
version | The resolved version (e.g. latest → 1.7.1) |
expires_at | When the presigned URL stops working |
The presigned URL is generated with SigV4 (s3v4) so it can read the SSE-KMS-encrypted artifact. It is single-object, read-only, and expires quickly.
How the runner knows it is permitted
The runner does not make its own licensing decision. It is handed, by the operator's already-authorized StrataCTL invocation, a short-lived presigned URL that only an entitled caller could have obtained. Possession of that URL is itself the proof that the entitlement check passed. The runner then independently establishes two more things before it applies anything:
- Authenticity + integrity. It downloads the bundle, recomputes the SHA-256, and verifies the KMS ECDSA-P256 signature over that hash offline, against a public key pinned in your StrataCTL config (
STRATA_HQ_PUBKEY). WithSTRATA_REQUIRE_SIGNATURE=1an unsigned or unverifiable bundle aborts the run. This means even a leaked presigned URL, a poisoned cache, or a tampered S3 object cannot inject altered Terraform — the signature won't verify. - Account self-check (replay protection). The runner calls
sts:GetCallerIdentityand compares the account it is actually running in to the licensed account passed in the job spec (STRATA_CUSTOMER_ID). If a job spec were copied and replayed into a different account, the runner refuses and marks the job failed.
Put together: the presigned URL proves entitlement, the signature proves authenticity, and the self-check proves the right account — three independent properties, no single point of trust.
Module order forms
For Official Modules (not the platform itself), the same install/update call also records a per-account order form: StrataCTL shows you the module's license terms, you accept once, and StrataHQ stores an account-stamped record. The license is a perpetual, per-account run right — modules you install keep running even if Premier lapses — while Premier is what gates extraction and updates. See Module order forms for the terms, the recorded fields, and how to review them.
Teardown is never trapped
destroy / uninstall is always permitted. For a destroy action StrataHQ will serve the retained artifact even if the grant has lapsed, expired, or the version has been retired — the grant must still exist (you were legitimately entitled at some point), but it need not be active. With the default local delivery the bundle is already cached in your own bucket and re-verified offline, so teardown does not depend on Shaleio connectivity at all. See Delivery & teardown.
Retrieving entitlement without CodeBuild
The same entitlement check is available to pipelines that don't use StrataCI at all. Two StrataCTL commands expose it directly, with no bootstrap and no CodeBuild:
stratactl entitlement resolve --module stratabi --version <v> --output <file>returns the raw metadata —artifact_url,sha256,signature,version,expires_at— to a0600file.stratactl fetch-bundle --module stratabi --version <v> --output module.zipdownloads the bundle over the presigned URL and verifies the SHA-256 and KMS signature before writing it, fail-closed.
Both run the identical two-gate check described above — SigV4 account proof and license-token gate — and return the identical signed, short-lived pointer. Nothing about the authorization is weaker than the installer path; only the execution moves into your pipeline. The security properties stay layered and distinct:
| Layer | What it proves | Where it's checked |
|---|---|---|
| License token | You hold a valid, active license | StrataHQ (SHA-256 compare) |
| AWS SigV4 identity | The request comes from the licensed account | API Gateway + StrataHQ |
| Presigned URL | The entitlement check passed (short-lived bearer) | Possession proves it |
| SHA-256 | The bytes weren't altered in transit/at rest | Your side (fetch-bundle) |
| KMS signature | The artifact is authentic Shaleio content | Your side, offline, against the pinned key |
| Deployment account | OpenTofu runs in the right account | Your pipeline (the runner's self-check is not in this path) |
The 15-minute expiry applies to the presigned artifact URL, not to your license — the license is perpetual for the versions it covers (see the licensing terms). Resolve or fetch close to when you deploy; don't store the URL.
See Bring your own CI/CD for the full workflow.
Secret handling
| Secret | Where it comes from | How it is stored | Lifetime |
|---|---|---|---|
| License token | STRATA_HQ_TOKEN, your config file, or SSM /strataci/hq/token | At StrataHQ: SHA-256 only. On your side: wherever you choose to keep it | Long-lived until rotated/revoked |
| Presigned artifact URL | Returned by the entitlement check | Not persisted | ≤ TTL (default 15 min) |
| HQ public key | Pinned in your StrataCTL config | Plain config value (it is public by nature) | Static |
StrataCTL and the runner treat the presigned URL and the token as sensitive: a single module declares which environment keys are secret, and those values are never printed and are scrubbed from any error text before it reaches a log or the jobs table.
Residual exposure, stated plainly. When the runner runs in the built-in CodeBuild plane, the presigned URL is passed as a plaintext build environment override, so it is visible in the build's environment metadata to principals inside your own account who can read CodeBuild. We accept that residual exposure because the value is ephemeral (≤ the presign TTL), single-object, read-only, and confined to your account. If that is not acceptable for your threat model, run the install in your own CI with your own secret handling — see Bring your own CI/CD.
Least-privilege credential model
The install plane separates three identities so no single one is both human-held and broadly privileged:
- Operator policy — attached to your engineer identity. It is what lets a human drive StrataCTL; it does not grant the deploy permissions.
- Runner role — the CodeBuild service role. Scoped to the state bucket, the registry/jobs/ lock tables, its own log group, and
sts:AssumeRoleon the deploy role only. - Deploy role — broad by design, but the runner assumes it with a module-scoped session policy derived from the module manifest. The effective permissions are the intersection of the deploy policy and the module's declared scope, so a module can never exceed what it declared.
All of these live in your account and are created by stratactl bootstrap; you can read the exact Terraform before you apply it. See the StrataCI reference for the full resource list.
What Shaleio can and cannot do
| Can | Cannot |
|---|---|
| Answer whether an account+version is entitled | Assume a role in your account |
| Serve a short-lived, signed artifact pointer | Read your data, state, or logs |
| Revoke a token (future installs stop) | Reach into or modify a running deployment |
| Retire a version in the catalog | Prevent you from tearing down what you installed |
Because every deploy runs under your identity against your state, revoking a token stops future installs and updates but cannot touch what is already running — that remains entirely yours to operate or remove.
Reviewer checklist
- Entitlement endpoint is IAM-authorized; account identity is SigV4-verified, not client-asserted.
- License token is bound to the AWS account; stored only as a SHA-256 at the control plane.
- Artifacts are content-hashed and KMS-signed; the runner verifies the signature offline against a pinned key. Enforce it with
STRATA_REQUIRE_SIGNATURE=1. - Presigned URLs are short-lived (default 15 min), single-object, read-only.
- The runner refuses to deploy outside the licensed account (self-check).
- Deploy permissions are the intersection of a broad role and a module-scoped session policy.
- The control plane holds no credentials in your account and cannot assume into it.
Related
- StrataCI — the execution plane — the in-account install plane and its IAM.
- Delivery & teardown —
localvsmanaged, offline/air-gapped installs. - Bring your own CI/CD — run the install under your own pipeline and scans.
- Security posture — the broader data/identity/network posture.
- Container image & supply chain — how the runtime image is built and verified.
Shaleio