Skip to content

Commit b7d188e

Browse files
authored
Add support for Keppel image reagistry (#134)
ref https://github.com/sapcc/keppel
1 parent 99e0d98 commit b7d188e

File tree

2 files changed

+34
-2
lines changed

2 files changed

+34
-2
lines changed

Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
3030
# Use distroless as minimal base image to package the manager binary
3131
# Refer to https://github.com/GoogleContainerTools/distroless for more details
3232
FROM gcr.io/distroless/static:nonroot
33+
LABEL source_repository="https://github.com/ironcore-dev/boot-operator"
3334
WORKDIR /
3435
COPY --from=builder /workspace/manager .
3536
COPY --from=builder /workspace/templates/ templates/

server/imageproxyserver.go

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818

1919
const (
2020
ghcrIOKey = "ghcr.io/"
21+
keppelKey = "keppel.global.cloud.sap/"
2122
imageKey = "imageName"
2223
layerDigestKey = "layerDigest"
2324
versionKey = "version"
@@ -45,6 +46,8 @@ func RunImageProxyServer(imageProxyServerAddr string, k8sClient client.Client, l
4546

4647
if strings.HasPrefix(imageDetails.OCIImageName, ghcrIOKey) {
4748
handleGHCR(w, r, &imageDetails, log)
49+
} else if strings.HasPrefix(imageDetails.OCIImageName, keppelKey) {
50+
handleKeppel(w, r, &imageDetails, log)
4851
} else {
4952
http.Error(w, "Bad Request", http.StatusBadRequest)
5053
log.Info("Unsupported registry")
@@ -84,6 +87,24 @@ func handleGHCR(w http.ResponseWriter, r *http.Request, imageDetails *ImageDetai
8487
proxy.ServeHTTP(w, r)
8588
}
8689

90+
func handleKeppel(w http.ResponseWriter, r *http.Request, imageDetails *ImageDetails, log logr.Logger) {
91+
log.Info("Processing Image Proxy request for Keppel", "method", r.Method, "path", r.URL.Path, "clientIP", r.RemoteAddr)
92+
93+
digest := imageDetails.LayerDigest
94+
targetURL := fmt.Sprintf("https://%sv2/%s/blobs/%s", keppelKey, imageDetails.RepositoryName, digest)
95+
proxyURL, _ := url.Parse(targetURL)
96+
97+
proxy := &httputil.ReverseProxy{
98+
Director: imageDetails.modifyDirector(proxyURL, "", digest),
99+
}
100+
101+
r.URL.Host = proxyURL.Host
102+
r.URL.Scheme = proxyURL.Scheme
103+
r.Host = proxyURL.Host
104+
105+
proxy.ServeHTTP(w, r)
106+
}
107+
87108
func (imageDetails ImageDetails) getBearerToken() (string, error) {
88109
url := fmt.Sprintf("https://ghcr.io/token?scope=repository:%s:pull", imageDetails.RepositoryName)
89110
resp, err := http.Get(url)
@@ -157,12 +178,20 @@ func parseImageURL(queries url.Values) (imageDetails ImageDetails, err error) {
157178
ociImageName := queries.Get(imageKey)
158179
layerDigest := queries.Get(layerDigestKey)
159180
version := queries.Get(versionKey)
160-
repositoryName := strings.TrimPrefix(ociImageName, ghcrIOKey)
161181

162182
if ociImageName == "" || layerDigest == "" || version == "" {
163183
return ImageDetails{}, fmt.Errorf("missing required query parameters 'image' or 'layer' or 'version'")
164184
}
165185

186+
var repositoryName string
187+
if strings.HasPrefix(ociImageName, ghcrIOKey) {
188+
repositoryName = strings.TrimPrefix(ociImageName, ghcrIOKey)
189+
} else if strings.HasPrefix(ociImageName, keppelKey) {
190+
repositoryName = strings.TrimPrefix(ociImageName, keppelKey)
191+
} else {
192+
return ImageDetails{}, fmt.Errorf("unsupported registry key")
193+
}
194+
166195
return ImageDetails{
167196
OCIImageName: ociImageName,
168197
RepositoryName: repositoryName,
@@ -176,6 +205,8 @@ func (ImageDetails ImageDetails) modifyDirector(proxyURL *url.URL, bearerToken s
176205
req.URL.Scheme = proxyURL.Scheme
177206
req.URL.Host = proxyURL.Host
178207
req.URL.Path = fmt.Sprintf("/v2/%s/blobs/%s", ImageDetails.RepositoryName, digest)
179-
req.Header.Set("Authorization", "Bearer "+bearerToken)
208+
if bearerToken != "" {
209+
req.Header.Set("Authorization", "Bearer "+bearerToken)
210+
}
180211
}
181212
}

0 commit comments

Comments
 (0)