mirror of
https://github.com/podman-container-tools/podman.git
synced 2026-08-09 02:15:41 +00:00
Also includes unreleased https://github.com/openshift/imagebuilder/pull/246 to work with the updated docker/docker dependency. And updates some references to newly deprecated docker/docker symbols. [NO NEW TESTS NEEDED] Signed-off-by: Miloslav Trmač <mitr@redhat.com>
124 lines
4 KiB
Go
124 lines
4 KiB
Go
package copy
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/containers/image/v5/types"
|
|
"github.com/containers/ocicrypt"
|
|
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
|
|
"golang.org/x/exp/maps"
|
|
"golang.org/x/exp/slices"
|
|
)
|
|
|
|
// isOciEncrypted returns a bool indicating if a mediatype is encrypted
|
|
// This function will be moved to be part of OCI spec when adopted.
|
|
func isOciEncrypted(mediatype string) bool {
|
|
return strings.HasSuffix(mediatype, "+encrypted")
|
|
}
|
|
|
|
// isEncrypted checks if an image is encrypted
|
|
func isEncrypted(i types.Image) bool {
|
|
layers := i.LayerInfos()
|
|
return slices.ContainsFunc(layers, func(l types.BlobInfo) bool {
|
|
return isOciEncrypted(l.MediaType)
|
|
})
|
|
}
|
|
|
|
// bpDecryptionStepData contains data that the copy pipeline needs about the decryption step.
|
|
type bpDecryptionStepData struct {
|
|
decrypting bool // We are actually decrypting the stream
|
|
}
|
|
|
|
// blobPipelineDecryptionStep updates *stream to decrypt if, it necessary.
|
|
// srcInfo is only used for error messages.
|
|
// Returns data for other steps; the caller should eventually use updateCryptoOperation.
|
|
func (c *copier) blobPipelineDecryptionStep(stream *sourceStream, srcInfo types.BlobInfo) (*bpDecryptionStepData, error) {
|
|
if isOciEncrypted(stream.info.MediaType) && c.ociDecryptConfig != nil {
|
|
desc := imgspecv1.Descriptor{
|
|
Annotations: stream.info.Annotations,
|
|
}
|
|
reader, decryptedDigest, err := ocicrypt.DecryptLayer(c.ociDecryptConfig, stream.reader, desc, false)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("decrypting layer %s: %w", srcInfo.Digest, err)
|
|
}
|
|
|
|
stream.reader = reader
|
|
stream.info.Digest = decryptedDigest
|
|
stream.info.Size = -1
|
|
maps.DeleteFunc(stream.info.Annotations, func(k string, _ string) bool {
|
|
return strings.HasPrefix(k, "org.opencontainers.image.enc")
|
|
})
|
|
return &bpDecryptionStepData{
|
|
decrypting: true,
|
|
}, nil
|
|
}
|
|
return &bpDecryptionStepData{
|
|
decrypting: false,
|
|
}, nil
|
|
}
|
|
|
|
// updateCryptoOperation sets *operation, if necessary.
|
|
func (d *bpDecryptionStepData) updateCryptoOperation(operation *types.LayerCrypto) {
|
|
if d.decrypting {
|
|
*operation = types.Decrypt
|
|
}
|
|
}
|
|
|
|
// bpdData contains data that the copy pipeline needs about the encryption step.
|
|
type bpEncryptionStepData struct {
|
|
encrypting bool // We are actually encrypting the stream
|
|
finalizer ocicrypt.EncryptLayerFinalizer
|
|
}
|
|
|
|
// blobPipelineEncryptionStep updates *stream to encrypt if, it required by toEncrypt.
|
|
// srcInfo is primarily used for error messages.
|
|
// Returns data for other steps; the caller should eventually call updateCryptoOperationAndAnnotations.
|
|
func (c *copier) blobPipelineEncryptionStep(stream *sourceStream, toEncrypt bool, srcInfo types.BlobInfo,
|
|
decryptionStep *bpDecryptionStepData) (*bpEncryptionStepData, error) {
|
|
if toEncrypt && !isOciEncrypted(srcInfo.MediaType) && c.ociEncryptConfig != nil {
|
|
var annotations map[string]string
|
|
if !decryptionStep.decrypting {
|
|
annotations = srcInfo.Annotations
|
|
}
|
|
desc := imgspecv1.Descriptor{
|
|
MediaType: srcInfo.MediaType,
|
|
Digest: srcInfo.Digest,
|
|
Size: srcInfo.Size,
|
|
Annotations: annotations,
|
|
}
|
|
reader, finalizer, err := ocicrypt.EncryptLayer(c.ociEncryptConfig, stream.reader, desc)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("encrypting blob %s: %w", srcInfo.Digest, err)
|
|
}
|
|
|
|
stream.reader = reader
|
|
stream.info.Digest = ""
|
|
stream.info.Size = -1
|
|
return &bpEncryptionStepData{
|
|
encrypting: true,
|
|
finalizer: finalizer,
|
|
}, nil
|
|
}
|
|
return &bpEncryptionStepData{
|
|
encrypting: false,
|
|
}, nil
|
|
}
|
|
|
|
// updateCryptoOperationAndAnnotations sets *operation and updates *annotations, if necessary.
|
|
func (d *bpEncryptionStepData) updateCryptoOperationAndAnnotations(operation *types.LayerCrypto, annotations *map[string]string) error {
|
|
if !d.encrypting {
|
|
return nil
|
|
}
|
|
|
|
encryptAnnotations, err := d.finalizer()
|
|
if err != nil {
|
|
return fmt.Errorf("Unable to finalize encryption: %w", err)
|
|
}
|
|
*operation = types.Encrypt
|
|
if *annotations == nil {
|
|
*annotations = map[string]string{}
|
|
}
|
|
maps.Copy(*annotations, encryptAnnotations)
|
|
return nil
|
|
}
|