Giter Site home page Giter Site logo

bitnami-labs / sealed-secrets Goto Github PK

View Code? Open in Web Editor NEW
7.4K 70.0 671.0 40.57 MB

A Kubernetes controller and tool for one-way encrypted Secrets

Home Page: https://sealed-secrets.netlify.app/

License: Apache License 2.0

Makefile 2.52% Go 62.94% Dockerfile 0.42% Jsonnet 15.44% Shell 1.48% Smarty 1.71% HTML 7.07% SCSS 8.26% JavaScript 0.15%
kubernetes kubernetes-secrets devops-workflow encrypt-secrets gitops

sealed-secrets's Introduction

"Sealed Secrets" for Kubernetes

Build Status Download Status Go Report Card Downloads

Problem: "I can manage all my K8s config in git, except Secrets."

Solution: Encrypt your Secret into a SealedSecret, which is safe to store - even inside a public repository. The SealedSecret can be decrypted only by the controller running in the target cluster and nobody else (not even the original author) is able to obtain the original Secret from the SealedSecret.

Overview

Sealed Secrets is composed of two parts:

  • A cluster-side controller / operator
  • A client-side utility: kubeseal

The kubeseal utility uses asymmetric crypto to encrypt secrets that only the controller can decrypt.

These encrypted secrets are encoded in a SealedSecret resource, which you can see as a recipe for creating a secret. Here is how it looks:

apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  name: mysecret
  namespace: mynamespace
spec:
  encryptedData:
    foo: AgBy3i4OJSWK+PiTySYZZA9rO43cGDEq.....

Once unsealed this will produce a secret equivalent to this:

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
  namespace: mynamespace
data:
  foo: YmFy  # <- base64 encoded "bar"

This normal kubernetes secret will appear in the cluster after a few seconds you can use it as you would use any secret that you would have created directly (e.g. reference it from a Pod).

Jump to the Installation section to get up and running.

The Usage section explores in more detail how you craft SealedSecret resources.

SealedSecrets as templates for secrets

The previous example only focused on the encrypted secret items themselves, but the relationship between a SealedSecret custom resource and the Secret it unseals into is similar in many ways (but not in all of them) to the familiar Deployment vs Pod.

In particular, the annotations and labels of a SealedSecret resource are not the same as the annotations of the Secret that gets generated out of it.

To capture this distinction, the SealedSecret object has a template section which encodes all the fields you want the controller to put in the unsealed Secret.

The Sprig function library is available in addition to the default Go Text Template functions.

The metadata block is copied as is (the ownerReference field will be updated unless disabled).

Other secret fields are handled individually. The type and immutable fields are copied, and the data field can be used to template complex values on the Secret. All other fields are currently ignored.

apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  name: mysecret
  namespace: mynamespace
  annotations:
    "kubectl.kubernetes.io/last-applied-configuration": ....
spec:
  encryptedData:
    .dockerconfigjson: AgBy3i4OJSWK+PiTySYZZA9rO43cGDEq.....
  template:
    type: kubernetes.io/dockerconfigjson
    immutable: true
    # this is an example of labels and annotations that will be added to the output secret
    metadata:
      labels:
        "jenkins.io/credentials-type": usernamePassword
      annotations:
        "jenkins.io/credentials-description": credentials from Kubernetes

The controller would unseal that into something like:

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
  namespace: mynamespace
  labels:
    "jenkins.io/credentials-type": usernamePassword
  annotations:
    "jenkins.io/credentials-description": credentials from Kubernetes
  ownerReferences:
  - apiVersion: bitnami.com/v1alpha1
    controller: true
    kind: SealedSecret
    name: mysecret
    uid: 5caff6a0-c9ac-11e9-881e-42010aac003e
type: kubernetes.io/dockerconfigjson
immutable: true
data:
  .dockerconfigjson: ewogICJjcmVk...

As you can see, the generated Secret resource is a "dependent object" of the SealedSecret and as such it will be updated and deleted whenever the SealedSecret object gets updated or deleted.

Public key / Certificate

The key certificate (public key portion) is used for sealing secrets, and needs to be available wherever kubeseal is going to be used. The certificate is not secret information, although you need to ensure you are using the correct one.

kubeseal will fetch the certificate from the controller at runtime (requires secure access to the Kubernetes API server), which is convenient for interactive use, but it's known to be brittle when users have clusters with special configurations such as private GKE clusters that have firewalls between control plane and nodes.

An alternative workflow is to store the certificate somewhere (e.g. local disk) with kubeseal --fetch-cert >mycert.pem, and use it offline with kubeseal --cert mycert.pem. The certificate is also printed to the controller log on startup.

Since v0.9.x certificates get automatically renewed every 30 days. It's good practice that you and your team update your offline certificate periodically. To help you with that, since v0.9.2 kubeseal accepts URLs too. You can set up your internal automation to publish certificates somewhere you trust.

kubeseal --cert https://your.intranet.company.com/sealed-secrets/your-cluster.cert

It also recognizes the SEALED_SECRETS_CERT env var. (pro-tip: see also direnv).

NOTE: we are working on providing key management mechanisms that offload the encryption to HSM based modules or managed cloud crypto solutions such as KMS.

Scopes

SealedSecrets are from the POV of an end user a "write only" device.

The idea is that the SealedSecret can be decrypted only by the controller running in the target cluster and nobody else (not even the original author) is able to obtain the original Secret from the SealedSecret.

The user may or may not have direct access to the target cluster. More specifically, the user might or might not have access to the Secret unsealed by the controller.

There are many ways to configure RBAC on k8s, but it's quite common to forbid low-privilege users from reading Secrets. It's also common to give users one or more namespaces where they have higher privileges, which would allow them to create and read secrets (and/or create deployments that can reference those secrets).

Encrypted SealedSecret resources are designed to be safe to be looked at without gaining any knowledge about the secrets it conceals. This implies that we cannot allow users to read a SealedSecret meant for a namespace they wouldn't have access to and just push a copy of it in a namespace where they can read secrets from.

Sealed-secrets thus behaves as if each namespace had its own independent encryption key and thus once you seal a secret for a namespace, it cannot be moved in another namespace and decrypted there.

We don't technically use an independent private key for each namespace, but instead we include the namespace name during the encryption process, effectively achieving the same result.

Furthermore, namespaces are not the only level at which RBAC configurations can decide who can see which secret. In fact, it's possible that users can access a secret called foo in a given namespace but not any other secret in the same namespace. We cannot thus by default let users freely rename SealedSecret resources otherwise a malicious user would be able to decrypt any SealedSecret for that namespace by just renaming it to overwrite the one secret user does have access to. We use the same mechanism used to include the namespace in the encryption key to also include the secret name.

That said, there are many scenarios where you might not care about this level of protection. For example, the only people who have access to your clusters are either admins or they cannot read any Secret resource at all. You might have a use case for moving a sealed secret to other namespaces (e.g. you might not know the namespace name upfront), or you might not know the name of the secret (e.g. it could contain a unique suffix based on the hash of the contents etc).

These are the possible scopes:

  • strict (default): the secret must be sealed with exactly the same name and namespace. These attributes become part of the encrypted data and thus changing name and/or namespace would lead to "decryption error".
  • namespace-wide: you can freely rename the sealed secret within a given namespace.
  • cluster-wide: the secret can be unsealed in any namespace and can be given any name.

In contrast to the restrictions of name and namespace, secret items (i.e. JSON object keys like spec.encryptedData.my-key) can be renamed at will without losing the ability to decrypt the sealed secret.

The scope is selected with the --scope flag:

kubeseal --scope cluster-wide <secret.yaml >sealed-secret.json

It's also possible to request a scope via annotations in the input secret you pass to kubeseal:

  • sealedsecrets.bitnami.com/namespace-wide: "true" -> for namespace-wide
  • sealedsecrets.bitnami.com/cluster-wide: "true" -> for cluster-wide

The lack of any of such annotations means strict mode. If both are set, cluster-wide takes precedence.

