Skip to content

Policy reference

This page is the source-checked Cedar reference. The compatibility policy.md route retains the explanatory guide and old anchors; this page records the vocabulary, action names, and context contract from crates/gdsgate-policy/src/schema.cedarschema.

Action map

Every action below is declared in the schema and has a production call site. The action string is case-sensitive. An action absent from this list is not a supported policy action.

connect kubeRequest dbQuery mcpCallTool mcpReadResource mcpGetPrompt llmCall httpRequest viewTools view enrollNode revokeNode manageCatalog disableUser issueJoinToken viewNodes viewAudit rotateCA editPolicy approvePolicyEdit viewRecordings approveRequest killSession sshForwardLocal sshForwardRemote sshForwardAgent mintOnwardSshCert

Action matrix table

The table uses a compact delta notation. Every row has the common required context mfa_satisfied:Bool, mfa_age_seconds:Long, step_up_satisfied:Bool, step_up_age_seconds:Long, totp_satisfied:Bool, totp_age_seconds:Long, webauthn_satisfied:Bool, webauthn_age_seconds:Long, webauthn_uv_satisfied:Bool, in_corp_vpn:Bool, timestamp:Long, hour:Long, weekday:Long, ticket_open:Bool, ticket_id:String, and recheck_confirmed:Bool. Every row may also receive optional src_ip:ipaddr; code must guard it with context has src_ip because derived credentials do not have a client address. The required and optional columns below are only the action-specific delta. A dash means that the action adds no field. Struct fields use the exact Cedar shape from the marker immediately below this table.

