Sealed Secrets

repository·main·Indexed 11 days ago

https://github.com/bitnami-labs/sealed-secrets

A system for encrypting Kubernetes Secrets into a custom SealedSecret resource that can be safely stored in version control. It consists of a cluster-side controller for decryption and the kubeseal CLI for client-side encryption using asymmetric cryptography.

Tokens
30.1K
Snippets
82
Records
116
Agent score
93%

What's inside Sealed Secrets

  1. How the Sealing process works

    main

    The sealing process follows these steps to transform a plain secret into a Sealed Secret:

    1. Secret Encryption: The secret is encrypted using AES-256-GCM with a randomly generated 32-byte single-use session key ($K_s$). This produces the AES encrypted data.
    2. Session Key Encryption: The session key ($K_s$) is encapsulated using the controller's public key ($K_{pub}$) via RSA-OAEP with SHA-256. This step uses a label derived from the controller's scope configuration to ensure the secret can only be decrypted by the intended controller instance.
    3. Storage: The final Sealed Secret is a concatenated byte array: size of AES encrypted key (2 bytes) || RSA encrypted data || AES encrypted data.

    RSA-OAEP Label Scopes

    The label used during encryption depends on the controller's scope:

    • Default scope: label = Secret's namespace || Secret's name
    • Namespace-wide scope: label = Secret's namespace
    • Cluster-wide scope: label is empty
                                   Secret
                                                                       |
                                                                       │
                                                       K_s────────────►│
                                                        │              │
                                           K_pub───────►│              │
                                                        │              │
                                           label───────►│ 2.           │
                                                        │              │
                         ┌──────────────────────┬───────▼───────┬──────▼───────┐
    Sealed Secret data = │size of AES encrypted │ RSA encrypted │ AES encrypted│
                         │key (2 bytes)         │ data          │ data         │
                         └──────────────────────┴───────────────┴──────────────┘
  2. What are Sealed Secrets?

    main

    Sealed Secrets is a Kubernetes extension that allows you to safely store secrets in a public Git repository. It uses asymmetric encryption to create 'SealedSecrets' (custom resources) that can only be decrypted by a controller running within your Kubernetes cluster.

    Key features include:

    • GitOps Friendly: You can commit encrypted secrets to version control without exposing sensitive data.
    • Asymmetric Encryption: Only the controller holding the private key can decrypt the secrets.
    • Scope-based Security: You can restrict the scope of a secret (e.g., to a specific namespace or name) to prevent accidental use in the wrong context.
  3. Understand the Sealed Secrets Controller

    main

    The controller is responsible for maintaining synchronization between the current state of SealedSecret objects and their declared desired state in Kubernetes.

    The controller exposes an API defined by a Swagger or OpenAPI v3 specification. Developers can download the swagger.yml file from the repository to inspect the API surface.

  4. Manually manage sealing keys

    main

    Sealing keys are standard Kubernetes secrets located in the namespace where the SealedSecret controller resides (typically kube-system).

    • Identification: Keys are labeled with sealedsecrets.bitnami.com/sealed-secrets-key.
    • Status Labels: Keys are identified as either active or compromised.
    • Deactivating a key: Labeling a sealing key secret with anything other than active effectively removes it from the controller's active set (though the secret remains in Kubernetes).
    • Applying changes: The controller does not automatically detect manual changes to keys (creation, deletion, or relabeling). You must restart the controller for these changes to take effect.
  5. How Sealed Secrets works

    main

    Sealed Secrets is a two-part system for managing Kubernetes secrets securely:

    1. Cluster-side controller/operator: A component running in your Kubernetes cluster that holds the private key and decrypts SealedSecret resources into standard Kubernetes Secret resources.
    2. Client-side utility (kubeseal): A CLI tool used to encrypt secrets using asymmetric cryptography. Only the controller in the target cluster can decrypt the resulting resource.

    The output of kubeseal is a SealedSecret custom resource (kind: SealedSecret) which acts as a 'recipe' for creating a standard Secret. Once the controller unseals it, the resulting Secret can be used by Pods and other Kubernetes resources just like any native secret.

    apiVersion: bitnami.com/v1alpha1
    kind: SealedSecret
    metadata:
      name: mysecret
      namespace: mynamespace
    spec:
      encryptedData:
        foo: AgBy3i4OJSWK+PiTySYZZA9rO43cGDEq.....
  6. How the RSA-OAEP label is determined by scope

    main

    To prevent secrets from being moved between namespaces or scopes, the RSA-OAEP encryption process uses a label as additional input. The content of this label depends on the controller's scope configuration:

    • Default scope: label = Secret's namespace + Secret's name (concatenation).
    • Namespace-wide scope: label = Secret's namespace.
    • Cluster-wide scope: label is empty.

    This ensures that a Sealed Secret created for a specific namespace or name cannot be successfully decrypted if it is moved to a different context.

  7. Manage, Patch, or Decouple existing Secrets

    main

    You can control how the Sealed Secrets controller interacts with existing Secret resources using specific annotations:

    Full Management

    To allow the controller to manage an existing Secret (overwriting it when unsealing and taking ownership so that deleting the SealedSecret also deletes the Secret), add the following annotation to the Secret:

    • sealedsecrets.bitnami.com/managed: "true"

    Patching Keys

    To add or modify specific keys in an existing Secret without deleting keys that are not present in the SealedSecret, use the following annotation:

    • sealedsecrets.bitnami.com/patch: "true"
    • Note: You can combine patch and managed to patch while also taking ownership.

    Decoupling Ownership

    To prevent the Secret from being deleted when the SealedSecret is deleted (making them independent), add this annotation to the Secret before applying the usage steps:

    • sealedsecrets.bitnami.com/skip-set-owner-references: "true"
  8. Understand the Sealed Secrets components

    main

    Sealed Secrets is composed of three primary parts that work together to manage encrypted secrets in Kubernetes:

    1. SealedSecret Custom Resource: The Kubernetes resource used to declare the desired state of an encrypted secret.
    2. Controller: A cluster-side operator that manages SealedSecret objects, ensuring the current state of the cluster stays in sync with the declared state.
    3. kubeseal utility: A client-side tool that uses asymmetric cryptography to encrypt secrets. Only the controller possesses the private key required to decrypt these secrets.
  9. How the Decryption process works

    main

    Decryption is the inverse of the sealing process:

    1. The controller reads the size of AES encrypted key to correctly split the RSA encrypted data from the AES encrypted data.
    2. The controller uses its private key and the appropriate label (based on its scope and the secret's metadata) to decrypt the RSA encrypted data, retrieving the original AES session key.
    3. The controller uses the retrieved AES session key to decrypt the AES encrypted data, resulting in the original plain Secret.
  10. Post-quantum cryptography considerations

    main

    The current cryptographic implementation has the following post-quantum security profile:

    • AES-256-GCM: Considered quantum resistant. While Grover's algorithm can reduce effective security, it remains highly secure.
    • SHA-256: Considered quantum resistant.
    • RSA-OAEP: NOT quantum resistant. It is vulnerable to Shor's algorithm.

    Future improvements would require replacing RSA with lattice-based (e.g., LMS, XMSS) or code-based (e.g., McEliece) algorithms once reliable Go implementations and industry standards emerge.

  11. Understand the relationship between sealing keys and user secrets

    main

    It is critical to distinguish between the sealing key (the 'envelope' used by the controller) and your actual secrets (the sensitive data like passwords).

    1. Sealing Key Renewal: The controller periodically adds new keys to the registry. Old keys are kept so existing SealedSecret resources can still be decrypted. This is NOT a substitute for rotating your actual data.
    2. User Secret Rotation: You must periodically rotate your actual secret values (e.g., changing a database password) and create new SealedSecret resources using kubeseal.

    Security Rule: If a sealing key is compromised, all SealedSecret resources encrypted with that specific key are considered compromised. You must perform an early key renewal to ensure future secrets use a new key, and then rotate your actual secrets.

  12. How Sealed Secrets encryption works

    main

    Sealed Secrets uses a hybrid encryption approach to secure Kubernetes secrets. The process involves two main steps:

    1. Secret Encryption: The actual secret data is encrypted using AES-256-GCM with a randomly generated, single-use 32-byte session key ($K_s$).
    2. Session Key Encryption: The AES session key is encapsulated using the controller's public key via RSA-OAEP with SHA-256. This step uses a label to bind the encrypted key to a specific scope.

    The final Sealed Secret data format is a concatenation: size of AES encrypted key (2 bytes) || RSA encrypted data || AES encrypted data

    Sealed Secret data = │size of AES encrypted │ RSA encrypted │ AES encrypted│
                         │key (2 bytes)         │ data         │ data         │