Home

Awesome

krmfnsops

stability-beta

krmfnsops is a kustomize plugin that you can use to decrypt resources encrypted with SOPS. It uses the Exec KRM functions mechanism that is currently cooking both in Kustomize and Kpt.

As it embeds SOPS, you don't need to install SOPS in addition to krmfnsops.

You can use it either as a Generator or as a Transformer (see below). To obtain the expected results, you need to run kustomize with the following flags:

> kustomize build . --enable-alpha-plugins --enable-exec

Use case 1/4: Configuration as a Generator

You create a sops-generator.yaml resource for the generator:

# sops-generator.yaml
apiVersion: kaweezle
# suffix Generator
kind: SecretsGenerator
metadata:
  name: whatever
  annotations:
    config.kubernetes.io/function: |
      exec:
        path: ../dist/krmfnsops_linux_amd64/krmfnsops
spec:
  files:
    - ./secret.enc.yaml

The files to decrypt are specified in spec/files. Then reference the generator in the kustomization.yaml configuration file:

# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

generators:
  - sops-generator.yaml

Use case 2/4: Configuration as a Transformer

CAUTION Sops computes a Message authentication code from the source file and checks it after decrypt in order to verify that the encrypted file has not been modified. However, the transformer doesn't receive the original source, but an object representing each resource inside it, modified by kustomize for processing purposes. In consequence, the MAC verification is disabled in transformer mode.

The following is the configuration for the function in Transformer mode:

# sops-transformer.yaml
apiVersion: kaweezle
# suffix Transformer
kind: SecretsTransformer
metadata:
  name: whatever
  annotations:
    config.kubernetes.io/function: |
      exec:
        path: ../dist/krmfnsops_linux_amd64/krmfnsops

# Note that there is no spec

And configure it in your kustomization.yaml:

# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

# Add the encrypted resources
resources:
  - ./secret.yaml

transformers:
  - sops-transformer.yaml

Use case 3/4: Configuration as an In place Generator

In this use case, the generator configuration is the actual resource that needs to be added. Let's imagine that you have this secret in your kustomization:

# secret.yaml
apiVersion: v1
kind: Secret
metadata:
  labels:
    argocd.argoproj.io/secret-type: repository
  name: private-repo
  namespace: argocd
stringData:
  password: my-password
  type: git
  url: https://github.com/argoproj/private-repo
  username: my-username

You want it encrypted. For that, you add the krmfnsops function annotation:

annotations:
  config.kubernetes.io/function: |
    exec:
      path: krmfnsops

and encrypt it with sops:

> sops -e -i secret.yaml

You obtain an encrypted version of the secret that can be added as is as a generator in your kustomization:

# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

generators:
  - secret.yaml

The command:

> kustomize build --enable-alpha-plugins --enable-exec .

will output the unencrypted secret.

Use case 4/4: Use an encrypted generator as a source for replacements

In this use case, we use an encrypted generator that contains all our secrets:

# secrets.yaml
apiVersion: krmfnsops.kaweezle.com/v1alpha1
kind: Secrets
metadata:
  name: all-my-secrets
  annotations:
    # this annotation will keep the resource out of the output
    krmfnsops.kaweezle.com/keep-local-config: "true"
    # this annotation will perform decryption for us
    config.kubernetes.io/function: |
      exec:
        path: ../../krmfnsops
data:
  github:
    password: gh_<github_token>
    application_secret: <secret>
  ovh:
    consumer_key: <secret>
    application_secret: <secret>

Note that it contains the function annotation, and a new annotation krmfnsops.kaweezle.com/keep-local-config. This annotation will make the resource available in the kustomization pipeline but will keep it out of the output. This will allow us to use the data of the resource as a source for replacements.

We encrypt our secrets with the following command:

> sops -e -i secret.yaml

Now we can have a secret in our kustomization with a fake password:

# secret.yaml
apiVersion: v1
kind: Secret
metadata:
  labels:
    argocd.argoproj.io/secret-type: repository
  name: private-repo
stringData:
  password: this-is-a-fake-password
  type: git
  url: https://github.com/argoproj/private-repo
  username: my-username

A make the kustomization replace the fake password with the unencrypted one:

# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

# Add the faked resource
resources:
  - secret.yaml

# Add our encypted secrets
generators:
  - secrets.yaml

# Replace the fake password with te real one
replacements:
  - source:
      kind: Secrets
      fieldPath: data.github.password
    targets:
      - select:
          kind: Secret
          name: private-repo
        fieldPaths:
          - stringData.password

Now the kustomization gives:

❯ kustomize build --enable-alpha-plugins --enable-exec
apiVersion: v1
kind: Secret
metadata:
  labels:
    argocd.argoproj.io/secret-type: repository
  name: private-repo
stringData:
  password: gh_<github_token>
  type: git
  url: https://github.com/argoproj/private-repo
  username: my-username

The files are available in examples/secrets.

Installation

