# Unix to the Rescue

- Link: https://www.agilicus.com/unix-to-the-rescue/
- Published: 2019-04-10T14:57:01+00:00
- Author: Kyle Larose

All the cool kids these days use an operating system based somewhat off [Unix](https://en.wikipedia.org/wiki/Unix).
A core feature of Unix is that [everything is a file](https://en.wikipedia.org/wiki/Everything_is_a_file).“
A file,” you ask? Like a picture? How can a everything be a file?

A file, like anything else in a computer, is at its core a sequence of bits — data.
Programs _read_ or _write_ files by accessing or modifying that sequence. They infer
the meaning of the data from the context in which it was read.

What we typically think of as files is simply data stored on a persistent disk. 
However, since files are just sequences of bits, there is no reason for them to 
be limited to data stored somewhere persistent. They could be just a block of data
in RAM. They could be data read off the wire from the network. They could be anything!
Or, if you design it to be, everything.

Pretty cool! In fact, if we treat everything as a file, it allows us to solve problems
in consistent and simple ways. Take for example a problem I have been toying with–
the problem of Kubernetes [secrets](https://kubernetes.io/docs/concepts/configuration/secret/):

 * I want to expose a secret (a token) to my Kubernetes [pod](https://kubernetes.io/docs/concepts/workloads/pods/pod/).
 * Possession of the token is sufficient to gain access to a protected system.
 * Only the pod I’m creating should have access to the secret.
 * The pod accesses the secret (as a file!) by mounting it.
 * I may want to change the secret in the future.
 * To decrease the chance of the token leaking, I don’t want the token or the secret
   dumped to the screen or written to the disk.

Some might use [sops](https://github.com/mozilla/sops) for static secrets (as we
showed in [Safely Secure Secrets: a SOPS plugin for kustomize](https://www.agilicus.com/safely-secure-secrets-a-sops-plugin-for-kustomize/)),
but I have a nifty API to generate new ones on demand. I want to use that with as
little fuss as possible. So, I need a strategy to create my secret using that API
without violating the above constraints.

Kubernetes provides a few methods to create secrets. The one most comfortable for
those who’ve used Kubernetes for a while is likely to be creating the secret from
a yaml document, probably stored on disk. That’s easy, but I’d have to jump through
some hoops to satisfy my requirement that I don’t dump the token to the screen or
write it to disk.

Another method provided by Kubernetes uses _kubectl_ — a CLI for tickling the Kubernetes
API — directly. You can create secrets with kubectl by reading the value from a 
file, or by passing the value on the command line. For example:

    ```wp-block-code
    kubectl create secret -n secret-place generic token \
      --from-literal=token-file=secret-value
    ```

The above command creates a secret named _token_ in the namespace _secret-place_.
When mounted, it will provide a file named _token-file_ with the literal value “
secret-value”. This is great, except for the fact that I’d need to copy and paste
the token onto the command line. Or, I _could_ simply pass it in as the result of
a sub-shell. Let’s try that.

Note for that this example I create two functions in bash which return different
values. In reality, I would probably use [curl](https://curl.haxx.se/) or some SDK
to get the token.

    ```wp-block-code
    $ kubectl create secret -n secret-place generic token \
      --from-literal=token-value=$(get_secret)
    secret/token created
    $ kubectl create secret -n secret-place generic token \
      --from-literal=token-file=$(get_new_secret)
    Error from server (AlreadyExists): secrets "token" already exists
    ```

Oh. I can’t create the secret twice. _sadface_. I refuse to be defeated, though.
Valiantly, I check the help for the command, which mentions the following two parameters.

    ```wp-block-code
          --dry-run=false: If true, only print the object that would 
    be sent, without sending it.
      -o, --output='': Output format. One of:
    json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-file.
    ```

Passing _–dry-run-false_ will give me the secret without creating it. Passing _–
o=yaml_ will output the secret to the console in a format that _kubectl apply_ will
accept. _kubectl apply_ allows updates to resources! I may just have my solution.
Here is where everything being a file shines.

_stdin_ is the name given to the file in which a program reads its input. For example,
when you type into your shell, your shell is reading the characters you write from
the file stdin. Kubectl can read input to _kubectl apply_ from stdin by telling 
it to read from a special file named _–_. So, let’s see how it all works!

    ```wp-block-code
    $ kubectl create secret -n secret-place generic token \
      --from-literal=token-file=$(get_secret) --dry-run=true -o=yaml | kubectl apply -f -
    secret/token created
    $ kubectl create secret -n secret-place generic token \
      --from-literal=token-file=$(get_new_secret) --dry-run=true \
      -o=yaml | kubectl apply -f -
    secret/token configured
    ```

Great success! You may notice that I used another Unix technique, _pipes_, to pass
the information from the output of _create secret_ to the input of _apply_ without
the secret ever being displayed or written to a file. This is a very powerful technique
that likely deserves its own post. That said, I can improve my commands even further
by making use of pipes end-to-end.

    ```wp-block-code
    $ get_secret | kubectl create secret -n secret-place \
      generic token --from-file=token-file=/dev/stdin  \
      --dry-run=true -o=yaml | kubectl apply -f -
    secret/token created
    $ get_new_secret | kubectl create secret -n secret-place \
      generic token --from-file=token-file=/dev/stdin \
      --dry-run=true  -o=yaml | kubectl apply -f -
    secret/token configured
    ```

How does it improve things? Well, besides using pipes, the contents of the secret
passed on the command line may be seen by inspecting the output of the command (
e.g. via _ps_, _/proc/$pid/cmdline_, etc.). Using pipes lets us pass the data end-
to-end through a chain of inputs and outputs without it ever being leaked.

Note that in the example I have changed _–from-literal_ to _–from-file_: I have 
instructed kubectl to read _stdin_ to get the contents of the secret. By making 
use of pipelines, and yet again treating the standard input to the program as a 
file, I can update my secrets with a simple chain of commands:

 1. Get the value.
 2. Write the value to stdout.
 3. Read the value from stdin.
 4. Output the value into a secret document yaml format.
 5. Apply the value to the kubernetes API.

This achieves all my goals, while being quite simple.

I’m happy. Thanks, Unix!
