Skip to content

vault-subpath-proxy: Add read-only mode#5197

Open
psalajova wants to merge 1 commit into
openshift:mainfrom
psalajova:add-vault-read-only-mode
Open

vault-subpath-proxy: Add read-only mode#5197
psalajova wants to merge 1 commit into
openshift:mainfrom
psalajova:add-vault-read-only-mode

Conversation

@psalajova
Copy link
Copy Markdown
Contributor

@psalajova psalajova commented May 21, 2026

Adds a --read-only flag to vault-subpath-proxy that rejects all KV write operations (PUT/POST/PATCH/DELETE) with a 403 while allowing reads to pass through. This will be used to freeze Vault during the Vault-to-GSM migration, preventing secret modifications while the secrets are copied to GSM.

To freeze Vault: add -read-only to the subpath-proxy args in the StatefulSet manifest here; to unfreeze: remove it. Release repo PR is prepared: openshift/release#79591

vault-subpath-proxy: Add read-only mode

This PR adds a --read-only flag to the vault-subpath-proxy component, which is used to control access to Vault secrets in CI infrastructure.

What changed

The vault-subpath-proxy now supports read-only mode, which can be enabled by adding the --read-only flag to the proxy's command-line arguments (typically via StatefulSet manifest configuration). When enabled, this mode:

  • Blocks all write operations: HTTP requests using PUT, POST, PATCH, and DELETE methods are rejected with a 403 Forbidden response
  • Allows read operations: GET and LIST requests continue to work normally

Operational impact

This feature is designed to safely freeze Vault's write capabilities during a Vault-to-Google Secret Manager (GSM) migration. By enabling read-only mode on the vault-subpath-proxy, CI operators can:

  1. Prevent any accidental or unintended secret modifications while the migration is in progress
  2. Ensure all existing secrets remain unchanged as they're being copied to GSM
  3. Toggle the mode on and off by modifying the proxy's configuration (without restarting services)

Once the migration is complete, the flag can be removed from the configuration to restore normal read-write functionality.

Implementation details

The implementation adds:

  • A readOnly flag to the proxy options
  • A read-only mode check in the KV transport layer that intercepts write requests before they reach the upstream Vault server
  • Test coverage validating that write/delete operations return the expected 403 error while read operations pass through normally

@openshift-merge-bot
Copy link
Copy Markdown
Contributor

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: automatic mode

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 21, 2026

📝 Walkthrough

Walkthrough

This PR adds a --read-only flag to the vault-subpath-proxy that rejects Vault write and delete operations at the transport layer while preserving read and list functionality. Configuration flows from flag parsing through createProxyServer into the kvUpdateTransport, which returns HTTP 403 when write operations are attempted in read-only mode. Tests verify the rejection and allow-through behavior.

Changes

Read-only mode implementation

