feat(jans-cedarling): Cedarling PostgreSQL Extension#13856
feat(jans-cedarling): Cedarling PostgreSQL Extension#13856haileyesus2433 wants to merge 94 commits into
Conversation
…go.toml`. - Created `cedarling_pg` package with necessary configurations and dependencies. - Added `.gitignore` for `cedarling_pg` to exclude build artifacts. - Implemented a basic PostgreSQL extension with a sample function `hello_cedarling_pg`. - Included regression test setup files for the new extension. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a new cedarling_pg PostgreSQL extension crate (engine, authz, mask, policy, observability), codegen CLI, installer/Docker packaging, generated SQL/catalog bundles, CI jobs for pgrx tests and per-PG packaging, workspace/manifest updates, comprehensive docs, and extensive unit/pg_test coverage. ChangesCedarling PostgreSQL Extension
Estimated code review effort 🎯 4 (Complex) | ⏱️ ~60 minutes
✨ Finishing Touches🧪 Generate unit tests (beta)
|
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
- Introduced `guc_config.rs` to define Grand Unified Configuration (GUC) parameters for Cedarling, including modes, fail modes, log levels, cache TTL, and token management. - Implemented validation logic for the `cedarling.tokens` GUC in a new `validate.rs` file. - Updated `lib.rs` to register GUCs during PostgreSQL extension initialization and added tests for default values and token validation. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
…ng `EntityData`, including error handling for invalid input. - Introduced `token_sql.rs` with SQL-callable functions for managing `cedarling.tokens`, including setting, clearing, and retrieving tokens. - Updated `lib.rs` to include new modules and added tests for token management functionality. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
…ization - Added `authz_bridge.rs` for handling multi-issuer and unsigned authorization requests, including error handling. - Introduced `engine.rs` to manage the global Cedarling engine initialization from a bootstrap configuration file. - Updated `guc_config.rs` to include a new GUC for specifying the bootstrap configuration path. - Created `token_bundle.rs` for parsing session token bundle JSON into Cedarling `TokenInput` values. - Modified `lib.rs` to integrate new modules and ensure proper function exposure for testing. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
- Introduced `cedarling_authorized` and `cedarling_authorize_unsigned` functions for handling authorization requests with JWT and unsigned principals. - Implemented internal logic for decision-making based on resource and action inputs, including error handling based on fail modes. - Updated `guc_config.rs` to clarify behavior of the `cedarling.mode` GUC. - Added tests for new authorization functions to ensure correct fail-open and fail-closed behavior. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
- Added `authz_cache.rs` to manage a process-local cache for successful Cedarling authorization decisions, utilizing the `sparkv` crate. - Enhanced `cedarling_authorized_inner` and `cedarling_authorize_unsigned_inner` functions to leverage caching for improved performance. - Updated `guc_config.rs` documentation to clarify caching behavior and configuration. - Modified `Cargo.toml` to include new dependencies for caching functionality. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
- Introduced `extension_log.rs` to manage structured logging for Cedarling authorization processes, ensuring sensitive information is not logged. - Updated `cedarling_authorized_inner` and `cedarling_authorize_unsigned_inner` functions to include detailed diagnostic logging for various error conditions. - Enhanced documentation in `guc_config.rs` to clarify the logging behavior and its integration with authorization functions. - Modified `lib.rs` to include the new logging module. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
- Introduced `catalog.rs` to define the schema and tables for Cedarling's masking and policy history. - Added `error.rs` to implement a unified error handling mechanism for the extension, including detailed error types and logging capabilities. - Enhanced `guc_config.rs` to include new GUCs for strategy and policy versioning, improving configuration flexibility. - Updated `extension_log.rs` to support structured logging of errors and audit entries. - Modified `lib.rs` to integrate new modules and ensure proper function exposure for testing. - Added regression tests to verify catalog creation and error handling behavior. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
…gnostic functions Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
… retrieval function Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
…r RLS policies Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
…king and new test cases Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
- Added support for a new `cedarling.context` GUC to pass contextual information during authorization. - Implemented validation for the context JSON object to ensure it is either empty or a valid JSON object. - Updated authorization functions to utilize the new context, improving flexibility in policy evaluations. - Introduced new tests to validate context handling and ensure robustness of the authorization logic. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
Signed-off-by: Haileyesus Ayanaw <85413826+haileyesus2433@users.noreply.github.com>
…dded a new `policy_versions` table to track policy versions. - Introduced new GUC settings for `diff_mode` and `schema_validate_strict` to enhance configuration flexibility. - Added row-level authorization helpers and resource building functions to improve authorization capabilities. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
…gnostics - Introduced `AuthorizeOutcome` struct to encapsulate decision results along with request ID, policy hits, and diagnostic errors. - Updated authorization functions to return `AuthorizeOutcome` instead of simple boolean values, improving error handling and traceability. - Added `peek_cedarling` function to retrieve the current engine state without initialization. - Enhanced observability by recording additional metadata in authorization traces, including resource type and ID. - Updated status reporting to include new metrics for error tracking and policy updates. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
…le hash salt - Added `MASK_HASH_SALT` GUC setting to configure salt for SHA-256 hash masking. - Implemented `mask_hash_salt_bytes` function to retrieve the current salt as raw bytes. - Created a new module for masking configuration, including default mask strategies for sensitive fields. - Enhanced `cedarling_mask_row` and `cedarling_test_masking` functions to utilize the new masking strategies and salt. - Introduced `MaskType` enum to define various masking strategies and their application logic. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
…logic - Added `condition_sql` and `data_type` columns to the `mask_rules` table for improved masking configurations. - Updated authorization functions to incorporate a masking strategy that stashes masked rows when access is denied. - Enhanced `AuthorizationTrace` to include a `masked` field indicating when a deny decision results in a masked-row allow. - Introduced new tests to validate the behavior of the masking strategy and ensure proper integration with existing authorization logic. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
- Refactored masking functionality to include new `MaskRule` struct for better handling of explicit masking rules. - Updated `lookup_explicit_rules` to return `MaskRule` instances, allowing for conditional SQL evaluation in masking. - Improved `cedarling_mask_row` and related functions to utilize the new masking structure and logic. - Enhanced authorization functions to streamline decision-making and trace logging, including cache hit and error handling. - Added tests to validate the new masking behavior and ensure robustness in authorization processes. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
- Introduced a new `install.sh` script to automate the build and installation of the cedarling_pg extension in a local pgrx-managed PostgreSQL environment. - The script includes a health check that verifies the installation by checking for the presence of the extension, catalog schema, and required functions. - Added support for environment variable overrides to customize PostgreSQL version, database name, and psql binary path. - Provided usage instructions and options for release builds and skipping health checks. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
…ing_pg - Introduced a new SQL file defining the schema for the cedarling_pg extension, including tables for masking rules, policy history, entity mapping, and policy versions. - Added several authorization-related functions to enhance the extension's capabilities, including `cedarling_authorize_unsigned`, `cedarling_authorized`, and `cedarling_build_resource`. - Included comments for clarity on the purpose of each table and function, improving documentation within the SQL file. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
tareknaser
left a comment
There was a problem hiding this comment.
Thanks for addressing my previous review comments. I have one follow up
| if let Err(e2) = engine::rollback_policy() { | ||
| extension_log::log_diagnostic( | ||
| guc_config::CedarlingLogLevelGuc::Error, | ||
| &format!( |
There was a problem hiding this comment.
Follow-up to my earlier comment on set_policy_version_guc (which has been mostly addressed).
I noticed one edge case the new rollback path doesn't catch: engine::rollback_policy() returns Ok(None) when there is no previous engine to revert to (this is what happens on the very first cedarling_use_policy call in a backend)
The Ok(None) arm is silently ignored so I think it would work like:
engine::use_policysucceeds and installs the new policy.set_policy_version_gucfails for some reasonrollback_policy()returnsOk(None)which means nothing to roll back to.- Function returns
false. - The engine is still running the new policy but
cedarling.policy_versionandcedarling.policy_historyare stale.
Handle the case where no previous engine version exists to roll back to, ensuring users are notified when the engine and GUC state become inconsistent. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
Update GUC registration to use `GucContext::Suset` for settings that affect authorization logic, preventing unprivileged users from bypassing security policies or changing enforcement modes. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
configuration functions Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
authorization Introduce a `pg_test` that exercises the `cedarling_authorized` SQL function with a real engine configuration. This covers the signed path previously only tested at the Rust unit level. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
- Clear global cache on schema or mask configuration updates to prevent stale authorization decisions. - Reject non-finite floats in SQL pushdown to avoid ambiguous predicate behavior. - Update documentation for `cosign` verification, function parameter types, and SLSA metadata. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
Signed-off-by: Haileyesus Ayanaw <85413826+haileyesus2433@users.noreply.github.com>
Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
|
Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
Re-check of remaining review items after fix batch (e2e86cc – 0ab17e5)Re-verified all 13 items from the review. Summary: ✅ Fully addressed (9/13)
⬜ Remaining — 3 not addressed, 1 partial1. JWT tokens via GUC — end-to-end untested (was: "token functions pg_test")This is more important than "no pg_test for 3 thin wrappers." The production JWT RLS path is:
The existing signed test (
But the end-to-end Severity: Medium. The components are individually correct, but the integration path is untested. Would be good to add before the first release. 2.
|
Refactor the existing signed authorization test to extract helper functions for engine bootstrapping and token bundle generation. Added a new test case that validates the full end-to-end integration of `cedarling_authorized_row_jwt` reading tokens from the `cedarling.tokens` GUC, which mimics the production RLS pattern. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
diffing - Add `test_guc_check_hooks_reject_invalid_input_at_set_time` to verify that GUC validation logic correctly rejects invalid JSON inputs via SQLSTATE 22023. - Add `test_diff_policies_structural_lines_and_io_error` to validate both structural and line-based policy diffing modes and ensure file I/O errors are handled gracefully. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
|
olehbozhok
left a comment
There was a problem hiding this comment.
LOW / defense-in-depth: trace & observability functions are PUBLIC-executable over a per-backend ring buffer
cedarling_last_trace(), cedarling_recent_traces(int), cedarling_explain(text, text), and cedarling_status() are not
REVOKEd from PUBLIC (sql/cedarling_pg--0.1.0.sql:196,208,241,311), unlike the policy-lifecycle and entity/mask
writers.
The trace ring is per-backend (observability/trace.rs), so it persists across sessions that share the same backend
process — i.e. in any connection-pooled deployment (PgBouncer in session/transaction pooling, app-side pools). A
low-privilege role can therefore call cedarling_recent_traces() and read trace entries produced by other sessions that
previously ran on that backend.
What's exposed per entry: resource_type, resource_id (the row's primary-key value), action, principal_id, and
diag_errors. This is authorization metadata, not row contents — so impact is limited — but resource_id can be a
sensitive identifier, and this crosses a session boundary the caller shouldn't see across.
Note this is metadata-only and gated behind connection pooling — hence LOW, not a merge blocker. Raising it for an
explicit decision.
Suggested fix — pick one:
- Restrict the readers (preferred if traces aren't needed by app roles):
REVOKE EXECUTE ON FUNCTION cedarling_last_trace() FROM PUBLIC;
REVOKE EXECUTE ON FUNCTION cedarling_recent_traces(int) FROM PUBLIC;
REVOKE EXECUTE ON FUNCTION cedarling_explain(text, text) FROM PUBLIC;
REVOKE EXECUTE ON FUNCTION cedarling_status() FROM PUBLIC;
-- GRANT EXECUTE ... TO <observability_role>; -- as needed - Or document the pooling caveat in docs/cedarling/integrations/postgres.md (security section) — state that trace
readers may surface cross-session metadata under shared backends and should be granted only to trusted observability
roles.
cedarling_explain is borderline: it re-runs authorization on caller-supplied input and returns the caller's own
diagnostics, so it's less of a cross-session leak — but it still reads the shared ring indirectly via push_trace, so
include it in whichever option you choose.
Everything else in the security pass came back clean (H1/H2 confirmed fixed, SQL fully parameterized, pushdown
fail-closed). This is the only residual.
tareknaser
left a comment
There was a problem hiding this comment.
Thank you! I only have one main comment left then I think we're ready to merge
| return None; | ||
| } | ||
|
|
||
| let when_clauses = extract_clauses(&meta.source, "when")?; |
There was a problem hiding this comment.
I think there's a correctness issue here. lower_policy_to_sql only looks at when/unless clauses and ignores constraints in the policy head.
For example, permit(principal, action, resource == Doc::"42") lowers to TRUE, even though the policy only applies to a single resource. Similarly, permit(principal, action, resource == Doc::"42") when { resource.public == true } lowers to "public" = TRUE, dropping the resource constraint entirely.
From what I can tell, matching_policies_for_table filters policies by entity type rather than specific scope constraints so scoped policies can reach this code path and have their principal/resource restrictions discarded during SQL lowering.
That means cedarling_where can produce predicates that match more rows than the underlying Cedar policy allows.
| }, | ||
| }; | ||
|
|
||
| let previous = match engine::use_policy(&resolved.bootstrap_path) { |
There was a problem hiding this comment.
The GUC failure handling looks good now. One thing that still seems worth documenting is that the policy swap is per-backend and not transactional.
engine::use_policy updates the Rust static ENGINE immediately so a ROLLBACK will undo the catalog changes and set_config but the backend will keep using the new policy. Also, because the engine is process-local, cedarling_use_policy only affects the current backend. other connections keep their own engine instance.
The current comment in catalog.rs ("global policy swap") and the wording in postgres.md read as if this is cluster-wide. It would be helpful to clarify that the swap is per-backend and non-transactional and that cluster-wide changes should be done by updating cedarling.bootstrap_config and reconnecting rather than relying on cedarling_use_policy to propagate.
Ensure `lower_policy_to_sql` does not drop principal or resource identity restrictions by forcing such policies to the unhandled-residual path. This prevents over-permitting when the SQL predicate cannot enforce specific entity ID constraints. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
extension owner Revoke EXECUTE permissions from PUBLIC for all observability functions to prevent potential cross-session data leakage when using connection pooling. Grant these permissions explicitly to monitoring roles as required. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
behavior Clarify that `cedarling_use_policy` and `cedarling_rollback_policy` mutate process-local state. Explicitly note that while catalog updates are transactional, the engine swap is not, and advise using `cedarling.bootstrap_config` for cluster-wide changes. Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
20a8dd8
addressed the remaining comments in here 2f3e7da |
Signed-off-by: haileyesus2433 <haileyesusbe@gmail.com>
Prepare
Description
Target issue
closes #12071
Implementation Details
Test and Document the changes
Please check the below before submitting your PR. The PR will not be merged if there are no commits that start with
docs:to indicate documentation changes or if the below checklist is not selected.Summary by CodeRabbit
New Features
Documentation
CI