Action Principal -> resource Required context delta Optional context delta Catalog / target prerequisite Audit evidence Tested request + task
connect User, Agent -> SshHost, Database, KubernetesCluster, TcpService, McpServer, WebApp, WebEgress presented:String db_role:String; approved_request; step_up_grant A served catalog row of the listed kind; a Database child inherits its catalogued host policy.decision POL-0101; admitted sessions emit session.open and session.close policy_examples::developer_may_ssh_non_prod; one connect
kubeRequest User, Agent -> KubernetesCluster verb:String; resource_kind:String; namespace:String; resource_name:String; subresource:String; read_only:Bool approved_request; step_up_grant The cluster must resolve to a served KubernetesCluster catalog row Denial is policy.decision POL-0201; an allowed request emits kube.request SES-0501 tenant_baseline::idp_admins_get_the_working_set; Kubernetes request authorization
dbQuery User, Agent -> Database sql_category:String (read, write, ddl, dcl, or other) db_role; approved_request The database host must be served; a nested database is resolved through its parent host POL-0202 is evaluated by category at session open; a refused statement emits db.query SES-0301 session_role_live::restricted_session_blocks_writes_and_evasions; per-statement authorization
mcpCallTool User, Agent -> Tool - approved_request; step_up_grant The parent McpServer must be catalogued; the transient Tool child supplies its name and destructive flag Denial is policy.decision POL-0203; an allowed call emits mcp.tool_call MCP-0101 proxy_mcp_decider::every_data_path_is_put_to_the_decider; MCP per-tool policy
mcpReadResource User, Agent -> McpResource - approved_request; step_up_grant The parent McpServer must be catalogued; the URI is a transient McpResource child Denial is policy.decision POL-0204; an allowed read emits mcp.resource_read MCP-0102 proxy_mcp_decider::every_data_path_is_put_to_the_decider; MCP per-tool policy
mcpGetPrompt User, Agent -> McpPrompt - approved_request; step_up_grant The parent McpServer must be catalogued; the prompt name is a transient McpPrompt child Denial is policy.decision POL-0205; an allowed get emits mcp.prompt_get MCP-0103 proxy_mcp_decider::every_data_path_is_put_to_the_decider; MCP per-tool policy
llmCall User, Agent -> LlmModel - approved_request; step_up_grant The parent LlmService must be catalogued; LlmModel is a transient child resolved under that service Denial is policy.decision POL-0206; an allowed call emits llm.call SES-0401 authorize_llm_call::a_permitted_model_is_allowed; model calls
httpRequest User, Agent -> WebApp, WebEgress method:String; host:String; port:Long; route:String; path:String; read_only:Bool; inspected:Bool; presented:String; upgrade:String approved_request; step_up_grant The web endpoint must resolve to a served WebApp or WebEgress row Denial is policy.decision POL-0207; allowed traffic emits http.request or http.tunnel SES-0701/SES-0702 proxy_tcp_mcp::a_browser_opens_a_real_page_through_the_web_lane; HTTP routes
viewTools User, Agent -> Tool - - The listing is filtered from the catalogued MCP server inventory; the transient tool is not a grant target No audit row for a listing filter by design; POL-0302 is the schema action identity tenant_baseline::destructive_tool_is_refused_even_for_admins; listing visibility
view User, Agent -> SshHost, Database, KubernetesCluster, TcpService, McpServer, LlmService, WebApp, WebEgress - - The catalog listing is the source of visible resources; no backend string bypasses it No audit row for a listing filter by design; POL-0301 is the schema action identity policy_examples::view_allows_non_prod_resource; catalog visibility
enrollNode User -> EnrolledNode - - Imports a leaf into the enrolled-node registry; it does not require a data-plane catalog row Admission denial is enroll.node_admission IDN-0401; successful import is identity.import IDN-0301 tenant_baseline::admin_certificate_identity_runs_control_plane_actions; registration lifecycle
revokeNode User -> EnrolledNode - - The target must be an enrolled identity; workload revocation also removes its registry row Admission denial is identity.revoke_admission IDN-0402; effects emit identity.revoke IDN-0302 or identity.delete IDN-0303 admin_rpc::admin_can_create_token_list_and_revoke_through_grpc; per-node revocation
manageCatalog User -> SshHost, Database, KubernetesCluster, TcpService, McpServer, LlmService, Catalog - - This action creates, changes, removes, or reads catalog rows; Catalog::all is the collection handle catalog.manage CAT-0101 records allow and deny outcomes catalog_admin_rpc::catalog_write_is_refused_when_policy_denies; resource catalog lifecycle
disableUser User -> User - - The user and owner delegations are identity state, not catalog resources Owner cascade emits delegation.revoke_by_owner DLG-0201; schema code POL-0405 is not a separate policy row four_actions_that_write_no_decision::the_disable_user_decision_arrives_as_the_cascade_it_gates; administrative actions
issueJoinToken User -> EnrolledNode - step_up_grant The target is a positive role allowlist: gdsgate-connector, gdsgate-proxy, or gdsgate-workload for the provisioner and people baseline Denial is enroll.token_admission IDN-0403; creation emits enroll.token.create IDN-0101 spending_a_one_time_grant::minting_a_join_token_costs_a_ceremony_each_time; bootstrap tokens
viewNodes User -> EnrolledNode - - Registry-wide handle EnrolledNode::*; no catalog row is needed A denied listing emits view_nodes.admission IDN-0404; an allowed listing has no row catalog_admin_rpc::the_listing_is_gated_on_view_nodes; registration lifecycle
viewAudit User -> AuditLog - - Chain handle AuditLog::chain; it reads the audit store rather than a served backend audit.view AUD-0101 records both allow and deny admin_through_gateway::a_person_granted_the_chain_reads_it_and_the_reading_is_on_it; audit export
rotateCA User -> CertificateAuthority - step_up_grant The authority is a control-plane CA object; mTLS and emergency paths do not supply a factor automatically ca.rotate CAS-0101 records the outcome step_up_on_administrative_actions::rotate_ca_denies_without_a_key_confirmation_and_allows_after_one; CA rotation
editPolicy User -> PolicyDoc - - The singleton policy document is the target; the break-glass permit is checked before a push policy.edit PED-0101 records the proposal outcome step_up_on_operator_actions::edit_policy_denies_without_a_step_up_and_allows_after_one; policy lifecycle
approvePolicyEdit User -> PolicyDoc - step_up_grant The target is a pending policy proposal; approval requires the separate approver lane and min_approvers >= 2 policy.edit_approve PED-0102 records each vote/outcome step_up_on_operator_actions::approve_policy_edit_denies_without_a_step_up_and_allows_after_one; policy lifecycle
viewRecordings User -> AuditLog recording_session_uid:String; recording_actor:String; recording_target:String; recording_kind:String step_up_grant Recording metadata is in the audit store; list requests use empty strings, row requests use actual values recordings.view REC-0101 records allow and deny, including per-row gates spending_a_one_time_grant::reading_one_recording_costs_a_ceremony_each_time; audit export
approveRequest User -> AccessRequest - step_up_grant The access-request row names requester, action, target, and expiry; its target resource must also be catalog-served before use access_request.approve JIT-0102 records each review step_up_on_operator_actions::approving_an_elevation_denies_without_a_step_up_and_allows_after_one; JIT approvers
killSession User -> Session - step_up_grant The target must be a live session registry entry; it is not a catalog row A real termination emits session.kill SES-0601; list visibility does not consume a grant or emit a row data_plane::kill_session_terminates_a_live_relay_and_reports_it; session termination
sshForwardLocal User, Agent -> SshHost forward_target:{host:String,port:Long} - The SSH host must resolve in the catalog and the active session must allow local forwarding policy.decision POL-0102 records allow or deny a_decision_names_its_session::every_gate_inside_a_session_names_the_session; SSH -L/-R
sshForwardRemote User, Agent -> SshHost forward_bind:{host:String,port:Long} - The SSH host must resolve in the catalog; config and Cedar both constrain the bind address policy.decision POL-0103 records allow or deny No dedicated request test found; source-checked authorize_forward, not tested in this inventory; SSH -L/-R
sshForwardAgent User, Agent -> SshHost - - The SSH host must resolve in the catalog and the backend must set allow_agent_forward = true policy.decision POL-0105 records allow or deny agent_forward_is_a_decision::permission_to_forward_a_port_is_not_permission_to_forward_the_agent; SSH -A
mintOnwardSshCert User, Agent -> SshHost login_user:String - The SSH host must resolve in the catalog and the gateway CA mints the downstream certificate policy.decision POL-0104 records allow or deny authority_relay_failure_model::a_severed_control_plane_refuses_the_jump_host_session; downstream certificate minting

