Repository navigation
(bedrockagentcore): Policy construct always emits Definition.Cedar.Statement, so guardrail and temporal policies cannot be declared with it, and there is no enforcementMode prop #39530
Description
Describe the bug
The Policy construct in aws-cdk-lib/aws-bedrockagentcore takes a statement: PolicyStatement. A PolicyStatement is built either with its constructor, whose effect can only be PERMIT or FORBID, or with fromCedar(). Either way, the construct emits the statement as Definition.Cedar.Statement on AWS::BedrockAgentCore::Policy.
The CloudFormation resource defines Definition as a union of Cedar.Statement and Policy.Statement. The AgentCore developer guide says to put a guardrail statement (when guardrails { ... }, BedrockGuardrails::* functions, the suppressOutput effect) in the policy field of the definition property. The API reference describes the policy member as the one that supports temporal conditions and guardrails. AWS's own sample, aws-samples/sample-native-guardrails-for-bedrock-agentcore, does this with the L1 resource and comments that only the policy member accepts a when guardrails block.
The L2 construct has no prop and no factory for the policy member. I used CfnPolicy directly. I did not try a raw override of Definition on the construct's default child. A second, smaller gap: the construct has no enforcementMode prop, although the resource has EnforcementMode (ACTIVE or LOG_ONLY) and the guide's recommended rollout is to create a policy in LOG_ONLY first.
Regression Issue
- Select this option if this issue appears to be a regression.
Last Known Working CDK Library Version
No response
Expected Behavior
- A way to place a statement in the
policymember. For example, aPolicyStatement.fromPolicy(statement)factory, or adefinitionTypeprop onPolicyProps. - An
enforcementModeprop onPolicyProps, with an enum for ACTIVE and LOG_ONLY. - At minimum, a note in the module README that guardrail and temporal statements and the enforcement mode need
CfnPolicytoday.
Current Behavior
Deploying a guardrail policy with the documented when guardrails { ... } form through Policy fails in CloudFormation with (CreatePolicy request id 522ee87b-48d1-4fce-ac25-a121b368967d, us-east-1):
When parsing the policy statement, the following errors occurred:
* unexpected token `guardrails`
Sending the same statement with a plain when { ... } block fails with (CreatePolicy request id 8d12cb06-1d35-44cb-abce-2192db48eae6, us-east-1):
When parsing the policy statement, the following errors occurred:
* invalid policy effect: suppressOutput
* `BedrockGuardrails::SensitiveInformation` is not a valid function
Both are the Cedar grammar rejecting the statement, which is expected because the construct placed it in Definition.Cedar.Statement.
Dropping to CfnPolicy with definition: { policy: { statement } } works and is what I deployed. The same statement through the control plane API with boto3 create_policy(definition={"policy": {"statement": ...}}) returns 202 and reaches ACTIVE (request ids f78a810b-eb35-4719-b0df-48bc4b44a734 and 95e3d2ea-f1d5-48a8-ad76-eee89481849e, us-east-1).
For the enforcement mode I use policy.node.default_child.add_property_override("EnforcementMode", "LOG_ONLY"), which works but bypasses the construct.
Reproduction Steps
Python, aws-cdk-lib 2.273.0.
from aws_cdk import Stack
from aws_cdk import aws_bedrockagentcore as agentcore
from constructs import Construct
GATEWAY_ARN = "arn:aws:bedrock-agentcore:us-east-1:111122223333:gateway/example-gw-abcdefghij"
STATEMENT = f'''suppressOutput(
principal,
action == AgentCore::Action::"ExampleTarget___get_record",
resource == AgentCore::Gateway::"{GATEWAY_ARN}"
)
when guardrails {{
BedrockGuardrails::SensitiveInformation(
["US_SOCIAL_SECURITY_NUMBER"],
[context.output.text]
).count() > 0
}};'''
class ReproStack(Stack):
def __init__(self, scope: Construct, id: str) -> None:
super().__init__(scope, id)
engine = agentcore.PolicyEngine(self, "Engine", policy_engine_name="repro_engine")
agentcore.Policy(
self,
"GuardrailPolicy",
policy_engine=engine,
policy_name="repro_suppress_output",
statement=agentcore.PolicyStatement.from_cedar(STATEMENT),
validation_mode=agentcore.PolicyValidationMode.IGNORE_ALL_FINDINGS,
)cdk synth. The template showsDefinition: { Cedar: { Statement: ... } }. There is no way to produceDefinition: { Policy: { Statement: ... } }fromPolicyProps.cdk deploy. The stack fails withunexpected token `guardrails`.- Replace
when guardrails {withwhen {and deploy again. The stack fails withinvalid policy effect: suppressOutputand`BedrockGuardrails::SensitiveInformation` is not a valid function. - Replace the
Policyconstruct withCfnPolicyanddefinition=CfnPolicy.PolicyDefinitionProperty(policy=CfnPolicy.PolicyStatementProperty(statement=STATEMENT)). The deploy succeeds and the policy reaches ACTIVE.
Possible Solution
export class PolicyStatement {
/** Raw Cedar, placed in Definition.Cedar.Statement (existing). */
static fromCedar(cedarStatement: string): PolicyStatement;
/** A guardrail or temporal statement, placed in Definition.Policy.Statement. */
static fromPolicy(policyStatement: string): PolicyStatement;
}
export interface PolicyProps {
// existing props
/** @default PolicyEnforcementMode.ACTIVE */
readonly enforcementMode?: PolicyEnforcementMode;
}
export enum PolicyEnforcementMode { ACTIVE = 'ACTIVE', LOG_ONLY = 'LOG_ONLY' }I am willing to open a PR for this if the approach is acceptable.
Additional Information/Context
- Guardrails in policies: https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/policy-guardrails-in-policies.html
- Test a policy in LOG_ONLY mode: https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/policy-test-a-policy.html
- PolicyDefinition API union: https://docs.aws.amazon.com/bedrock-agentcore-control/latest/APIReference/API_PolicyDefinition.html
- CloudFormation PolicyDefinition: https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-properties-bedrockagentcore-policy-policydefinition.html
- Construct reference: https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_bedrockagentcore.Policy.html
- AWS sample using CfnPolicy with the policy member: https://github.com/aws-samples/sample-native-guardrails-for-bedrock-agentcore/blob/main/infra/lib/guardrails-demo-stack.ts
- Still the same in v2.275.0 (latest release) and on main: the construct always writes
definition: { cedar: { statement } }and has no enforcement mode prop. https://github.com/aws/aws-cdk/blob/v2.275.0/packages/aws-cdk-lib/aws-bedrockagentcore/lib/policy/policy.ts#L231-L232
AWS CDK Library version (aws-cdk-lib)
2.273.0
AWS CDK CLI version
2.1145.0
Node.js Version
v20.19.5
OS
macOS 26.5.2
Language
Python
Language Version
3.12
Other information
Region us-east-1. The CloudFormation rejections above were produced by this construct in my stack on Oct 22, four per form. The statements in those attempts carried comment headers, and the successful API calls through the policy member did not, so the two sets are not byte-identical. The claim in this issue rests on two things: the synthesized template shows Definition.Cedar.Statement as the only member the construct can emit, and the Cedar grammar rejects guardrail syntax, as the recorded errors show. The AWS sample linked above reaches the same conclusion and uses the L1 resource for that reason.
Activity
hsiddhu2 commentedon Oct 28, 2026
FYI - This is the aws-bedrockagentcore module, not aws-iam.
pahud commentedon Oct 28, 2026
Hi @hsiddhu2,
Issue at a Glance:
Thanks for the detailed report and the
CfnPolicyworkaround.I reproduced this with
cdk synthon 2.273.0 (reported) and 2.275.0 (latest); both produce identical templates with the statement underDefinition.Cedar.Statement, andenforcementModefails to compile (TS2353).CfnPolicyor property overrides emitDefinition.Policy.StatementwithEnforcementModeas expected.It appears the L2 predates the
Policymember andEnforcementMode(L1 update #38189, v2.261.0) and was graduated in #38687 without picking them up. Thecedarmember is hardcoded here:aws-cdk/packages/aws-cdk-lib/aws-bedrockagentcore/lib/policy/policy.ts
Lines 228 to 236 in 2b95e32
From my view, your proposal looks right: an
enforcementModeprop plus aPolicyStatement.fromPolicy()factory, with today's output kept when neither is set. I don't see an open PR yet, and since you offered, we'd be happy to review one!hsiddhu2 commentedon Oct 29, 2026
Thanks, @pahud, for reproducing this in both versions and for the pointers to #38189 and #38687.
I'll open a PR with the approach from the issue:
enforcementModeprop onPolicyProps, with an enum for ACTIVE and LOG_ONLY.PolicyStatement.fromPolicy()factory that writes the statement toDefinition.Policy.Statement.It will include unit tests, an integ test, and a README update. Thanks again!
hsiddhu2 commentedon Oct 29, 2026
Hi @pahud - I've opened #39548 with the approach above. It adds the enforcementMode prop and PolicyStatement.fromPolicy(), and the default output is unchanged. It includes unit tests, an integ test, and a README update. Please let me know if you have any questions. Thank you.