Skip to content

feat(agentcore): add L2 constructs for policy and policy engine #37238

Open
dineshSajwan wants to merge 22 commits intoaws:mainfrom
dineshSajwan:agentcore-policy
Open

feat(agentcore): add L2 constructs for policy and policy engine #37238
dineshSajwan wants to merge 22 commits intoaws:mainfrom
dineshSajwan:agentcore-policy

Conversation

@dineshSajwan
Copy link
Copy Markdown
Contributor

@dineshSajwan dineshSajwan commented Mar 12, 2026

Issue # (if applicable)

Add L2 constructs for Policy and PolicyEngine with type-safe Cedar policy builder
Closes # 37219 .

Reason for this change

This PR adds support for Amazon Bedrock AgentCore Policy and PolicyEngine constructs to enable fine-grained authorization control for Bedrock agents using Cedar policy language. Previously, there was no CDK construct support for creating and managing AgentCore policies, requiring users to manually configure Cedar authorization rules through the console or API calls.

Description of changes

New Constructs Added:

  1. Policy-engine.ts
    L2 construct with base class pattern (PolicyEngineBase)
    Support for KMS encryption, tags, and descriptions
    Import method: PolicyEngine.fromPolicyEngineAttributes()
    Convenience method: addPolicy() for attaching policies

  2. Policy.ts -
    L2 construct with base class pattern (PolicyBase)
    Two ways to define policies:
    Raw Cedar: definition property for advanced users
    Type-safe builder: PolicyStatement class for guided policy creation
    Validation modes: FAIL_ON_ANY_FINDINGS (default) or IGNORE_ALL_FINDINGS
    Import method: Policy.fromPolicyAttributes()

  3. PolicyStatement Builder - Type-safe Cedar policy builder
    This is required because cedar policy use cedar language . The user has to be well aware of this language when creating raw cedar policy. This statement builder mimic the AWS console Form capability to create a cedar policy which makes it easy for user who are not well versed with cedar language to create cedar policy.

Describe any new or updated permissions being added

PolicyEngine.grantRead()
Actions Granted: bedrock-agentcore:GetPolicyEngine
Use Case: Read policy engine configuration at runtime for monitoring/audit

PolicyEngine.grantEvaluate()
Actions Granted: bedrock-agentcore:GetPolicyEnginebedrock-agentcore:AuthorizeActionbedrock-agentcore:PartiallyAuthorizeActions
Use Case: Evaluate authorization decisions during agent requests

Policy.grantRead()
Actions Granted: bedrock-agentcore:GetPolicy
Use Case: Read individual policy configuration and Cedar statements

Description of how you validated changes

Unit test, Integration test and with a sample CDK APP deployed the policies.

Checklist


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license

@aws-cdk-automation aws-cdk-automation requested a review from a team March 12, 2026 17:08
@github-actions github-actions bot added p2 valued-contributor [Pilot] contributed between 6-12 PRs to the CDK labels Mar 12, 2026
Copy link
Copy Markdown
Collaborator

@aws-cdk-automation aws-cdk-automation left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(This review is outdated)

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 12, 2026

⚠️ Experimental Feature: This security report is currently in experimental phase. Results may include false positives and the rules are being actively refined.
This security report is NOT a review blocker. Please try merge from main to avoid findings unrelated to the PR.


TestsPassed ✅SkippedFailed
Security Guardian Results96 ran96 passed
TestResult
No test annotations available

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 12, 2026

⚠️ Experimental Feature: This security report is currently in experimental phase. Results may include false positives and the rules are being actively refined.
This security report is NOT a review blocker. Please try merge from main to avoid findings unrelated to the PR.


TestsPassed ✅SkippedFailed
Security Guardian Results with resolved templates96 ran96 passed
TestResult
No test annotations available

@dineshSajwan dineshSajwan changed the title Agentcore policy feat(agentcore): Add L2 constructs for Policy and PolicyEngine with type-safe Cedar policy builder Mar 12, 2026
@dineshSajwan dineshSajwan changed the title feat(agentcore): Add L2 constructs for Policy and PolicyEngine with type-safe Cedar policy builder feat(agentcore): add L2 constructs for policy and policy engine with type-safe cedar policy builder Mar 12, 2026
@aws-cdk-automation aws-cdk-automation dismissed their stale review March 12, 2026 17:37

✅ Updated pull request passes all PRLinter validations. Dismissing previous PRLinter review.

@aws-cdk-automation aws-cdk-automation added the pr/needs-further-review PR requires additional review from our team specialists due to the scope or complexity of changes. label Mar 12, 2026
/**
* IAM permissions for PolicyEngine runtime operations (data plane)
*/
export namespace PolicyEnginePerms {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this file will no longer be required, due to the new way of setting grants: https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md#grants
But if still needed, then lets drop namespace and use flat exports instead (like in runtime perms, or tools perms)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Namespace - removed.
Autogenerated grant.json - Checked this, the auto-generated grants pattern (grants.json + spec2cdk) doesn't apply to alpha packages, only stable L1 modules get that pipeline.

* @param grantee - The IAM principal to grant permissions to
* @param actions - The actions to grant
*/
grant(grantee: iam.IGrantable, ...actions: string[]): iam.Grant;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are using a new pattern for grants: https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md#grants
They are now autogenerated (could be wrong for alpha modules tho, please double check) and the permission are based on the grants.json that needs to be added. Please review the documentation for this new pattern, and let us know if something cannot be applied (due to alpha module, but I am 99% sure it should work)

* Minimal reference interface for Policy resources.
* Used for resource identification and ARN construction.
*/
export interface IPolicyRef {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These IxxxRef classes are autogenerated, there is no need to implement them, just consume them in the IPolicy one. Check this example: https://github.com/aws/aws-cdk/blob/main/packages/%40aws-cdk/aws-mediapackagev2-alpha/lib/channel.ts#L36
Same applies for all other IxxRef I saw in the PR

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. IPolicy now extends the auto-generated IPolicyRef and IPolicyEngine extends IPolicyEngineRef, both imported from aws-cdk-lib/aws-bedrockagentcore.

/**
* The ARN of the policy
*/
readonly policyArn: string;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing @attribute tag?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added @Attribute tags on the interface properties and the concrete class properties.

* Contains methods and attributes valid for Policies either created with CDK or imported.
*/
export abstract class PolicyBase extends Resource implements IPolicy {
public abstract readonly policyArn: string;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing @attribute tag here too? review all attributes are correctly tagged please

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added @Attribute tags on the interface properties and the concrete class properties. Abstract base class properties intentionally don't carry them since CDK tooling resolves them via the interface and concrete implementation.

*/
public grantEvaluateForGateway(grantee: iam.IGrantable, gateway: IGateway): iam.Grant {
const getPolicyEngineGrant = this.grant(grantee, 'bedrock-agentcore:GetPolicyEngine');
const gatewayResourceName = Token.isUnresolved(gateway.name) ? '*' : `${gateway.name}-*`;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't this use the gateway.gatewayArn directly?

Copy link
Copy Markdown
Contributor Author

@dineshSajwan dineshSajwan Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes , gateway.name is used intentionally to to avoid a circular dependency between PolicyEngine and Gateway. The gateway needs policyengine and the policyengine needs gateway arn. The gateway.gatewayArnis synthesized as a CloudFormation Fn::GetAtt token that references the Gateway resource, and if PolicyEngine tries to reference that ARN directly, it creates a circular dependency that CloudFormation cannot resolve at deploy time.
By using gateway.name with a wildcard suffix, we can construct the necessary ARN pattern without directly referencing the unresolved gateway ARN, thus avoiding the circular dependency while still granting permissions scoped to the correct gateway.

Added JS doc.

* @param scope - The construct scope for error reporting (optional)
* @returns Array of validation error messages, empty if valid
*/
export function validatePolicyEngineName(name: string, scope?: IConstruct): string[] {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this file in general, any string that is validated needs to also check if its a unresolved token first

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

public addPolicy(id: string, options: AddPolicyOptions): any {
// Import Policy here to avoid circular dependency
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { Policy } = require('./policy');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not the correct way to add imports. What is the circular dependency?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bad check in. I used it to fix a false circular dependency . Now removed the bad import created a policy-types.ts file and the false circular dependency was also removed.

* Effect of the policy statement - whether to permit or forbid the action.
* @internal
*/
enum PolicyEffect {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think all this enums here potentially can be extended to support new values. Correct me if I am wrong on this. We need to use enum-like instead, to provide the escape hatch if a new value is added but not yet supported in CDK

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are all @internal enumns and the user will not use these. Also we support multiple ways to create the cedar policy, for example PolicyStatement.fromCedar('any raw cedar string you want'); . The user can always use the fromCedar for raw string to support any value. IMHO , I think this should be fine.

@alvazjor alvazjor self-assigned this Apr 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

p2 pr/needs-community-review This PR needs a review from a Trusted Community Member or Core Team Member. pr/needs-further-review PR requires additional review from our team specialists due to the scope or complexity of changes. valued-contributor [Pilot] contributed between 6-12 PRs to the CDK

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants