fix(aws): explicitly deny Secrets Manager encryption with non-environment keys
The AWS-managed aws/secretsmanager key (or a customer key whose key policy grants account principals) needs no identity-policy Allow, so the tagged-key Allow alone did not keep user secrets on environment keys. An explicit Deny on kms:Encrypt / kms:GenerateDataKey* via secretsmanager when the key lacks triple-c:component does. README claim corrected; verify-live entry added. Check.context doc now states the StringList rule as a requirement on the simulation builder. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9d1630eb97
commit
7fdd5dc277
3 files changed
+73
-4
No files matched your search
@@ -56,7 +56,9 @@ pub struct Check {
|
||||
/// An ARN template ([`render`]).
|
||||
pub resource: &'static str,
|
||||
/// Context entries. A key that appears more than once is a multi-valued
|
||||
/// key (e.g. `aws:TagKeys`) and is sent as one `StringList` entry.
|
||||
/// key (e.g. `aws:TagKeys`): whoever builds the simulation request must
|
||||
/// send all its values as one `StringList` context entry (not enforced
|
||||
/// here; the permission check's simulation builder owns it).
|
||||
pub context: &'static [(&'static str, ContextValue)],
|
||||
pub write: bool,
|
||||
}
|
||||
@@ -1693,4 +1695,45 @@ mod tests {
|
||||
("aws:TagKeys", Literal("c"))
|
||||
])));
|
||||
}
|
||||
|
||||
/// A key whose *key policy* grants account principals through Secrets
|
||||
/// Manager (the AWS-managed `aws/secretsmanager` key, or any such customer
|
||||
/// key) needs no identity-policy Allow, so only an explicit Deny keeps a
|
||||
/// workspace user's secrets on environment keys.
|
||||
#[test]
|
||||
fn untagged_keys_are_explicitly_denied_through_secrets_manager() {
|
||||
let tier = Tier::WorkspaceUser;
|
||||
const VIA_SECRETS_MANAGER: Context = &[(
|
||||
"kms:ViaService",
|
||||
Literal("secretsmanager.{region}.amazonaws.com"),
|
||||
)];
|
||||
const VIA_SECRETS_MANAGER_ENVIRONMENT_KEY: Context = &[
|
||||
(
|
||||
"kms:ViaService",
|
||||
Literal("secretsmanager.{region}.amazonaws.com"),
|
||||
),
|
||||
(COMPONENT_RESOURCE_TAG, Literal("environment")),
|
||||
];
|
||||
for action in [
|
||||
"kms:Encrypt",
|
||||
"kms:GenerateDataKey",
|
||||
"kms:GenerateDataKeyWithoutPlaintext",
|
||||
] {
|
||||
assert!(
|
||||
explicitly_denied(tier, &write(action, PROBE_KEY, VIA_SECRETS_MANAGER)),
|
||||
"{action} on an untagged key via Secrets Manager is not explicitly denied"
|
||||
);
|
||||
assert!(
|
||||
!explicitly_denied(
|
||||
tier,
|
||||
&write(action, PROBE_KEY, VIA_SECRETS_MANAGER_ENVIRONMENT_KEY)
|
||||
),
|
||||
"{action} on an environment key must not be denied"
|
||||
);
|
||||
}
|
||||
// The checks themselves (environment key) stay allowed.
|
||||
for c in checks(tier).iter().filter(|c| c.action.starts_with("kms:")) {
|
||||
assert!(allowed(tier, c, ME, ME), "{}", c.action);
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-3
@@ -31,8 +31,11 @@ following:
|
||||
`triple-c:component`. `CreateSecret` must name the key by its full ARN in `KmsKeyId`, and the
|
||||
user can use KMS (`Encrypt`/`GenerateDataKey`) only through Secrets Manager and only with
|
||||
environment keys.
|
||||
- A secret on the default `aws/secretsmanager` key is refused. That key can't carry the tag, so
|
||||
the workspace's own task role, which is limited by the boundary, couldn't decrypt it.
|
||||
- A secret on any other key is refused by an **explicit Deny**: `kms:Encrypt` and
|
||||
`kms:GenerateDataKey*` through Secrets Manager on a key without `triple-c:component`. The Deny
|
||||
is needed because the AWS-managed `aws/secretsmanager` key, or any customer key whose key
|
||||
policy grants account principals directly, needs no identity-policy Allow. A secret on such a
|
||||
key would be unreadable by the workspace's own task role, which is limited by the boundary.
|
||||
- A secret tagged `triple-c:component` belongs to the environment. A workspace user can never
|
||||
tag, untag, overwrite or delete one; an explicit Deny enforces this.
|
||||
- **Manage their own access points.** They can create and delete EFS access points tagged with
|
||||
@@ -121,7 +124,8 @@ detection should flag any environment that breaks them.
|
||||
4. **Every environment KMS key and EFS file system carries `triple-c:component`.** The boundary
|
||||
and the admin tier both rely on this tag.
|
||||
5. **User secrets use the environment key.** The app must pass the environment KMS key's ARN as
|
||||
`KmsKeyId` when it creates a secret. The policy refuses any other choice.
|
||||
`KmsKeyId` when it creates a secret. The workspace policy explicitly denies Secrets Manager
|
||||
encryption with any key that lacks `triple-c:component`, including `aws/secretsmanager`.
|
||||
|
||||
## One-time setup: the boundary policy
|
||||
|
||||
@@ -209,6 +213,9 @@ a real account:
|
||||
- Check that Secrets Manager calls `GenerateDataKey`/`Encrypt` as the caller, so the KMS
|
||||
statement's `aws:ResourceTag/triple-c:component` rule is what enforces the environment key.
|
||||
- Check that `PutSecretValue` on such a secret passes.
|
||||
- Check that a `CreateSecret` naming the AWS-managed `aws/secretsmanager` key's ARN is denied.
|
||||
KMS should leave `aws:ResourceTag/triple-c:component` absent for that key, so the
|
||||
`NeverEncryptSecretsWithOtherKeys` Deny fires even though the key policy allows the call.
|
||||
- **Tag keys.** Check that `aws:TagKeys` is populated for `RunTask`, for `CreateSecret` and secret
|
||||
`TagResource`, for `CreateAccessPoint`, and for the ECS and EFS tag-on-create `TagResource`
|
||||
calls. Check also whether ECS-managed (`aws:ecs:*`) or propagated task-definition tags appear in
|
||||
|
||||
@@ -292,6 +292,25 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Sid": "NeverEncryptSecretsWithOtherKeys",
|
||||
"Effect": "Deny",
|
||||
"Action": [
|
||||
"kms:Encrypt",
|
||||
"kms:GenerateDataKey*"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:kms:*:*:key/*"
|
||||
],
|
||||
"Condition": {
|
||||
"StringLike": {
|
||||
"kms:ViaService": "secretsmanager.*.amazonaws.com"
|
||||
},
|
||||
"Null": {
|
||||
"aws:ResourceTag/triple-c:component": "true"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Sid": "ReadEcs",
|
||||
"Effect": "Allow",
|
||||
|
||||
Reference in new issue
Block a user