openshift-update-proxy 1.0.2__tar.gz → 1.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {openshift_update_proxy-1.0.2 → openshift_update_proxy-1.2.0}/PKG-INFO +128 -21
- openshift_update_proxy-1.2.0/README.md +309 -0
- {openshift_update_proxy-1.0.2 → openshift_update_proxy-1.2.0}/pyproject.toml +1 -1
- {openshift_update_proxy-1.0.2 → openshift_update_proxy-1.2.0}/src/openshift_update_proxy/__init__.py +1 -1
- openshift_update_proxy-1.2.0/src/openshift_update_proxy/app.py +299 -0
- openshift_update_proxy-1.2.0/src/openshift_update_proxy/cache.py +18 -0
- openshift_update_proxy-1.2.0/src/openshift_update_proxy/catalog.py +147 -0
- {openshift_update_proxy-1.0.2 → openshift_update_proxy-1.2.0}/src/openshift_update_proxy/config.py +9 -0
- openshift_update_proxy-1.2.0/src/openshift_update_proxy/graph.py +39 -0
- openshift_update_proxy-1.2.0/src/openshift_update_proxy/lifecycle.py +71 -0
- {openshift_update_proxy-1.0.2 → openshift_update_proxy-1.2.0}/src/openshift_update_proxy.egg-info/PKG-INFO +128 -21
- {openshift_update_proxy-1.0.2 → openshift_update_proxy-1.2.0}/src/openshift_update_proxy.egg-info/SOURCES.txt +7 -1
- {openshift_update_proxy-1.0.2 → openshift_update_proxy-1.2.0}/tests/test_app.py +62 -0
- openshift_update_proxy-1.2.0/tests/test_catalog.py +195 -0
- openshift_update_proxy-1.2.0/tests/test_lifecycle.py +145 -0
- openshift_update_proxy-1.0.2/README.md +0 -202
- openshift_update_proxy-1.0.2/src/openshift_update_proxy/app.py +0 -138
- {openshift_update_proxy-1.0.2 → openshift_update_proxy-1.2.0}/LICENSE +0 -0
- {openshift_update_proxy-1.0.2 → openshift_update_proxy-1.2.0}/setup.cfg +0 -0
- {openshift_update_proxy-1.0.2 → openshift_update_proxy-1.2.0}/src/openshift_update_proxy/__main__.py +0 -0
- {openshift_update_proxy-1.0.2 → openshift_update_proxy-1.2.0}/src/openshift_update_proxy.egg-info/dependency_links.txt +0 -0
- {openshift_update_proxy-1.0.2 → openshift_update_proxy-1.2.0}/src/openshift_update_proxy.egg-info/entry_points.txt +0 -0
- {openshift_update_proxy-1.0.2 → openshift_update_proxy-1.2.0}/src/openshift_update_proxy.egg-info/requires.txt +0 -0
- {openshift_update_proxy-1.0.2 → openshift_update_proxy-1.2.0}/src/openshift_update_proxy.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openshift-update-proxy
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Forwarding proxy for OpenShift update resources (Cincinnati API, mirror, release signatures)
|
|
5
5
|
Author-email: Simon Lauger <simon@lauger.de>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -36,10 +36,10 @@ Dynamic: license-file
|
|
|
36
36
|
[](https://pypi.org/project/openshift-update-proxy/)
|
|
37
37
|
[](LICENSE)
|
|
38
38
|
|
|
39
|
-
A small Flask based service which forwards HTTP requests to `api.openshift.com
|
|
40
|
-
`mirror.openshift.com`. Built for
|
|
41
|
-
|
|
42
|
-
access) exists.
|
|
39
|
+
A small Flask based service which forwards HTTP requests to `api.openshift.com`,
|
|
40
|
+
`mirror.openshift.com`, `catalog.redhat.com` and `access.redhat.com`. Built for
|
|
41
|
+
restricted networks where OpenShift clusters have no direct internet access, but a
|
|
42
|
+
central egress proxy (or a single host with internet access) exists.
|
|
43
43
|
|
|
44
44
|
## Features
|
|
45
45
|
|
|
@@ -51,6 +51,11 @@ access) exists.
|
|
|
51
51
|
`ClusterVersion.spec.signatureStores` (OpenShift 4.14+)
|
|
52
52
|
- 🗺️ **ConfigMap Generator** - renders ready-to-apply signature ConfigMaps for the
|
|
53
53
|
classic disconnected verification workflow
|
|
54
|
+
- 🎛️ **Operator Catalog API** - serves operator channels and versions from the
|
|
55
|
+
Red Hat Pyxis API (`catalog.redhat.com`), ready to use as a
|
|
56
|
+
[Renovate custom datasource](https://docs.renovatebot.com/modules/datasource/custom/)
|
|
57
|
+
- 📅 **Supported Versions API** - combines the Red Hat product lifecycle API with the
|
|
58
|
+
update graph to list supported OpenShift minor versions and their latest release
|
|
54
59
|
- 🚦 **Egress Proxy Aware** - honors `HTTPS_PROXY` / `NO_PROXY` for all upstream requests
|
|
55
60
|
- 🐳 **Hardened Container** - UBI9 based, rootless (UID 1001), digest-pinned base image,
|
|
56
61
|
Cosign signed
|
|
@@ -64,22 +69,28 @@ flowchart LR
|
|
|
64
69
|
subgraph restricted["Restricted network"]
|
|
65
70
|
CVO["Cluster Version Operator"]
|
|
66
71
|
ADMIN["Admin (oc / curl)"]
|
|
72
|
+
RENOVATE["Renovate"]
|
|
67
73
|
PROXY["openshift-update-proxy"]
|
|
68
74
|
end
|
|
69
75
|
|
|
70
76
|
subgraph internet["Internet"]
|
|
71
77
|
API["api.openshift.com"]
|
|
72
78
|
MIRROR["mirror.openshift.com"]
|
|
79
|
+
PYXIS["catalog.redhat.com"]
|
|
80
|
+
LIFECYCLE["access.redhat.com"]
|
|
73
81
|
end
|
|
74
82
|
|
|
75
83
|
CVO -- "/api/upgrades_info/v1/graph" --> PROXY
|
|
76
84
|
CVO -- "/signatures/sha256=…" --> PROXY
|
|
77
85
|
ADMIN -- "/configmaps/sha256=…" --> PROXY
|
|
78
86
|
ADMIN -- "/pub/…" --> PROXY
|
|
87
|
+
RENOVATE -- "/operators/v1/…" --> PROXY
|
|
79
88
|
|
|
80
89
|
PROXY -- "optional egress proxy (HTTPS_PROXY)" --> EGRESS["Egress Proxy"]
|
|
81
90
|
EGRESS --> API
|
|
82
91
|
EGRESS --> MIRROR
|
|
92
|
+
EGRESS --> PYXIS
|
|
93
|
+
EGRESS --> LIFECYCLE
|
|
83
94
|
```
|
|
84
95
|
|
|
85
96
|
## Endpoints
|
|
@@ -89,7 +100,12 @@ flowchart LR
|
|
|
89
100
|
| `/api/<path>` | `https://api.openshift.com/api/` | Cincinnati update graph (`/api/upgrades_info/v1/graph`) |
|
|
90
101
|
| `/pub/<path>` | `https://mirror.openshift.com/pub/` | OpenShift mirror (clients, release artifacts) |
|
|
91
102
|
| `/signatures/<path>` | `https://mirror.openshift.com/pub/openshift-v4/signatures/openshift/release/` | Release image signature store |
|
|
92
|
-
| `/configmaps
|
|
103
|
+
| `/configmaps/<version or sha256=digest>` | derived from signature store | Ready-to-apply signature ConfigMap (YAML) |
|
|
104
|
+
| `/catalog/<path>` | `https://catalog.redhat.com/api/containers/v1/` | Red Hat Pyxis API (operator catalog metadata) |
|
|
105
|
+
| `/operators/v1/<catalog>/<package>/channels` | derived from Pyxis | Channels, default channel and latest CSV per channel |
|
|
106
|
+
| `/operators/v1/<catalog>/<package>/<channel>/releases` | derived from Pyxis | Version feed in Renovate custom datasource format |
|
|
107
|
+
| `/lifecycle/<path>` | `https://access.redhat.com/product-life-cycles/api/v1/` | Red Hat product lifecycle API |
|
|
108
|
+
| `/versions/v1/supported` | derived from lifecycle API + update graph | Supported OpenShift minors with latest release per channel |
|
|
93
109
|
| `/healthz` | - | Health check for liveness/readiness probes |
|
|
94
110
|
|
|
95
111
|
## Configuration
|
|
@@ -103,6 +119,10 @@ All configuration is done via environment variables:
|
|
|
103
119
|
| `API_UPSTREAM` | `https://api.openshift.com/api/` | Cincinnati API base URL |
|
|
104
120
|
| `MIRROR_UPSTREAM` | `https://mirror.openshift.com/pub/` | Mirror base URL |
|
|
105
121
|
| `SIGNATURE_UPSTREAM` | `https://mirror.openshift.com/pub/openshift-v4/signatures/openshift/release/` | Signature store base URL |
|
|
122
|
+
| `CATALOG_UPSTREAM` | `https://catalog.redhat.com/api/containers/v1/` | Red Hat Pyxis API base URL |
|
|
123
|
+
| `CATALOG_CACHE_TTL` | `600` | Cache TTL in seconds for operator catalog lookups (`0` disables caching) |
|
|
124
|
+
| `LIFECYCLE_UPSTREAM` | `https://access.redhat.com/product-life-cycles/api/v1/` | Red Hat product lifecycle API base URL |
|
|
125
|
+
| `LIFECYCLE_CACHE_TTL` | `3600` | Cache TTL in seconds for lifecycle and latest-release lookups (`0` disables caching) |
|
|
106
126
|
| `REQUEST_TIMEOUT` | `30` | Upstream request timeout in seconds |
|
|
107
127
|
| `LISTEN_HOST` | `0.0.0.0` | Listen address |
|
|
108
128
|
| `LISTEN_PORT` | `5000` | Listen port |
|
|
@@ -157,26 +177,21 @@ spec:
|
|
|
157
177
|
### Release signatures
|
|
158
178
|
|
|
159
179
|
For updates by digest (`oc adm upgrade --to-image ...@sha256:...`) the CVO must verify the
|
|
160
|
-
release image signature.
|
|
180
|
+
release image signature.
|
|
161
181
|
|
|
162
|
-
|
|
182
|
+
The `/configmaps/` endpoint fetches all signatures for a release and renders a
|
|
183
|
+
ready-to-apply ConfigMap (same format as `oc adm release mirror` / oc-mirror produces).
|
|
184
|
+
It accepts a release version directly - the digest is resolved via the update graph:
|
|
163
185
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
```yaml
|
|
167
|
-
apiVersion: config.openshift.io/v1
|
|
168
|
-
kind: ClusterVersion
|
|
169
|
-
metadata:
|
|
170
|
-
name: version
|
|
171
|
-
spec:
|
|
172
|
-
signatureStores:
|
|
173
|
-
- url: http://update-proxy.example.com:5000/signatures
|
|
186
|
+
```bash
|
|
187
|
+
curl -s "http://update-proxy.example.com:5000/configmaps/4.16.8" | oc apply -f -
|
|
174
188
|
```
|
|
175
189
|
|
|
176
|
-
|
|
190
|
+
The optional `arch` (default `amd64`) and `channel_prefix` (default `stable`) query
|
|
191
|
+
parameters select the architecture and the update channel used for the lookup, e.g.
|
|
192
|
+
`/configmaps/4.16.8?arch=arm64`.
|
|
177
193
|
|
|
178
|
-
|
|
179
|
-
ready-to-apply ConfigMap (same format as `oc adm release mirror` / oc-mirror produces):
|
|
194
|
+
Alternatively, a release digest can be passed directly:
|
|
180
195
|
|
|
181
196
|
```bash
|
|
182
197
|
DIGEST=$(oc adm release info quay.io/openshift-release-dev/ocp-release:4.16.8-x86_64 -o jsonpath='{.digest}')
|
|
@@ -186,6 +201,98 @@ curl -s "http://update-proxy.example.com:5000/configmaps/${DIGEST/:/=}" | oc app
|
|
|
186
201
|
The ConfigMap is created in `openshift-config-managed` with the
|
|
187
202
|
`release.openshift.io/verification-signatures` label, where the CVO picks it up.
|
|
188
203
|
|
|
204
|
+
> **Note:** The ClusterVersion API also has a `spec.signatureStores` field, but it is
|
|
205
|
+
> gated behind the TechPreview-only `SignatureStores` feature gate and will not be
|
|
206
|
+
> promoted to GA ([OTA-1118](https://issues.redhat.com/browse/OTA-1118)). The ConfigMap
|
|
207
|
+
> above is the supported way to provide signatures.
|
|
208
|
+
|
|
209
|
+
## Operator catalog and Renovate
|
|
210
|
+
|
|
211
|
+
The `/operators/v1/` endpoints answer "which operator versions exist in which
|
|
212
|
+
channel?" without pulling the multi-hundred-MB catalog index images and without any
|
|
213
|
+
registry credentials. The data comes from the public
|
|
214
|
+
[Red Hat Pyxis API](https://catalog.redhat.com/api/containers/docs/) and covers all
|
|
215
|
+
four default catalogs: `redhat-operators`, `certified-operators`,
|
|
216
|
+
`community-operators` and `redhat-marketplace`.
|
|
217
|
+
|
|
218
|
+
List channels, default channel and the latest CSV per channel:
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
curl -s "http://update-proxy.example.com:5000/operators/v1/redhat-operators/openshift-gitops-operator/channels?ocp_version=4.16"
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
```json
|
|
225
|
+
{
|
|
226
|
+
"package": "openshift-gitops-operator",
|
|
227
|
+
"organization": "redhat-operators",
|
|
228
|
+
"default_channel": "latest",
|
|
229
|
+
"channels": [
|
|
230
|
+
{"name": "gitops-1.21", "latest_version": "1.21.4", "latest_csv": "openshift-gitops-operator.v1.21.4"}
|
|
231
|
+
]
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
List all versions of a channel in the format Renovate expects from a
|
|
236
|
+
[custom datasource](https://docs.renovatebot.com/modules/datasource/custom/):
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
curl -s "http://update-proxy.example.com:5000/operators/v1/redhat-operators/openshift-gitops-operator/gitops-1.21/releases?ocp_version=4.16"
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
```json
|
|
243
|
+
{
|
|
244
|
+
"releases": [
|
|
245
|
+
{"version": "1.21.3", "releaseTimestamp": "2026-08-14T23:45:28.177000+00:00"},
|
|
246
|
+
{"version": "1.21.4", "releaseTimestamp": "2026-09-03T12:13:37.391000+00:00"}
|
|
247
|
+
]
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
The optional `ocp_version` query parameter limits results to bundles shipped in the
|
|
252
|
+
catalog for that OpenShift minor version. Responses are cached in memory for
|
|
253
|
+
`CATALOG_CACHE_TTL` seconds. The raw Pyxis API is available under `/catalog/`, e.g.
|
|
254
|
+
`/catalog/operators/indices?filter=organization==redhat-operators` lists all index
|
|
255
|
+
image tags with their end-of-life dates.
|
|
256
|
+
|
|
257
|
+
With this feed, Renovate can bump pinned operator versions (`startingCSV` in OLM
|
|
258
|
+
`Subscription` manifests, whether managed directly via Argo CD or embedded in ACM
|
|
259
|
+
policies) just like any other dependency - merging the PR rolls out the operator
|
|
260
|
+
update. See [examples/renovate/](examples/renovate/) for a complete working setup:
|
|
261
|
+
a `renovate.json` with the custom datasource and regex manager, plus matching
|
|
262
|
+
Subscription and ACM Policy manifests.
|
|
263
|
+
|
|
264
|
+
## Supported OpenShift versions
|
|
265
|
+
|
|
266
|
+
`/versions/v1/supported` combines the
|
|
267
|
+
[Red Hat product lifecycle API](https://access.redhat.com/product-life-cycles) with
|
|
268
|
+
the Cincinnati update graph: all OpenShift minor versions that are not end-of-life,
|
|
269
|
+
together with the latest release in the corresponding update channel.
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
curl -s "http://update-proxy.example.com:5000/versions/v1/supported"
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
```json
|
|
276
|
+
{
|
|
277
|
+
"product": "OpenShift Container Platform",
|
|
278
|
+
"architecture": "amd64",
|
|
279
|
+
"versions": [
|
|
280
|
+
{"version": "4.22", "support_phase": "Full Support", "channel": "stable-4.22", "latest_release": "4.22.11"},
|
|
281
|
+
{"version": "4.20", "support_phase": "Maintenance Support", "channel": "stable-4.20", "latest_release": "4.20.35"}
|
|
282
|
+
]
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
The optional `channel_prefix` (default `stable`, e.g. `eus`, `fast`, `candidate`) and
|
|
287
|
+
`arch` (default `amd64`) query parameters select the channel and architecture;
|
|
288
|
+
`latest_release` is `null` when the channel has no published releases yet. The raw
|
|
289
|
+
lifecycle API is available under `/lifecycle/`, e.g.
|
|
290
|
+
`/lifecycle/products?name=OpenShift Container Platform`.
|
|
291
|
+
|
|
292
|
+
[examples/create-configmaps.sh](examples/create-configmaps.sh) combines this with
|
|
293
|
+
the `/configmaps/` endpoint: it fetches the release signatures for a set of update
|
|
294
|
+
channels through the proxy and applies them as ConfigMaps.
|
|
295
|
+
|
|
189
296
|
## Local Development
|
|
190
297
|
|
|
191
298
|
```bash
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# 🔄 openshift-update-proxy
|
|
2
|
+
|
|
3
|
+
[](https://github.com/slauger/openshift-update-proxy/actions/workflows/ci.yml)
|
|
4
|
+
[](https://github.com/slauger/openshift-update-proxy/actions/workflows/release.yml)
|
|
5
|
+
[](https://pypi.org/project/openshift-update-proxy/)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
A small Flask based service which forwards HTTP requests to `api.openshift.com`,
|
|
9
|
+
`mirror.openshift.com`, `catalog.redhat.com` and `access.redhat.com`. Built for
|
|
10
|
+
restricted networks where OpenShift clusters have no direct internet access, but a
|
|
11
|
+
central egress proxy (or a single host with internet access) exists.
|
|
12
|
+
|
|
13
|
+
## Features
|
|
14
|
+
|
|
15
|
+
- 🔀 **Update Graph Proxy** - forwards Cincinnati update graph requests
|
|
16
|
+
(`/api/upgrades_info/v1/graph`) to `api.openshift.com`
|
|
17
|
+
- 📦 **Mirror Proxy** - forwards requests for clients and release artifacts to
|
|
18
|
+
`mirror.openshift.com/pub`
|
|
19
|
+
- 🔏 **Signature Store** - serves release image signatures for
|
|
20
|
+
`ClusterVersion.spec.signatureStores` (OpenShift 4.14+)
|
|
21
|
+
- 🗺️ **ConfigMap Generator** - renders ready-to-apply signature ConfigMaps for the
|
|
22
|
+
classic disconnected verification workflow
|
|
23
|
+
- 🎛️ **Operator Catalog API** - serves operator channels and versions from the
|
|
24
|
+
Red Hat Pyxis API (`catalog.redhat.com`), ready to use as a
|
|
25
|
+
[Renovate custom datasource](https://docs.renovatebot.com/modules/datasource/custom/)
|
|
26
|
+
- 📅 **Supported Versions API** - combines the Red Hat product lifecycle API with the
|
|
27
|
+
update graph to list supported OpenShift minor versions and their latest release
|
|
28
|
+
- 🚦 **Egress Proxy Aware** - honors `HTTPS_PROXY` / `NO_PROXY` for all upstream requests
|
|
29
|
+
- 🐳 **Hardened Container** - UBI9 based, rootless (UID 1001), digest-pinned base image,
|
|
30
|
+
Cosign signed
|
|
31
|
+
- ⛵ **Helm Chart** - deploy to Kubernetes/OpenShift with probes and sane security defaults
|
|
32
|
+
- 🩺 **Health Endpoint** - `/healthz` for liveness and readiness probes
|
|
33
|
+
|
|
34
|
+
## How it works
|
|
35
|
+
|
|
36
|
+
```mermaid
|
|
37
|
+
flowchart LR
|
|
38
|
+
subgraph restricted["Restricted network"]
|
|
39
|
+
CVO["Cluster Version Operator"]
|
|
40
|
+
ADMIN["Admin (oc / curl)"]
|
|
41
|
+
RENOVATE["Renovate"]
|
|
42
|
+
PROXY["openshift-update-proxy"]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
subgraph internet["Internet"]
|
|
46
|
+
API["api.openshift.com"]
|
|
47
|
+
MIRROR["mirror.openshift.com"]
|
|
48
|
+
PYXIS["catalog.redhat.com"]
|
|
49
|
+
LIFECYCLE["access.redhat.com"]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
CVO -- "/api/upgrades_info/v1/graph" --> PROXY
|
|
53
|
+
CVO -- "/signatures/sha256=…" --> PROXY
|
|
54
|
+
ADMIN -- "/configmaps/sha256=…" --> PROXY
|
|
55
|
+
ADMIN -- "/pub/…" --> PROXY
|
|
56
|
+
RENOVATE -- "/operators/v1/…" --> PROXY
|
|
57
|
+
|
|
58
|
+
PROXY -- "optional egress proxy (HTTPS_PROXY)" --> EGRESS["Egress Proxy"]
|
|
59
|
+
EGRESS --> API
|
|
60
|
+
EGRESS --> MIRROR
|
|
61
|
+
EGRESS --> PYXIS
|
|
62
|
+
EGRESS --> LIFECYCLE
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Endpoints
|
|
66
|
+
|
|
67
|
+
| Endpoint | Upstream | Purpose |
|
|
68
|
+
|----------|----------|---------|
|
|
69
|
+
| `/api/<path>` | `https://api.openshift.com/api/` | Cincinnati update graph (`/api/upgrades_info/v1/graph`) |
|
|
70
|
+
| `/pub/<path>` | `https://mirror.openshift.com/pub/` | OpenShift mirror (clients, release artifacts) |
|
|
71
|
+
| `/signatures/<path>` | `https://mirror.openshift.com/pub/openshift-v4/signatures/openshift/release/` | Release image signature store |
|
|
72
|
+
| `/configmaps/<version or sha256=digest>` | derived from signature store | Ready-to-apply signature ConfigMap (YAML) |
|
|
73
|
+
| `/catalog/<path>` | `https://catalog.redhat.com/api/containers/v1/` | Red Hat Pyxis API (operator catalog metadata) |
|
|
74
|
+
| `/operators/v1/<catalog>/<package>/channels` | derived from Pyxis | Channels, default channel and latest CSV per channel |
|
|
75
|
+
| `/operators/v1/<catalog>/<package>/<channel>/releases` | derived from Pyxis | Version feed in Renovate custom datasource format |
|
|
76
|
+
| `/lifecycle/<path>` | `https://access.redhat.com/product-life-cycles/api/v1/` | Red Hat product lifecycle API |
|
|
77
|
+
| `/versions/v1/supported` | derived from lifecycle API + update graph | Supported OpenShift minors with latest release per channel |
|
|
78
|
+
| `/healthz` | - | Health check for liveness/readiness probes |
|
|
79
|
+
|
|
80
|
+
## Configuration
|
|
81
|
+
|
|
82
|
+
All configuration is done via environment variables:
|
|
83
|
+
|
|
84
|
+
| Variable | Default | Description |
|
|
85
|
+
|----------|---------|-------------|
|
|
86
|
+
| `HTTPS_PROXY` | - | Egress proxy for upstream requests (standard `requests` behaviour, `NO_PROXY` is honored) |
|
|
87
|
+
| `INSECURE_SKIP_TLS_VERIFY` | `false` | Skip TLS certificate verification for upstream requests (`true`/`1`/`yes`) |
|
|
88
|
+
| `API_UPSTREAM` | `https://api.openshift.com/api/` | Cincinnati API base URL |
|
|
89
|
+
| `MIRROR_UPSTREAM` | `https://mirror.openshift.com/pub/` | Mirror base URL |
|
|
90
|
+
| `SIGNATURE_UPSTREAM` | `https://mirror.openshift.com/pub/openshift-v4/signatures/openshift/release/` | Signature store base URL |
|
|
91
|
+
| `CATALOG_UPSTREAM` | `https://catalog.redhat.com/api/containers/v1/` | Red Hat Pyxis API base URL |
|
|
92
|
+
| `CATALOG_CACHE_TTL` | `600` | Cache TTL in seconds for operator catalog lookups (`0` disables caching) |
|
|
93
|
+
| `LIFECYCLE_UPSTREAM` | `https://access.redhat.com/product-life-cycles/api/v1/` | Red Hat product lifecycle API base URL |
|
|
94
|
+
| `LIFECYCLE_CACHE_TTL` | `3600` | Cache TTL in seconds for lifecycle and latest-release lookups (`0` disables caching) |
|
|
95
|
+
| `REQUEST_TIMEOUT` | `30` | Upstream request timeout in seconds |
|
|
96
|
+
| `LISTEN_HOST` | `0.0.0.0` | Listen address |
|
|
97
|
+
| `LISTEN_PORT` | `5000` | Listen port |
|
|
98
|
+
|
|
99
|
+
## Quick Start
|
|
100
|
+
|
|
101
|
+
### Container
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
docker run --rm -p 5000:5000 \
|
|
105
|
+
-e HTTPS_PROXY=http://proxy.example.com:3128 \
|
|
106
|
+
ghcr.io/slauger/openshift-update-proxy:latest
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The image is based on `registry.access.redhat.com/ubi9/python-314`, runs as UID `1001`
|
|
110
|
+
and is built from the `Containerfile` in this repository.
|
|
111
|
+
|
|
112
|
+
### Helm
|
|
113
|
+
|
|
114
|
+
The chart is published as an OCI artifact to ghcr.io on every release:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
helm install update-proxy oci://ghcr.io/slauger/charts/openshift-update-proxy \
|
|
118
|
+
--set env[0].name=HTTPS_PROXY,env[0].value=http://proxy.example.com:3128
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Or from a git checkout: `helm install update-proxy ./chart`
|
|
122
|
+
|
|
123
|
+
### PyPI
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
python3 -m venv .venv && source .venv/bin/activate
|
|
127
|
+
pip install openshift-update-proxy
|
|
128
|
+
openshift-update-proxy
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Cluster integration
|
|
132
|
+
|
|
133
|
+
### Update graph
|
|
134
|
+
|
|
135
|
+
Point the ClusterVersion `upstream` at the proxy:
|
|
136
|
+
|
|
137
|
+
```yaml
|
|
138
|
+
apiVersion: config.openshift.io/v1
|
|
139
|
+
kind: ClusterVersion
|
|
140
|
+
metadata:
|
|
141
|
+
name: version
|
|
142
|
+
spec:
|
|
143
|
+
upstream: http://update-proxy.example.com:5000/api/upgrades_info/v1/graph
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Release signatures
|
|
147
|
+
|
|
148
|
+
For updates by digest (`oc adm upgrade --to-image ...@sha256:...`) the CVO must verify the
|
|
149
|
+
release image signature.
|
|
150
|
+
|
|
151
|
+
The `/configmaps/` endpoint fetches all signatures for a release and renders a
|
|
152
|
+
ready-to-apply ConfigMap (same format as `oc adm release mirror` / oc-mirror produces).
|
|
153
|
+
It accepts a release version directly - the digest is resolved via the update graph:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
curl -s "http://update-proxy.example.com:5000/configmaps/4.16.8" | oc apply -f -
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
The optional `arch` (default `amd64`) and `channel_prefix` (default `stable`) query
|
|
160
|
+
parameters select the architecture and the update channel used for the lookup, e.g.
|
|
161
|
+
`/configmaps/4.16.8?arch=arm64`.
|
|
162
|
+
|
|
163
|
+
Alternatively, a release digest can be passed directly:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
DIGEST=$(oc adm release info quay.io/openshift-release-dev/ocp-release:4.16.8-x86_64 -o jsonpath='{.digest}')
|
|
167
|
+
curl -s "http://update-proxy.example.com:5000/configmaps/${DIGEST/:/=}" | oc apply -f -
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The ConfigMap is created in `openshift-config-managed` with the
|
|
171
|
+
`release.openshift.io/verification-signatures` label, where the CVO picks it up.
|
|
172
|
+
|
|
173
|
+
> **Note:** The ClusterVersion API also has a `spec.signatureStores` field, but it is
|
|
174
|
+
> gated behind the TechPreview-only `SignatureStores` feature gate and will not be
|
|
175
|
+
> promoted to GA ([OTA-1118](https://issues.redhat.com/browse/OTA-1118)). The ConfigMap
|
|
176
|
+
> above is the supported way to provide signatures.
|
|
177
|
+
|
|
178
|
+
## Operator catalog and Renovate
|
|
179
|
+
|
|
180
|
+
The `/operators/v1/` endpoints answer "which operator versions exist in which
|
|
181
|
+
channel?" without pulling the multi-hundred-MB catalog index images and without any
|
|
182
|
+
registry credentials. The data comes from the public
|
|
183
|
+
[Red Hat Pyxis API](https://catalog.redhat.com/api/containers/docs/) and covers all
|
|
184
|
+
four default catalogs: `redhat-operators`, `certified-operators`,
|
|
185
|
+
`community-operators` and `redhat-marketplace`.
|
|
186
|
+
|
|
187
|
+
List channels, default channel and the latest CSV per channel:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
curl -s "http://update-proxy.example.com:5000/operators/v1/redhat-operators/openshift-gitops-operator/channels?ocp_version=4.16"
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
```json
|
|
194
|
+
{
|
|
195
|
+
"package": "openshift-gitops-operator",
|
|
196
|
+
"organization": "redhat-operators",
|
|
197
|
+
"default_channel": "latest",
|
|
198
|
+
"channels": [
|
|
199
|
+
{"name": "gitops-1.21", "latest_version": "1.21.4", "latest_csv": "openshift-gitops-operator.v1.21.4"}
|
|
200
|
+
]
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
List all versions of a channel in the format Renovate expects from a
|
|
205
|
+
[custom datasource](https://docs.renovatebot.com/modules/datasource/custom/):
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
curl -s "http://update-proxy.example.com:5000/operators/v1/redhat-operators/openshift-gitops-operator/gitops-1.21/releases?ocp_version=4.16"
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
```json
|
|
212
|
+
{
|
|
213
|
+
"releases": [
|
|
214
|
+
{"version": "1.21.3", "releaseTimestamp": "2026-08-14T23:45:28.177000+00:00"},
|
|
215
|
+
{"version": "1.21.4", "releaseTimestamp": "2026-09-03T12:13:37.391000+00:00"}
|
|
216
|
+
]
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
The optional `ocp_version` query parameter limits results to bundles shipped in the
|
|
221
|
+
catalog for that OpenShift minor version. Responses are cached in memory for
|
|
222
|
+
`CATALOG_CACHE_TTL` seconds. The raw Pyxis API is available under `/catalog/`, e.g.
|
|
223
|
+
`/catalog/operators/indices?filter=organization==redhat-operators` lists all index
|
|
224
|
+
image tags with their end-of-life dates.
|
|
225
|
+
|
|
226
|
+
With this feed, Renovate can bump pinned operator versions (`startingCSV` in OLM
|
|
227
|
+
`Subscription` manifests, whether managed directly via Argo CD or embedded in ACM
|
|
228
|
+
policies) just like any other dependency - merging the PR rolls out the operator
|
|
229
|
+
update. See [examples/renovate/](examples/renovate/) for a complete working setup:
|
|
230
|
+
a `renovate.json` with the custom datasource and regex manager, plus matching
|
|
231
|
+
Subscription and ACM Policy manifests.
|
|
232
|
+
|
|
233
|
+
## Supported OpenShift versions
|
|
234
|
+
|
|
235
|
+
`/versions/v1/supported` combines the
|
|
236
|
+
[Red Hat product lifecycle API](https://access.redhat.com/product-life-cycles) with
|
|
237
|
+
the Cincinnati update graph: all OpenShift minor versions that are not end-of-life,
|
|
238
|
+
together with the latest release in the corresponding update channel.
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
curl -s "http://update-proxy.example.com:5000/versions/v1/supported"
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
```json
|
|
245
|
+
{
|
|
246
|
+
"product": "OpenShift Container Platform",
|
|
247
|
+
"architecture": "amd64",
|
|
248
|
+
"versions": [
|
|
249
|
+
{"version": "4.22", "support_phase": "Full Support", "channel": "stable-4.22", "latest_release": "4.22.11"},
|
|
250
|
+
{"version": "4.20", "support_phase": "Maintenance Support", "channel": "stable-4.20", "latest_release": "4.20.35"}
|
|
251
|
+
]
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
The optional `channel_prefix` (default `stable`, e.g. `eus`, `fast`, `candidate`) and
|
|
256
|
+
`arch` (default `amd64`) query parameters select the channel and architecture;
|
|
257
|
+
`latest_release` is `null` when the channel has no published releases yet. The raw
|
|
258
|
+
lifecycle API is available under `/lifecycle/`, e.g.
|
|
259
|
+
`/lifecycle/products?name=OpenShift Container Platform`.
|
|
260
|
+
|
|
261
|
+
[examples/create-configmaps.sh](examples/create-configmaps.sh) combines this with
|
|
262
|
+
the `/configmaps/` endpoint: it fetches the release signatures for a set of update
|
|
263
|
+
channels through the proxy and applies them as ConfigMaps.
|
|
264
|
+
|
|
265
|
+
## Local Development
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
python3 -m venv .venv
|
|
269
|
+
source .venv/bin/activate
|
|
270
|
+
pip install -e ".[dev]"
|
|
271
|
+
openshift-update-proxy
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Run tests and linting:
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
make test
|
|
278
|
+
make lint
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Build the container image:
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
make build
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## Supply Chain Security
|
|
288
|
+
|
|
289
|
+
- The UBI9 base image is pinned by digest and kept up to date by
|
|
290
|
+
[Renovate](https://docs.renovatebot.com/); remaining CVEs are patched at build time via
|
|
291
|
+
`dnf upgrade`.
|
|
292
|
+
- Python and GitHub Actions dependencies are also managed by Renovate (with automerge for
|
|
293
|
+
non-major updates).
|
|
294
|
+
- Releases are fully automated with
|
|
295
|
+
[python-semantic-release](https://python-semantic-release.readthedocs.io/) based on
|
|
296
|
+
Conventional Commits and published to PyPI.
|
|
297
|
+
- Container images are signed with [Cosign](https://github.com/sigstore/cosign) (keyless,
|
|
298
|
+
GitHub Actions OIDC). Verify with:
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
cosign verify \
|
|
302
|
+
--certificate-identity-regexp 'https://github.com/slauger/openshift-update-proxy/.*' \
|
|
303
|
+
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
|
|
304
|
+
ghcr.io/slauger/openshift-update-proxy:latest
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## License
|
|
308
|
+
|
|
309
|
+
[Apache License 2.0](LICENSE)
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "openshift-update-proxy"
|
|
7
|
-
version = "1.0
|
|
7
|
+
version = "1.2.0"
|
|
8
8
|
description = "Forwarding proxy for OpenShift update resources (Cincinnati API, mirror, release signatures)"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "Apache-2.0"
|