Validating Cedar Policies
Learn how to validate Common Fate authorization policies.
Common Fate uses authorization policy-as-code powered by Cedar. In this guide, you’ll learn how to validate Cedar policies to catch issues before they are deployed.
Prerequisites
If you’re running a BYOC (“Bring-Your-Own-Cloud”) deployment of Common Fate in your own AWS account, you’ll need to be on v1.31.0
or later of the common-fate/common-fate-deployment/aws
Terraform module.
You’ll also need the Common Fate cf
CLI installed - v1.12.0 or higher. You can check this by running cf --version
. You should see an output similar to the below
cf --version
cf version v1.12.0
# version must be v1.12.0 or higher for this guide.
Validating Cedar policies using the CLI
Validating policies is a linting step which helps you catch issues quickly during policy development. Validation helps prevent issues like referencing an nonexistent action or a resource attribute in Cedar policies, or simply making a typo in a policy.
To get started, let’s create a sample invalid policy. Create a new folder for our policy testing:
mkdir common-fate-policy-testing
cd common-fate-policy-testing
Inside this folder, we’ll create a file called example.cedar
. This file will contain an invalid Cedar policy:
permit (
principal,
action == Action::"Invalid",
resource
);
The policy above is invalid because Action::"Invalid"
does not correspond to any possible actions within Common Fate.
To validate the policy, run:
cf authz policyset validate
You should see an output similar to below, showing that validation has failed:
validating 1 policies
example.cedar ... FAILED
issues:
---- example.cedar ----
[ERROR] validation error on policy `policy0`: unrecognized action `Action::"Invalid"`
[ERROR] validation error on policy `policy0`: unable to find an applicable action given the policy head constraints
[ERROR] validation error on policy `policy0`: policy is impossible: the policy expression evaluates to false for all valid requests
Let’s fix the policy. Replace the contents of example.cedar
with:
permit (
principal,
action == Access::Action::"Request",
resource
);
Now validate the policy again, by running:
cf authz policyset validate
You should see an output similar to the below, showing that validation has succeeded:
validating 1 policies
example.cedar ... ok
Retrieving the Cedar schema
How does Common Fate know which actions are valid, and which aren’t? Common Fate checks the policies against a Cedar schema. The schema contains type definitions for all principals, actions, and resources used in Common Fate.
To see all of these type definitions, you can download the Cedar schema in JSON format:
cf authz schema get
You should see a JSON output similar to the below:
{
"AWS": {
"entityTypes": {
"Account": {
"shape": {
"type": "Record",
"attributes": {
"name": {
"type": "String"
},
... (the rest of the output omitted for brevity)
Fixing common validation issues
The following actions may require you to specify a Grant resource type, such as AWS::IDC::AccountGrant
to prevent validation errors:
Access::Action::"Activate"
Access::Action::"Approve"
Access::Action::"Close"
Access::Action::"Extend"
For example:
permit (
principal,
action == Access::Action::"Activate",
- resource
+ resource is AWS::IDC::AccountGrant
);
The following actions may require you to specify an Entitlement resource type, such as AWS::IDC::AccountEntitlement
to prevent validation errors:
Access::Action::"Request"
For example:
permit (
principal,
action == Access::Action::"Request",
- resource
+ resource is AWS::IDC::AccountEntitlement
);
These are described in more detail below.
Activate, Close, and Approve actions on Grants
If you’ve come from an earlier version of Common Fate prior to the introduction of Cedar schemas, you may have Cedar policies similar referencing resource attributes similar to the below:
permit (
principal,
action == Access::Action::"Activate",
resource
)
when { resource.target.tags.contains({key:"department", value:"engineering"}) };
When validating this policy using cf authz policyset validate
, you’ll see an error similar to the below:
validating 1 policies
example.cedar ... FAILED
issues:
---- example.cedar ----
[ERROR] validation error on policy `policy0` at offset 88-158: attribute `tags` for entity type DataStax::Organization not found
[ERROR] validation error on policy `policy0` at offset 88-158: attribute `tags` for entity type Test::Vault not found
[ERROR] validation error on policy `policy0` at offset 88-158: attribute `tags` for entity type AWS::IDC::Group not found
[ERROR] validation error on policy `policy0` at offset 88-158: attribute `tags` for entity type Okta::Group not found
[ERROR] validation error on policy `policy0` at offset 88-158: attribute `tags` for entity type Entra::Group not found
[ERROR] validation error on policy `policy0` at offset 88-158: attribute `tags` for entity type GCP::Project not found
[ERROR] validation error on policy `policy0` at offset 88-158: attribute `tags` for entity type GCP::Folder not found
Cedar is complaining because the Access::Action::"Activate"
action can be performed on Grants with different targets, such as AWS accounts, GCP projects, and Okta groups, but only AWS accounts have a tags
attribute.
To fix this, we can specify the type of grant to be AWS::IDC::AccountGrant
in the policy:
permit (
principal,
action == Access::Action::"Activate",
- resource
+ resource is AWS::IDC::AccountGrant
)
when { resource.target.tags.contains({key:"department", value:"engineering"}) };
After changing the policy, cf authz policyset validate
runs successfully:
validating 1 policies
example.cedar ... ok
The AWS::IDC::AccountGrant
entity type represents Grants to different target and role types. Here’s a table with the various grant types:
Resource Type (resource ) | Role (resource.role ) | Target (resource.target ) |
---|---|---|
AWS::IDC::AccountGrant | AWS::IDC::PermissionSet | AWS::Account |
GCP::ProjectGrant | GCP::Role | GCP::Project |
GCP::FolderGrant | GCP::Role | GCP::Folder |
DataStax::OrganizationGrant | DataStax::Role | DataStax::Organization |
Okta::GroupGrant | Okta::GroupRole | Okta::Group |
We’re constantly adding integrations to Common Fate, so the above table may
not represent the authoritative list of grant types. If in doubt, you can
reference the Cedar schema using cf authz schema get
.
Request actions on Entitlements
Similar the the above, the below policy will fail validation:
permit (
principal,
action == Access::Action::"Request",
resource
)
when { resource.target.tags.contains({key:"department", value:"engineering"}) };
When validating this policy using cf authz policyset validate
, you’ll see an error similar to the below:
validating 1 policies
example.cedar ... FAILED
issues:
---- example.cedar ----
[ERROR] validation error on policy `policy0` at offset 88-158: attribute `tags` for entity type DataStax::Organization not found
[ERROR] validation error on policy `policy0` at offset 88-158: attribute `tags` for entity type Test::Vault not found
[ERROR] validation error on policy `policy0` at offset 88-158: attribute `tags` for entity type AWS::IDC::Group not found
[ERROR] validation error on policy `policy0` at offset 88-158: attribute `tags` for entity type Okta::Group not found
[ERROR] validation error on policy `policy0` at offset 88-158: attribute `tags` for entity type Entra::Group not found
[ERROR] validation error on policy `policy0` at offset 88-158: attribute `tags` for entity type GCP::Project not found
[ERROR] validation error on policy `policy0` at offset 88-158: attribute `tags` for entity type GCP::Folder not found
Cedar is complaining because the Access::Action::"Request"
action can be performed on Entitlements with different targets, such as AWS accounts, GCP projects, and Okta groups, but only AWS accounts have a tags
attribute.
To fix this, we can specify the type of entitlement to be AWS::IDC::AccountEntitlement
in the policy:
permit (
principal,
action == Access::Action::"Request",
- resource
+ resource is AWS::IDC::AccountEntitlement
)
when { resource.target.tags.contains({key:"department", value:"engineering"}) };
After changing the policy, cf authz policyset validate
runs successfully:
validating 1 policies
example.cedar ... ok
The AWS::IDC::AccountEntitlement
entity type represents Entitlements to different target and role types. Here’s a table with the various entitlement types:
Resource Type (resource ) | Role (resource.role ) | Target (resource.target ) |
---|---|---|
AWS::IDC::AccountEntitlement | AWS::IDC::PermissionSet | AWS::Account |
GCP::ProjectEntitlement | GCP::Role | GCP::Project |
GCP::FolderEntitlement | GCP::Role | GCP::Folder |
DataStax::OrganizationEntitlement | DataStax::Role | DataStax::Organization |
Okta::GroupEntitlement | Okta::GroupRole | Okta::Group |
We’re constantly adding integrations to Common Fate, so the above table may
not represent the authoritative list of entitlement types. If in doubt, you
can reference the Cedar schema using cf authz schema get
.