Layer / File(s) Summary
Read-only transport implementation
cmd/vault-subpath-proxy/kv_update_transport.go
Add readOnly field to kvUpdateTransport and check it in RoundTrip to return 403 Forbidden when write operations are attempted in read-only mode.
Configuration, flag, and wiring
cmd/vault-subpath-proxy/main.go
Register --read-only flag in options, extend createProxyServer signature to accept readOnly, wire the parameter into kvUpdateTransport construction, and log a warning when enabled.
Read-only mode testing
cmd/vault-subpath-proxy/main_test.go
Update test setup to pass readOnly parameter; add readOnlyMode subtest that toggles read-only, runs table-driven test cases, and asserts 403 responses for writes/deletes and successful responses for reads/lists.

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 12 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Test Structure And Quality ❓ Inconclusive The custom check targets Ginkgo test code quality, but the PR contains only standard Go testing.T tests with t.Run() subtests, not Ginkgo (no Describe/Context/It blocks). Clarify whether the check applies to standard Go tests using testing.T, or if only Ginkgo-based tests should be reviewed.
✅ Passed checks (12 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding read-only mode to vault-subpath-proxy, which is the core feature across all modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Go Error Handling ✅ Passed The PR's readOnly feature code follows Go error handling best practices: no ignored errors, no panic calls, errors wrapped with fmt.Errorf %w, and safe nil pointer handling.
Test Coverage For New Features ✅ Passed New read-only mode functionality includes comprehensive test coverage: table-driven tests validate write/delete rejection with 403 status and correct error messages, while confirming reads succeed.
Stable And Deterministic Test Names ✅ Passed PR adds standard Go tests with stable, static test names. No Ginkgo test framework usage or dynamic test names found in the changes.
Microshift Test Compatibility ✅ Passed No new Ginkgo e2e tests added. The PR modifies unit tests in main_test.go using Go's standard testing.T package with t.Run() subtests, not Ginkgo framework. Check is not applicable.
Single Node Openshift (Sno) Test Compatibility ✅ Passed PR adds standard Go unit tests (TestProxy using t.Run), not Ginkgo e2e tests. SNO compatibility check only applies to Ginkgo e2e tests.
Topology-Aware Scheduling Compatibility ✅ Passed PR modifies only application binary code (vault-subpath-proxy), adding a read-only flag. No deployment manifests, operator code, controllers, or scheduling constraints are added or modified.
Ote Binary Stdout Contract ✅ Passed vault-subpath-proxy is a Vault proxy service, not an OTE test binary. All new output (logrus.Warn) correctly goes to stderr via logrusutil.ComponentInit().
Ipv6 And Disconnected Network Test Compatibility ✅ Passed The PR adds tests to main_test.go, which is a standard Go unit test using testing.T, not a Ginkgo e2e test. The custom check explicitly applies to Ginkgo e2e tests only, so it is not applicable here.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@openshift-ci openshift-ci Bot requested review from Prucek and pruan-rht May 21, 2026 10:09
@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label May 21, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
cmd/vault-subpath-proxy/main.go (1)

119-119: ⚡ Quick win

Refactor createProxyServer to an options struct.

Line 119 now has 6 parameters, which is getting brittle for future changes and call-site ordering safety.

Proposed refactor
+type proxyServerOptions struct {
+	vaultAddr            string
+	listenAddr           string
+	kvMountPath          string
+	clients              func() map[string]ctrlruntimeclient.Client
+	privilegedVaultClient *vaultclient.VaultClient
+	readOnly             bool
+}
-
-func createProxyServer(vaultAddr string, listenAddr string, kvMountPath string, clients func() map[string]ctrlruntimeclient.Client, privilegedVaultClient *vaultclient.VaultClient, readOnly bool) (*http.Server, error) {
+func createProxyServer(opts proxyServerOptions) (*http.Server, error) {
-	vaultClient, err := api.NewClient(&api.Config{Address: vaultAddr})
+	vaultClient, err := api.NewClient(&api.Config{Address: opts.vaultAddr})
 	...
-	vaultURL, err := url.Parse(vaultAddr)
+	vaultURL, err := url.Parse(opts.vaultAddr)
 	...
-	transport := &kvUpdateTransport{kvMountPath: kvMountPath, upstream: http.DefaultTransport, kubeClients: clients, privilegedVaultClient: privilegedVaultClient, readOnly: readOnly}
+	transport := &kvUpdateTransport{kvMountPath: opts.kvMountPath, upstream: http.DefaultTransport, kubeClients: opts.clients, privilegedVaultClient: opts.privilegedVaultClient, readOnly: opts.readOnly}
 	...
-		Addr:    listenAddr,
+		Addr:    opts.listenAddr,
As per coding guidelines, "Keep function signatures small — if a function takes more than 3-4 parameters, consider grouping them into an options struct".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/vault-subpath-proxy/main.go` at line 119, The createProxyServer function
has too many positional parameters (vaultAddr, listenAddr, kvMountPath, clients,
privilegedVaultClient, readOnly); refactor it to accept a single options struct
(e.g., type ProxyServerOptions struct { VaultAddr string; ListenAddr string;
KVMountPath string; Clients func() map[string]ctrlruntimeclient.Client;
PrivilegedVaultClient *vaultclient.VaultClient; ReadOnly bool }) and update
createProxyServer signature to createProxyServer(opts *ProxyServerOptions)
(*http.Server, error), then update all call sites to construct and pass that
struct (or a small constructor like NewProxyServerOptions) so ordering is
explicit and future parameters can be added without changing call sites.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@cmd/vault-subpath-proxy/main.go`:
- Line 119: The createProxyServer function has too many positional parameters
(vaultAddr, listenAddr, kvMountPath, clients, privilegedVaultClient, readOnly);
refactor it to accept a single options struct (e.g., type ProxyServerOptions
struct { VaultAddr string; ListenAddr string; KVMountPath string; Clients func()
map[string]ctrlruntimeclient.Client; PrivilegedVaultClient
*vaultclient.VaultClient; ReadOnly bool }) and update createProxyServer
signature to createProxyServer(opts *ProxyServerOptions) (*http.Server, error),
then update all call sites to construct and pass that struct (or a small
constructor like NewProxyServerOptions) so ordering is explicit and future
parameters can be added without changing call sites.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 4732765b-2ec4-41f6-8423-7f1c11849b42

📥 Commits

Reviewing files that changed from the base of the PR and between 003dbcd and 31b3e42.

📒 Files selected for processing (3)
  • cmd/vault-subpath-proxy/kv_update_transport.go
  • cmd/vault-subpath-proxy/main.go
  • cmd/vault-subpath-proxy/main_test.go

@psalajova
Copy link
Copy Markdown
Contributor Author

/test e2e

@openshift-merge-bot
Copy link
Copy Markdown
Contributor

Pipeline controller notification

No second-stage tests were triggered for this PR.

This can happen when:

  • The changed files don't match any pipeline_run_if_changed patterns
  • All files match pipeline_skip_if_only_changed patterns
  • No pipeline-controlled jobs are defined for the main branch

Use /test ? to see all available tests.

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label May 21, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 21, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: Prucek, psalajova

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

The pull request process is described 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
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 21, 2026

@psalajova: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/integration 31b3e42 link unknown /test integration
ci/prow/checkconfig 31b3e42 link unknown /test checkconfig
ci/prow/frontend-checks 31b3e42 link unknown /test frontend-checks

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

approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants