Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal to add Encrypted Layer Mediatype #775

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions annotations.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ This specification defines the following annotation keys, intended for but not l
* This SHOULD be the immediate image sharing zero-indexed layers with the image, such as from a Dockerfile `FROM` statement.
* This SHOULD NOT reference any other images used to generate the contents of the image (e.g., multi-stage Dockerfile builds).
* If the `image.base.name` annotation is specified, the `image.base.digest` annotation SHOULD be the digest of the manifest referenced by the `image.ref.name` annotation.
* **org.opencontainers.image.org.opencontainers.image.enc.keys.pkcs7** Base64 comma separated [PKCS7(RFC2315)](https://tools.ietf.org/html/rfc2315) encrypted messages that contain wrapped PrivateLayerBlockCipherOptions JSON objects for [encryption](layer.md#layer-encryption)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* **org.opencontainers.image.org.opencontainers.image.enc.keys.pkcs7** Base64 comma separated [PKCS7(RFC2315)](https://tools.ietf.org/html/rfc2315) encrypted messages that contain wrapped PrivateLayerBlockCipherOptions JSON objects for [encryption](layer.md#layer-encryption)
* **org.opencontainers.image.enc.keys.pkcs7** Base64 comma separated [PKCS7(RFC2315)](https://tools.ietf.org/html/rfc2315) encrypted messages that contain wrapped PrivateLayerBlockCipherOptions JSON objects for [encryption](layer.md#layer-encryption)

* **org.opencontainers.image.enc.keys.jwe** Base64 comma separated [JWE(RFC7516)](https://tools.ietf.org/html/rfc7516) encrypted messages that contain wrapped PrivateLayerBlockCipherOptions JSON objects for [encryption](layer.md#layer-encryption)
* **org.opencontainers.image.enc.keys.openpgp** Base64 comma separated [OpenPGP(RFC4880)](https://tools.ietf.org/html/rfc4880) encrypted messages that contain wrapped PrivateLayerBlockCipherOptions JSON objects for [encryption](layer.md#layer-encryption)
* **org.opencontainers.image.enc.pubopts** Base64 encoded PublicLayerBlockCipherOptions JSON object for [encryption](layer.md#layer-encryption)

## Back-compatibility with Label Schema

Expand Down
99 changes: 98 additions & 1 deletion layer.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This document describes how to serialize a filesystem and filesystem changes lik
One or more layers are applied on top of each other to create a complete filesystem.
This document will use a concrete example to illustrate how to create and consume these filesystem layers.

This section defines the `application/vnd.oci.image.layer.v1.tar`, `application/vnd.oci.image.layer.v1.tar+gzip`, `application/vnd.oci.image.layer.v1.tar+zstd`, `application/vnd.oci.image.layer.nondistributable.v1.tar`, `application/vnd.oci.image.layer.nondistributable.v1.tar+gzip`, and `application/vnd.oci.image.layer.nondistributable.v1.tar+zstd` [media types](media-types.md).
This section defines the `application/vnd.oci.image.layer.v1.tar`, `application/vnd.oci.image.layer.v1.tar+gzip`, `application/vnd.oci.image.layer.v1.tar+zstd`, `application/vnd.oci.image.layer.nondistributable.v1.tar`, `application/vnd.oci.image.layer.nondistributable.v1.tar+gzip`, `application/vnd.oci.image.layer.nondistributable.v1.tar+zstd`, `application/vnd.oci.image.layer.v1.tar+encrypted`, `application/vnd.oci.image.layer.v1.tar+gzip+encrypted`, `application/vnd.oci.image.layer.nondistributable.v1.tar+encrypted` and `application/vnd.oci.image.layer.nondistributable.v1.tar+gzip+encrypted` [media types](media-types.md).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May I ask a question why tar+ encrypted + zstd or tar + zstd + encrypted is not supported? Thanks.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

at the time, there wasn't +zstd yet, but yes it should support. +encrypted should be treated as a suffix and thus should be handled on all mediatypes that end with +encrypted


## `+gzip` Media Types

Expand All @@ -16,6 +16,13 @@ This section defines the `application/vnd.oci.image.layer.v1.tar`, `application/
* The media type `application/vnd.oci.image.layer.v1.tar+zstd` represents an `application/vnd.oci.image.layer.v1.tar` payload which has been compressed with [zstd][rfc8478].
* The media type `application/vnd.oci.image.layer.nondistributable.v1.tar+zstd` represents an `application/vnd.oci.image.layer.nondistributable.v1.tar` payload which has been compressed with [zstd][rfc8478].

## `+encrypted` Media Types

* The media type `application/vnd.oci.image.layer.v1.tar+encrypted` represents an `application/vnd.oci.image.layer.v1.tar` payload which has been [encrypted](#layer-encryption).
* The media type `application/vnd.oci.image.layer.v1.tar+gzip+encrypted` represents an `application/vnd.oci.image.layer.v1.tar+gzip` payload which has been [encrypted](#layer-encryption).
* The media type `application/vnd.oci.image.layer.nondistributable.v1.tar+encrypted` represents an `application/vnd.oci.image.layer.nondistributable.v1.tar` payload which has been [encrypted](#layer-encryption).
* The media type `application/vnd.oci.image.layer.nondistributable.v1.tar+gzip+encrypted` represents an `application/vnd.oci.image.layer.nondistributable.v1.tar+gzip` payload which has been [encrypted](#layer-encryption).

## Distributable Format

* Layer Changesets for the [media type](media-types.md) `application/vnd.oci.image.layer.v1.tar` MUST be packaged in [tar archive][tar-archive].
Expand Down Expand Up @@ -332,6 +339,96 @@ Implementations SHOULD NOT upload layers tagged with this media type; however, s

[Descriptors](descriptor.md) referencing non-distributable layers MAY include `urls` for downloading these layers directly; however, the presence of the `urls` field SHOULD NOT be used to determine whether or not a layer is non-distributable.


# Layer Encryption

To be able to protect the confidentiality of the data in layers, encryption of the layer data blobs can be done to prevent unauthorized access to layer data. Encryption is performed on the data blob of a layer by specifying a mediatype with the `+encrypted` suffix. For example, `application/vnd.oci.image.layer.v1.tar+encrypted` is an layer representation of an encrypted `application/vnd.oci.image.layer.v1.tar` layer.

When using the `+encrypted` mediatype, the layer data blobs are encrypted. In order to decrypt an image, the encryption metadata is required.

## Encryption Metadata

The encryption metadata consists of 2 parts: PublicLayerBlockCipherOptions and PrivateLayerBlockCipherOptions. The PublicLayerBlockCipherOptions contain encryption metadata that is public, i.e. cipher type, HMAC, etc. and PrivateLayerBlockCipherOptions contains the encryption metadata which should be confidential, i.e. symmetric key, nonce (optional), etc. These are stored in the respective [**org.opencontainers.image.enc** prefixed annotations](annotations.md).

Below are golang definitions of these JSON objects:

```go
// LayerCipherType is the ciphertype as specified in the layer metadata
type LayerCipherType string

// PublicLayerBlockCipherOptions includes the information required to encrypt/decrypt
// an image which are public and can be deduplicated in plaintext across multiple
// recipients
type PublicLayerBlockCipherOptions struct {
// CipherType denotes the cipher type according to the list of OCI suppported
// cipher types.
CipherType LayerCipherType `json:"cipher"`

// Hmac contains the hmac string to help verify encryption
Hmac []byte `json:"hmac"`

// CipherOptions contains the cipher metadata used for encryption/decryption
// This field should be populated by Encrypt/Decrypt calls
CipherOptions map[string][]byte `json:"cipheroptions"`
}

// PrivateLayerBlockCipherOptions includes the information required to encrypt/decrypt
// an image which are sensitive and should not be in plaintext
type PrivateLayerBlockCipherOptions struct {
// SymmetricKey represents the symmetric key used for encryption/decryption
// This field should be populated by Encrypt/Decrypt calls
SymmetricKey []byte `json:"symkey"`

// Digest is the digest of the original data for verification.
// This is NOT populated by Encrypt/Decrypt calls
Digest digest.Digest `json:"digest"`

// CipherOptions contains the cipher metadata used for encryption/decryption
// This field should be populated by Encrypt/Decrypt calls
CipherOptions map[string][]byte `json:"cipheroptions"`
}
```

Details of the algorithms and protocols used in the encryption of the data blob are defined in these JSON objects. Here are some examples of the Public/Private LayerBlockCipherOptions.
- The `cipher` field specifies the encryption algorithm to use according to the [list of cipher types supported](#cipher-types).
- The `symkey` field specifies the base64 encoded bytes of the symmetric key used in decryption.
- The `cipherOptions` field specifies additional parameters used in the decryption process of the specified algorithm. This should be in accordance with the RFC standard of the algorithm used.
```
PublicLayerBlockCipherOption
{
"cipher": "AES_256_CTR_HMAC_SHA256",
"hmac": "M0M5OTA5QUZFQzI1MzU0RDU1MURBRTIxNTkwQkIyNkUzOEQ1M0YyMTczQjhEM0RDM0VFRTRDMDQ3RTdBQjFDMQ=="
"cipheroptions": {}
}

PrivateLayerBlockCipherOption
{
"symkey": "54kiln1USEaKnlYhKdz+aA==",
"cipheroptions": {
"nonce": "AdcRPTAEhXx6uwuYcOquNA==",
...
}
}

```

The PublicLayerBlockCipherOptions JSON object is stored base64 encoded in the layer annotation **org.opencontainers.image.enc.pubopts**.

The PrivateLayerBlockCipherOptions JSON object is not stored in plaintext due to the sensitive nature of the contents. Instead, the object goes through a cryptographic wrapping process. This ensures that only authorized parties are able to decrypt the layers, the decryption metadata objects are wrapped as encrypted messages to the authorized recipients in accordance with encrypted message standards such as [OpenPGP(RFC4880)](https://tools.ietf.org/html/rfc4880), [PKCS7(RFC2315)](https://tools.ietf.org/html/rfc2315), [JWE(RFC7516)](https://tools.ietf.org/html/rfc7516).

The following annotations are used to communicate these encrypted messages:
- `org.opencontainers.image.enc.keys.pkcs7` - An array of base64 comma separated encrypted messages that contain PrivateLayerBlockCipherOptions to perform decryption of the layer data in accordance with [PKCS7(RFC2315)](https://tools.ietf.org/html/rfc2315)
- `org.opencontainers.image.enc.keys.jwe` - An array of base64 comma separated encrypted messages that contain PrivateLayerBlockCipherOptions to perform decryption of the layer data in accordance with [JWE(RFC7516)](https://tools.ietf.org/html/rfc7516)
- `org.opencontainers.image.enc.keys.openpgp` - An array of base64 comma separated encrypted messages that contain PrivateLayerBlockCipherOptions to perform decryption of the layer data in accordance with [OpenPGP(RFC4880)](https://tools.ietf.org/html/rfc4880)
- `org.opencontainers.image.enc.keys.*` - An array of base64 comma separated encrypted messages that contain PrivateLayerBlockCipherOptions to perform decryption of the layer data in accordance with an appropriate standard of specified protocol.

The decryption of the image can be performed by unwrapping the PrivateLayerBlockCipherOptions using the `org.opencontainers.image.enc.keys.*` annotations and using the appropriate cipher with the unwrapped PrivateLayerBlockCipherOptions to decrypt the layer data blob.

### Cipher Types

The current list of cipher types supported are:
- `AES_256_CTR_HMAC_SHA256` - Encryption with `AES_256_CTR` algorithm [FIPS-197](https://csrc.nist.gov/csrc/media/publications/fips/197/final/documents/fips-197.pdf) with Encrypt-then-mac [RFC7366](https://tools.ietf.org/html/rfc7366). The protocols used in this cipher type is in accordance to FIPS 140-2 compliant standards.

[libarchive-tar]: https://github.com/libarchive/libarchive/wiki/ManPageTar5#POSIX_ustar_Archives
[gnu-tar-standard]: http://www.gnu.org/software/tar/manual/html_node/Standard.html
[rfc1952_2]: https://tools.ietf.org/html/rfc1952
Expand Down
4 changes: 4 additions & 0 deletions media-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ The following media types identify the formats described here and their referenc
- `application/vnd.oci.image.layer.nondistributable.v1.tar`: ["Layer", as a tar archive with distribution restrictions](layer.md#non-distributable-layers)
- `application/vnd.oci.image.layer.nondistributable.v1.tar+gzip`: ["Layer", as a tar archive with distribution restrictions](layer.md#gzip-media-types) compressed with [gzip][rfc1952]
- `application/vnd.oci.image.layer.nondistributable.v1.tar+zstd`: ["Layer", as a tar archive with distribution restrictions](layer.md#zstd-media-types) compressed with [zstd][rfc8478]
- `application/vnd.oci.image.layer.v1.tar+encrypted` : ["Layer", as an encrypted tar archive](layer.md#enc-media-types)
- `application/vnd.oci.image.layer.v1.tar+gzip+encrypted` : ["Layer", as an encrypted gzipped tar archive](layer.md#enc-media-types)
- `application/vnd.oci.image.layer.nondistributable.v1.tar+encrypted` : ["Layer", as an encrypted tar archive with distribution restrictions](layer.md#enc-media-types)
- `application/vnd.oci.image.layer.nondistributable.v1.tar+gzip+encrypted` : ["Layer", as an encrypted gzipped tar archive with distribution restrictions](layer.md#enc-media-types)

## Media Type Conflicts

Expand Down
12 changes: 12 additions & 0 deletions specs-go/v1/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,16 @@ const (

// AnnotationBaseImageName is the annotation key for the image reference of the image's base image.
AnnotationBaseImageName = "org.opencontainers.image.base.name"

// AnnotationEncryptionKeysPkcs7 is the annotation key for the base64 encoded encrypted
// messages containing metadata for decrypting encrypted data blobs.
AnnotationEncryptionKeysPkcs7 = "org.opencontainers.image.enc.keys.pkcs7"

// AnnotationEncryptionKeysJwe is the annotation key for the base64 encoded encrypted
// messages containing metadata for decrypting encrypted data blobs.
AnnotationEncryptionKeysJwe = "org.opencontainers.image.enc.keys.jwe"

// AnnotationEncryptionKeysOpenPgp is the annotation key for the base64 encoded encrypted
// messages containing metadata for decrypting encrypted data blobs.
AnnotationEncryptionKeysOpenPgp = "org.opencontainers.image.enc.keys.openpgp"
)
23 changes: 23 additions & 0 deletions specs-go/v1/encryption.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2016 The Linux Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package v1

// LayerBlockCipherOptions includes the information required to encrypt/decrypt
// layer blob data.
type LayerBlockCipherOptions struct {
CipherType string `json:'cipher'`
SymmetricKey []byte `json:'symkey'`
CipherOptions map[string][]byte `json:'cipheroptions'`
}
17 changes: 17 additions & 0 deletions specs-go/v1/mediatype.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ const (
// MediaTypeImageLayer is the media type used for layers referenced by the manifest.
MediaTypeImageLayer = "application/vnd.oci.image.layer.v1.tar"

// MediaTypeImageLayerEnc is the media type used for encrypted layers
// referenced by the manifest.
MediaTypeImageLayerEnc = "application/vnd.oci.image.layer.v1.tar+encrypted"

// MediaTypeImageLayerGzip is the media type used for gzipped layers
// referenced by the manifest.
MediaTypeImageLayerGzip = "application/vnd.oci.image.layer.v1.tar+gzip"
Expand All @@ -38,6 +42,10 @@ const (
// layers referenced by the manifest.
MediaTypeImageLayerZstd = "application/vnd.oci.image.layer.v1.tar+zstd"

// MediaTypeImageLayerGzipEnc is the media type used for encrypted
// gzipped layers referenced by the manifest.
MediaTypeImageLayerGzipEnc = "application/vnd.oci.image.layer.v1.tar+gzip+encrypted"

// MediaTypeImageLayerNonDistributable is the media type for layers referenced by
// the manifest but with distribution restrictions.
MediaTypeImageLayerNonDistributable = "application/vnd.oci.image.layer.nondistributable.v1.tar"
Expand All @@ -52,6 +60,15 @@ const (
// restrictions.
MediaTypeImageLayerNonDistributableZstd = "application/vnd.oci.image.layer.nondistributable.v1.tar+zstd"

// MediaTypeImageLayerNonDistributableEnc is the media type for encrypted
// layers referenced by the manifest but with distribution restrictions.
MediaTypeImageLayerNonDistributableEnc = "application/vnd.oci.image.layer.nondistributable.v1.tar+encrypted"

// MediaTypeImageLayerNonDistributableGzipEnc is the media type for
// gzipped and encrypted layers referenced by the manifest but with
// distribution restrictions.
MediaTypeImageLayerNonDistributableGzipEnc = "application/vnd.oci.image.layer.nondistributable.v1.tar+gzip+encrypted"

// MediaTypeImageConfig specifies the media type for the image configuration.
MediaTypeImageConfig = "application/vnd.oci.image.config.v1+json"
)