The exact source serialization used by the standalone inventory check is below. Each row is action|principal types|resource types|required fields|optional fields.

connect|User,Agent|SshHost,Database,KubernetesCluster,TcpService,McpServer,WebApp,WebEgress|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool,presented:String|src_ip:ipaddr,db_role:String,approved_request:{expires:Long,for_action:String},step_up_grant:{method:String,for_action:String} kubeRequest|User,Agent|KubernetesCluster|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool,verb:String,resource_kind:String,namespace:String,resource_name:String,subresource:String,read_only:Bool|src_ip:ipaddr,approved_request:{expires:Long,for_action:String},step_up_grant:{method:String,for_action:String} dbQuery|User,Agent|Database|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool,sql_category:String|src_ip:ipaddr,db_role:String,approved_request:{expires:Long,for_action:String} mcpCallTool|User,Agent|Tool|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool|src_ip:ipaddr,approved_request:{expires:Long,for_action:String},step_up_grant:{method:String,for_action:String} mcpReadResource|User,Agent|McpResource|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool|src_ip:ipaddr,approved_request:{expires:Long,for_action:String},step_up_grant:{method:String,for_action:String} mcpGetPrompt|User,Agent|McpPrompt|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool|src_ip:ipaddr,approved_request:{expires:Long,for_action:String},step_up_grant:{method:String,for_action:String} llmCall|User,Agent|LlmModel|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool|src_ip:ipaddr,approved_request:{expires:Long,for_action:String},step_up_grant:{method:String,for_action:String} httpRequest|User,Agent|WebApp,WebEgress|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool,method:String,host:String,port:Long,route:String,path:String,read_only:Bool,inspected:Bool,presented:String,upgrade:String|src_ip:ipaddr,approved_request:{expires:Long,for_action:String},step_up_grant:{method:String,for_action:String} viewTools|User,Agent|Tool|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool|src_ip:ipaddr view|User,Agent|SshHost,Database,KubernetesCluster,TcpService,McpServer,LlmService,WebApp,WebEgress|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool|src_ip:ipaddr enrollNode|User|EnrolledNode|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool|src_ip:ipaddr revokeNode|User|EnrolledNode|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool|src_ip:ipaddr manageCatalog|User|SshHost,Database,KubernetesCluster,TcpService,McpServer,LlmService,Catalog|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool|src_ip:ipaddr disableUser|User|User|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool|src_ip:ipaddr issueJoinToken|User|EnrolledNode|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool|src_ip:ipaddr,step_up_grant:{method:String,for_action:String} viewNodes|User|EnrolledNode|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool|src_ip:ipaddr viewAudit|User|AuditLog|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool|src_ip:ipaddr rotateCA|User|CertificateAuthority|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool|src_ip:ipaddr,step_up_grant:{method:String,for_action:String} editPolicy|User|PolicyDoc|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool|src_ip:ipaddr approvePolicyEdit|User|PolicyDoc|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool|src_ip:ipaddr,step_up_grant:{method:String,for_action:String} viewRecordings|User|AuditLog|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool,recording_session_uid:String,recording_actor:String,recording_target:String,recording_kind:String|src_ip:ipaddr,step_up_grant:{method:String,for_action:String} approveRequest|User|AccessRequest|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool|src_ip:ipaddr,step_up_grant:{method:String,for_action:String} killSession|User|Session|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool|src_ip:ipaddr,step_up_grant:{method:String,for_action:String} sshForwardLocal|User,Agent|SshHost|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool,forward_target:{host:String,port:Long}|src_ip:ipaddr sshForwardRemote|User,Agent|SshHost|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool,forward_bind:{host:String,port:Long}|src_ip:ipaddr sshForwardAgent|User,Agent|SshHost|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool|src_ip:ipaddr mintOnwardSshCert|User,Agent|SshHost|mfa_satisfied:Bool,mfa_age_seconds:Long,step_up_satisfied:Bool,step_up_age_seconds:Long,totp_satisfied:Bool,totp_age_seconds:Long,webauthn_satisfied:Bool,webauthn_age_seconds:Long,webauthn_uv_satisfied:Bool,in_corp_vpn:Bool,timestamp:Long,hour:Long,weekday:Long,ticket_open:Bool,ticket_id:String,recheck_confirmed:Bool,login_user:String|src_ip:ipaddr