NOTE: Next release will consolidate this into a single sealedsecrets.bitnami.com/scope annotation.

Installation

See https://github.com/bitnami-labs/sealed-secrets/releases for the latest release and detailed installation instructions.

Cloud platform specific notes and instructions:

Controller

Once you deploy the manifest it will create the SealedSecret resource and install the controller into kube-system namespace, create a service account and necessary RBAC roles.

After a few moments, the controller will start, generate a key pair, and be ready for operation. If it does not, check the controller logs.

Kustomize

The official controller manifest installation mechanism is just a YAML file.

In some cases you might need to apply your own customizations, like set a custom namespace or set some env variables.

kubectl has native support for that, see kustomize.

Helm Chart

The Sealed Secrets helm chart is now officially supported and hosted in this GitHub repo.

helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets

NOTE: The versioning scheme of the helm chart differs from the versioning scheme of the sealed secrets project itself.

Originally the helm chart was maintained by the community and the first version adopted a major version of 1 while the sealed secrets project itself is still at major 0. This is ok because the version of the helm chart itself is not meant to be necessarily the version of the app itself. However this is confusing, so our current versioning rule is:

  1. The SealedSecret controller version scheme: 0.X.Y
  2. The helm chart version scheme: 1.X.Y-rZ

There can be thus multiple revisions of the helm chart, with fixes that apply only to the helm chart without affecting the static YAML manifests or the controller image itself.

NOTE: The helm chart readme still contains a deprecation notice, but it no longer reflects reality and will be removed upon the next release.

NOTE: The helm chart by default installs the controller with the name sealed-secrets, while the kubeseal command line interface (CLI) tries to access the controller with the name sealed-secrets-controller. You can explicitly pass --controller-name to the CLI:

kubeseal --controller-name sealed-secrets <args>

Alternatively, you can set fullnameOverride when installing the chart to override the name. Note also that kubeseal assumes that the controller is installed within the kube-system namespace by default. So if you want to use the kubeseal CLI without having to pass the expected controller name and namespace you should install the Helm Chart like this:

helm install sealed-secrets -n kube-system --set-string fullnameOverride=sealed-secrets-controller sealed-secrets/sealed-secrets
Helm Chart on a restricted environment

In some companies you might be given access only to a single namespace, not a full cluster.

One of the most restrictive environments you can encounter is:

  • A namespace was allocated to you with some service account.
  • You do not have access to the rest of the cluster, not even cluster CRDs.
  • You may not even be able to create further service accounts or roles in your namespace.
  • You are required to include resource limits in all your deployments.

Even with these restrictions you can still install the sealed secrets Helm Chart, there is only one pre-requisite:

  • The cluster must already have the sealed secrets CRDs installed.

Once your admins installed the CRDs, if they were not there already, you can install the chart by preparing a YAML config file such as this:

serviceAccount:
  create: false
  name: {allocated-service-account}
rbac:
  create: false
  clusterRole: false
resources:
  limits:
    cpu: 150m
    memory: 256Mi

Note that:

  • No service accounts are created, instead the one allocated to you will be used.
    • {allocated-service-account} is the name of the service account you were allocated on the cluster.
  • No RBAC roles are created neither in the namespace nor the cluster.
  • Resource limits must be specified.
    • The limits are samples that should work, but you might want to review them in your particular setup.

Once that file is ready, if you named it config.yaml you now can install the sealed secrets Helm Chart like this:

helm install sealed-secrets -n {allocated-namespace} sealed-secrets/sealed-secrets --skip-crds -f config.yaml

Where {allocated-namespace} is the name of the namespace you were allocated in the cluster.

Kubeseal

Homebrew

The kubeseal client is also available on homebrew:

brew install kubeseal

MacPorts

The kubeseal client is also available on MacPorts:

port install kubeseal

Nixpkgs

The kubeseal client is also available on Nixpkgs: (DISCLAIMER: Not maintained by bitnami-labs)

nix-env -iA nixpkgs.kubeseal

Linux

The kubeseal client can be installed on Linux, using the below commands:

KUBESEAL_VERSION='' # Set this to, for example, KUBESEAL_VERSION='0.23.0'
curl -OL "https://github.com/bitnami-labs/sealed-secrets/releases/download/v${KUBESEAL_VERSION:?}/kubeseal-${KUBESEAL_VERSION:?}-linux-amd64.tar.gz"
tar -xvzf kubeseal-${KUBESEAL_VERSION:?}-linux-amd64.tar.gz kubeseal
sudo install -m 755 kubeseal /usr/local/bin/kubeseal

If you have curl and jq installed on your machine, you can get the version dynamically this way. This can be useful for environments used in automation and such.

