debian-forge-composer/internal/weldr/upload.go
Tom Gundersen a2f8a06e79 weldr/upload: don't expose AWS/Azure acconut details
Change the translation from our internal structs to the structs used for
weldr serialization to drop account details. These must obviously be
passed in to configure an upload, but exposing them in the logs may be
surprising.

There is no notion of user accounts in the weldr API, and the state
should not be considered private. However, this is likely to take people
by surprise, so let us guard the secrets entrusted to us.

Fixes #907.

Signed-off-by: Tom Gundersen <teg@jklm.no>
2020-08-18 08:55:57 +02:00

167 lines
4.6 KiB
Go

package weldr
import (
"encoding/json"
"errors"
"time"
"github.com/osbuild/osbuild-composer/internal/common"
"github.com/osbuild/osbuild-composer/internal/distro"
"github.com/google/uuid"
"github.com/osbuild/osbuild-composer/internal/target"
)
type uploadResponse struct {
UUID uuid.UUID `json:"uuid"`
Status common.ImageBuildState `json:"status"`
ProviderName string `json:"provider_name"`
ImageName string `json:"image_name"`
CreationTime float64 `json:"creation_time"`
Settings uploadSettings `json:"settings"`
}
type uploadSettings interface {
isUploadSettings()
}
type awsUploadSettings struct {
Region string `json:"region"`
AccessKeyID string `json:"accessKeyID,omitempty"`
SecretAccessKey string `json:"secretAccessKey,omitempty"`
Bucket string `json:"bucket"`
Key string `json:"key"`
}
func (awsUploadSettings) isUploadSettings() {}
type azureUploadSettings struct {
StorageAccount string `json:"storageAccount,omitempty"`
StorageAccessKey string `json:"storageAccessKey,omitempty"`
Container string `json:"container"`
}
func (azureUploadSettings) isUploadSettings() {}
type uploadRequest struct {
Provider string `json:"provider"`
ImageName string `json:"image_name"`
Settings uploadSettings `json:"settings"`
}
type rawUploadRequest struct {
Provider string `json:"provider"`
ImageName string `json:"image_name"`
Settings json.RawMessage `json:"settings"`
}
func (u *uploadRequest) UnmarshalJSON(data []byte) error {
var rawUploadRequest rawUploadRequest
err := json.Unmarshal(data, &rawUploadRequest)
if err != nil {
return err
}
var settings uploadSettings
switch rawUploadRequest.Provider {
case "azure":
settings = new(azureUploadSettings)
case "aws":
settings = new(awsUploadSettings)
default:
return errors.New("unexpected provider name")
}
err = json.Unmarshal(rawUploadRequest.Settings, settings)
if err != nil {
return err
}
u.Provider = rawUploadRequest.Provider
u.ImageName = rawUploadRequest.ImageName
u.Settings = settings
return err
}
// Converts a `Target` to a serializable `uploadResponse`.
//
// This ignore the status in `targets`, because that's never set correctly.
// Instead, it sets each target's status to the ImageBuildState equivalent of
// `state`.
//
// This also ignores any sensitive data passed into targets. Access keys may
// be passed as input to composer, but should not be possible to be queried.
func targetsToUploadResponses(targets []*target.Target, state common.ComposeState) []uploadResponse {
var uploads []uploadResponse
for _, t := range targets {
upload := uploadResponse{
UUID: t.Uuid,
ImageName: t.ImageName,
CreationTime: float64(t.Created.UnixNano()) / 1000000000,
}
switch state {
case common.CWaiting:
upload.Status = common.IBWaiting
case common.CRunning:
upload.Status = common.IBRunning
case common.CFinished:
upload.Status = common.IBFinished
case common.CFailed:
upload.Status = common.IBFailed
}
switch options := t.Options.(type) {
case *target.AWSTargetOptions:
upload.ProviderName = "aws"
upload.Settings = &awsUploadSettings{
Region: options.Region,
Bucket: options.Bucket,
Key: options.Key,
// AccessKeyID and SecretAccessKey are intentionally not included.
}
uploads = append(uploads, upload)
case *target.AzureTargetOptions:
upload.ProviderName = "azure"
upload.Settings = &azureUploadSettings{
Container: options.Container,
// StorageAccount and StorageAccessKey are intentionally not included.
}
uploads = append(uploads, upload)
}
}
return uploads
}
func uploadRequestToTarget(u uploadRequest, imageType distro.ImageType) *target.Target {
var t target.Target
t.Uuid = uuid.New()
t.ImageName = u.ImageName
t.Status = common.IBWaiting
t.Created = time.Now()
switch options := u.Settings.(type) {
case *awsUploadSettings:
t.Name = "org.osbuild.aws"
t.Options = &target.AWSTargetOptions{
Filename: imageType.Filename(),
Region: options.Region,
AccessKeyID: options.AccessKeyID,
SecretAccessKey: options.SecretAccessKey,
Bucket: options.Bucket,
Key: options.Key,
}
case *azureUploadSettings:
t.Name = "org.osbuild.azure"
t.Options = &target.AzureTargetOptions{
Filename: imageType.Filename(),
StorageAccount: options.StorageAccount,
StorageAccessKey: options.StorageAccessKey,
Container: options.Container,
}
}
return &t
}