connect is the general resource session action. Protocol-specific request gates such as kubeRequest, dbQuery, mcpCallTool, mcpReadResource, mcpGetPrompt, llmCall, and httpRequest carry protocol context and do not replace the base catalog decision. viewTools and view control catalog visibility. Administrative actions target control-plane entities and remain separate from data-plane sessions.

One connect, seven kinds of resource

The action applies to SshHost, KubernetesCluster, Database, McpServer, TcpService, WebApp, and WebEgress resources. llmCall targets an LlmModel child, whose catalogued parent is an LlmService. No connect session is opened for an LlmService or LlmModel. The catalog kind and parent relationships are resolved before Cedar evaluation; an arbitrary backend string is not a resource identity.

kubeRequest and context.read_only

Kubernetes request policy receives the cluster resource and a read_only boolean. A mutating request must not be treated as read-only because the HTTP method is merely an input to the request gate. Use an explicit policy condition for the boolean.

Credential type: context.presented

context.presented describes how the credential reached the gateway. Policies can distinguish a user-presented identity from a machine or delegated path, but the field does not prove that the principal has access. Pair it with the principal, resource, and action.

Entity types

The schema uses structural, principal, target-resource, control-plane, and runtime entities. Required fields are deliberately typed so Cedar validation can reject an ill-typed policy before activation.

Organization|- Project|Organization Group|Group User|Group,Organization Agent|Group,Project SshHost|Project KubernetesCluster|Project Database|Project,Database McpServer|Project Tool|McpServer McpResource|McpServer McpPrompt|McpServer TcpService|Project WebApp|Project WebEgress|Project LlmService|Project LlmModel|LlmService Catalog|- EnrolledNode|- CertificateAuthority|- PolicyDoc|- AccessRequest|- AuditLog|- Session|-

Entity parent table

Entity Declared parents
Organization -
Project Organization
Group Group
User Group, Organization
Agent Group, Project
SshHost Project
KubernetesCluster Project
Database Project, Database
McpServer Project
Tool McpServer
McpResource McpServer
McpPrompt McpServer
TcpService Project
WebApp Project
WebEgress Project
LlmService Project
LlmModel LlmService
Catalog -
EnrolledNode -
CertificateAuthority -
PolicyDoc -
AccessRequest -
AuditLog -
Session -

Reserved baseline groups

gdsgate-admin gdsgate-break-glass gdsgate-provisioner

Group Source role
gdsgate-admin Control-plane mTLS identity
gdsgate-break-glass Synthetic policy-edit invariant probe
gdsgate-provisioner External provisioning mTLS identity

Structural

Organization, Project, and nested Group provide grouping. A Project is in an Organization; a Group can be nested in another Group.

Principals

