SIF Image Decryption
Secrets for decrypting encrypted SIF (Singularity Image Format) images can be specified in a YAML file with the following syntax.
For SIF images encrypted with a passphrase:
type: sif-decryption-key
secret:
passphrase: your-encryption-passphrase
For SIF images encrypted with an RSA public/private key pair:
type: sif-decryption-key
secret:
pem: |
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA2Z3qX5mNr8X...
[... complete PEM private key content ...]
-----END RSA PRIVATE KEY-----
The sif-decryption-key secret type provides credentials to decrypt encrypted
SIF container
images at runtime, allowing
jobs to use protected
container images without exposing the encryption keys in
Fuzzfiles.
- passphrase (optional): The passphrase used to decrypt the SIF image. Use this field for images encrypted with Apptainer’s passphrase-based encryption method.
- pem (optional): The complete PEM-formatted RSA private key used to decrypt the SIF image that was encrypted with the corresponding RSA public key including the header and footer. Use this field for images encrypted with Apptainer’s PEM key-based encryption method.
passphraseandpemare mutually exclusive.
Decryption secrets are referenced in a
workflow specification using
the decryption-secret field of a job’s image configuration:
jobs:
my-secure-job:
image:
uri: oras://registry.example.com/secure/app.sif:latest
decryption-secret: secret://user/my-decryption-key
command: [./run-app.sh]
The secret reference follows the standard format:
secret://<scope>/<secret-name> where scope is user, account,
organization, or cluster.
Encrypted SIF images are created using Apptainer. For detailed instructions on creating encrypted containers please refer to the Apptainer Encryption Documentation and see the example below.
Generate a 4096-bit RSA key pair:
$ openssl genrsa -traditional -out rsa_private.pem 4096
$ openssl rsa -in rsa_private.pem -RSAPublicKey_out -out rsa_public.pemBoth the private and public keys should be in PKCS#1 format for Apptainer:
- Use
-traditionalflag withopenssl genrsato get-----BEGIN RSA PRIVATE KEY-----(PKCS#1 private key format)- Use
-RSAPublicKey_outflag to get-----BEGIN RSA PUBLIC KEY-----(PKCS#1 public key format)Without these flags, modern OpenSSL versions default to PKCS#8 format which Apptainer may not accept.
With a passphrase. The example here is interactive but you can provide the key
as an environment variable ($APPTAINER_ENCRYPTION_PASSPHRASE) instead.
$ cat > app.def <<EOF
Bootstrap: docker
From: alpine:latest
EOF
$ apptainer build --passphrase passphrase_app.sif app.def
Enter encryption passphrase:
INFO: Starting build...
...With the key created above:
$ apptainer build --pem-path rsa_public.pem key_app.sif app.def$ apptainer push key_app.sif oras://registry.example.com/apps/secure-app:v1.0Create a YAML file (decryption_key_secret.yaml) with your private key:
$ cat > decryption_key_secret.yaml <<EOF
type: sif-decryption-key
secret:
pem: |
$(sed 's/^/ /' rsa_private.pem)
EOFUpload the secret:
$ fuzzball secret create secure-app-key \
--scope user \
--from-file decryption_key_secret.yamlversion: v1
jobs:
run-secure-app:
image:
uri: oras://registry.example.com/apps/secure-app:v1.0
decryption-secret: secret://user/secure-app-key
script: |
#!/bin/sh
echo "Hello from an encrypted container"
resource:
cpu:
cores: 1
memory:
size: 1GB
- Protect Private Keys: Never commit PEM private keys to version control or share them insecurely. Use secure secret management practices.
- Key Rotation: Regularly rotate encryption keys for enhanced security. This requires re-encrypting images with new keys.
- Scope Selection: Choose the narrowest appropriate scope for your decryption secrets:
- user: for personal development and testing
- account: for team projects and shared workflows
- organization: only when images need to be shared across multiple accounts
- cluster: reserved for system-level images (requires admin privileges)
- Separate Concerns: Use different decryption keys for different images or projects to limit the impact if a key is compromised.