# Fetch the latest sealed-secrets version using GitHub API
KUBESEAL_VERSION=$(curl -s https://api.github.com/repos/bitnami-labs/sealed-secrets/tags | jq -r '.[0].name' | cut -c 2-)

# Check if the version was fetched successfully
if [ -z "$KUBESEAL_VERSION" ]; then
    echo "Failed to fetch the latest KUBESEAL_VERSION"
    exit 1
fi

curl -OL "https://github.com/bitnami-labs/sealed-secrets/releases/download/v${KUBESEAL_VERSION}/kubeseal-${KUBESEAL_VERSION}-linux-amd64.tar.gz"
tar -xvzf kubeseal-${KUBESEAL_VERSION}-linux-amd64.tar.gz kubeseal
sudo install -m 755 kubeseal /usr/local/bin/kubeseal

where KUBESEAL_VERSION is the version tag of the kubeseal release you want to use. For example: v0.18.0.

Installation from source

If you just want the latest client tool, it can be installed into $GOPATH/bin with:

go install github.com/bitnami-labs/sealed-secrets/cmd/kubeseal@main

You can specify a release tag or a commit SHA instead of main.

The go install command will place the kubeseal binary at $GOPATH/bin:

$(go env GOPATH)/bin/kubeseal

Upgrade

Don't forget to check the release notes for guidance about possible breaking changes when you upgrade the client tool and/or the controller.

Supported Versions

Currently, only the latest version of Sealed Secrets is supported for production environments.

Compatibility with Kubernetes versions

The Sealed Secrets controller ensures compatibility with different versions of Kubernetes by relying on a stable Kubernetes API. Typically, Kubernetes versions above 1.16 are considered compatible. However, we officially support the currently recommended Kubernetes versions. Additionally, versions above 1.24 undergo thorough verification through our CI process with every release.

Usage

# Create a json/yaml-encoded Secret somehow:
# (note use of `--dry-run` - this is just a local file!)
echo -n bar | kubectl create secret generic mysecret --dry-run=client --from-file=foo=/dev/stdin -o json >mysecret.json

# This is the important bit:
kubeseal -f mysecret.json -w mysealedsecret.json

# At this point mysealedsecret.json is safe to upload to Github,
# post on Twitter, etc.

# Eventually:
kubectl create -f mysealedsecret.json

# Profit!
kubectl get secret mysecret

Note the SealedSecret and Secret must have the same namespace and name. This is a feature to prevent other users on the same cluster from re-using your sealed secrets. See the Scopes section for more info.

kubeseal reads the namespace from the input secret, accepts an explicit --namespace argument, and uses the kubectl default namespace (in that order). Any labels, annotations, etc on the original Secret are preserved, but not automatically reflected in the SealedSecret.

By design, this scheme does not authenticate the user. In other words, anyone can create a SealedSecret containing any Secret they like (provided the namespace/name matches). It is up to your existing config management workflow, cluster RBAC rules, etc to ensure that only the intended SealedSecret is uploaded to the cluster. The only change from existing Kubernetes is that the contents of the Secret are now hidden while outside the cluster.

Managing existing secrets

If you want the Sealed Secrets controller to manage an existing Secret, you can annotate your Secret with the sealedsecrets.bitnami.com/managed: "true" annotation. The existing Secret will be overwritten when unsealing a SealedSecret with the same name and namespace, and the SealedSecret will take ownership of the Secret (so that when the SealedSecret is deleted the Secret will also be deleted).

Patching existing secrets

New in v0.23.0

There are some use cases in which you don't want to replace the whole Secret but just add or modify some keys from the existing Secret. For this, you can annotate your Secret with sealedsecrets.bitnami.com/patch: "true". Using this annotation will make sure that secret keys, labels and annotations in the Secret that are not present in the SealedSecret won't be deleted, and those present in the SealedSecret will be added to the Secret (secret keys, labels and annotations that exist both in the Secret and the SealedSecret will be modified by the SealedSecret).

This annotation does not make the SealedSecret take ownership of the Secret. You can add both the patch and managed annotations to obtain the patching behavior while also taking ownership of the Secret.

Seal secret which can skip set owner references

If you want SealedSecret and the Secret to be independent, which mean when you delete the SealedSecret the Secret won't disappear with it, then you have to annotate that Secret with the annotation sealedsecrets.bitnami.com/skip-set-owner-references: "true" ahead of applying the Usage steps. You still may also add sealedsecrets.bitnami.com/managed: "true" to your Secret so that your secret will be updated when SealedSecret is updated.

Update existing secrets

If you want to add or update existing sealed secrets without having the cleartext for the other items, you can just copy&paste the new encrypted data items and merge it into an existing sealed secret.

You must take care of sealing the updated items with a compatible name and namespace (see note about scopes above).

You can use the --merge-into command to update an existing sealed secrets if you don't want to copy&paste:

echo -n bar | kubectl create secret generic mysecret --dry-run=client --from-file=foo=/dev/stdin -o json \
  | kubeseal > mysealedsecret.json
echo -n baz | kubectl create secret generic mysecret --dry-run=client --from-file=bar=/dev/stdin -o json \
  | kubeseal --merge-into mysealedsecret.json

Raw mode (experimental)

Creating temporary Secret with the kubectl command, only to throw it away once piped to kubeseal can be a quite unfriendly user experience. We're working on an overhaul of the CLI experience. In the meantime, we offer an alternative mode where kubeseal only cares about encrypting a value to stdout, and it's your responsibility to put it inside a SealedSecret resource (not unlike any of the other k8s resources).

It can also be useful as a building block for editor/IDE integrations.

The downside is that you have to be careful to be consistent with the sealing scope, the namespace and the name.

See Scopes

strict scope (default):

$ echo -n foo | kubeseal --raw --namespace bar --name mysecret
AgBChHUWLMx...

namespace-wide scope:

$ echo -n foo | kubeseal --raw --namespace bar --scope namespace-wide
AgAbbFNkM54...

Include the sealedsecrets.bitnami.com/namespace-wide annotation in the SealedSecret

metadata:
  annotations:
    sealedsecrets.bitnami.com/namespace-wide: "true"

cluster-wide scope:

$ echo -n foo | kubeseal --raw --scope cluster-wide
AgAjLKpIYV+...

Include the sealedsecrets.bitnami.com/cluster-wide annotation in the SealedSecret

metadata:
  annotations:
    sealedsecrets.bitnami.com/cluster-wide: "true"

Validate a Sealed Secret

If you want to validate an existing sealed secret, kubeseal has the flag --validate to help you.

Giving a file named sealed-secrets.yaml containing the following sealed secret:

apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  name: mysecret
  namespace: mynamespace
spec:
  encryptedData:
    foo: AgBy3i4OJSWK+PiTySYZZA9rO43cGDEq.....

You can validate if the sealed secret was properly created or not:

$ cat sealed-secrets.yaml | kubeseal --validate

In case of an invalid sealed secret, kubeseal will show:

$ cat sealed-secrets.yaml | kubeseal --validate
error: unable to decrypt sealed secret

Secret Rotation

You should always rotate your secrets. But since your secrets are encrypted with another secret, you need to understand how these two layers relate to take the right decisions.

TL;DR:

If a sealing private key is compromised, you need to follow the instructions below in "Early key renewal" section before rotating any of your actual secret values.

SealedSecret key renewal and re-encryption features are not a substitute for periodical rotation of your actual secret values.

Sealing key renewal

Sealing keys are automatically renewed every 30 days. Which means a new sealing key is created and appended to the set of active sealing keys the controller can use to unseal SealedSecret resources.

The most recently created sealing key is the one used to seal new secrets when you use kubeseal and it's the one whose certificate is downloaded when you use kubeseal --fetch-cert.

The renewal time of 30 days is a reasonable default, but it can be tweaked as needed with the --key-renew-period=<value> flag for the command in the pod template of the SealedSecret controller. The value field can be given as golang duration flag (eg: 720h30m). Assuming that you've installed Sealed Secrets into the kube-system namespace, use the following command to edit the Deployment controller, and add the --key-renew-period parameter. Once you close your text editor, and the Deployment controller has been modified, a new Pod will be automatically created to replace the old Pod.

kubectl edit deployment/sealed-secrets-controller --namespace=kube-system

A value of 0 will deactivate automatic key renewal. Of course, you may have a valid use case for deactivating automatic sealing key renewal but experience has shown that new users often tend to jump to conclusions that they want control over key renewal, before fully understanding how sealed secrets work. Read more about this in the common misconceptions section below.

Unfortunately, you cannot use e.g. "d" as a unit for days because that's not supported by the Go stdlib. Instead of hitting your face with a palm, take this as an opportunity to meditate on the falsehoods programmers believe about time.

A common misunderstanding is that key renewal is often thought of as a form of key rotation, where the old key is not only obsolete but actually bad and that you thus want to get rid of it. It doesn't help that this feature has been historically called "key rotation", which can add to the confusion.

Sealed secrets are not automatically rotated and old keys are not deleted when new keys are generated. Old SealedSecret resources can be still decrypted (that's because old sealing keys are not deleted).

User secret rotation

The sealing key renewal and SealedSecret rotation are not a substitute for rotating your actual secrets.

A core value proposition of this tool is:

Encrypt your Secret into a SealedSecret, which is safe to store - even inside a public repository.

If you store anything in a version control storage, and in a public one in particular, you must assume you cannot ever delete that information.

If a sealing key somehow leaks out of the cluster you must consider all your SealedSecret resources encrypted with that key as compromised. No amount of sealing key rotation in the cluster or even re-encryption of existing SealedSecrets files can change that.

The best practice is to periodically rotate all your actual secrets (e.g. change the password) and craft new SealedSecret resources with those new secrets.

But if the SealedSecret controller was not renewing the sealing key that rotation would be moot, since the attacker could just decrypt the new secrets as well. Thus, you need to do both: periodically renew the sealing key and rotate your actual secrets!

Early key renewal

If you know or suspect a sealing key has been compromised you should renew the key ASAP before you start sealing your new rotated secrets, otherwise you'll be giving attackers access to your new secrets as well.

A key can be generated early by passing the current timestamp to the controller into a flag called --key-cutoff-time or an env var called SEALED_SECRETS_KEY_CUTOFF_TIME. The expected format is RFC1123, you can generate it with the date -R unix command.

Common misconceptions about key renewal

Sealed secrets sealing keys are not access control keys (e.g. a password). They are more like the GPG key you might use to read encrypted mail sent to you. Let's continue with the email analogy for a bit:

Imagine you have reasons to believe your private GPG key might have been compromised. You'd have more to lose than to gain if the first thing you do is just delete your private key. All the previous emails sent with that key are no longer accessible to you (unless you have a decrypted copy of those emails), nor are new emails sent by your friends whom you have not yet managed to tell to use the new key.

Sure, the content of those encrypted emails is not secure, as an attacker might now be able to decrypt them, but what's done is done. Your sudden loss of the ability to read those emails surely doesn't undo the damage. If anything, it's worse because you no longer know for sure what secret the attacker got to know. What you really want to do is to make sure that your friend stops using your old key and that from now on all further communication is encrypted with a new key pair (i.e. your friend must know about that new key).

The same logic applies to SealedSecrets. The ultimate goal is to secure your actual "user" secrets. The "sealing" secrets are just a mechanism, an "envelope". If a secret is leaked there is no going back, what's done is done.

You first need to ensure that new secrets don't get encrypted with that old compromised key (in the email analogy above that's: create a new key pair and give all your friends your new public key).

The second logical step is to neutralize the damage, which depends on the nature of the secret. A simple example is a database password: if you accidentally leak your database password, the thing you're supposed to do is simply to change your database password (on the database; and revoke the old one!) and update the SealedSecret resource with the new password (i.e. running kubeseal again).

Both steps are described in the previous sections, albeit in a less verbose way. There is no shame in reading them again, now that you have a more in-depth grasp of the underlying rationale.

Manual key management (advanced)

The SealedSecret controller and the associated workflow are designed to keep old sealing keys around and periodically add new ones. You should not delete old keys unless you know what you're doing.

That said, if you want you can manually manage (create, move, delete) sealing keys. They are just normal k8s secrets living in the same namespace where the SealedSecret controller lives (usually kube-system, but it's configurable).

There are advanced use cases that you can address by creative management of the sealing keys. For example, you can share the same sealing key among a few clusters so that you can apply exactly the same sealed secret in multiple clusters. Since sealing keys are just normal k8s secrets you can even use sealed secrets themselves and use a GitOps workflow to manage your sealing keys (useful when you want to share the same key among different clusters)!

Labeling a sealing key secret with anything other than active effectively deletes the key from the SealedSecret controller, but it is still available in k8s for manual encryption/decryption if need be.

NOTE SealedSecret controller currently does not automatically pick up manually created, deleted or relabeled sealing keys. An admin must restart the controller before the effect will apply.

Re-encryption (advanced)

Before you can get rid of some old sealing keys you need to re-encrypt your SealedSecrets with the latest private key.

kubeseal --re-encrypt <my_sealed_secret.json >tmp.json \
  && mv tmp.json my_sealed_secret.json

The invocation above will produce a new sealed secret file freshly encrypted with the latest key, without making the secrets leave the cluster to the client. You can then save that file in your version control system (kubeseal --re-encrypt doesn't update the in-cluster object).

Currently, old keys are not garbage collected automatically.

It's a good idea to periodically re-encrypt your SealedSecrets. But as mentioned above, don't lull yourself in a false sense of security: you must assume the old version of the SealedSecret resource (the one encrypted with a key you think of as dead) is still potentially around and accessible to attackers. I.e. re-encryption is not a substitute for periodically rotating your actual secrets.

Details (advanced)

This controller adds a new SealedSecret custom resource. The interesting part of a SealedSecret is a base64-encoded asymmetrically encrypted Secret.

The controller maintains a set of private/public key pairs as kubernetes secrets. Keys are labeled with sealedsecrets.bitnami.com/sealed-secrets-key and identified in the label as either active or compromised. On startup, The sealed secrets controller will...

  1. Search for these keys and add them to its local store if they are labeled as active.
  2. Create a new key
  3. Start the key rotation cycle

Crypto

More details about crypto can be found here.

Developing

Developing guidelines can be found in the Developer Guide.

FAQ

Can I encrypt multiple secrets at once, in one YAML / JSON file?

Yes, you can! Drop as many secrets as you like in one file. Make sure to separate them via --- for YAML and as extra, single objects in JSON.

Will you still be able to decrypt if you no longer have access to your cluster?

No, the private keys are only stored in the Secret managed by the controller (unless you have some other backup of your k8s objects). There are no backdoors - without that private key used to encrypt a given SealedSecrets, you can't decrypt it. If you can't get to the Secrets with the encryption keys, and you also can't get to the decrypted versions of your Secrets live in the cluster, then you will need to regenerate new passwords for everything, seal them again with a new sealing key, etc.

How can I do a backup of my SealedSecrets?

If you do want to make a backup of the encryption private keys, it's easy to do from an account with suitable access:

kubectl get secret -n kube-system -l sealedsecrets.bitnami.com/sealed-secrets-key -o yaml >main.key

echo "---" >> main.key
kubectl get secret -n kube-system sealed-secrets-key -o yaml >>main.key

NOTE: You need the second statement only if you ever installed sealed-secrets older than version 0.9.x on your cluster.

NOTE: This file will contain the controller's public + private keys and should be kept omg-safe!

NOTE: After sealing key renewal you should recreate your backup. Otherwise, your backup won't be able to decrypt new sealed secrets.

To restore from a backup after some disaster, just put that secrets back before starting the controller - or if the controller was already started, replace the newly-created secrets and restart the controller:

  • For Helm deployment:

    kubectl apply -f main.key
    kubectl delete pod -n kube-system -l app.kubernetes.io/name=sealed-secrets
  • For deployment via controller.yaml manifest

    kubectl apply -f main.key
    kubectl delete pod -n kube-system -l name=sealed-secrets-controller

Can I decrypt my secrets offline with a backup key?

While treating sealed-secrets as long term storage system for secrets is not the recommended use case, some people do have a legitimate requirement for being able to recover secrets when the k8s cluster is down and restoring a backup into a new SealedSecret controller deployment is not practical.

If you have backed up one or more of your private keys (see previous question), you can use the kubeseal --recovery-unseal --recovery-private-key file1.key,file2.key,... command to decrypt a sealed secrets file.

What flags are available for kubeseal?

You can check the flags available using kubeseal --help.

How do I update parts of JSON/YAML/TOML/.. file encrypted with sealed secrets?

A kubernetes Secret resource contains multiple items, basically a flat map of key/value pairs. SealedSecrets operate at that level, and does not care what you put in the values. In other words it cannot make sense of any structured configuration file you might have put in a secret and thus cannot help you update individual fields in it.

Since this is a common problem, especially when dealing with legacy applications, we do offer an example of a possible workaround.

Can I bring my own (pre-generated) certificates?

Yes, you can provide the controller with your own certificates, and it will consume them. Please check here for a workaround.

How to use kubeseal if the controller is not running within the kube-system namespace?

If you installed the controller in a different namespace than the default kube-system, you need to provide this namespace to the kubeseal commandline tool. There are two options:

  1. You can specify the namespace via the command line option --controller-namespace <namespace>:
kubeseal --controller-namespace sealed-secrets <mysecret.json >mysealedsecret.json
  1. Via the environment variable SEALED_SECRETS_CONTROLLER_NAMESPACE:
export SEALED_SECRETS_CONTROLLER_NAMESPACE=sealed-secrets
kubeseal <mysecret.json >mysealedsecret.json

How to verify the images?

Our images are being signed using cosign. The signatures have been saved in our GitHub Container Registry.

Images up to and including v0.20.2 were signed using Cosign v1. Newer images are signed with Cosign v2.

It is pretty simple to verify the images:

# export the COSIGN_VARIABLE setting up the GitHub container registry signs path
export COSIGN_REPOSITORY=ghcr.io/bitnami-labs/sealed-secrets-controller/signs

# verify the image uploaded in GHCR
cosign verify --key .github/workflows/cosign.pub ghcr.io/bitnami-labs/sealed-secrets-controller:latest

# verify the image uploaded in Dockerhub
cosign verify --key .github/workflows/cosign.pub docker.io/bitnami/sealed-secrets-controller:latest

How to use one controller for a subset of namespaces

If you want to use one controller for more than one namespace, but not all namespaces, you can provide additional namespaces using the command line flag --additional-namespaces=<namespace1>,<namespace2>,<...>. Make sure you provide appropriate roles and rolebindings in the target namespaces, so the controller can manage the secrets in there.

Community

Click here to sign up to the Kubernetes Slack org.

Related projects

sealed-secrets's People

Contributors

adrien-mollet avatar agarcia-oss avatar ajcann avatar alemorcuq avatar alvneiayu avatar anguslees avatar anzboi avatar bakins avatar bors[bot] avatar c-knowles avatar chrisharm avatar davidkarlsen avatar dependabot[bot] avatar hamza3202 avatar hezhizhen avatar jenecomprendpas avatar jsoref avatar kamilpp avatar karlskewes avatar kvandenhoute avatar lapeyus avatar mashail avatar mkmik avatar rytswd avatar sullerandras avatar tewfik-ghariani avatar theurichde avatar vibioh avatar vivescere avatar wjam avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sealed-secrets's Issues

The ThirdPartyResourceData "" is invalid: metadata.name: Required value: name or generateName is required

I'm trying to use sealed-secret v0.3.1 on minikube v0.20.0 with OSX Sierra

I installed it using README.md instrucctions

+ release=0.3.1
++ go env GOOS
+ GOOS=darwin
++ go env GOARCH
+ GOARCH=amd64
+ wget https://github.com/bitnami/sealed-secrets/releases/download/v0.3.1/kubeseal-darwin-amd64
--2017-07-18 13:29:36--  https://github.com/bitnami/sealed-secrets/releases/download/v0.3.1/kubeseal-darwin-amd64
Resolving github.com... 192.30.253.112, 192.30.253.113
Connecting to github.com|192.30.253.112|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://github-production-release-asset-2e65be.s3.amazonaws.com/92702519/ee64c40c-6650-11e7-855f-ca729a8770a3?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20170718%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20170718T112936Z&X-Amz-Expires=300&X-Amz-Signature=4171846265a90752b458a9989910c5285a2e824d0205b9af0009b80a8a66d4d9&X-Amz-SignedHeaders=host&actor_id=0&response-content-disposition=attachment%3B%20filename%3Dkubeseal-darwin-amd64&response-content-type=application%2Foctet-stream [following]
--2017-07-18 13:29:36--  https://github-production-release-asset-2e65be.s3.amazonaws.com/92702519/ee64c40c-6650-11e7-855f-ca729a8770a3?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20170718%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20170718T112936Z&X-Amz-Expires=300&X-Amz-Signature=4171846265a90752b458a9989910c5285a2e824d0205b9af0009b80a8a66d4d9&X-Amz-SignedHeaders=host&actor_id=0&response-content-disposition=attachment%3B%20filename%3Dkubeseal-darwin-amd64&response-content-type=application%2Foctet-stream
Resolving github-production-release-asset-2e65be.s3.amazonaws.com... 54.231.115.11
Connecting to github-production-release-asset-2e65be.s3.amazonaws.com|54.231.115.11|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 38325968 (37M) [application/octet-stream]
Saving to: โ€˜kubeseal-darwin-amd64โ€™

kubeseal-darwin-amd64                         100%[==============================================================================================>]  36.55M  8.88MB/s    in 5.4s

2017-07-18 13:29:43 (6.74 MB/s) - โ€˜kubeseal-darwin-amd64โ€™ saved [38325968/38325968]

+ sudo install -m 755 kubeseal-darwin-amd64 /usr/local/bin/kubeseal
Password:
+ kubectl create -f https://github.com/bitnami/sealed-secrets/releases/download/v0.3.1/controller.yaml
deployment "sealed-secrets-controller" created
service "sealed-secrets-controller" created
thirdpartyresource "sealed-secret.bitnami.com" created
rolebinding "sealed-secrets-controller" created
role "sealed-secrets-key-admin" created
clusterrolebinding "sealed-secrets-controller" created
clusterrole "secrets-unsealer" created
serviceaccount "sealed-secrets-controller" created

I created a simple JSON file:

{
  "version": "v0.3.1"
}

Then, I encrypted it using kubeseal:

 kubeseal < file.json  > sealed-secret.json

The recently created sealed-secrets.json file renders like this:

{
  "kind": "SealedSecret",
  "apiVersion": "bitnami.com/v1alpha1",
  "metadata": {
    "namespace": "default",
    "creationTimestamp": null
  },
  "spec": {
    "data": "AgAsE+U1LXfhDDFfA/aK7+fCo6ChFV/hAxxifSSbKME3TbTp+glYK0j4G4EIHwGzsFxSXus/ERBAUpQieHLkhVOSuvWLOvuinlmyeBzDxYBvxm2ZI+jtrscPi+3sbXbtFgPB+lQTEM9dbZooDphUX/Ma5sGavTtB1FSXrqjOJjsqeHOhR2sWPEm5nbRbMUjy8iJh7A6ZN4IJ5bNcdhJnsMLdgqxxsGu2CBdlD38z5RANKhDvN65nywzH9tu2aXdrS4wwH+FQeo8/UegBMTSF6eAJPVhwCoZ9x4be9++0CvPqFruorjbR8O1MRBIqQkzRjP6RJn422VvIzCXAjijwO5cUnb2Amw3e9zU5fD7eujWeR+wVR/nTL3+3tH7nzRXMxYB2AZ89qsW4svsNdkAgK2/MlcZzkQUvQvSDjLrjxHvQrkbxLuU+gg+BTbH7NWc8wCp8VPyvw8s2ZBrcS4hEYp7L8JcggjStNWDY2vEi4zerGCe9WJEzDg9scDbhlQOTCTZYp2rryRRhZj+g2aj5GzLwRsfNEzqoFiuwLc8uE4msEMOaSIZ1lct8NgFehsrSCGwc+yeCs7Exn5rwBUDTTkNaBGVzPp7Om0MhnPBjhSq/nFaDtlJejCSOFEE3nxbplaJzEsgM5I3B6Z3VJwlAI8qHChmCGC0MuwuvOtAO8woBEV9jlXIaqoy3J891H30C1EJter5MmEB/MXYWnWKAElOhIthpWjtEJ/sFnGCnbSMOLGafrEideNkSlPukl9oxEkICteulsMTp1srqtDOHYoz/+wXzvOJP2/6DtaxjzlByBw60o0XWVDoJnrzez9vu+Tk="
  }
}

But, when I try to create the resulting resource on K8s....

kubectl create -f sealed-secret.json
The ThirdPartyResourceData "" is invalid: metadata.name: Required value: name or generateName is required

So, I added metadata.name field, like this:

... skipped ... 
 "metadata": {
    "name": "arandomname",
    "namespace": "default",
    "creationTimestamp": null
  },
... skipped ...

And finally it works.

Applying/Creating sealed secrets failure

Hi everyone,

Just ran into this issue on k8s v1.9.0. This is a fresh kops instalation of k8s with RBAC enabled. I'm creating sealed secrets from an yaml file. While trying to apply the json sealed secrets file i get:

validation failure list:
spec.data in body should match '^[^A-Za-z0-9+/=]*$'

Tried with --validate=false, but i get the same result as above.
If I apply the yaml file only, it goes through (of course it's not a sealed secret anymore)

As a reference, the yaml file contents below:

apiVersion: v1
kind: Secret
metadata:
  name: test
type: Opaque
data:
  SECRET: U0VDUkVU

Kubectl version

$ kubectl version
Client Version: version.Info{Major:"1", Minor:"9", GitVersion:"v1.9.0", GitCommit:"925c127ec6b946659ad0fd596fa959be43f0cc05", GitTreeState:"clean", BuildDate:"2017-12-15T21:07:38Z", GoVersion:"go1.9.2", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"9", GitVersion:"v1.9.0", GitCommit:"925c127ec6b946659ad0fd596fa959be43f0cc05", GitTreeState:"clean", BuildDate:"2017-12-15T20:55:30Z", GoVersion:"go1.9.2", Compiler:"gc", Platform:"linux/amd64"}

Any ideas?

Periodic loss of secrets

This is mostly a question, maybe a bug report. The question being: How does the controller interact with secrets already created that have an owner reference to the Sealed Secrets CRD. My reason for asking which might be a bug report, is that on multiple occasions I've had in use secrets disappear from my clusters after something bad happens to the controller, ie. loss of a node, unexpected deletion of the controller pod, etc. I'm not strictly filing this as a bug because I have zero logs from anything indicating sealed-secrets is the culprit, just a hunch.

ETA on 0.8.0 Release?

Really need the fix in #87, hoping an official release comes down soon. Building from source adds some complication we'd prefer not to go down. Anyone have an ETA?

Command to add/update an existing sealed secret

Now we have per-key encryption, perhaps we could add a command which takes an existing sealed secret plus the details of a new individual key/value and adds/updates it as appropriate. This workflow can happen right now but requires a diff and manual merge.

I'd imagine it could work a bit like from-literal part of the kubectl create secret:
kubectl create secret generic prod-db-secret --from-literal=username=produser

Add/restore openapi schema for CRD

See discussion during PR #73. We had to remove the schema due to upstream k8s limitations that left us with no option to keep the schema and allow an object with arbitrary keys. This issue is to track finding a workaround and/or upstream fix that allows us to have key/value objects and a CRD schema.

Missing mechanism to rotate keys in the cluster

I don't see it in the documentation: is there a way to rotate keys in the cluster, so that more than one keypair is supported simultaneously? By the encoding being used in the secret, it doesn't seem like it's possible.

It should be possible to rotate keys, supporting multiple keys, potentially flagging Secret objects that are using an "old" key so they can be updated to a newer key. Having an expiration period, and metrics exposed for number of secret objects using old key(s) and time left for a key to expire would also be helpful to make it possible to alert based on expiring keys, similar to a capacity alert for storage.

Invalid field resourceName in controller.yaml

The sealed-secrets-key-admin Role has resourceName instead of resourceNames in its rules so fails on kubectl create -f controller.yaml with:

error validating "controller.yaml": error validating data: found invalid field resourceName for v1beta1.PolicyRule; if you choose to ignore these errors, turn validation off with --validate=false

ksonnet-seal should fetch certificate automatically

Currently ksonnet-seal requires you to fetch the certificate manually, and currently it is only exposed in the controller logs at startup (or by reading the root Secret object directly!).

"Better" probably involves adding an HTTP-accessible endpoint that serves the certificate, and fetching it automatically at runtime in ksonnet-seal.

can't deploy `controller.jsonnet`

So, I tried jsonnet to generate json from controller.jsonnet. Then kubectl create -f has error

$ jsonnet controller.jsonnet > controller.json
$ kubectl create -f controller.json 
error: unable to decode "controller.json": Object 'Kind' is missing in

cc/ @anguslees

Namespace arg apparently ignored

~/tmp$ kubectl create secret generic mysecret --dry-run --from-literal=foo=bar -o json >mysecret.json
~/tmp$ kubeseal <mysecret.json | grep namespace
    "namespace": "mnelson",
~/tmp$ kubeseal --namespace=foo <mysecret.json | grep namespace
    "namespace": "mnelson",
~/tmp$ kubeseal --namespace=toolchain-web <mysecret.json | grep namespace
    "namespace": "mnelson",

It works fine if I manually edit mysecret.json and add the namespace metadata:

~/tmp$ cat mysecret.json 
{
    "kind": "Secret",
    "apiVersion": "v1",
    "metadata": {
        "name": "mysecret",
        "creationTimestamp": null,
        "namespace": "foo"
    },
    "data": {
        "foo": "YmFy"
    }
}
~/tmp$ kubeseal <mysecret.json | grep namespace
    "namespace": "foo",

This makes the secret creation a little more fiddly, as unless I'm missing something, the namespace can't be included in the initial kubectl create command:

~/tmp$ kubectl create secret generic mysecret --dry-run --from-literal=foo=bar -o json --namespace foo | grep namespace
~/tmp$ 

EKS authentication requires newer client-go

Getting the following error when trying to use kubeseal with EKS.

$ kubeseal --fetch-cert
panic: Error fetching certificate: services "http:sealed-secrets-controller:" is forbidden: User "system:anonymous" cannot get services/proxy in the namespace "kube-system"

I am able to interact with the cluster normally using kubectl.

$ kubectl get pods -n kube-system
NAME                                         READY     STATUS    RESTARTS   AGE
aws-node-68vfm                               1/1       Running   0          6d
aws-node-hl9ww                               1/1       Running   1          6d
aws-node-nhkwb                               1/1       Running   1          6d
fluentd-78l2j                                1/1       Running   0          6d
fluentd-kfdn4                                1/1       Running   0          6d
fluentd-wfj48                                1/1       Running   0          6d
kube-dns-7cc87d595-fbmxq                     3/3       Running   0          6d
kube-proxy-fkpsw                             1/1       Running   0          6d
kube-proxy-lbwvz                             1/1       Running   0          6d
kube-proxy-qqs2p                             1/1       Running   0          6d
sealed-secrets-controller-5bc5488bb4-79blg   1/1       Running   0          22m

Garbage collection errors when deleting the secret before sealedsecret

Steps to reproduce:

  • Create a sealedsecret in the cluster
  • kubectl delete the secret (not the sealed one)
  • kubectl delete the sealedsecret

The controller will keep trying to delete the associate secret as part of the garbage collection, but will err continuously as the secret was already deleted:

2017/09/18 09:23:56 Updating default/mysecret
2017/09/18 09:33:16 SealedSecret default/mysecret has gone, deleting Secret
2017/09/18 09:33:16 Error updating default/mysecret, will retry: secrets "mysecret" not found
2017/09/18 09:33:16 SealedSecret default/mysecret has gone, deleting Secret
2017/09/18 09:33:16 Error updating default/mysecret, will retry: secrets "mysecret" not found
2017/09/18 09:33:16 SealedSecret default/mysecret has gone, deleting Secret
2017/09/18 09:33:16 Error updating default/mysecret, will retry: secrets "mysecret" not found
2017/09/18 09:33:16 SealedSecret default/mysecret has gone, deleting Secret
2017/09/18 09:33:16 Error updating default/mysecret, will retry: secrets "mysecret" not found
2017/09/18 09:33:16 SealedSecret default/mysecret has gone, deleting Secret
2017/09/18 09:33:16 Error updating default/mysecret, will retry: secrets "mysecret" not found
2017/09/18 09:33:16 SealedSecret default/mysecret has gone, deleting Secret
2017/09/18 09:33:16 Error updating default/mysecret, giving up: secrets "mysecret" not found
E0918 09:33:16.488086       1 controller.go:162] secrets "mysecret" not found

kubeseal should make it easier to make the public key available offline

The idea is that the public key is available for use offline, and this enables all sorts of interesting asymmetric workflows. It's certainly possible to do all this now, but the current implementation "hides" those possibilities: kubeseal by default just re-fetches the key at runtime, requiring appropriate privileges and access.

kubeseal should have an obvious --fetch-cert option that dumps the public key to stdout - and some clear docs/examples showing how to use that file with --cert again for offline use.

Release does not include trp/crd manifests?

The following link obtained from the instructions in the readme returns a 404. Does the release include these files?

https://github.com/bitnami/sealed-secrets/releases/download/v0.4.0/sealedsecret-crd.yaml

manifest fails on Azure ("attempt to grant extra privileges")

After fixing the error mentioned in #16 I get the following error:

Error from server (Forbidden): error when creating "controller.yaml": roles.rbac.authorization.k8s.io "sealed-secrets-key-admin" is forbidden: attempt to grant extra privileges: [{[get] [] [secrets] [sealed-secrets-key] []} {[create] [] [secrets] [] []}] user=&{client  [system:authenticated] map[]} ownerrules=[] ruleResolutionErrors=[]
Error from server (Forbidden): error when creating "controller.yaml": clusterroles.rbac.authorization.k8s.io "secrets-unsealer" is forbidden: attempt to grant extra privileges: [{[get] [ksonnet.io] [sealedsecrets] [] []} {[list] [ksonnet.io] [sealedsecrets] [] []} {[watch] [ksonnet.io] [sealedsecrets] [] []} {[create] [] [secrets] [] []} {[update] [] [secrets] [] []} {[delete] [] [secrets] [] []}] user=&{client  [system:authenticated] map[]} ownerrules=[] ruleResolutionErrors=[]

I have just created a fresh cluster on azure, via acs-engine running on k8s 1.6.6 - not quite sure where the issues is.

Allow a user to know whether the controller actually unsealed a secret

Some users can create/read the sealedsecrets resource kind but they cannot list the secrets on the api server nor tail the logs of the sealed secrets controller (e.g. because of RBAC); it's currently impossible to know whether the secret has been successfully unsealed.

Possible ideas: events and/or a "status" section (like pods, deployments etc)

status:
  secret:
    created: True

(I was also wondering about the condition objects but it seems they might be going away kubernetes/kubernetes#7856)

Documentation needs to list cipher and bitlength

This looks like an awesome project but there's no technical detail about the strength of the cipher or what cipher is being used.

I'd love to add this to the list of options when presenting but there's no detail and I don't want to dig through the code to find the answer to this kinda important question!

Support for AWS KMS

This is a feature request for KMS support like that of sops. Extracted from #63.

  1. Get key rotation for almost free.
  2. For those who wish to centralise their root keys and access to KMS + IAM rather than base it off those with access to kube-system secrets.
  3. KMS together with IAM users/roles still provide the access control needed to restrict decryption to the cluster, the cluster controllers, admin users.

kubeseal: Add better input validation

See #34. In particular:

  • it makes no sense to have a missing/empty metadata.name, this should be an error
  • an empty data almost certainly indicates a misunderstanding in how to use the tool (but is possibly valid), so should trigger an explanatory warning.

`type` property is removed between SealedSecret and Secret

I have a SealedSecret like this

apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  creationTimestamp: null
  name: ceph-admin
  namespace: ns
  labels:
    component: ceph-secrets
type:
  kubernetes.io/rbd
spec:
  encryptedData:
    key: 1234

But the type: kubernetes.io/rbd argument is not passed forward to the Secret object

Missing annotations & labels

When creating a new sealed-secret based on a existing secret.yaml labels and annotations are lost.

This is very important, as some labels and annotations are related to helm lifecycle.

Add support for stringData

The Secret spec allows for non-binary data to be provided in the stringData key as a raw string, rather than base64-encoded, for convenience. Most of my secrets are just plain strings, so it'd be awesome to add support for this to kubeseal.

Currently:

  • with no data key kubeseal panics:
$ cat secret-no-data.yaml
apiVersion: v1
kind: Secret
metadata:
  name: string-data-secret
  namespace: default
stringData:
  foo: baz

$ kubeseal < secret-no-data.yaml
panic: Secret.data is empty in input Secret, assuming this is an error and aborting

goroutine 1 [running]:
main.main()
	/Users/travis/gopath/src/github.com/bitnami-labs/sealed-secrets/cmd/kubeseal/main.go:233 +0x2a8
  • with a data key kubeseal creates a SealedSecret that decrypts to the key-value pair foo: bar
$ cat secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: string-data-secret
  namespace: default
data:
  foo: YmFy # bar
stringData:
  foo: baz

$ kubeseal < secret.yaml | kubectl apply -f -
sealedsecret "string-data-secret" created

$ kubectl get secret string-data-secret -o jsonpath="{['data']['foo"]}" | base64 -D
bar

In both cases I would expect it to create a SealedSecret that decrypts to the key-value pair foo: baz.

Windows build of kubeseal CLI

I use Windows, and have been using the kubeseal tool by using the Linux build with WSL, but it would be nice if a native Windows binary was available.

Support docker-registry secret type

I'm trying to seal a docker registry secret, but when the controller unseals the secret it is always of type: Opaque.

Sample:

$ kubectl create secret docker-registry my-registry \
  --docker-server=myserver.example.com \
  --docker-username=user \
  --docker-password=password \
  [email protected] \
  --output json --dry-run | kubeseal > sealed.json
$ kubectl apply -f sealed.json
$ kubectl get secret my-registry -o yaml
apiVersion: v1
data:
  .dockerconfigjson: [snip]
kind: Secret
metadata:
  creationTimestamp: 2018-04-09T20:52:03Z
  name: my-registry
  namespace: default
  ownerReferences:
  - apiVersion: bitnami.com/v1alpha1
    controller: true
    kind: SealedSecret
    name: my-registry
    uid: db17d8cf-3c37-11e8-98fb-0a58ac1f010d
  resourceVersion: "3425531"
  selfLink: /api/v1/namespaces/default/secrets/my-registry
  uid: db1c68ac-3c37-11e8-98fb-0a58ac1f010d
type: Opaque

Expected result: The secret's type is kubernetes.io/dockerconfigjson.

Actual result: The secret type is Opaque.

Cannot build on go 1.9.3

Running a go get github.com/bitnami-labs/sealed-secrets/cmd/kubeseal results in the following output:

# github.com/bitnami/sealed-secrets/cmd/kubeseal
./main.go:179:44: cannot use codecs (type "github.com/bitnami/sealed-secrets/vendor/k8s.io/apimachinery/pkg/runtime/serializer".CodecFactory) as type "github.com/bitnami-labs/sealed-secrets/vendor/k8s.io/apimachinery/pkg/runtime/serializer".CodecFactory in argument to v1alpha1.NewSealedSecret
./main.go:179:44: cannot use secret (type *"github.com/bitnami/sealed-secrets/vendor/k8s.io/api/core/v1".Secret) as type *"github.com/bitnami-labs/sealed-secrets/vendor/k8s.io/api/core/v1".Secret in argument to v1alpha1.NewSealedSecret
./main.go:194:33: cannot use v1alpha1.SchemeGroupVersion (type "github.com/bitnami-labs/sealed-secrets/vendor/k8s.io/apimachinery/pkg/runtime/schema".GroupVersion) as type "github.com/bitnami/sealed-secrets/vendor/k8s.io/apimachinery/pkg/runtime".GroupVersioner in argument to prettyEncoder:
	"github.com/bitnami-labs/sealed-secrets/vendor/k8s.io/apimachinery/pkg/runtime/schema".GroupVersion does not implement "github.com/bitnami/sealed-secrets/vendor/k8s.io/apimachinery/pkg/runtime".GroupVersioner (wrong type for KindForGroupVersionKinds method)
		have KindForGroupVersionKinds([]"github.com/bitnami-labs/sealed-secrets/vendor/k8s.io/apimachinery/pkg/runtime/schema".GroupVersionKind) ("github.com/bitnami-labs/sealed-secrets/vendor/k8s.io/apimachinery/pkg/runtime/schema".GroupVersionKind, bool)
		want KindForGroupVersionKinds([]"github.com/bitnami/sealed-secrets/vendor/k8s.io/apimachinery/pkg/runtime/schema".GroupVersionKind) ("github.com/bitnami/sealed-secrets/vendor/k8s.io/apimachinery/pkg/runtime/schema".GroupVersionKind, bool)
./main.go:199:28: cannot use ssecret (type *v1alpha1.SealedSecret) as type "github.com/bitnami/sealed-secrets/vendor/k8s.io/apimachinery/pkg/runtime".Object in argument to "github.com/bitnami/sealed-secrets/vendor/k8s.io/apimachinery/pkg/runtime".Encode:
	*v1alpha1.SealedSecret does not implement "github.com/bitnami/sealed-secrets/vendor/k8s.io/apimachinery/pkg/runtime".Object (wrong type for DeepCopyObject method)
		have DeepCopyObject() "github.com/bitnami-labs/sealed-secrets/vendor/k8s.io/apimachinery/pkg/runtime".Object
		want DeepCopyObject() "github.com/bitnami/sealed-secrets/vendor/k8s.io/apimachinery/pkg/runtime".Object

I am using go 1.9.3 on macOS 10.13.2. Running a git bisect over the last few recent commits while points at commit d086031bdd8657ff04ebc5f4f5d9ef1048da7015 as the first unbuildable commit.

Looks like some of the rename during the move changed some things?

Controller fails to create unsealed secret if sealed secret created with certain metadata

To reproduce:

  1. Get an existing k8s secret as a local json file
  2. Run kubeseal as per the README
  3. Remove the original secret from k8s and create the sealed secret

Expected result:

  • The corresponding secret is created by the sealed secret controller

Actual result:

  • The secret is never created, checking the logs, the controller fails with Error updating foo/foo-secrets, giving up: resourceVersion may not be set on objects to be created

Easy to work around by removing resourceVersion (and uuid, selflink, creationTimestamp) from the metadata after step 1 above.

Encrypt each secret separately

Just found this great project today! It looks pretty much exactly what we were considering save for a few details. Would like to contribute some extras, just had a few questions first.

We were likely going to utilize sops for the main portion of it with a controller or initializer wrapped around it. In terms of differences, there's a few things I'd be interested to gain. Mostly encrypting each secret separately to make diffs meaningful and conflicts easier to resolve. KMS support and CLI editing for those with access to the key might be good too although likely separate issues.

Do not add default namespace if there is none in source file?

This is probably a bit related to #44

Input file:

{
    "kind": "Secret",
    "apiVersion": "v1",
    "metadata": {
        "name": "credentials",
        "creationTimestamp": null
    },
    "data": {
        "password": "whatever",
        "username": "whatever"
    },
    "type": "Opaque"
}

Output from kubeseal:

{
  "kind": "SealedSecret",
  "apiVersion": "bitnami.com/v1alpha1",
  "metadata": {
    "name": "credentials",
    "namespace": "default",
    "creationTimestamp": null
  },
  "spec": {
    "data": <snip>
  }
}

Is there a reason why "namespace": "default" was added, though there was none in source file?

Unable to use kubeseal offline with public certificate

Hi,

I have a minikube kubernetes cluster.
I installed kubeseal and yaml necesary to use kubeseal.
From my local, I was able to download the certificate (kubeseal --fetch-cert >mycert.pem)
However, when I try to run kubeseal --cert mycert.pem < mysecret.json > encrypted.json in other machine which has not configured the minikube cluster, the kubeseal sais to me that it has not the right configuration file (it spect the .kube/* files to exists).
Would be posible to use kubeseal offline without kube configuration, only with the publick key and the secret json or yaml file?

Best regards,

Juanjo.

Move out of kube-system namespace

When running on GKE, nothing other than core Kubernetes components can run in the kube-system namespace (GKE throws errors).

Most likely it should be possible to run in any namespace. It looks like kubeseal has a --namespace argument, but from brief testing it looks like this is used for the namespace of the secret, rather than for finding the sealed-secrets-controller?

Import secrets from file using API

Hi I would like to import a SealedSecret from a file. I can do this right now with kubectl apply -f, but I need to import it via the API since the kubectl binary wouldn't be available in my execution context.

In the integration tests I saw plaintext being encrypted as a new SealedSecret using a PublicKey - https://github.com/bitnami-labs/sealed-secrets/blob/master/integration/controller_test.go#L85

I would like to import a SealedSecret which was created ahead of time and dumped in a git repo. Does that API exist currently?

Thanks,

Alex

Ability to append values to the secret name within a namespace

We have a use case where we want to be able to append variables to the name of a secret and not sure what might be the best way to deal with it. Looking for ideas first and then can think about whether it's PR appropriate.

When we used plain secrets, we appended the name of the secret with a version because we deploy a lot of feature branches and there's potential for changes or conflicts in the secrets. That gets done automatically by our deploy mechanism, so no need to manually update branches etc and our users never get conflicts with existing secrets. In the places we used sealed-secrets, we turned that versioning off because the name is encrypted into the data values - it needs that to ensure that one cannot just copy/paste the secret data from another sealed secret into your own one in the same cluster. So now we have two slightly different systems, we'd like to start using sealed-secrets everywhere but without a way to append variables to the name we'd need to rely on users to always keep backwards compatibility in secrets across all branches of an app.

I was wondering if/how it could be possible to deal with this situation. My idea was define the name as a pattern with substitutions and allow the substitutions to be passed in with the sealed-secret, maybe as separate labels. That idea might be quite powerful but also puts more of the burden of knowing if it's really secure on the shoulders of the user, so perhaps not a great way to go.

@anguslees any thoughts on this one?

idempotent command

i am trying to use Sealed-Secrets as part of my CI/CD flow, but it requires extra logic to run different commands depending on if the secret is already installed or not.
Ideally same command should take care of it.

Questioning wisdom of making ciphertexts public.

This looks like a very convenient way to version control secrets.

However, I question the wisdom of suggesting to users it's safe to make the resulting ciphertext public. From your README:

Encrypt your Secret into a SealedSecret, which is safe to store - even to a public repository.

mysealedsecret.json is safe to upload to github, post to twitter,

This is counter to the principle that ciphertext be restricted to the smallest possible audience, lest a weakness be later discovered in the cipher, or if the keys were to be made public.

At least, I think, it would be responsible to explain this to users and for them to then to weigh up for themselves the tradeoff of risk versus convenience with regard to their particular use-case.

As it is, it seems flippant to suggest users they can "post to twitter" the encrypted secrets (not sure why they would ever want to do this).

RBAC rules are insufficient: Failed to list *v1alpha1.SealedSecret

v0.3.0 release fails in 1.7 cluster:

E0703 13:41:25.346224       6 reflector.go:201] github.com/bitnami/sealed-secrets/cmd/controller/controller.go:126: Failed to list *v1alpha1.SealedSecret: User "system:serviceaccount:kube-system:sealed-secrets-controller" cannot list sealedsecrets.bitnami.com at the cluster scope. (get sealedsecrets.bitnami.com)

Document Cluster wide secret usage

Any chance of some improved documentation or an example? It's not really clear to me how this is supposed to work...

Does the annotation go on the unencrypted or encrypted secret?
How does the controller propagate the secret to other namespaces in the cluster?

I can see you guys have an integration test for it, but I haven't been able to get it working in my cluster.

Upgrade k8s library?

Currently, we have a custom command (like kubeseal) that has a lot of copy pasted code from this repo but we'd like to just use this as a library. Unfortunately, I quickly ran into issues as we need a newer version of the k8s client. k8s client seems to change package layout every release. Any interest in upgrading the k8s client used by sealed-secrets? I'm happy to do the work to make it happen.

Add support for running the controller with replicas>1

We need to ensure that the controller doesn't do the wrong thing with replicas>1, since that can happen during transient events like node/partition recovery, mis-configured upgrades, etc. Replicas>1 is a desirable feature for some HA configurations.

Note that this is just about avoiding breakage. Horizontal scalability (active/active or sharding) is not included in this issue.

Note also this could either be via a lock (as is typically done with other controllers), or via careful auditing of atomic operations and race recovery (sealed-secrets-controller only has very simple side-effects).

kubeseal should not require a `~/.kube/config`

Love the idea of this project, but I encountered a (user?) problem of a non-responsive terminal. On ubuntu with the v0.7.0 kubeseal-linux-amd64.

Documentation:

...
# This is the important bit:
$ kubeseal <mysecret.json >mysealedsecret.json
...

I'm trying to do this offline so I've saved the public key as a pem file.

kubeseal <secret.json >mysealedsecret.json --cert test.pem
panic: invalid configuration: no configuration has been provided

Figuring that the '<' before secret.json might not belong there(?):

kubeseal secret.json >mysealedsecret.json --cert test.pem

This leads to kubeseal not returning anything, just seemingly working in the background. I can type more text, but it doesn't do anything so I just have to close the process. mysealedsecret.json is created, but the size is 0 bytes. (I also tried kubeseal secret.json mysealedsecret.json --cert test.pem with the same result.)

What am I missing here?

add version to cli

kubeseal should provide a version command for debugging. Recently hit an issue that was difficult to debug due to not knowing what version was running. Thanks

Upstream proposal

Hi there, this is just a general question really: have you guys considered proposing sealed secrets as a complemente of the new 1.7 encrypted secrets?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.