id: spicedb-authorization-schema-and-permission-sentinel
namespace: company.security
description: |
Continuously monitors SpiceDB fine-grained authorization (ReBAC) cluster readiness, verifies schema integrity, evaluates critical subject permission checks against expected states, and dispatches actionable Slack incident notifications upon authorization drift or datastore outages.
inputs:
- id: spicedb_endpoint
type: STRING
displayName: SpiceDB Gateway Endpoint
defaults: "http://spicedb.internal:8443"
description: "Base HTTP/REST gateway URL of the target SpiceDB instance."
- id: target_resource_type
type: STRING
displayName: Resource Type
defaults: "document"
description: "Target object type defined in the SpiceDB schema."
- id: target_resource_id
type: STRING
displayName: Resource ID
defaults: "platform-security-policy"
description: "Target object identifier to evaluate for authorization."
- id: target_permission
type: STRING
displayName: Permission Name
defaults: "read"
description: "Target permission or relation to verify on the resource."
- id: target_subject_type
type: STRING
displayName: Subject Type
defaults: "user"
description: "Subject object type to check permissions for."
- id: target_subject_id
type: STRING
displayName: Subject ID
defaults: "platform-admin"
description: "Subject identifier whose permissions are audited."
- id: expected_permissionship
type: STRING
displayName: Expected Permissionship
defaults: "PERMISSIONSHIP_HAS_PERMISSION"
description: "Expected SpiceDB permissionship result (e.g.,
PERMISSIONSHIP_HAS_PERMISSION or PERMISSIONSHIP_NO_PERMISSION)."
- id: slack_channel
type: STRING
displayName: Alert Slack Channel
defaults: "#security-alerts"
description: "Slack destination channel for authorization drift alerts."
triggers:
- id: scheduled_sentinel_audit
type: io.kestra.plugin.core.trigger.Schedule
cron: "0 */4 * * *"
disabled: true
inputs:
spicedb_endpoint: "http://spicedb.internal:8443"
target_resource_type: "document"
target_resource_id: "platform-security-policy"
target_permission: "read"
target_subject_type: "user"
target_subject_id: "platform-admin"
expected_permissionship: "PERMISSIONSHIP_HAS_PERMISSION"
tasks:
- id: probe_engine_readiness
type: io.kestra.plugin.core.http.Request
description: "Verifies that the SpiceDB server and underlying datastore are
healthy and ready to serve authorization traffic."
uri: "{{ inputs.spicedb_endpoint }}/readyz"
method: GET
- id: probe_authorization_schema
type: io.kestra.plugin.core.http.Request
description: "Pulls the current authorization schema from SpiceDB to ensure
schema availability and detect model corruption."
uri: "{{ inputs.spicedb_endpoint }}/v1/schema/read"
method: POST
headers:
Authorization: "Bearer {{ secret('SPICEDB_PRESHARED_KEY') }}"
Content-Type: application/json
body: "{}"
- id: check_critical_permission
type: io.kestra.plugin.core.http.Request
description: "Executes a fine-grained permission check against SpiceDB for the
specified resource, relation, and subject."
uri: "{{ inputs.spicedb_endpoint }}/v1/permissions/check"
method: POST
headers:
Authorization: "Bearer {{ secret('SPICEDB_PRESHARED_KEY') }}"
Content-Type: application/json
body: |
{
"resource": {
"objectType": "{{ inputs.target_resource_type }}",
"objectId": "{{ inputs.target_resource_id }}"
},
"permission": "{{ inputs.target_permission }}",
"subject": {
"object": {
"objectType": "{{ inputs.target_subject_type }}",
"objectId": "{{ inputs.target_subject_id }}"
}
}
}
- id: evaluate_authorization_status
type: io.kestra.plugin.core.flow.Switch
description: "Evaluates probe results using Pebble template logic and routes to
appropriate remediation or alert notifications."
value: |
{% if outputs.probe_engine_readiness.code != 200 %}
ENGINE_UNHEALTHY
{% elseif outputs.probe_authorization_schema.code != 200 or outputs.probe_authorization_schema.body.schemaText is empty %}
SCHEMA_UNAVAILABLE
{% elseif outputs.check_critical_permission.code != 200 %}
CHECK_API_FAILED
{% elseif outputs.check_critical_permission.body.permissionship != inputs.expected_permissionship %}
PERMISSION_STATE_DRIFT
{% else %}
COMPLIANT
{% endif %}
cases:
COMPLIANT:
- id: log_compliant_state
type: io.kestra.plugin.core.log.Log
level: INFO
message: "SpiceDB fine-grained authorization cluster is healthy, schema is
intact, and subject '{{ inputs.target_subject_id }}' holds expected
permissionship '{{ inputs.expected_permissionship }}' on '{{
inputs.target_resource_type }}:{{ inputs.target_resource_id }}'."
PERMISSION_STATE_DRIFT:
- id: alert_permission_drift
type: io.kestra.plugin.slack.notifications.SlackIncomingWebhook
url: "{{ secret('SLACK_WEBHOOK_URL') }}"
payload: |
{
"attachments": [
{
"color": "#D32F2F",
"title": "SpiceDB Authorization State Drift Detected",
"text": "CRITICAL: SpiceDB subject `{{ inputs.target_subject_id }}` evaluation drifted from expected state.\n• Expected: `{{ inputs.expected_permissionship }}`\n• Received: `{{ outputs.check_critical_permission.body.permissionship }}`\n• Target Resource: `{{ inputs.target_resource_type }}:{{ inputs.target_resource_id }}`\n• Permission: `{{ inputs.target_permission }}`\n• Checked At: `{{ outputs.check_critical_permission.body.checkedAt }}`"
}
]
}
- id: log_drift_failure
type: io.kestra.plugin.core.log.Log
level: WARN
message: "CRITICAL: Detected SpiceDB permission drift. Expected {{
inputs.expected_permissionship }} but received {{
outputs.check_critical_permission.body.permissionship }}"
SCHEMA_UNAVAILABLE:
- id: alert_schema_failure
type: io.kestra.plugin.slack.notifications.SlackIncomingWebhook
url: "{{ secret('SLACK_WEBHOOK_URL') }}"
payload: |
{
"attachments": [
{
"color": "#E65100",
"title": "SpiceDB Authorization Schema Read Failure",
"text": "WARNING: Unable to retrieve or parse active SpiceDB authorization schema from `{{ inputs.spicedb_endpoint }}` (HTTP status `{{ outputs.probe_authorization_schema.code }}`). Verify SpiceDB preshared key credentials and datastore connectivity."
}
]
}
ENGINE_UNHEALTHY:
- id: alert_cluster_down
type: io.kestra.plugin.slack.notifications.SlackIncomingWebhook
url: "{{ secret('SLACK_WEBHOOK_URL') }}"
payload: |
{
"attachments": [
{
"color": "#B71C1C",
"title": "SpiceDB Authorization Cluster Unhealthy",
"text": "EMERGENCY: SpiceDB readiness probe `/readyz` at `{{ inputs.spicedb_endpoint }}` responded with HTTP status `{{ outputs.probe_engine_readiness.code }}`. Fine-grained authorization checks across all dependent microservices may be failing."
}
]
}
CHECK_API_FAILED:
- id: alert_api_error
type: io.kestra.plugin.slack.notifications.SlackIncomingWebhook
url: "{{ secret('SLACK_WEBHOOK_URL') }}"
payload: |
{
"attachments": [
{
"color": "#F57C00",
"title": "SpiceDB Permission Check Request Failed",
"text": "SpiceDB `/v1/permissions/check` request failed with HTTP status `{{ outputs.check_critical_permission.code }}`. Verify request payload, preshared key credentials, and schema object definitions."
}
]
}
- id: record_audit_log
type: io.kestra.plugin.core.log.Log
description: "Records a final compliance audit summary in Kestra execution history."
level: INFO
message: "SpiceDB authorization sentinel audit completed. Resource={{
inputs.target_resource_type }}:{{ inputs.target_resource_id }},
Permission={{ inputs.target_permission }}, Subject={{
inputs.target_subject_type }}:{{ inputs.target_subject_id }}, Ready={{
outputs.probe_engine_readiness.code == 200 }}."