Configuring access policies
Reference for P0 Security access policies: the full policy format, worked scenarios for AWS and on-call approvals, and the order in which P0 evaluates a request against your rules.
Access policies give you fine-grained control over your organization's just-in-time access workflow: who can request access, which resources they can request, and how those requests are approved. This page is the reference for the policy format, worked scenarios, and evaluation order.
To build a policy from scratch, start with the Configure your first access policy tutorial. It walks you through Policy Studio and gets a working policy in place in about ten minutes. Come back here for the full field reference.
Prerequisites
Before you begin, confirm the following:
Owner or Security Reviewer role in your P0 organization.
At least one resource integration installed (AWS, Google Cloud, Azure, Kubernetes, or another supported resource).
A directory integration configured (Google Workspace, Okta, or Microsoft Entra ID) if you plan to use group-based policies.
Where to edit policies
Policy Studio is at Policy Studio in the p0.app sidebar, or at https://p0.app/o/<your-organization>/policies. The View options (⋯) menu in the page header switches between Table view and YAML view.
The YAML editor takes the format on this page directly. You can also manage policies through the Access policies API and the Terraform provider.
Guided editor
Add New Policy opens the visual form. Name the policy at the top, for example "Engineering - AWS read-only", then fill in its three sections. Each one sets a part of the rule this page documents below:
Two buttons add entries within a section. Add New Resource Filter adds a filter under Resource(s), where you choose a filter type, an effect, and a pattern. Add New Access Rule adds another approver under Actions. When a policy has several approvers, approval from any one of them is enough.
Create Policy saves a new policy, and reads Save Policy when you edit an existing one. Confirm the policy then appears in the list with its Enabled toggle on.
Policies take effect as soon as you save them, and apply to every later access request.
Check that a policy works
Have someone who matches the policy make a request through Slack (/p0 request), the P0 CLI, or the web request modal. The Activity page at https://p0.app/o/<your-organization>/access-management/activity shows the request and which policy decided it.
If the requestor sees "This resource doesn't exist, or your organization doesn't allow this principal to access this resource", no policy matched. Check the requestor and resource parts of your rule against the request.
Access policy format
Structure of a policy configuration
A policy configuration is a collection of access policies. To change how P0 routes your requests (such as sending engineers' requests to their managers or restricting access to a particular prod resource to a small group), submit a new policy configuration.
You only have one policy configuration active at any given time, but that one configuration can have as many individual access policies as you want. You don't need to separate out different rule types or anything like that.
Here's an example policy configuration that you can copy into your app as a starting point:
Structure of a "rule"
The core of policy configurations are the rules, so let's break them down.
Requestor
The first part of a rule is a "requestor", which matches who makes the request. There are four types of requestors you can choose from:
"Any"
This matches all requestors. Useful for global rules like fall-back restrictions of sensitive resources.
"Group"
This rule matches any requestor that is a member of a group in your IdP. Currently, this supports Google Workspace, Microsoft Entra ID, and Okta.
All three of type, groups, and effect are required, and no other keys are accepted. Note that the group's own fields sit under groups, not directly on the rule.
groups: A list of one or more groups. Each entry needs all three of id, label, and directory.
effect: keep matches requestors who are a member of at least one of the listed groups. remove matches requestors who are a member of none of them.
id: For Google Workspace, this is the group email address (that is, engineering@yourco.com). For Entra, this is the Entra ID group's UUID. For Okta, this is the group ID found in the URL of the group's page in the admin console. See Okta docs.
label: This is any friendly human-readable name you like, although P0 suggests using the same name as displayed in your directory.
directory: For Google Workspace this is "workspace", for Okta this is "okta", and for Entra ID, this is "entra-id". Use "azure-ad" only if you are on P0's legacy Entra ID integration, which the app labels "Entra ID (Legacy)".
"User"
This rule matches only a specific user, as identified by their email address.
"Agentic"
This rule matches requests made by AI agents through the P0 AI Gateway, based on the combination of the agent that is acting and whoever it is acting for. See Agentic access policies for the actor and subject rule types and examples.
Resource
The second part of an access policy is the resource this rule should apply to.
"Any"
This matches all resources. This is useful, for instance, when you want to route access for a particular user, regardless of what resource or service they are looking to access.
"Integration"
This rule matches a specific type of access request. For instance, maybe you want to create a rule that routes all AWS requests to your DevOps team. Or you want to restrict access to GCP to only a select group.
service: For GCloud, "gcloud", for AWS, "aws", for Microsoft Azure "azure", for Snowflake, "snowflake", and for SSH, "ssh".
accessType (Optional): The access type within the service that the rule applies to, or "any" meaning the rule matches requests of any access type. Defaults to "any" if omitted.
filters (Optional): Filters allow you to apply the rule only to the service components that match the filtering condition.
Each filter has a filter-name that refers to the type of the requested object. For instance, when "service" is "aws", the filter with the name "policy" only allows requesting policies whose ARNs match the pattern.
Filters are independent when the access type is omitted or set to "any." For example, if you specify a filter-name=permission filter for service=gcloud requests, but omit a filter-name=role filter, then roles are unaffected by the filter, and all roles remain requestable.
Each filter has three potential properties:
effect - Describes how this filter is applied
keep - This rule retains objects that match the pattern as requestable
remove - This rule only retains objects that do not match the pattern
removeAll - This rule disables the object type entirely.
To allow all objects of a type as requestable, omit the filter altogether
key - Describes which property of the object the filter must match; only applies if "effect" is one of "keep" or "remove". For instance, if
service=awsandaccess-type=permission-setthen the key can be "name" or "arn". If "name", the regex pattern matches the name of permission sets. If "arn", the regex pattern matches the entire arn.pattern - A regex pattern used to match against the specified property; only applies if "effect" is one of "keep" or "remove"
Filter behavior
The behavior of filters depends on the requested access type.
For example, the "role" filter in the Gcloud integration has a slightly different meaning depending on which access type is used in the request:
When making a GCP request with "role" as the access type (for example,
p0 request gcloud role), the filter limits the roles the user can request access toWhen making a GCP request with "resource" as the access type (for example,
p0 request gcloud resource), the filter limits the roles that the user can request on the resource they are requesting
By setting the rule's access type to either "role" or "resource", you can explicitly specify which of these requests is allowable.
To ensure predictable filtering behavior, P0 recommends setting an accessType constraint when using filters.
The following table summarizes valid filter filter-name / key combinations. For more detailed information on the filters, see the documentation for AWS, Microsoft Azure, Google Cloud, and SSH.
aws
tag
<tag key>
Only filters policies and permission sets. AWS managed policies can't be tagged.
group
name
Filters IAM group names
permission-set
arn | name
Filters Identity Center permission sets
policy
arn
Filters policies with matching ARNs
resource
arn | name | service
Filters resource requests based on the resource ARN, the resource name, or the service the resource belongs to.
azure
subscription
id
Filters requests at a subscription level
resource
id | name
Filters requests based on what resource is requested
role
id | name
Filters requests based on the role requested
azure-ad|okta
group
id | label
Filters directory groups
gcloud
permission
id
Filters IAM permissions
role
id
Filters IAM roles based on full ID (for example, the ID for "Owner" is roles/owner)
resource
name | type | full-resource-name
Filters resource requests based on the resource name, resource type, or the full resource name.
snowflake
role
name
Filters roles
k8s
resource
kind | name | namespace
Filters resources
role
name
Filters roles and cluster roles
cluster
name
Filters clusters based on the cluster name specified when installed in P0
ssh
provider
id
Filters by cloud provider (aws, gcloud, azure, or self-hosted)
destination
arn | name | full-resource-name
Filters by instance identifier
group
name
Filters by SSH group name
parent
id
Filters by parent resource ID (AWS account ID, GCP project ID, or Azure subscription ID)
region
id
Filters by AWS region, GCP zone, or Azure region
sudo
(boolean)
Filters by whether sudo privileges are requested
Filters are not currently available for AWS or GCP resource-level grants, nor for Snowflake SQL grants.
Example that covers each possible access type in the AWS service:
Exclude all permission sets and policies containing "FullAccess"
Only allow AWS policies and permission sets where the tag "P0Grantable" is equal to the string "true"
Do not allow requesting any AWS groups
Approval
The final part of an access policy is the "approval". Unlike the requestor and resource parts, the approval part is an array of multiple rules, referring to the people/groups/services that can approve (or deny) access requests.
"p0"
This approval type is analogous to the default approval behavior. This rule routes approvals to the people designated as "Security Reviewers" on the Settings page of your app. The "options" key is optional. You can use it to:
allow the requestor to approve their own requests for this flow with the
allowOneParty: truesetting. Defaults tofalse.require the requestor to specify a reason when submitting requests with the
requireReason: truesetting. Defaults tofalse.designate this approver as a break glass approver for SSH "all" access requests with the
breakGlassApprover: truesetting. Defaults tofalse. See SSH Filtering for details.
"Group"
This rule matches any requestor who is a member of a group in your Identity Provider. Currently, P0 supports Google Workspace, Microsoft Entra ID, and Okta.
The shape matches a group requestor rule: type, groups, and effect are all required, and the group's own fields sit under groups. Note that options stays on the rule, beside groups, rather than moving in with the group.
groups: A list of one or more groups. Each entry needs all three of id, label, and directory.
effect: keep routes approval to members of the listed groups. remove routes it to everyone who is a member of none of them.
id: For Google Workspace, this is the group email address (that is, engineering@yourco.com). For Entra ID, this is the Entra ID group's UUID. For Okta, this is the group ID found in the URL of the group's page in the admin console. See Okta docs.
label: This is any friendly human-readable name you like, although P0 suggests using the same name as displayed in your directory. This label will be printed in approval notifications.
directory: For Google Workspace this is "workspace", for Okta this is "okta", and for Entra ID this is "entra-id". Use "azure-ad" only if you are on P0's legacy Entra ID integration, which the app labels "Entra ID (Legacy)".
options: See "P0" section
"Auto"
This rule automatically approves matching access requests for one hour.
integration: "pagerduty" or "incidentio". P0 automatically approves the request if the requestor is on-call. For PagerDuty, P0 checks the escalation policies configured on the integration page. For Incident.io, P0 checks the schedules selected on the Incident.io integration settings page.
options: The "options" key is optional. You can use it to require the requestor to specify a reason when submitting requests with the requireReason: true setting. Defaults to false.
"Escalation"
This rule routes approval to users who are currently on-call for the specified services or schedules. When combined with other approval rules, it enables on-call users to approve requests that have been escalated.
integration: "pagerduty" or "incidentio".
For PagerDuty, on-call status is determined by the escalation policies of the configured services. An incident is created against the specified services when the request is escalated.
For Incident.io, on-call status is determined by the specified schedule IDs. Users who are on-call for any of the listed schedules can approve the request.
options: See "P0" section.
services: List of PagerDuty service IDs or Incident.io schedule IDs, depending on the configured integration.
"Always allowed"
Access is always granted automatically.
options: The "options" key is optional. You can use it to require the requestor to specify a reason when submitting requests with the requireReason: true setting. Defaults to false.
"Deny"
This rule denies all requests that match. This supersedes other matching rules: if at least one "deny" rule matches, the request will be denied.
Common scenarios
These worked scenarios cover the most common access-policy setups. Adapt the group identifiers, account IDs, and service names to your own organization.
Route requests by team
Route your engineering team's requests to the SRE team for approval, and your data team's requests to the Data Ops team.
In Policy Studio, enter the following access policies:
Replace the group email addresses with your organization's actual directory groups.
Click Submit to activate the access policies.
What this does:
Any engineer who requests access to any resource gets routed to the SRE team for approval.
Any data team member who requests Snowflake access gets routed to Data Ops for approval.
allowOneParty: falseprevents requestors from approving their own requests.
If a request doesn't match any access policy, P0 rejects it with the message: "This resource doesn't exist, or your organization doesn't allow this principal to access this resource." Add a catch-all policy at the end of your workflow if you want unmatched requests to fall through to default approvers.
Add a catch-all policy
To ensure unmatched requests still reach your security reviewers, add this policy at the end of your workflow:
The type: p0 approval routes requests to the Security Reviewers configured under P0 Management → Access control.
Restrict access to production resources
Block requests to production AWS accounts while allowing development and staging access with different approval requirements.
In Policy Studio, add the following policies. Replace the AWS account IDs and Okta group IDs with your own values:
Click Submit.
What this does:
Development (account
111111111111): Engineers can self-approve their own requests.Staging (account
222222222222): Engineers need a peer to approve, and must provide a reason.Production (account
333333333333): P0 denies all requests. No one can request access through P0.
Exclude dangerous permissions
To further restrict which AWS permissions engineers can request, add filters that remove overly broad policies:
This removes any policy containing "FullAccess" in its ARN, and only keeps policies tagged with P0Grantable: true.
Auto-approve on-call engineers
Automatically approve requests from engineers who are currently on-call in PagerDuty or Incident.io, while directing all other requests to the SRE team.
Confirm that your PagerDuty or Incident.io integration is installed.
In Policy Studio, add the following policies:
Click Submit.
What this does:
If the requestor is currently on-call (as determined by PagerDuty escalation policies or Incident.io schedules), P0 automatically approves their request for one hour.
If the requestor is not on-call, P0 routes the request to the SRE team for manual approval.
requireReason: trueensures all requests include a justification in the audit log, even auto-approved ones.
Add escalation for urgent requests
You can also configure on-call users as escalation approvers. When a request is pending, the requestor can escalate it to the on-call engineer:
Replace PSJXXXG with your PagerDuty service ID. When the requestor escalates, PagerDuty creates an incident against the specified service, and the on-call engineer receives both a PagerDuty alert and a P0 approval notification.
Additional examples
Access policies support a wide range of setups. These examples show patterns beyond the common scenarios described earlier.
Different rules by AWS account
Development AWS account (123456789) allows one-party approvals. Staging AWS account (234567891) allows peer approvals but no one-party approvals. Production AWS account (345678912) requires a manager approver represented by an Okta group. Assumes an AWS Identity Center setup where resource filters allow requesting customer-managed policies in specific AWS accounts, enforced by an ARN match that includes the AWS account ID. Permission sets are implicitly allowed because the permission-set access type filter is not defined.
Approve by manager or service owner
Allow either the requestor's manager or the service owner to approve requests:
Require a reason for a specific resource type
Make reason mandatory for AWS requests
Exclude cluster-admin and restrict to the default namespace (Kubernetes)
Exclude the cluster-admin role and only allow requests in the default namespace:
Allow Google Cloud roles but not permissions
Let users request Google Cloud roles while denying direct permission requests:
Deny specific roles while allowing others
Deny requests for the Owner role while allowing all other Google Cloud roles:
Evaluation of access policies
Match Rules to the Request
Identify rules that match the request. A rule matches if both the requestor and the resource criteria in the rule align with the request details.
Handle Missing Matches
If no rules match, the access request is not created, and further evaluation stops. The requestor will see the following message:
This resource doesn't exist, or your organization doesn't allow this principal to access this resource
Evaluate Access Control of Matching Rules
For matching rules, review the Access Control field in the following order:
Deny all access If any matching rule specifies "Deny all access", the request is denied immediately, and further evaluation stops.
Always allowed If any rule specifies "Always allowed," the request is automatically approved and provisioned, and further evaluation stops.
Third-party auto-approval If a rule specifies a third-party auto-approval, such as a PagerDuty or Incident.io on-call rule, the request is evaluated for automatic approval. If it cannot be auto-approved, proceed to the next step.
Manual approval For all other Access Control values, the request requires manual approval by a designated person or group. When multiple rules with different manual approvers match, approval from any one approver is sufficient to provision the request. All approvers are notified.
Key points to remember
Deny all access: Always takes precedence and stops further evaluation immediately.
Always allowed: Overrides other Access Control values and is prioritized in the evaluation process.
Multiple matching rules: When multiple rules match the requestor and resource, approvers are combined using an ANY relationship, meaning approval from any one approver is sufficient.
Examples
Always allowed rule takes precedence over other allow rules
Consider a scenario where two rules apply to the same resource, node1 in the devstack group:
An "Always allow" rule grants access to
node1.Another "Allow" rule requires approval before granting access.
In this case, the "Always allow" rule takes precedence. As a result:
The user is immediately granted access to
node1without requiring additional approval.
Deny Rules are evaluated first, before ANY allow rules
Using the same example as before, if there is an additional rule that denies access to any instance containing node in its name, the system evaluates the "Deny" rule first.
In this case:
The "Deny" rule matches because
node1contains the stringnodein its name.The user's request is immediately denied, and is not evaluated further.
This highlights the priority of "Deny" rules: the system enforces them before considering any other rules.
Troubleshooting
Request rejected with "This resource doesn't exist..."
No access policy matches the request.
Add a catch-all policy or verify that your requestor and resource filters match the request.
Wrong approver notified
A broader policy matches before the specific one.
Reorder policies so more specific policies come first. Deny policies always take precedence regardless of order.
Auto-approval not working
The requestor is not on-call, or the PagerDuty/Incident.io integration is not installed.
Verify the requestor's on-call status in your incident management tool, and confirm the integration is active in Integrations.
Filter not matching
Regex pattern mismatch.
Patterns are unanchored by default. Use ^ and $ to anchor. P0 uses the JavaScript regex dialect.
Next steps
Fine-tune which resources are requestable with AWS, Google Cloud, Microsoft Azure, or SSH filtering.
Route or auto-approve requests made by AI agents with agentic access policies.
Manage policies programmatically with the Access Policies API or the Terraform provider.
New to access policies? Start with the Configure your first access policy tutorial.
Last updated