User may carry email, org, and mfa_enrolled. Agent may carry spiffe_id, project, kind, and owner. EnrolledNode is a control-plane resource, not a principal. Optional principal attributes require guarded Cedar access.

Target resources

SshHost, KubernetesCluster, Database, McpServer, Tool, McpResource, McpPrompt, TcpService, WebApp, WebEgress, LlmService, and LlmModel represent data-plane targets. Infrastructure resources carry required environment; Database may carry engine. MCP child entities belong to an MCP server.

Control-plane resources

Catalog, EnrolledNode, CertificateAuthority, PolicyDoc, and AccessRequest represent administrative state. AuditLog is the audit record resource used by audit visibility rules.

Runtime resources

Session represents a live or recorded session and may carry owner, resource, kind, source IP, and start time. Runtime attributes describe observed state; they do not create a catalog declaration.

Context fields per action

The schema declares context fields on each action. Runtime code supplies the relevant subset; an action whose policy reads a missing required field evaluates to deny. Optional src_ip and approved_request must be guarded with Cedar has checks. Typical fields include environment, project, source address, credential presentation, read-only mode, MCP tool metadata, database query metadata, and approval state.

Use the action-specific declaration as the contract. Do not copy a field from one action into another without validating the complete Cedar schema. The schema tests reject unknown attributes and ill-typed policies, while the unwired-action test requires every declared action to have a production call site.

For the table shorthand, db_role means db_role:String, approved_request means approved_request:{expires:Long,for_action:String}, and step_up_grant means step_up_grant:{method:String,for_action:String}. The canonical marker remains the byte-for-byte inventory source for these shapes.

JIT approvals and one-time step-up grants

approved_request and step_up_grant are different controls. An approved_request is an active access request approval with an expiry and an exact principal/resource/action key. It can be used while active; it is not a general-purpose permit, and it is not supplied to listing actions such as viewTools. A listing must remain reachable before an operator can select an individual MCP, recording, request, or session target.

step_up_grant is one-time. The grant is spent only when every allowing rule needed for the decision names the grant marker. A denial does not spend it, and another permit that allows the operation without the marker does not spend it. The schema and authority code narrow the one-time key as follows:

Lane One-time grant scope
connect The selected served resource
kubeRequest The cluster; the Cedar rule must further narrow verb, kind, namespace, name, or subresource
mcpCallTool The transient Tool child
mcpReadResource The transient McpResource child
mcpGetPrompt The transient McpPrompt child
llmCall The transient LlmModel child
httpRequest The WebApp or WebEgress resource; the rule must further narrow route or path
issueJoinToken The EnrolledNode role named by the token
rotateCA The CertificateAuthority
approvePolicyEdit The pending proposal version
viewRecordings The recording session UID; a list does not spend a grant
approveRequest The AccessRequest ID
killSession The live Session UID; listing visibility does not spend a grant

The method is checked by the policy context and the grant is consumed by the authority only for the decisive operation. dbQuery has approved_request but no step_up_grant in the schema; its categories are enforced at database session open and by the connector query path. Workload requests in the Kubernetes lane do not receive an interactive ceremony. These rules are source-checked against the action comments in schema.cedarschema and the corresponding authority authorization functions.

Hierarchy and subresources

Cedar parent membership is part of the entity contract. Project is below Organization; User is below Group and Organization; Agent is below Group and Project. SshHost, KubernetesCluster, Database, TcpService, McpServer, WebApp, WebEgress, and LlmService are below Project. Database has Database as a nested parent so Database::host.database inherits the served host's catalog membership. Tool, McpResource, and McpPrompt are transient children of an McpServer. LlmModel is a transient child of an LlmService.

The LLM lane is therefore a call decision over LlmModel, not a connect decision over LlmService. The service must be catalogued before the model child can be resolved, and the model body is read only after the per-call policy decision. The same parent-resolution rule applies to MCP children and database subresources. Catalog::all, EnrolledNode::*, and AuditLog::chain are explicit collection handles for control-plane operations, not wildcard substitutes for data-plane catalog rows.

Reserved baseline capabilities

The shipped tenant baseline is deny-by-default and uses separate identities for recovery, provisioning, and people. These are capabilities of the source baseline, not an assertion that every tenant policy must copy them:

