Initial import of demo-secure
This commit is contained in:
commit
352d79e5fc
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
demo-secure
|
||||||
17
Dockerfile
Normal file
17
Dockerfile
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
FROM registry.access.redhat.com/ubi9/go-toolset:1.22 AS build
|
||||||
|
WORKDIR /opt/app-root/src
|
||||||
|
COPY go.mod go.sum ./
|
||||||
|
RUN go mod download
|
||||||
|
COPY . .
|
||||||
|
ARG GIT_COMMIT=unknown
|
||||||
|
ENV CGO_ENABLED=0
|
||||||
|
RUN go build -trimpath -ldflags "-s -w -X main.commit=${GIT_COMMIT}" -o /tmp/demo-secure .
|
||||||
|
|
||||||
|
FROM registry.access.redhat.com/ubi9-minimal:latest
|
||||||
|
LABEL org.opencontainers.image.title="demo-secure" \
|
||||||
|
org.opencontainers.image.description="RHADS supply-chain demo service" \
|
||||||
|
org.opencontainers.image.source="http://nas1.internal.hilltopcampground.net:23232/openshift-lab/bootstrap"
|
||||||
|
COPY --from=build /tmp/demo-secure /usr/local/bin/demo-secure
|
||||||
|
USER 1001
|
||||||
|
EXPOSE 8080
|
||||||
|
ENTRYPOINT ["/usr/local/bin/demo-secure"]
|
||||||
26
README.md
Normal file
26
README.md
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# demo-secure
|
||||||
|
|
||||||
|
Minimal Go HTTP service used by the RHADS supply-chain demo.
|
||||||
|
|
||||||
|
## The deliberate CVE
|
||||||
|
|
||||||
|
`go.mod` pins `github.com/dgrijalva/jwt-go v3.2.0+incompatible`, which has a
|
||||||
|
documented vulnerability (CVE-2020-26160 — `alg=none` not rejected). The
|
||||||
|
`/verify` handler actually calls into this library, so SBOM scanners pick the
|
||||||
|
dependency up as in-use and RHTPA flags it.
|
||||||
|
|
||||||
|
## Fixing the CVE (the "patch" act)
|
||||||
|
|
||||||
|
1. `go get github.com/golang-jwt/jwt/v5`
|
||||||
|
2. `go mod tidy`
|
||||||
|
3. Update the import in `main.go` from `github.com/dgrijalva/jwt-go` to
|
||||||
|
`github.com/golang-jwt/jwt/v5`
|
||||||
|
4. Commit and push — the Tekton pipeline rebuilds, re-signs, ArgoCD redeploys,
|
||||||
|
RHTPA dashboard flips from red to green.
|
||||||
|
|
||||||
|
## Endpoints
|
||||||
|
|
||||||
|
- `GET /` — landing page
|
||||||
|
- `GET /version` — JSON with Go version + dep list (proves which JWT lib is shipped)
|
||||||
|
- `GET /healthz` — liveness probe target
|
||||||
|
- `POST /verify` — `Authorization: Bearer <jwt>` → returns claims if valid
|
||||||
27
catalog-info.yaml
Normal file
27
catalog-info.yaml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
apiVersion: backstage.io/v1alpha1
|
||||||
|
kind: Component
|
||||||
|
metadata:
|
||||||
|
name: demo-secure
|
||||||
|
description: Minimal Go service demonstrating the RHADS supply chain (build → sign → scan → patch).
|
||||||
|
annotations:
|
||||||
|
backstage.io/kubernetes-id: demo-secure
|
||||||
|
backstage.io/kubernetes-namespace: demo-secure
|
||||||
|
backstage.io/techdocs-ref: dir:.
|
||||||
|
janus-idp.io/tekton: demo-secure
|
||||||
|
argocd/app-name: demo-secure
|
||||||
|
links:
|
||||||
|
- url: https://demo-secure-demo-secure.apps.lab.hibachi.ninja
|
||||||
|
title: Live service
|
||||||
|
spec:
|
||||||
|
type: service
|
||||||
|
lifecycle: experimental
|
||||||
|
owner: platform
|
||||||
|
system: rhads-demo
|
||||||
|
---
|
||||||
|
apiVersion: backstage.io/v1alpha1
|
||||||
|
kind: System
|
||||||
|
metadata:
|
||||||
|
name: rhads-demo
|
||||||
|
description: End-to-end RHADS supply-chain demo (RHDH + RHTAS + RHTPA).
|
||||||
|
spec:
|
||||||
|
owner: platform
|
||||||
5
go.mod
Normal file
5
go.mod
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module github.com/openshift-lab/demo-secure
|
||||||
|
|
||||||
|
go 1.22
|
||||||
|
|
||||||
|
require github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||||
2
go.sum
Normal file
2
go.sum
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
102
main.go
Normal file
102
main.go
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"runtime/debug"
|
||||||
|
|
||||||
|
jwt "github.com/dgrijalva/jwt-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
func signingKey() []byte {
|
||||||
|
if k := os.Getenv("JWT_KEY"); k != "" {
|
||||||
|
return []byte(k)
|
||||||
|
}
|
||||||
|
return []byte("demo-only-not-for-real-use")
|
||||||
|
}
|
||||||
|
|
||||||
|
type versionInfo struct {
|
||||||
|
Service string `json:"service"`
|
||||||
|
Commit string `json:"commit"`
|
||||||
|
GoVersion string `json:"go_version"`
|
||||||
|
Deps map[string]string `json:"deps"`
|
||||||
|
JWTLibrary string `json:"jwt_library"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/", index)
|
||||||
|
mux.HandleFunc("/version", version)
|
||||||
|
mux.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
fmt.Fprintln(w, "ok")
|
||||||
|
})
|
||||||
|
mux.HandleFunc("/verify", verifyToken)
|
||||||
|
|
||||||
|
port := os.Getenv("PORT")
|
||||||
|
if port == "" {
|
||||||
|
port = "8080"
|
||||||
|
}
|
||||||
|
log.Printf("demo-secure listening on :%s", port)
|
||||||
|
if err := http.ListenAndServe(":"+port, mux); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func index(w http.ResponseWriter, _ *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
|
fmt.Fprintf(w, `<!doctype html>
|
||||||
|
<html><head><title>demo-secure</title></head>
|
||||||
|
<body style="font-family:sans-serif;max-width:40em;margin:3em auto">
|
||||||
|
<h1>demo-secure</h1>
|
||||||
|
<p>A minimal Go service used to demonstrate the RHADS supply chain:
|
||||||
|
RHDH onboarding → RHTAS signing → RHTPA scanning → patch.</p>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/version">/version</a> — dependency info</li>
|
||||||
|
<li><a href="/healthz">/healthz</a> — liveness</li>
|
||||||
|
<li><code>POST /verify</code> with a Bearer token — exercises the JWT library</li>
|
||||||
|
</ul>
|
||||||
|
</body></html>`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func version(w http.ResponseWriter, _ *http.Request) {
|
||||||
|
info := versionInfo{
|
||||||
|
Service: "demo-secure",
|
||||||
|
Commit: os.Getenv("GIT_COMMIT"),
|
||||||
|
Deps: map[string]string{},
|
||||||
|
}
|
||||||
|
if bi, ok := debug.ReadBuildInfo(); ok {
|
||||||
|
info.GoVersion = bi.GoVersion
|
||||||
|
for _, d := range bi.Deps {
|
||||||
|
info.Deps[d.Path] = d.Version
|
||||||
|
if d.Path == "github.com/dgrijalva/jwt-go" || d.Path == "github.com/golang-jwt/jwt/v5" {
|
||||||
|
info.JWTLibrary = fmt.Sprintf("%s@%s", d.Path, d.Version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
_ = json.NewEncoder(w).Encode(info)
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyToken(w http.ResponseWriter, r *http.Request) {
|
||||||
|
tok := r.Header.Get("Authorization")
|
||||||
|
if len(tok) > 7 && tok[:7] == "Bearer " {
|
||||||
|
tok = tok[7:]
|
||||||
|
}
|
||||||
|
if tok == "" {
|
||||||
|
http.Error(w, "missing bearer token", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
parsed, err := jwt.Parse(tok, func(t *jwt.Token) (interface{}, error) {
|
||||||
|
return signingKey(), nil
|
||||||
|
})
|
||||||
|
if err != nil || !parsed.Valid {
|
||||||
|
http.Error(w, "invalid token", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
_ = json.NewEncoder(w).Encode(parsed.Claims)
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user