Skip to content

Thycotic DevOps Secrets Vault Kubernetes Secrets Injector

License

Notifications You must be signed in to change notification settings

emily599/dsv-k8s

Repository files navigation

Thycotic DevOps Secrets Vault Kubernetes Secret Injector

Docker GitHub Package Registry Red Hat Quay

A Kubernetes Mutating Webhook that injects Secret data from Thycotic DevOps Secrets Vault (DSV) into Kubernetes (k8s) cluster Secrets. The webhook is made available to the Kubernetes cluster as the dsv-injector which can be hosted in k8s or as a stand-alone service.

The webhook intercepts CREATE and UPDATE Secret admissions and supplements or overwrites the Secret data with Secret data from DSV. The webhook configuration is a set of DSV Role to Client Credential and Tenant mappings. The webhook updates k8s Secrets based on a set of annotations (see below).

The webhook uses the DSV Go SDK to communicate with DSV.

It was built and tested with Minikube.

Configure

The webhook requires a JSON formatted list of DSV Role to Client Credential and Tenant mappings, stored in configs/roles.json:

{
    "my-role": {
        "credentials": {
            "clientId": "93d866d4-635f-4d4e-9ce3-0ef7f879f319",
            "clientSecret": "xxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxx-xxxxx"
        },
        "tenant": "mytenant"
    },
    "default": {
        "credentials": {
            "clientId": "64241412-3934-4aed-af26-95b1eaba0e6a",
            "clientSecret": "xxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxx-xxxxx"
        },
        "tenant": "mytenant"
    }
}

The default Role is used when the k8s secret being modified does not specify a particular Role.

Run

The thycotic/dsv-injector image contains the dsv-injector-svc executable, but it requires a certificate, the associated key and a roles.json file (see above).

$ /usr/bin/dsv-injector-svc -?
flag provided but not defined: -?
Usage of ./dsv-injector-svc:
  -cert string
        the path of the certificate file in PEM format (default "injector.pem")
  -hostport string
        the host:port e.g. localhost:8080 (default ":18543")
  -key string
        the path of the certificate key file in PEM format (default "injector.key")
  -roles string
        the path of JSON formatted roles file (default "roles.json")

To get a certificate and key, ensure that openssl and Use scripts/get_cert.sh, to get a certificate from your Kubernetes cluster:

$ sh scripts/get_cert.sh
Usage: get_cert.sh -n NAME [OPTIONS]...

        -n, -name, --name NAME
                Maps to the host portion of the FQDN that is the subject of the
                certificate; also the basename of the certificate and key files.
        -d, -directory, --directory=DIRECTORY
                The location of the resulting certificate and private-key. The
                default is '.'
        -N, -namespace, --namespace=NAMESPACE
                Represents the Kubernetes cluster Namespace and maps to the
                domain of the FQDN that is the subject of the certificate.
                the default is 'default'
        -b, -bits, --bits=BITS
                the RSA key size in bits; default is 2048

Build

Building the dsv-injector image requires Docker or Podman.

Building and deploying the test_image requires a Kubernetes cluster.

The Makefile defaults are based on Minikube.

To build the image run:

make image

Test

To configure the Kubernetes cluster to to call the webhook as stand-alone service running on the host at $(SERVICE_IP):

make deploy_host

Note that $(SERVICE_IP) defaults to the IP address of the host executing the build. Also note that localhost will not work as an alternative.

To deploy the dsv-injector service as a POD and configure the webhook to call it, run:

make deploy

Minikube

By default, the build uses Minikube and it must be up to build the test image.

minikube tunnel must also be running so that the build can communicate with the registry unless the build uses an external $(REGISTRY).

Execute eval $(minikube dockerenv) in the build shell to use the Minikube Docker daemon.

The Registry

The test image is based on the release image so the build needs to pull the latter to build the former.

By default, the build will look for a 'registry' service on the cluster and if none is found it will run minikube addons enable registry to start one.

This behavior can be overridden by specifying the registry host:port in $(REGISTRY). Note that the Makefile does not invoke docker login.

The CA Certificate

The WebHook uses the cluster CA certificate. The default location is ${HOME}/.minikube/ca.crt but that can be overridden by setting $(CA_CRT).

The location of the CA certificate can be gotten from the cluster configuration:

kubectl config view -o jsonpath='{.clusters[*].cluster.certificate-authority}'

If that returns null then the certificate is embedded in the cluster configuration. In that case, set $(CA_BUNDLE) to the output of:

kubectl config view -o jsonpath='{.clusters[*].cluster.certificate-authority-data}' | tr -d '"'

Use

Once the dsv-injector is up and available to the Kubernetes cluster, and the MutatingAdmissionWebhook is configured to call it, any appropriately annotated k8s Secrets will be modified by it whenever they are created or updated.

The four annotations that affect the behavior of the webhook are:

const(
    roleAnnotation   = "dsv.thycotic.com/role"
    setAnnotation    = "dsv.thycotic.com/set-secret"
    addNotation      = "dsv.thycotic.com/add-to-secret"
    updateAnnotation = "dsv.thycotic.com/update-secret"
)

roleAnnotation sets the DSV Role that k8s should use to access the DSV Secret that will be used to modify the k8s Secret. If it is present then the Role must exist in the above mentioned Role mappings that the webhook is configured to use. If it is absent then the default mapping is used.

The setAnnotation, addAnnotation and updateAnnotation contain the path to the DSV Secret that will be used to modified the k8s Secret being admitted.

  • addAnnotation adds missing fields without overwriting or removing existing fields.
  • updateAnnotation adds and overwrites existing fields but does not remove fields.
  • setAnnotation overwrites fields and removes fields that do not exist in the DSV Secret.

Only one of these should be specified on any given k8s Secret, however, if more than one are defined then the order of precedence is setAnnotation then addAnnotation then updateAnnotation.

Examples

---
apiVersion: v1
kind: Secret
metadata:
  name: example-secret
  annotations:
    dsv.thycotic.com/role: my-role
    dsv.thycotic.com/set-secret: /test/secret
type: Opaque
data:
  username: dW5tb2RpZmllZC11c2VybmFtZQ==
  domain: dW5tb2RpZmllZC1kb21haW4=
  password: dW5tb2RpZmllZC1wYXNzd29yZA==

The above example specifies a Role so a mapping for that role must exist in the current webhook configuration. It uses the setAnnotation so the data in the secret will be overwritten; if /test/secret contains a username and password but no domain then the secret would contain the username and password from the DSV Secret Data and the domain field will be removed.

There are more examples in the examples directory. Each one will show how each annotation works when run against an example with only a username and password in it.

$ thy secret read /test/secret -f .data
{
  "password": "alongpassword",
  "username": "someuser"
}

About

Thycotic DevOps Secrets Vault Kubernetes Secrets Injector

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published