With each Release, we provide binaries for most platforms as well as Alpine based packages. Typically, you would install it on linux with the following command:

> KRMFNSOPS_VERSION="v0.1.5"
> curl -sLo /usr/local/bin/krmfnsops https://github.com/kaweezle/krmfnsops/releases/download/${KRMFNSOPS_VERSION}/krmfnsops_${KRMFNSOPS_VERSION}_linux_amd64

Argo CD integration

To use krmfnsops with Argo CD, you need to:

To add krmfnsops on argo-repo-server, the Argo CD documentation provides different methods to make custom tools available.

If you get serious about Argo CD, you will probably end up cooking your own image. This docker file shows how to use the above installation instructions in your image. To summarize:

FROM argoproj/argocd:latest

ARG KRMFNSOPS_VERSION=v0.1.5

# Switch to root for the ability to perform install
USER root

# Install tools
RUN apt-get update && \
    apt-get install -y curl && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/* && \
    curl -sLo /usr/local/bin/krmfnsops https://github.com/kaweezle/krmfnsops/releases/download/${KRMFNSOPS_VERSION}/krmfnsops_${KRMFNSOPS_VERSION}_linux_amd64

USER argocd

For the other points, we assume in the following that your Argo CD deployment occurs through kustomize. Here is the kustomization file layout:

.
├── argocd-cm.yaml
├── argocd-repo-server-patch.yaml
├── kustomization.yaml
├── secrets.yaml
└── sops-generator.yaml

The base kustomization.yaml contains:

# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: argocd

resources:
  # The standard Argo CD installation
  - https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

generators:
  # This generator will generate the secret containing our AGE key
  - sops-generator.yaml

# Kustomization of the Argo CD standard installation
patches:
  - path: argocd-repo-server-patch.yaml
    target:
      kind: Deployment
      name: argocd-repo-server
  - path: argocd-cm.yaml

The argocd-cm.yaml patch contains the configuration needed for the parameters:

# argocd-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
data:
  # Options to enable exec plugins (krmfnsops).
  kustomize.buildOptions: "--enable-alpha-plugins --enable-exec"
  ...

The sops-generator.yaml file will allow decrypting our secrets on deployment:

# sops-generator.yaml
apiVersion: iknite.krm.kaweezle.com/v1beta1
kind: SopsGenerator
metadata:
  name: secrets
  annotations:
    config.kubernetes.io/function: |
      exec:
        path: krmfnsops
spec:
  files:
    - ./secrets.yaml

The secrets.yaml file is a SOPS encrypted file containing all the secrets needed by Argo CD, including the key used by krmfnsops on the server.

We will use here an Age key as an example. The key is generated and exported as a base64 payload with the following:

> mkdir -p ~/.config/sops/age && age-keygen -o ~/.config/sops/age/keys.txt
> cat ~/.config/sops/age/keys.txt | openssl base64 -e -A
<base64 encoded key>

Then it's added it to the secrets.yaml file:

# secrets.yaml
# In addition, this file would contain:
# - The git credentials to access private repositories
# - The admin password
# - The external OIDC identification credentials (client secret, ...)
# ...
---
apiVersion: v1
kind: Secret
metadata:
  name: argocd-sops-private-keys
type: Opaque
data:
  keys.txt: <base64 encoded key>

It is encrypted with the following command:

> export SOPS_AGE_RECIPIENTS=$(cat ~/.config/sops/age/keys.txt | age-keygen -y)
> sops -e -i secrets.yaml

The file now contains encrypted entries:

apiVersion: v1
kind: Secret
metadata:
    name: argocd-sops-private-keys
type: Opaque
data:
    age_key.txt: ENC[AES256_GCM,data:xbP4U...,type:str]
sops:
    age:
        - recipient: age1...
          enc: | ...
    kms: []

⚠️ To keep the encrypted entries to a minimum, add a .sops.yaml file to your project with the following:

creation_rules:
  - encrypted_regex: "^(data|stringData)$"
    # You can put your age key here (obtain it with cat ~/.config/sops/age/keys.txt| age-keygen -y)
    # age: age1..

Now that the secret is configured, making it available for the argocd-repo-sever is done with the argocd-repo-server-patch.yaml patch file:

# argocd-repo-server-patch.yaml
# Use custom image
- op: replace
  path: /spec/template/spec/containers/0/image
  value: <your custom image>
# Add sops secrets volume
- op: add
  path: /spec/template/spec/volumes/-
  value:
    name: argocd-sops-private-keys
    secret:
      secretName: argocd-sops-private-keys
      optional: true
      defaultMode: 420
# Mount volume on server
- op: add
  path: /spec/template/spec/containers/0/volumeMounts/-
  value:
    mountPath: /home/argocd/.config/sops/age
    name: argocd-sops-private-keys

Deploy Argo CD with:

> kustomize build --enable-alpha-plugins --enable-exec . | kubectl apply -f

Similar projects