This repository has been archived by the owner on Dec 9, 2022. It is now read-only.
forked from simon3z/image-inspector
-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #39 from enoodle/image-server
factor out image serving
- Loading branch information
Showing
8 changed files
with
257 additions
and
141 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package api | ||
|
||
import ( | ||
docker "github.com/fsouza/go-dockerclient" | ||
"time" | ||
) | ||
|
||
// OpenSCAPStatus is the status of openscap scan | ||
type OpenSCAPStatus string | ||
|
||
const ( | ||
StatusNotRequested OpenSCAPStatus = "NotRequested" | ||
StatusSuccess OpenSCAPStatus = "Success" | ||
StatusError OpenSCAPStatus = "Error" | ||
) | ||
|
||
type OpenSCAPMetadata struct { | ||
Status OpenSCAPStatus // Status of the OpenSCAP scan report | ||
ErrorMessage string // Error message from the openscap | ||
ContentTimeStamp string // Timestamp for this data | ||
} | ||
|
||
func (osm *OpenSCAPMetadata) SetError(err error) { | ||
osm.Status = StatusError | ||
osm.ErrorMessage = err.Error() | ||
osm.ContentTimeStamp = string(time.Now().Format(time.RFC850)) | ||
} | ||
|
||
var ( | ||
ScanOptions = []string{"openscap"} | ||
) | ||
|
||
// InspectorMetadata is the metadata type with information about image-inspector's operation | ||
type InspectorMetadata struct { | ||
docker.Image // Metadata about the inspected image | ||
// OpenSCAP describes the state of the OpenSCAP scan | ||
OpenSCAP *OpenSCAPMetadata | ||
} | ||
|
||
// APIVersions holds a slice of supported API versions. | ||
type APIVersions struct { | ||
// Versions is the supported API versions | ||
Versions []string `json:"versions"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package imageserver | ||
|
||
import ( | ||
iiapi "github.com/openshift/image-inspector/pkg/api" | ||
) | ||
|
||
// ImageServer abstracts the serving of image information. | ||
type ImageServer interface { | ||
// ServeImage Serves the image | ||
ServeImage(meta *iiapi.InspectorMetadata, | ||
scanReport []byte, | ||
htmlScanReport []byte) error | ||
} | ||
|
||
// ImageServerOptions is used to configure an image server. | ||
type ImageServerOptions struct { | ||
// ServePath is the root path/port of serving. ex 0.0.0.0:8080 | ||
ServePath string | ||
// HealthzURL is the relative url of the health check. ex /healthz | ||
HealthzURL string | ||
// APIURL is the relative url where the api will be served. ex /api | ||
APIURL string | ||
// APIVersions are the supported API versions. | ||
APIVersions iiapi.APIVersions | ||
// MetadataURL is the relative url of the metadata content. ex /api/v1/metadata | ||
MetadataURL string | ||
// ContentURL is the relative url of the content. ex /api/v1/content/ | ||
ContentURL string | ||
// ImageServeURL is the location that the image is being served from. | ||
// NOTE: if the image server supports a chroot the server implementation will perform | ||
// the chroot based on this URL. | ||
ImageServeURL string | ||
// ScanType is the type of the scan that was done on the inspected image | ||
ScanType string | ||
// ScanReportURL is the url to publish the scan report | ||
ScanReportURL string | ||
// HTMLScanReport wether or not to publish an HTML scan report | ||
HTMLScanReport bool | ||
// HTMLScanReportURL url for the scan html report | ||
HTMLScanReportURL string | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package imageserver | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"log" | ||
"net/http" | ||
"syscall" | ||
|
||
"golang.org/x/net/webdav" | ||
|
||
iiapi "github.com/openshift/image-inspector/pkg/api" | ||
) | ||
|
||
const ( | ||
// CHROOT_SERVE_PATH is the path to server if we are performing a chroot | ||
// this probably does not belong here. | ||
CHROOT_SERVE_PATH = "/" | ||
) | ||
|
||
// webdavImageServer implements ImageServer. | ||
type webdavImageServer struct { | ||
opts ImageServerOptions | ||
chroot bool | ||
} | ||
|
||
// ensures this always implements the interface or fail compilation. | ||
var _ ImageServer = &webdavImageServer{} | ||
|
||
// NewWebdavImageServer creates a new webdav image server. | ||
func NewWebdavImageServer(opts ImageServerOptions, chroot bool) ImageServer { | ||
return &webdavImageServer{ | ||
opts: opts, | ||
chroot: chroot, | ||
} | ||
} | ||
|
||
// ServeImage Serves the image. | ||
func (s *webdavImageServer) ServeImage(meta *iiapi.InspectorMetadata, | ||
scanReport []byte, | ||
htmlScanReport []byte) error { | ||
|
||
servePath := s.opts.ImageServeURL | ||
if s.chroot { | ||
if err := syscall.Chroot(s.opts.ImageServeURL); err != nil { | ||
return fmt.Errorf("Unable to chroot into %s: %v\n", s.opts.ImageServeURL, err) | ||
} | ||
servePath = CHROOT_SERVE_PATH | ||
} else { | ||
log.Printf("!!!WARNING!!! It is insecure to serve the image content without changing") | ||
log.Printf("root (--chroot). Absolute-path symlinks in the image can lead to disclose") | ||
log.Printf("information of the hosting system.") | ||
} | ||
|
||
log.Printf("Serving image content %s on webdav://%s%s", s.opts.ImageServeURL, s.opts.ServePath, s.opts.ContentURL) | ||
|
||
http.HandleFunc(s.opts.HealthzURL, func(w http.ResponseWriter, r *http.Request) { | ||
w.Write([]byte("ok\n")) | ||
}) | ||
|
||
http.HandleFunc(s.opts.APIURL, func(w http.ResponseWriter, r *http.Request) { | ||
body, err := json.MarshalIndent(s.opts.APIVersions, "", " ") | ||
if err != nil { | ||
http.Error(w, err.Error(), http.StatusInternalServerError) | ||
return | ||
} | ||
w.Write(body) | ||
}) | ||
|
||
http.HandleFunc(s.opts.MetadataURL, func(w http.ResponseWriter, r *http.Request) { | ||
body, err := json.MarshalIndent(meta, "", " ") | ||
if err != nil { | ||
http.Error(w, err.Error(), http.StatusInternalServerError) | ||
return | ||
} | ||
w.Write(body) | ||
}) | ||
|
||
http.HandleFunc(s.opts.ScanReportURL, func(w http.ResponseWriter, r *http.Request) { | ||
if s.opts.ScanType != "" && meta.OpenSCAP.Status == iiapi.StatusSuccess { | ||
w.Write(scanReport) | ||
} else { | ||
if meta.OpenSCAP.Status == iiapi.StatusError { | ||
http.Error(w, fmt.Sprintf("OpenSCAP Error: %s", meta.OpenSCAP.ErrorMessage), | ||
http.StatusInternalServerError) | ||
} else { | ||
http.Error(w, "OpenSCAP option was not chosen", http.StatusNotFound) | ||
} | ||
} | ||
}) | ||
|
||
http.HandleFunc(s.opts.HTMLScanReportURL, func(w http.ResponseWriter, r *http.Request) { | ||
if s.opts.ScanType != "" && meta.OpenSCAP.Status == iiapi.StatusSuccess && s.opts.HTMLScanReport { | ||
w.Write(htmlScanReport) | ||
} else { | ||
if meta.OpenSCAP.Status == iiapi.StatusError { | ||
http.Error(w, fmt.Sprintf("OpenSCAP Error: %s", meta.OpenSCAP.ErrorMessage), | ||
http.StatusInternalServerError) | ||
} else { | ||
http.Error(w, "OpenSCAP option was not chosen", http.StatusNotFound) | ||
} | ||
} | ||
}) | ||
|
||
http.Handle(s.opts.ContentURL, &webdav.Handler{ | ||
Prefix: s.opts.ContentURL, | ||
FileSystem: webdav.Dir(servePath), | ||
LockSystem: webdav.NewMemLS(), | ||
}) | ||
|
||
return http.ListenAndServe(s.opts.ServePath, nil) | ||
} |
Oops, something went wrong.