Baseline identity Source-checked capabilities and boundary
gdsgate-admin enrollNode, revokeNode, disableUser, rotateCA, manageCatalog, issueJoinToken, viewNodes, and viewAudit; it never opens a data-plane session
gdsgate-provisioner manageCatalog, viewNodes, and issueJoinToken only for gdsgate-connector, gdsgate-proxy, and gdsgate-workload; it cannot enroll, revoke, disable, rotate, edit policy, read recordings, kill sessions, or connect
admins The people group can view and manage the working catalog, view nodes, revoke nodes, disable users, issue the three connector/proxy/workload tokens, and use the baseline data-plane grants; it cannot rotate the CA, enroll arbitrary identities, mint control-plane tokens, or use the SSH forwarding/onward-cert lanes
gdsgate-break-glass A synthetic User used by the policy push invariant probe; it retains editPolicy on PolicyDoc::0 and is not a real client identity

The gdsgate- namespace is reserved for cluster-populated machine groups. The baseline refuses an identity-provider token that tries to claim a new gdsgate-* group, and the source tests require every namespaced group named by the template to be one the cluster actually populates. gdsgate-admin and gdsgate-provisioner are mTLS identities, not human IdP groups.

Strict validation, missing fields, and forbids

Cedar validation rejects an unknown attribute or an ill-typed policy before activation. During evaluation, a policy that reads a required field not present in the action context raises a Cedar evaluation error and is skipped. With deny-by-default, skipping the matching permit leaves the request denied. An optional field is safe only behind a context has guard. The source tests schema_validation_rejects_ill_typed_policy, schema_validation_rejects_unknown_attribute, and connector_denied_for_unrelated_action_by_default exercise these boundaries.

Forbid has precedence over permit. The destructive MCP tool baseline proves that a forbid still denies an administrator even when a broader permit would otherwise allow mcpCallTool. The same deny-by-default rule means an unknown principal or unsupported action has no implicit access. The policy engine is not the catalog gate: authority resolves the resource first and refuses a withdrawn or unknown catalog resource before Cedar. The source test the_policy_engine_cannot_be_the_catalogue_gate pins that ordering.

Control-plane lanes

The audit registry distinguishes data-plane authorization from administrative operations. Eleven actions carry a policy.decision row directly: connect, sshForwardLocal, sshForwardRemote, sshForwardAgent, mintOnwardSshCert, kubeRequest, httpRequest, mcpCallTool, mcpReadResource, mcpGetPrompt, and llmCall. The control-plane actions enrollNode, revokeNode, issueJoinToken, viewNodes, manageCatalog, disableUser, rotateCA, editPolicy, approvePolicyEdit, approveRequest, viewAudit, viewRecordings, and killSession emit their own administration event and carry cedar_action in that event where the source registry specifies it.

dbQuery is intentionally different: the authority evaluates its five SQL categories at session open, records the categories with the connect decision, and the connector emits db.query for a refused statement. view and viewTools are listing filters. A successful filter is not an audited denial or a security event; a denied control-plane listing is still recorded where the action audit contract says so.

The catalog prerequisite applies before every data-plane row in the action table. A catalog withdrawal is a resource-not-served outcome, not a Cedar permit that happens to fail. This distinction prevents stale policy from resurrecting a backend.

Audit semantics

The policy audit code registry is the authority for codes and event names. policy.decision rows include cedar_action, code, deciding, deciding_at, session_uid, presented, and src_ip when a source address exists. Derived credentials therefore have no fabricated source IP. SessionActivity rows carry the operation-specific evidence: kube.request, db.query, MCP events, llm.call, http.request, and http.tunnel.

Control-plane rows use their own evidence codes: catalog.manage CAT-0101, delegation.revoke_by_owner DLG-0201, ca.rotate CAS-0101, policy.edit PED-0101, policy.edit_approve PED-0102, recordings.view REC-0101, access_request.approve JIT-0102, audit.view AUD-0101, and session.kill SES-0601. Node admission and identity effects use the IDN codes shown in the action table. The registry explicitly has no audit row for successful view or viewTools filtering and no separate dbQuery policy row per statement. Those are source-checked absences, not omissions from this reference.

Verification workflow

  1. Run gdsgate authority policy validate against the candidate policy.
  2. Compare action names and entity fields with this reference and the schema.
  3. Push only through the policy editor and approval workflow.
  4. Verify the policy version and audit event after activation.

A policy edit cannot grant an unsupported action, and a valid syntax parse does not prove that the intended principal or resource is in scope.