Skip to content

Secret File Format

Jake Paine edited this page Apr 20, 2026 · 1 revision

Secret File Format

Each .enc.yaml file contains a SOPS-encrypted YAML document. When decrypted, the document must conform to the schema described here.

Schema

version: 1
kind: env
name: production/platform/app
description: Core app secrets for production  # optional
values:
  APP_KEY: base64:...
  DB_HOST: 10.0.0.10
  DB_PASSWORD: hunter2

Fields

version

Required. Must be 1. Any other value (including zero or absent) fails validation.

This is the document schema version, not the Keyseal version. It allows future schema changes to be made without breaking existing files.

kind

Required. Must be "env".

Only kind: env is currently supported. Attempting to create a document with a different kind via keyseal add --kind <other> is rejected with an explicit error. If you manually write a file with a different kind and add it to the repo, Keyseal will fail validation when it tries to parse it.

name

Required. Must be a non-empty string.

Conventionally this matches the logical name used to address the file (e.g. production/platform/app). Keyseal sets this automatically when creating files via keyseal add. It is validated during parse but there is no enforcement that it matches the file's location - the name in the document is informational.

description

Optional. Free-form string describing the contents of the file. Keyseal sets this to "Secrets for <logical-name>" when creating via keyseal add.

values

Required (by default). A map of string keys to string values.

Key rules:

  • Every key must match the validation.key_pattern configured in keyseal.yaml (default: ^[A-Z0-9_]+$)
  • The default pattern accepts only uppercase letters A–Z, digits 0–9, and underscores
  • Lowercase letters, hyphens, dots, and other characters are rejected under the default pattern

Value rules:

  • Values are plain strings
  • No length restrictions
  • Values can contain whitespace, newlines, special characters - YAML quoting handles this
  • Boolean-looking values (true, false) and numeric-looking values must be quoted as strings in the YAML if you want them to be treated as strings; YAML's type coercion does not apply since values are decoded as map[string]string

The values map must be non-empty when validation.require_values is true (the default).


Validation behavior

Validation runs in two places:

  1. Before encryption (keyseal add): the starter document is validated before being passed to SOPS. If validation fails, no file is written.
  2. After decryption (keyseal render, keyseal exec, keyseal doctor): the decrypted plaintext is parsed and validated. If validation fails, the command errors out.

Validation errors identify the specific problem: missing version, wrong kind, empty name, empty values map, invalid key name.


Duplicate keys

The YAML parser Keyseal uses (yaml.Node traversal rather than direct struct decode) detects duplicate keys in the values map. Duplicate keys do not cause a hard error - the last value wins - but they are returned as a list of warnings. Doctor reports them as warn-level findings.


Encryption

The .enc.yaml file as stored in the repository is SOPS ciphertext. A typical encrypted file looks like:

version: ENC[AES256_GCM,data:...,tag:...,type:int]
kind: ENC[AES256_GCM,data:...,tag:...,type:str]
name: ENC[AES256_GCM,data:...,tag:...,type:str]
description: ENC[AES256_GCM,data:...,tag:...,type:str]
values:
    APP_KEY: ENC[AES256_GCM,data:...,tag:...,type:str]
    DB_PASSWORD: ENC[AES256_GCM,data:...,tag:...,type:str]
sops:
    age:
        - enc: |
            -----BEGIN AGE ENCRYPTED FILE-----
            ...
            -----END AGE ENCRYPTED FILE-----
    ...
    version: 3.x.y

The sops: metadata block at the top level is how Keyseal's schema.HasSOPSMetadata check detects whether a file has actually been encrypted. Doctor uses this to flag any .enc.yaml file that parses as a valid plaintext document without SOPS metadata.


What invalid looks like

A few examples of what will fail validation:

# Missing version
kind: env
name: production/platform/app
values:
  APP_KEY: abc
# Wrong kind
version: 1
kind: file
name: production/platform/app
values:
  APP_KEY: abc
# Key with lowercase letters (under default key_pattern)
version: 1
kind: env
name: production/platform/app
values:
  app_key: abc
# Empty values map (when require_values: true)
version: 1
kind: env
name: production/platform/app
values: {}

Example document (unencrypted)

From the project's examples/ directory:

version: 1
kind: env
name: production/platform/app
description: Core Laravel app secrets for production
values:
  APP_NAME: Barkway
  APP_ENV: production
  APP_KEY: base64:xxxxx
  APP_DEBUG: "false"
  DB_HOST: 10.0.0.10
  DB_PORT: "3306"
  DB_DATABASE: barkway
  DB_USERNAME: barkway_app
  DB_PASSWORD: super-secret

Note that APP_DEBUG and DB_PORT are quoted as strings. Without quotes, YAML would parse false as a boolean and 3306 as an integer - which would fail the map[string]string decode. Always quote values that look like non-string scalars.

Clone this wiki locally