Storing cloud credentials for discovery
The read-only credential each cloud scanner needs, the exact permissions to grant, why the test checks permissions and not just sign-in, and what is never returned.
Three of the four discovery scanners need a credential of their own to sign in to your cloud with. This article covers what to create on each provider, what to grant it, how the credential is protected here, and what the connection test does and does not prove.
These are not the credentials you put in the privileged-access vault. Vault credentials are the ones you manage and rotate; these are the ones Qorionix uses to look at your estate. They live in a separate table, under a separate encryption namespace, and no rotation engine touches them.
Where they live
Privileged Access → Discovery, in the Cloud credentials panel. Its description is the whole promise: AWS, Microsoft Entra ID and Google Cloud can each be scanned as soon as a read-only credential for them is stored here. Qorionix keeps the secret encrypted, never shows it again, and only ever reads with it.
Reading the list needs pam:cloud_credentials.read, creating and updating need .write, running a test needs .test, and removing one needs .delete. None of those is granted to member or viewer. If you cannot see the panel you get an explanation rather than an empty list, and the wording is worth quoting because it stops a wrong conclusion:
Cloud credentials are administrator-only, because the list names which cloud accounts this organisation owns and which client identity Qorionix signs in with. This is not a statement that none are stored — ask an administrator.
What to create on each provider
Each provider's requirement is stated in the console next to the form, and each one is the minimum that lets the scan work. Grant exactly this and nothing more.
AWS
Create an IAM user with read-only access — the AWS-managed policy IAMReadOnlyAccess covers everything discovery uses — and give it no write permissions. Qorionix only lists users, roles, access keys and attached policies.
You supply the 12-digit AWS account ID this key belongs to, the Access key ID, the Secret access key, and a Signing region. The account id is not decoration: the scanner checks it against the identity the key actually resolves to and stops rather than filing findings against the wrong account — verbatim: the stored credential belongs to AWS account X, not Y. Qorionix stopped rather than file findings against the wrong account.
Microsoft Entra ID
Give the app registration the application permissions Directory.Read.All and RoleManagement.Read.All, then grant admin consent. Without RoleManagement.Read.All the test fails, rather than passing and then returning a scan with no role assignments in it.
You supply the Directory (tenant) ID, the Application (client) ID and a Client secret. The second permission is the one people leave out, and the second sentence of that requirement is the reason this article exists: a credential that can read the directory but not the role assignments can enumerate every user in your tenant and tell you nothing about which of them is an administrator. An empty result from that state would be the most dangerous output the product could produce.
Google Cloud
Grant the service account roles/iam.securityReviewer and roles/resourcemanager.projectViewer, or the single role roles/viewer, then create a JSON key for it. Qorionix only reads service accounts and IAM bindings.
You supply the Project ID and paste the whole service-account JSON key file. There is no separate client identifier field for GCP — it is read out of the key. The token Qorionix requests is scoped to the read-only cloud-platform scope, so the credential cannot be used to change anything even if the role you granted would have allowed it.
How the secret is stored, and why you cannot read it back
Envelope encryption, the same pattern the credential vault uses: a fresh 256-bit data key per secret, the secret sealed with AES-256-GCM under it, and that data key itself wrapped by a key derived from the deployment's master key. What is different — and deliberate — is the namespace.
The secret is also structurally unreturnable, which is worth more than a policy that says it should not be returned. The type that carries it overrides every route by which a Go value normally escapes — printing it, formatting it, logging it, serialising it to JSON — and each of those returns [redacted]. Recovering the plaintext requires calling one deliberately conspicuous method, so every place that does it can be found by searching for a single word.
What you get back on a read is the metadata: the provider, the name, the account identifier, the client identifier, whether a secret is stored, a short hint, when it was last rotated, and the last test result. The hint is the last four characters for an opaque secret and the first eight of the key id for a JSON key — and it is empty entirely for a secret shorter than eight characters, because a four-character tail of a six-character secret is two thirds of the secret.
The test proves permissions, not just sign-in
Press Test on the row. The result is Works or Does not work, and the reason is one of six:
| Outcome | Meaning |
|---|---|
Works | Both stages passed: the credential signed in and could read what the scan needs. |
Authentication failed | The provider rejected the credential itself. A wrong secret, an expired client secret, a deleted key. |
Permission denied | It signed in and could not read. This is the interesting one — see below. |
Throttled by the provider | Rate-limited. Wait and retry; nothing is wrong. |
Provider unreachable | A network or endpoint problem, including a wrong sovereign-cloud endpoint. |
Not usable | The credential is malformed — most often a truncated JSON key. |
Every one of those returns HTTP 200. A failed test is a result, not an error, and a client that only checks the status code will believe every test passed.
Changing the secret clears the previous verdict rather than leaving a stale green tick next to a new value. Test again after any change.
One deliberate limitation on the error detail: the provider's own error message is never stored, only a short code, capped in length and restricted to a safe character set. A provider — or a customer-controlled endpoint standing in for one — could otherwise return a whole paragraph in that field, or a copy of the secret you just submitted, and have it persisted.
Sovereign and government clouds
The form has an advanced section headed Sovereign and government cloud endpoints with an Authentication endpoint and an API endpoint. Use it for Azure Government, Azure China, AWS GovCloud and equivalent.
Operating them
Used for scansis a per-credential switch —In useorNot in use. Keep one active credential per cloud account. If you have two active credentials for the same provider and do not name an account when scanning, the scan refuses rather than guessing which one you meant.- Qorionix will not fall through to a different account. If you name an account and no stored credential matches it, the scan fails. Falling back would enumerate one account and label the findings with another's name, which is worse than not scanning.
- The provider cannot be changed after creation. To move a credential from AWS to Azure you delete it and create a new one, which is the right shape for an audit trail.
- Nothing rotates these for you. They are not vault credentials and no rotation engine touches them. Put a renewal date against an Entra client secret in particular — those expire on a date you chose and forgot.
Every action here is audited: pam.cloud_credential.create, .update, .delete and .test, against the resource type cloud_credential.
What to do next
- Create the Entra app registration first, with both application permissions and admin consent, and press Test before you scan. It is the scanner with a live-tenant test behind it.
- Read Discovering privileged accounts for what each scanner covers and — more usefully — what it does not.
- If a scan finds nothing after a successful test, A discovery scan finds nothing has the four causes in order.