From 65d0e74b4601b7692b688fb25fedfdf0fa036eb9 Mon Sep 17 00:00:00 2001 From: user Date: Fri, 21 Aug 2026 16:49:27 -0400 Subject: [PATCH 1/2] fix(auth): enforce management API JWT audience --- components/api-server/go.mod | 26 ++++++++++- components/api-server/go.sum | 58 ++++++++++++++++++++++++- dependency-age-allowlist.json | 6 +-- deploy/kind/kustomization.yaml | 8 +++- deploy/openshift/kustomization.yaml | 23 ++++++++-- specs/platform/oidc-integration.spec.md | 29 ++++++++++--- 6 files changed, 133 insertions(+), 17 deletions(-) diff --git a/components/api-server/go.mod b/components/api-server/go.mod index c199b7e9..b7e4816b 100644 --- a/components/api-server/go.mod +++ b/components/api-server/go.mod @@ -8,7 +8,8 @@ require ( github.com/golang/glog v1.2.5 github.com/gorilla/mux v1.7.3 github.com/onsi/gomega v1.27.1 - github.com/openshift-online/rh-trex-ai v0.0.32-0.20260819203335-5798cb607fcb + github.com/openshift-online/rh-trex-ai v0.0.32-0.20260821204222-2efb23d4a8d5 + github.com/prometheus/client_golang v1.16.0 github.com/segmentio/ksuid v1.0.2 github.com/spf13/pflag v1.0.5 github.com/uptrace/opentelemetry-go-extra/otelgorm v0.3.2 @@ -35,11 +36,23 @@ require ( github.com/Masterminds/squirrel v1.1.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/antlr/antlr4 v0.0.0-20190518164840-edae2a1c9b4b // indirect + github.com/atotto/clipboard v0.1.4 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bxcodec/faker/v3 v3.2.0 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/charmbracelet/bubbles v1.0.0 // indirect + github.com/charmbracelet/bubbletea v1.3.10 // indirect + github.com/charmbracelet/colorprofile v0.4.1 // indirect + github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834 // indirect + github.com/charmbracelet/x/ansi v0.11.6 // indirect + github.com/charmbracelet/x/cellbuf v0.0.15 // indirect + github.com/charmbracelet/x/term v0.2.2 // indirect + github.com/clipperhouse/displaywidth v0.9.0 // indirect + github.com/clipperhouse/stringish v0.1.1 // indirect + github.com/clipperhouse/uax29/v2 v2.5.0 // indirect github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/containerd/log v0.1.0 // indirect @@ -51,6 +64,7 @@ require ( github.com/docker/go-connections v0.6.0 // indirect github.com/docker/go-healthcheck v0.1.0 // indirect github.com/docker/go-units v0.5.0 // indirect + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-logr/logr v1.4.3 // indirect @@ -72,8 +86,12 @@ require ( github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/lib/pq v1.10.9 // indirect + github.com/lucasb-eyer/go-colorful v1.3.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.10 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-localereader v0.0.1 // indirect + github.com/mattn/go-runewidth v0.0.19 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect @@ -84,14 +102,17 @@ require ( github.com/moby/sys/userns v0.1.0 // indirect github.com/moby/term v0.5.0 // indirect github.com/morikuni/aec v1.0.0 // indirect + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect + github.com/muesli/cancelreader v0.2.2 // indirect + github.com/muesli/termenv v0.16.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect - github.com/prometheus/client_golang v1.16.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/shirou/gopsutil/v3 v3.23.12 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sirupsen/logrus v1.9.3 // indirect @@ -101,6 +122,7 @@ require ( github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 // indirect diff --git a/components/api-server/go.sum b/components/api-server/go.sum index 8515e7df..aec3eafe 100644 --- a/components/api-server/go.sum +++ b/components/api-server/go.sum @@ -24,6 +24,12 @@ github.com/antlr/antlr4 v0.0.0-20190518164840-edae2a1c9b4b h1:IyTcB1l64U991qSZ0u github.com/antlr/antlr4 v0.0.0-20190518164840-edae2a1c9b4b/go.mod h1:T7PbCXFs94rrTttyxjbyT5+/1V8T2TYDejxUfHJjw1Y= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/aymanbagabas/go-udiff v0.3.1 h1:LV+qyBQ2pqe0u42ZsUEtPiCaUoqgA9gYRDs3vj1nolY= +github.com/aymanbagabas/go-udiff v0.3.1/go.mod h1:G0fsKmG+P6ylD0r6N/KgQD/nWzgfnl8ZBcNLgcbrw8E= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -35,7 +41,31 @@ github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1x github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/charmbracelet/bubbles v1.0.0 h1:12J8/ak/uCZEMQ6KU7pcfwceyjLlWsDLAxB5fXonfvc= +github.com/charmbracelet/bubbles v1.0.0/go.mod h1:9d/Zd5GdnauMI5ivUIVisuEm3ave1XwXtD1ckyV6r3E= +github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw= +github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4= +github.com/charmbracelet/colorprofile v0.4.1 h1:a1lO03qTrSIRaK8c3JRxJDZOvhvIeSco3ej+ngLk1kk= +github.com/charmbracelet/colorprofile v0.4.1/go.mod h1:U1d9Dljmdf9DLegaJ0nGZNJvoXAhayhmidOdcBwAvKk= +github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834 h1:ZR7e0ro+SZZiIZD7msJyA+NjkCNNavuiPBLgerbOziE= +github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834/go.mod h1:aKC/t2arECF6rNOnaKaVU6y4t4ZeHQzqfxedE/VkVhA= +github.com/charmbracelet/x/ansi v0.11.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF7ihZW8= +github.com/charmbracelet/x/ansi v0.11.6/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ= +github.com/charmbracelet/x/cellbuf v0.0.15 h1:ur3pZy0o6z/R7EylET877CBxaiE1Sp1GMxoFPAIztPI= +github.com/charmbracelet/x/cellbuf v0.0.15/go.mod h1:J1YVbR7MUuEGIFPCaaZ96KDl5NoS0DAWkskup+mOY+Q= +github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ= +github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= +github.com/charmbracelet/x/exp/teatest v0.0.0-20260311145557-c83711a11ffa h1:4rgvAp7etZ7KIDwS17zgM2HFqg6tLC2TgcESM+QdeU0= +github.com/charmbracelet/x/exp/teatest v0.0.0-20260311145557-c83711a11ffa/go.mod h1:aPVjFrBwbJgj5Qz1F0IXsnbcOVJcMKgu1ySUfTAxh7k= +github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk= +github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/clipperhouse/displaywidth v0.9.0 h1:Qb4KOhYwRiN3viMv1v/3cTBlz3AcAZX3+y9OLhMtAtA= +github.com/clipperhouse/displaywidth v0.9.0/go.mod h1:aCAAqTlh4GIVkhQnJpbL0T/WfcrJXHcj8C0yjYcjOZA= +github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs= +github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= +github.com/clipperhouse/uax29/v2 v2.5.0 h1:x7T0T4eTHDONxFJsL94uKNKPHrclyFI0lm7+w94cO8U= +github.com/clipperhouse/uax29/v2 v2.5.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= @@ -72,6 +102,8 @@ github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= @@ -181,6 +213,8 @@ github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag= +github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -188,6 +222,12 @@ github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8S github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= +github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= +github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= @@ -216,6 +256,12 @@ github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= +github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -231,8 +277,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= -github.com/openshift-online/rh-trex-ai v0.0.32-0.20260819203335-5798cb607fcb h1:UpFcCR6NSPkuLp/RrIdUCLb1kuYU6X9XxWmF32WKORU= -github.com/openshift-online/rh-trex-ai v0.0.32-0.20260819203335-5798cb607fcb/go.mod h1:bg13aORX6znydbb1wOtClX2MZBy7iUzc0+j4bd0rGiU= +github.com/openshift-online/rh-trex-ai v0.0.32-0.20260821204222-2efb23d4a8d5 h1:NGObXiVKdiumt06smV/pM1w5LIMhtxv/Okko2Qukbmw= +github.com/openshift-online/rh-trex-ai v0.0.32-0.20260821204222-2efb23d4a8d5/go.mod h1:z91AYMNi/YfIk5CuKxh9yLqNgd/80FENxgUItqj8CfQ= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= @@ -259,6 +305,8 @@ github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= @@ -312,6 +360,8 @@ github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2 h1:ZjUj9BLYf9PEqBn8W/Oa github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2/go.mod h1:O8bHQfyinKwTXKkiKNGmLQS7vRsqRxIQTFZpYpHK3IQ= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yaacov/tree-search-language v0.0.0-20190923184055-1c2dad2e354b h1:aWR0+NlUGQpFPxpjcYW7oXsN1GnYUVIdB5Act7I6jzc= github.com/yaacov/tree-search-language v0.0.0-20190923184055-1c2dad2e354b/go.mod h1:uXZEzDS1siuQsBuHL1A4gy27xIsnnL06MhqrwvySsIk= @@ -361,6 +411,8 @@ golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2d golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190523035834-f03afa92d3ff/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -411,7 +463,9 @@ golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/dependency-age-allowlist.json b/dependency-age-allowlist.json index 65257b82..f8148157 100644 --- a/dependency-age-allowlist.json +++ b/dependency-age-allowlist.json @@ -2,9 +2,9 @@ { "kind": "go", "name": "github.com/openshift-online/rh-trex-ai", - "version": "v0.0.32-0.20260819203335-5798cb607fcb", - "reason": "HyperShell requires the framework GORM plugin registry (openshift-online/rh-trex-ai#51) that installs API server database query tracing, merged inside the cooldown window.", - "compensatingVerification": "The dependency is commit-pinned; API server formatting, vet, and golangci-lint run against that exact commit." + "version": "v0.0.32-0.20260821204222-2efb23d4a8d5", + "reason": "HyperShell requires configurable JWT issuer and audience validation from openshift-online/rh-trex-ai#52 to prevent replay of same-realm tokens issued for other resources.", + "compensatingVerification": "The dependency is commit-pinned; upstream signed-token tests cover HTTP and gRPC claim validation, and HyperShell API server formatting, vet, tests, and golangci-lint run against that exact commit." }, { "kind": "go", diff --git a/deploy/kind/kustomization.yaml b/deploy/kind/kustomization.yaml index cb209e36..54817653 100644 --- a/deploy/kind/kustomization.yaml +++ b/deploy/kind/kustomization.yaml @@ -112,7 +112,7 @@ patches: secretKeyRef: name: hypershell-oidc-session key: session-secret - # --- API server: enable JWT + JWK cert URL + bypass paths --- + # --- API server: enable JWT + issuer/audience validation + bypass paths --- # Appending --enable-jwt=true is index-independent: --enable-jwt is a pflag # BoolVar, and repeated single-value flags are last-value-wins, so the # appended true overrides the base --enable-jwt=false no matter where it sits @@ -131,6 +131,12 @@ patches: - op: add path: /spec/template/spec/containers/0/command/- value: "--jwk-cert-url=http://keycloak-service.keycloak.svc.cluster.local:8080/realms/hypershell/protocol/openid-connect/certs" + - op: add + path: /spec/template/spec/containers/0/command/- + value: "--jwt-issuer=https://keycloak.hypershell.localhost/realms/hypershell" + - op: add + path: /spec/template/spec/containers/0/command/- + value: "--jwt-audience=hypershell-frontend" - op: add path: /spec/template/spec/containers/0/command/- value: "--auth-bypass-paths=/healthcheck,/metrics,/api/hypershell/v1/openapi,/openapi" diff --git a/deploy/openshift/kustomization.yaml b/deploy/openshift/kustomization.yaml index f8fc9c2e..6207fe6d 100644 --- a/deploy/openshift/kustomization.yaml +++ b/deploy/openshift/kustomization.yaml @@ -44,10 +44,14 @@ patches: secretKeyRef: name: hypershell-api-config key: api-service.clientSecret - # --- API server: enable JWT + JWK cert URL from OIDC secret + enforce RBAC --- - # The JWKS URL is read from the hypershell-api-config secret so it stays in - # sync with the Keycloak instance provisioned for this cluster. Without this, - # the framework defaults to sso.redhat.com and rejects Keycloak-issued tokens. + # --- API server: validate JWT signature, issuer, and audience + enforce RBAC --- + # The JWKS and issuer URLs are read from the hypershell-api-config secret so + # they stay in sync with the Keycloak instance provisioned for this cluster. + # The issuer is kept separate from the JWKS URL because tokens carry the + # external realm URL in `iss` while the keys may be fetched through another + # route. The API resource audience is the shared hypershell-frontend audience; + # individual callers (web console, hsctl, control plane) remain identifiable + # through `azp`. # # RBAC_ENFORCE=true turns on the three-role gateway RBAC model # (gateway:creator/owner/viewer); it is the sole gate for that model @@ -77,6 +81,11 @@ patches: secretKeyRef: name: hypershell-api-config key: api-service.jwkCertUrl + - name: JWT_ISSUER + valueFrom: + secretKeyRef: + name: hypershell-api-config + key: api-service.issuerUrl - name: RBAC_ENFORCE value: "true" - name: RBAC_SERVICE_ACCOUNTS @@ -90,6 +99,12 @@ patches: - op: add path: /spec/template/spec/containers/0/command/- value: "--jwk-cert-url=$(JWK_CERT_URL)" + - op: add + path: /spec/template/spec/containers/0/command/- + value: "--jwt-issuer=$(JWT_ISSUER)" + - op: add + path: /spec/template/spec/containers/0/command/- + value: "--jwt-audience=hypershell-frontend" - op: add path: /spec/template/spec/containers/0/command/- value: "--auth-bypass-paths=/healthcheck,/metrics,/api/hypershell/v1/openapi,/openapi" diff --git a/specs/platform/oidc-integration.spec.md b/specs/platform/oidc-integration.spec.md index 231584ba..c4897c63 100644 --- a/specs/platform/oidc-integration.spec.md +++ b/specs/platform/oidc-integration.spec.md @@ -31,7 +31,7 @@ Web Console BFF (Fastify) │ Refreshes token transparently when access token expires ▼ HyperShell REST API - │ Validates JWT: issuer, JWKS signature, expiry + │ Validates JWT: issuer, audience, JWKS signature, expiry │ gRPC watch methods bypass JWT (trusted in-cluster services) ▼ PostgreSQL / Control Plane / Gateway @@ -42,7 +42,7 @@ The platform supports two authentication modes: | Mode | API Server | BFF | Use Case | |------|-----------|-----|----------| | **No-auth** | JWT disabled | Stateless proxy, no session | Development without auth overhead | -| **OIDC** | JWT enabled, JWKS validation | Auth code + PKCE, encrypted cookie session | Production, staging, OIDC-enabled local dev | +| **OIDC** | JWT enabled, issuer/audience/JWKS validation | Auth code + PKCE, encrypted cookie session | Production, staging, OIDC-enabled local dev | Mode selection is deployment configuration. Application code consumes the same interfaces in both modes. @@ -50,7 +50,7 @@ Mode selection is deployment configuration. Application code consumes the same i ## API Server JWT Validation -The API server uses the upstream rh-trex-ai framework for JWT validation. When enabled, the framework validates Bearer tokens on incoming HTTP and gRPC requests against a JWKS endpoint. +The API server uses the upstream rh-trex-ai framework for JWT validation. When enabled, the framework validates Bearer tokens on incoming HTTP and gRPC requests against a JWKS endpoint and requires the configured issuer and API resource audience. ### Configuration @@ -59,10 +59,19 @@ The API server uses the upstream rh-trex-ai framework for JWT validation. When e | `--enable-jwt` | `true` (framework default) | Enable JWT validation | | `--jwk-cert-url` | Red Hat SSO JWKS | JWKS endpoint URL(s) for JWT signature validation | | `--grpc-jwk-cert-url` | (inherits `--jwk-cert-url`) | Override JWKS URL for gRPC validation | +| `--jwt-issuer` | empty | Exact expected `iss` claim; required by HyperShell OIDC deployments | +| `--jwt-audience` | empty | Required `aud` value; HyperShell uses `hypershell-frontend` as the management API resource audience | | `--enable-authz` | `true` (framework default) | Enable authorization middleware | | `--auth-bypass-paths` | `/healthcheck`, `/metrics`, `/openapi` | HTTP paths exempt from JWT validation | | `--auth-bypass-methods` | Health, Reflection | gRPC methods exempt from JWT validation | +`hypershell-frontend` identifies the management API as the token resource; it is +not a restriction to the web-console OAuth client. First-party callers such as +hsctl and the control plane receive that audience from dedicated Keycloak +mappers and remain distinguishable through `azp`. Per-gateway clients receive +only their gateway audience, so their tokens SHALL be rejected by management +API endpoints. + ### Environment System The API server selects behavior via `API_ENV`. The existing `development` environment hardcodes `EnableJWT = false` in its `OverrideConfig()`, which runs after CLI flag parsing and cannot be overridden by flags. @@ -236,7 +245,7 @@ The `hypershell-provisioner` client is a confidential service account used for a | Component | Configuration | |-----------|--------------| -| API server | `API_ENV=production`, `--enable-jwt=true`, `--jwk-cert-url=`, `--enable-authz=true` | +| API server | `API_ENV=production`, `--enable-jwt=true`, `--jwk-cert-url=`, `--jwt-issuer=`, `--jwt-audience=hypershell-frontend`, `--enable-authz=true` | | BFF | `OIDC_ISSUER=`, `OIDC_CLIENT_ID=hypershell-frontend`, `SESSION_SECRET=` | | Gateway | OIDC configured per `openshell-gateway-oidc.spec.md` | | Keycloak | Downstream Keycloak brokering to Red Hat SSO | @@ -250,7 +259,7 @@ OIDC is always enabled in the Kind cluster. `make kind-up` configures all compon `make kind-up` SHALL: -1. Deploy the API server with `--enable-jwt=true`, `--jwk-cert-url`, `--auth-bypass-paths`, and `--auth-bypass-methods` flags via Kustomize JSON patch (direct flag override avoids dependency on `API_ENV=development_oidc` which may not exist in baseline images) +1. Deploy the API server with `--enable-jwt=true`, `--jwk-cert-url`, `--jwt-issuer=https://keycloak.hypershell.localhost/realms/hypershell`, `--jwt-audience=hypershell-frontend`, `--auth-bypass-paths`, and `--auth-bypass-methods` flags via Kustomize JSON patch (direct flag override avoids dependency on `API_ENV=development_oidc` which may not exist in baseline images) 2. Deploy the web console BFF with: - `OIDC_ISSUER=https://keycloak.hypershell.localhost/realms/hypershell` - `OIDC_CLIENT_ID=hypershell-frontend` @@ -298,8 +307,17 @@ The API server SHALL support JWT validation against a configurable JWKS endpoint - AND a valid JWT is obtained from the configured IdP - WHEN a request is made with `Authorization: Bearer ` - THEN the API server SHALL validate the JWT signature against the JWKS endpoint +- AND the token `iss` SHALL exactly match the configured issuer +- AND the token `aud` SHALL contain `hypershell-frontend` - AND the request SHALL be processed normally +#### Scenario: Token Issued for Another Resource Is Rejected +- GIVEN the API server is started with issuer and audience validation enabled +- AND a correctly signed token has a missing or different `iss` +- OR its `aud` does not contain `hypershell-frontend` +- WHEN the token is presented to an HTTP or gRPC management endpoint +- THEN the API server SHALL reject the request as unauthenticated + #### Scenario: gRPC Watch Streams Bypass JWT - GIVEN the API server is started with JWT enabled - WHEN the control plane connects via gRPC watch streams @@ -536,6 +554,7 @@ The `hypershell-frontend` client SHALL be configured with deployment-appropriate | `@fastify/secure-session` for cookie encryption | Sodium-based secretbox (NaCl) is the gold standard for symmetric encryption. The library is maintained by the Fastify team and integrates natively. `iron-session` is an alternative but adds an extra dependency outside the Fastify ecosystem. | | RP-initiated logout (full IdP session termination) | Clearing the cookie alone leaves the IdP session alive -- the user could re-authenticate without credentials until TTL expires. Full logout is the expected UX for an enterprise console. One extra redirect is negligible. | | Control plane authenticates with its own service account | The control plane obtains JWTs via `client_credentials` grant using a dedicated `hypershell-control-plane` Keycloak client. This is the standard pattern for service-to-service auth with the rh-trex-ai framework (the JWT interceptor validates tokens on all gRPC methods). The service account is least-privilege ready for future RBAC enforcement. | +| Shared management API resource audience | Web-console, hsctl, and control-plane tokens carry `aud=hypershell-frontend` because they call the same management API; `azp` identifies the OAuth client. Gateway-specific tokens carry only their gateway audience and cannot be replayed against the management API. | | OIDC always-on in Kind | OIDC is the only supported authentication method. Running without it masks integration issues and diverges from production. | | `hypershell-frontend` client reused for BFF | The client already exists with the correct audience mapper and role claims. Creating a separate BFF client would duplicate configuration and require additional Keycloak provisioning. PKCE secures the public client adequately for a BFF. | | Restrict `redirectUris` from wildcard | Wildcard redirect URIs are an OAuth security anti-pattern (open redirect). Restricting to the deployment's console origin prevents authorization code interception. | From 3c99f171411957c267674b4f107df9cdd2b6649d Mon Sep 17 00:00:00 2001 From: user Date: Fri, 21 Aug 2026 17:06:51 -0400 Subject: [PATCH 2/2] chore(deps): include JWT verification hardening --- components/api-server/go.mod | 2 +- components/api-server/go.sum | 4 ++-- dependency-age-allowlist.json | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/components/api-server/go.mod b/components/api-server/go.mod index b7e4816b..d917b46e 100644 --- a/components/api-server/go.mod +++ b/components/api-server/go.mod @@ -8,7 +8,7 @@ require ( github.com/golang/glog v1.2.5 github.com/gorilla/mux v1.7.3 github.com/onsi/gomega v1.27.1 - github.com/openshift-online/rh-trex-ai v0.0.32-0.20260821204222-2efb23d4a8d5 + github.com/openshift-online/rh-trex-ai v0.0.32-0.20260821210346-d5888edfb8cd github.com/prometheus/client_golang v1.16.0 github.com/segmentio/ksuid v1.0.2 github.com/spf13/pflag v1.0.5 diff --git a/components/api-server/go.sum b/components/api-server/go.sum index aec3eafe..05bbdfc1 100644 --- a/components/api-server/go.sum +++ b/components/api-server/go.sum @@ -277,8 +277,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= -github.com/openshift-online/rh-trex-ai v0.0.32-0.20260821204222-2efb23d4a8d5 h1:NGObXiVKdiumt06smV/pM1w5LIMhtxv/Okko2Qukbmw= -github.com/openshift-online/rh-trex-ai v0.0.32-0.20260821204222-2efb23d4a8d5/go.mod h1:z91AYMNi/YfIk5CuKxh9yLqNgd/80FENxgUItqj8CfQ= +github.com/openshift-online/rh-trex-ai v0.0.32-0.20260821210346-d5888edfb8cd h1:e5ezTD9Ju4qAvvpBgjvWUNYMOhf4WfRL2OJDWKEtz9c= +github.com/openshift-online/rh-trex-ai v0.0.32-0.20260821210346-d5888edfb8cd/go.mod h1:z91AYMNi/YfIk5CuKxh9yLqNgd/80FENxgUItqj8CfQ= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= diff --git a/dependency-age-allowlist.json b/dependency-age-allowlist.json index f8148157..0e174736 100644 --- a/dependency-age-allowlist.json +++ b/dependency-age-allowlist.json @@ -2,8 +2,8 @@ { "kind": "go", "name": "github.com/openshift-online/rh-trex-ai", - "version": "v0.0.32-0.20260821204222-2efb23d4a8d5", - "reason": "HyperShell requires configurable JWT issuer and audience validation from openshift-online/rh-trex-ai#52 to prevent replay of same-realm tokens issued for other resources.", + "version": "v0.0.32-0.20260821210346-d5888edfb8cd", + "reason": "HyperShell requires configurable JWT issuer and audience validation from openshift-online/rh-trex-ai#52, plus the fail-closed signed-token verification hardening from openshift-online/rh-trex-ai#53, to prevent replay of same-realm tokens issued for other resources.", "compensatingVerification": "The dependency is commit-pinned; upstream signed-token tests cover HTTP and gRPC claim validation, and HyperShell API server formatting, vet, tests, and golangci-lint run against that exact commit." }, {