Skip to content

OLS-2459 enforce TLS security profile on Postgres connections#2921

Open
onmete wants to merge 1 commit into
openshift:mainfrom
onmete:OLS-2459-postgres-tls-hardening
Open

OLS-2459 enforce TLS security profile on Postgres connections#2921
onmete wants to merge 1 commit into
openshift:mainfrom
onmete:OLS-2459-postgres-tls-hardening

Conversation

@onmete
Copy link
Copy Markdown
Contributor

@onmete onmete commented May 7, 2026

Description

Enforce the cluster's TLS security profile on all Postgres connections
(cache, quota limiters, token usage history, quota scheduler).

This is the service-side half of OLS-2459. The operator-side changes
(APIServer CR propagation) will follow in a separate PR.

Changes

  • Default sslmode hardened — change POSTGRES_CACHE_SSL_MODE from
    "prefer" to "require" so the service never silently downgrades to
    cleartext, even when the operator config is absent (dev, test, or
    misconfiguration scenarios)
  • build_ssl_context helper — new factory in ols/utils/ssl.py that
    builds an ssl.SSLContext with minimum_version and cipher restrictions
    from the configured TLS security profile. Returns None when no profile
    is set (preserves current behaviour)
  • PostgresBase TLS threadingPostgresBase.__init__ accepts an
    optional tls_security_profile and passes the resulting SSLContext as
    sslcontext= to psycopg2.connect. Threaded through:
    PostgresCache, RevokableQuotaLimiter, UserQuotaLimiter,
    ClusterQuotaLimiter, QuotaLimiterFactory, TokenUsageHistory,
    CacheFactory, and AppConfig
  • Quota scheduler TLS — the standalone connect() function also builds
    and passes an SSLContext when a profile is configured
  • sslrootcert bug fix — un-commented sslrootcert=config.ca_cert_path
    in the quota scheduler's connect(), which was accidentally commented out,
    leaving it without CA verification

Type of change

  • Bug fix
  • New feature

Related Tickets & Documents

Checklist before requesting a review

  • I have performed a self-review of my code.
  • PR has passed all pre-merge test jobs.
  • If it is a core feature, I have added thorough tests.

Testing

  • All 1048 unit tests pass (make test-unit)
  • MyPy type checking passes (make check-types)
  • Ruff + Black formatting passes (make format)
  • New tests cover:
    • build_ssl_context with IntermediateType, ModernType, None profile,
      None profile_type, CA cert path forwarding
    • PostgresBase with and without TLS profile (sslcontext presence)
    • Quota scheduler connect() with sslrootcert and sslcontext assertions
    • Default POSTGRES_CACHE_SSL_MODE == "require" assertion

Made with Cursor

@openshift-ci openshift-ci Bot requested a review from bparees May 7, 2026 07:42
@openshift-ci
Copy link
Copy Markdown

openshift-ci Bot commented May 7, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign onmete for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci Bot requested a review from tisnik May 7, 2026 07:42
@onmete onmete force-pushed the OLS-2459-postgres-tls-hardening branch from 8f96125 to 3c0f55d Compare May 7, 2026 07:49
@onmete
Copy link
Copy Markdown
Contributor Author

onmete commented May 7, 2026

Self-review: Round 1 findings and fixes

Critical finding: sslcontext is not a valid libpq keyword

The initial implementation used sslcontext= as a kwarg to psycopg2.connect(),
which would raise ProgrammingError: invalid dsn: invalid connection option "sslcontext"
at runtime whenever a TLS profile was active. psycopg2 forwards all kwargs through
extensions.make_dsn() which only accepts libpq connection parameters.

Fix applied: Replaced build_ssl_context() / sslcontext= with libpq_tls_params()
which returns {"ssl_min_protocol_version": "TLSv1.2"} (or "TLSv1.3" for ModernType),
using libpq's native ssl_min_protocol_version parameter. This is validated to produce
correct DSN strings via extensions.make_dsn().

Cipher enforcement is not possible on the libpq client side — cipher negotiation is
controlled by the PostgreSQL server's ssl_ciphers setting. The minimum_version
enforcement is the security-critical part (prevents TLS downgrade).

Minor finding: inline import in test

Moved from psycopg2 import extensions from inside a test method to module level.

Integration test

Added test_result_can_be_merged_into_connect_kwargs which calls extensions.make_dsn()
with the output of libpq_tls_params() and asserts the DSN contains
ssl_min_protocol_version=TLSv1.2, proving the kwargs are valid for psycopg2.

All 1047 unit tests pass. MyPy, ruff, and black clean.

AI-generated via lightspeed-team-harness: https://github.com/openshift/lightspeed-team-harness

@onmete onmete force-pushed the OLS-2459-postgres-tls-hardening branch 2 times, most recently from 37787e7 to 7c33c89 Compare May 7, 2026 08:29
Change the default sslmode from "prefer" to "require" so the service
never silently downgrades to cleartext even when the operator config
is absent.

Add a shared build_ssl_context() helper that constructs an SSLContext
with minimum TLS version and cipher restrictions from the configured
TLS security profile.  Thread the profile through PostgresBase, the
cache factory, quota limiter factory, token usage history, and the
quota scheduler so every Postgres connection enforces the cluster's
TLS policy when configured.

Fix the quota scheduler's sslrootcert which was accidentally
commented out, leaving it without CA verification.

Co-authored-by: Cursor <cursoragent@cursor.com>
@onmete onmete force-pushed the OLS-2459-postgres-tls-hardening branch from 7c33c89 to 5a15367 Compare May 7, 2026 14:36
@openshift-ci
Copy link
Copy Markdown

openshift-ci Bot commented May 7, 2026

@onmete: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant