Sealpack - sealed packaging for files and containers
This project allows the secure bundling of mobile code.
Files and container images can be packed like with any compression tool, but with a focus on the
CIA triad.
In addition, it was designed for flexibility and extensibility, so it can be used in various contexts.
The approach consists of
The resulting file can then be safely transmitted over insecure channels.
Since v1.4.0, Sealpack can also be used as a [go module]
Basic CLI operation
In a very basic way, sealpack
is a single-command CLI with the 3 actions seal
, inspect
, and unseal
The seal
action
- Creates a compressed archive from files and/or container images
- Cryptographically signs the contents
- Encrypts the archive with a randomly generated key
- Seals the key for specific receivers
The inspect
action
- Checks if a file is a
sealpack
file
- Display size of compressed payload, used Hashing-Algorithm and number of potential receivers
The unseal
action
- Verifies that a file is a
sealpack
file
- Checks if encryption key is included and unseals the key
- Decompresses the contents and verifies the contents to match the signature
- Decrypts the files into a target directory and images to a container registry or a local
containerd
instance
High level overview
The prerequisite for a fully featured usage of sealpack
is every entity having a private-public-key-pair (PPK).
sealpack
supports multiple x509 key formats, among those are PEM, PKCS1, and PKIX.
(!) Private keys must never be shared, use files with the least access permissions possible.
A mutual trust must be established by exchanging the public Keys. This means, the sender must have access to all public
keys of potential receivers and each receiver must have access to the public key of the sender.
On the sender side, collection, packaging, signing, encryption, and sealing can then be performed in a single flow:
On the receiver side, unsealing, verification, unpacking and importing is also a single step:
Build & Install
To build the CLI binary, spin up a bash and run:
./build.sh
The sealpack
binary now includes everything needed to be used. Consider moving it to a place at system's PATH
.
Usage
Common flags:
Flag |
Short |
Type |
Multiple |
Mandatory |
Default |
Description |
loglevel |
l |
string |
n |
n |
info |
Minimal log level possible values are debug , info , warn , error , fatal . |
sealpack
supports 3 actions , which are subsequently described in detail:
seal
Create a sealed package
Usage:
sealpack seal [flags]
Flags:
-c, --contents string Provide all contents as a central configurations file
-f, --file strings Path to the files to be added
-a, --hashing-algorithm string Name of hashing algorithm to be used (default "SHA3_512")
-h, --help help for seal
-i, --image strings Name of container images to be added
-o, --output string Filename to store the result in
-p, --privkey string Path to the private signing key. AWS KMS keys can be used with awskms:/// prefix
--public Don't encrypt, contents are signed only and can be retrieved from any receiver
-r, --recipient-pubkey strings Paths of recipients' public keys
Flag |
Short |
Type |
Multiple |
Mandatory |
Default |
Description |
hashing-algorithm |
a |
string |
n |
n |
SHA512 |
Name of algorithm to be used for signature hashing. Valid values must implement crypto.Hash . |
contents |
c |
string |
n |
n |
- |
Provide all contents as a central configurations file (supports (JSON)[#json-format], (YAML)[#yaml-format]). |
file |
f |
string |
y |
n |
- |
Path to the files to be added to the package. |
help |
h |
- |
- |
- |
- |
Flag to display help message. Exits instantly. |
image |
i |
string |
y |
n |
- |
Names of container images to be added. Full tag with registry can be provided, short forms will default to docker.io |
output |
o |
string |
n |
y |
- |
Filename to store the resulting sealed file in. |
privkey |
p |
string |
n |
y |
- |
Path to the private signing key or AWS KMS keys can be used with awskms:/// prefix. PEM-based PKCS1, PKCS8 and EC keys are valid. |
public |
- |
bool |
- |
n |
true |
Flag to not encrypt contents only sign files, so can be retrieved from any receiver. |
recipient-pubkey |
r |
string |
y |
n |
- |
Paths of recipients' public keys. PEM-based PKIX and PKCS8 keys are valid. |
compression-algorithm |
z |
string |
n |
n |
gzip |
Name of compression algorithm to be used [gzip, zlib, zip, flate] |
The JSON format to define a list of contents, is kept very simple. The main object has 2 properties:
files
: array of strings, each entry defining one file
images
: array of objects, each one defining one container image. Omitting a tag defaults to latest
; omitting a registry defaults to docker.io
.
Example:
{
"files": [
"secrets.yaml",
"test.docx"
],
"images": [
"alpine",
"ghcr.io/simatic/sample:v0.0.1"
]
}
The YAML format follows the structure from (JSON)[#json-format].
Example:
files:
- secrets.yaml
- test.docx
images":
- alpine
- ghcr.io/simatic/sample:v0.0.1
seal
Example
sealpack seal -p path/to/sender_private.pem --public -o testupgrade.ipc -f /home/z003t8rs/OneDrive/Test.docx -i docker.io/alpine:3.17 -l debug
inspect
Inspects a sealed archive and allows for identifying any errors
Usage:
sealpack inspect [File]
Flags:
-h, --help help for inspect
Flag |
Short |
Description |
help |
h |
Flag to display help message. Exits instantly. |
Inspecting a file leads to one of the following outputs:
Sealed package:
File is a sealed package.
Payload size (compressed): 3368974 Bytes
Singatures hashed using SHA-512 (64 Bit)
Sealed for 2 Recievers
Public package:
File is a public package.
Payload size (compressed): 3369185 Bytes
Singatures hashed using SHA-512 (64 Bit)
unseal
Unpacks a sealed archive if the provided private key is valid
Usage:
sealpack unseal [flags]
Flags:
-a, --hashing-algorithm string Name of hashing algorithm to be used (default "SHA3_512")
-h, --help help for unseal
-o, --output string Output path to unpack the contents to (default "output")
-p, --privkey string Private key of the receiver
-s, --signer-key string Public key of the signing entity
-r, --target-registry string URL of the target registry to import container images; 'local' imports them locally (default "local")
Flag |
Short |
Type |
Multiple |
Mandatory |
Default |
Description |
hashing-algorithm |
a |
string |
n |
n |
SHA512 |
Name of algorithm to be used for signature hashing. Valid values must implement crypto.Hash . |
help |
h |
- |
- |
- |
- |
Flag to display help message. Exits instantly. |
output |
o |
string |
n |
n |
- |
Filename to store the resulting sealed file in. Defaults to current directory. |
privkey |
p |
string |
n |
n |
- |
Path to the private signing key or AWS KMS keys can be used with awskms:/// prefix. PEM-based PKCS1, PKCS8 are valid. |
signer-key |
s |
string |
n |
y |
- |
Public key of the signing entity. |
target-registry |
r |
string |
n |
n |
local |
PURL of the target registry to import container images; 'local' imports them to a local containerd service. Defaults to 'local'. |
namespace |
n |
string |
n |
n |
default |
Namespace of the containerd service ti import into. Defaults to 'default'. |
Go module
Using as a module is as simple as importing the package and using one ot the methods sealpack.Seal
, sealpack.Unseal
, or sealpack.Inspect
.
For Seal
and Unseal
, there are separate configuration structures available as sealpack.SealConfig
and sealpack.UnsealConfig
respectively.
Examples
Seal
package main
import "github.com/innomotics/sealpack"
sealpack.Seal(&sealpack.SealConfig{
// The private key to sign the contents
PrivKeyPath: "/home/foo/.ssh/private.key",
// Public keys of the recipients. You must either provide recipient keys or set SealConfig.Public = true
RecipientPubKeyPaths: []string{"/home/bar/keys/public.pem"},
// You can add files and folders
Files: []string{
"/etc/fnord/credentials.conf",
"../user_data",
},
// Container images can be added with docker.io defaults or with full image details
ImageNames: []string{
"alpine:latest",
"quay.io/kairos/debian:bookworm-core-amd64-generic-v3.0.0",
},
},
// If SealConfig.Output is set to "-", it will write to stdout
Output: "/tmp/output.sealed"
})
Unseal
You must provide a public key of the signer. If a sealed package is public, you can omit the private key of the recipient.
package main
import "github.com/innomotics/sealpack"
sealpack.Unseal("/tmp/output.sealed", &sealpack.UnsealConfig{
PrivKeyPath: "/home/bar/.ssh/private.key",
SigningKeyPath: "/etc/ssh/keys/foo_private.pem",
OutputPath: "/tmp/out",
})
Inspect
sealpack.Inspect
has no config. It only gets the filename of a sealed file as a parameter.
package main
import "github.com/innomotics/sealpack"
sealpack.Inspect("/tmp/output.sealed")