Makefile to base64 encode kubernetes secrets

11/28/2017

In Kubernetes, secret resources are base64 encoded. This is an example yaml file from the official documentation:

apiVersion: v1
kind: Secret
metadata:
  name: test-secret
data:
  USERNAME: bXktYXBwCg==
  PASSWORD: YV44KXlcNzw4QUF4YWEoeV54

Where the two pieces of secret data: a username and a password were base64 encoded using:

echo -n 'my-app' | base64
echo -n 'a^8)y\7<8AAxaa(y^x' | base64

The workflow I would like is to have a version of the yaml file with my naked secrets and a Makefile which could produce the base64 encoded version.

This is where I got to before I got stuck:

The input (my-secrets-naked.yaml):

apiVersion: v1
kind: Secret
metadata:
  name: test-secret
data:
  USERNAME: my-app
  PASSWORD: a^8)y\7<8AAxaa(y^x

The Makefile:

base64:
    @echo "Computing base64 of secret values..."
    cat my-secrets-naked.yaml | bash base64_secrets.sh > my-secrets-base64.yaml

The base64_secrets.sh script:

sed -r 's/(\s+[A-Z]\S+:\s*)(.*)/echo "\1$(echo -n "\2" | base64 -w0 )"/e;s/  -//'

The command: make base64

The output (my-secrets-base64.yaml):

apiVersion: v1
kind: Secret
metadata:
  name: test-secret
data:
  USERNAME: bXktYXBw
  PASSWORD: YV44KXkHPDhBQXhhYSh5Xng=

Ideally, I would like the sed inside the Makefile rather than a separate script but I couldn't figure it out. But most importantly the base64 for the PASSWORD is wrong! It breaks for secrets with backslashes in, in this case the \7 causes problems. I can't figure out how to echo the unescaped characters whilst still using the \2 back reference from the preceding sed. (echo -E doesn't work, it takes \2 literally. No luck with printf '%s' \2 either).

I know it seems like a specific question - but a good solution for this could be useful for all Kubernetes users?

If I get this workflow working I intend to extend it so the Makefile produces a 3rd file with the secrets redacted and hashed so safe to be committed in git, whilst still knowing when something changed.


I'm using Ubuntu 16.04, sed (GNU sed) 4.2.2.

-- Tom
bash
kubernetes
makefile
sed

2 Answers

11/28/2017

Consider using the stringData field instead of the data field and you can pass in unencoded value. It will still be stored as data internally and shows as such when queried back.

DESCRIPTION:
Secret holds secret data of a certain type. The total bytes of the values in the Data field must be less than MaxSecretSize bytes.

FIELDS:
   type <string>
     Used to facilitate programmatic handling of secret data.

   apiVersion   <string>
     APIVersion defines the versioned schema of this representation of an
     object. Servers should convert recognized schemas to the latest internal
     value, and may reject unrecognized values. More info:
     http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#resources

   data <object>
     Data contains the secret data. Each key must be a valid DNS_SUBDOMAIN or
     leading dot followed by valid DNS_SUBDOMAIN. The serialized form of the
     secret data is a base64 encoded string, representing the arbitrary (possibly
     non-string) data value here. Described in
     https://tools.ietf.org/html/rfc4648#section-4

   kind <string>
     Kind is a string value representing the REST resource this object
     represents. Servers may infer this from the endpoint the client submits
     requests to. Cannot be updated. In CamelCase. More info:
     http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds

   metadata <Object>
     Standard object's metadata. More info:
     http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata

   stringData   <object>
     stringData allows specifying non-binary secret data in string form. It is
     provided as a write-only convenience method. All keys and values are merged
     into the data field on write, overwriting any existing values. It is never
     output when reading from the API.

I would perhaps suggest using JSON rather than YAML though.

-- Graham Dumpleton
Source: StackOverflow

11/29/2017

you can do this with perl.

cat Makefile
base64:
        @echo "Computing base64 of secret values..."
        cat my-secrets-naked.yaml|perl -MMIME::Base64 -npe 's/^(\s+[A-Z]+:\s+)(.*)./"$1".encode_base64($2)/es;' > my-secrets-base64.yaml

Here is the output:

cat my-secrets-base64.yaml
apiVersion: v1
kind: Secret
metadata:
  name: test-secret
data:
  USERNAME: bXktYXBw
  PASSWORD: YV44KXlcNzw4QUF4YWEoeV54
-- sfgroups
Source: StackOverflow