gcp-gcs-hmac-key-create
storage.hmacKeys.create generates a long-lived HMAC key (ID + secret) for a Service Account; the secret grants S3-compatible access to all GCS buckets the SA can reach but is scoped to the GCS API only, not full SA impersonation.
match (effective permission)
{
"action": "storage.hmacKeys.create",
"resource_type": "google.storage.HmacKey"
}
where
principal has EFFECTIVE storage.hmacKeys.create at the project scope (included in roles/storage.hmacKeyAdmin)
principal also has EFFECTIVE iam.serviceAccounts.actAs on the target SA (to create a key FOR another SA; if creating for self, actAs is not required)
emit
| source type | Identity |
|---|---|
| target type | ServiceAccount |
| source | <principal> |
| target | <Service Account (HmacKey target)> |
| permissions | storage.hmacKeys.create iam.serviceAccounts.actAs? |
| conditions | iam_permission role_compatibility |
| state logic | CONDITIONAL(iam_permission) as default: the HMAC key secret grants S3-compatible GCS access only (NOT full Google Cloud API access). ACTIVE when storage.hmacKeys.create is confirmed at the project scope AND (the target SA is the calling SA itself OR iam.serviceAccounts.actAs is also confirmed on the target SA); CONDITIONAL(iam_permission) when actAs grant is uncertain for a cross-SA key creation; BLOCKED when an org policy disables HMAC key creation (constraints/storage.hmacKeyServiceAccount restrictions) or an IAM deny targets storage.hmacKeys.create. Note: this edge grants S3-compatible credential creation, not full SA impersonation across Google APIs. |
Narrative
{principal.name} holds storage.hmacKeys.create and can generate a long-lived HMAC key (access-key ID + secret) for service account {sa.name}; the returned secret grants S3-compatible access to all GCS buckets {sa.name} can reach via the GCS S3 API only (NOT full Google Cloud API access).
Raw rule rules/derived/gcp/gcs.yaml
id: gcp-gcs-hmac-key-create
emits: CanCreateCredentialFor
description: storage.hmacKeys.create generates a long-lived HMAC key (ID + secret) for a Service Account;
the secret grants S3-compatible access to all GCS buckets the SA can reach but is scoped to the GCS
API only, not full SA impersonation.
match_effective_permission:
action: storage.hmacKeys.create
resource_type: google.storage.HmacKey
where:
- principal has EFFECTIVE storage.hmacKeys.create at the project scope (included in roles/storage.hmacKeyAdmin)
- principal also has EFFECTIVE iam.serviceAccounts.actAs on the target SA (to create a key FOR another
SA; if creating for self, actAs is not required)
emit:
source_type: Identity
target_type: ServiceAccount
source: <principal>
target: <Service Account (HmacKey target)>
permissions:
- storage.hmacKeys.create
- iam.serviceAccounts.actAs?
conditions:
- iam_permission
- role_compatibility
scope_qualifier: gcs_s3_compatible_api_only
state_logic: 'CONDITIONAL(iam_permission) as default: the HMAC key secret grants S3-compatible GCS access
only (NOT full Google Cloud API access). ACTIVE when storage.hmacKeys.create is confirmed at the project
scope AND (the target SA is the calling SA itself OR iam.serviceAccounts.actAs is also confirmed on
the target SA); CONDITIONAL(iam_permission) when actAs grant is uncertain for a cross-SA key creation;
BLOCKED when an org policy disables HMAC key creation (constraints/storage.hmacKeyServiceAccount restrictions)
or an IAM deny targets storage.hmacKeys.create. Note: this edge grants S3-compatible credential creation,
not full SA impersonation across Google APIs.'
confidence: min(contributing_confidences) * 0.97
derived_from:
- storage.hmacKeys.create effective permission at project scope
- iam.serviceAccounts.actAs on target SA (if cross-SA)
false_positive_note: "The HMAC secret is returned ONLY at creation time (CreateHmacKeyResponse.secret);\
\ storage.hmacKeys.get / storage.hmacKeys.list return only the key metadata (ID, state, SA email)\
\ \u2014 NOT the secret. Only emit CanCreateCredentialFor from the CREATE action, not from list/get.\
\ Callers need iam.serviceAccounts.actAs on the target SA when the key is for a SA other than themselves\
\ \u2014 without actAs, the Storage API returns 403; downgrade to CONDITIONAL(iam_permission). The\
\ HMAC secret is valid only while the key state is ACTIVE; if the SA is disabled or the key is deactivated,\
\ the credential is not usable. An org policy constraints/storage.hmacKeyServiceAccount that restricts\
\ which SAs can have HMAC keys may block creation for certain SAs -> CONDITIONAL(scp_or_org_policy).\
\ CRITICAL: HMAC keys authenticate ONLY to the GCS S3-compatible XML API endpoint \u2014 NOT to the\
\ JSON API or other Google Cloud APIs. This is storage-scoped credential creation, not full SA impersonation.\
\ Query filters should exclude this edge from general CanImpersonate/CanExecuteAs paths unless explicitly\
\ scoped to GCS operations."
narrative: '{principal.name} holds storage.hmacKeys.create and can generate a long-lived HMAC key (access-key
ID + secret) for service account {sa.name}; the returned secret grants S3-compatible access to all
GCS buckets {sa.name} can reach via the GCS S3 API only (NOT full Google Cloud API access).'