README
¶
Delinea DevOps Secrets Vault Kubernetes Secret Injector
A Kubernetes Mutating Webhook that injects Secret data from Delinea DevOps Secrets Vault (DSV) into Kubernetes Secrets. The webhook can be hosted as a pod or as a stand-alone service.
The webhook works by intercepting CREATE and UPDATE Secret admissions and
mutating the Secret with data from DSV. The webhook configuration consists of
one or more role to Client Credential Tenant mappings. It updates Kubernetes
Secrets based on annotations on the Secret itself.
The webhook uses the Golang SDK to communicate with the DSV API.
It was tested with Minikube and Minishift.
Configure
The webhook requires a JSON formatted list of role to Client Credential and Tenant mappings. The role is a simple name that does not relate to Kubernetes Roles. It simply selects which credentials to use to get the Secret from DSV.
{
"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"
}
}
NOTE: the injector uses the default role when it mutates a Kubernetes Secret that does not have a roleAnnotation. See below
Run
The injector is a Golang executable that runs a built-in HTTPS server hosting the Kubernetes Mutating Webhook Webservice.
$ /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")
Thus the injector can run "anywhere," but, typically, the injector runs as a POD in the Kubernetes cluster that uses it.
Build
NOTE: Building the
dsv-injectorimage is not required to install it as it is available on multiple public registries.
Building the injector requires Docker or Podman. To build it, run:
make image
Minikube and Minishift
Remember to run eval $(minikube docker-env) in the shell to push the image to
Minikube's Docker daemon.💡 Likewise for Minishift except its
eval $(minishift docker-env).
To publish the image to the Minikube (or Minishift) registry, enable it:
minikube addons enable registry
Then start Minikube's tunnel in a separate terminal to make the service available on the host.
minikube tunnel
It will run continuously. Stopping it will render the registry inaccessible.
Publish
NOTE: Publishing is not required unless the cluster cannot download the image from the internet.
To publish, set $(REGISTRY) to the target registry, e.g., registry.example.com/myusername:
make release REGISTRY=registry.example.com/me
The Makefile sets it using kubectl:
kubectl get -n kube-system service registry -o jsonpath="{.spec.clusterIP}{':'}{.spec.ports[0].port}"
Thus make release without setting $(REGISTRY) will assume that the cluster hosts a registry and will push the image there.
Install
Installation requires Helm.
The Makefile demonstrates a typical installation via the
Helm chart. It imports roles.json as a file that it
templates as a Kubernetes Secret for the injector.
The Helm values.yaml file image.repository is thycotic/dsv-injector:
image:
repository: thycotic/dsv-injector
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: ""
That means, by default, make install will pull from Docker, GitHub, or Quay.
make install
However, the Makefile contains an install-image target that configures Helm
to use the image built with make image:
make install-image
make uninstall uninstalls the Helm Chart.
make clean removes the Docker image.
Use
Once the injector is available in the Kubernetes cluster, and the MutatingAdmissionWebhook is in place, any appropriately annotated Kubernetes Secrets are modified on create and update.
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 selects the credentials that the injector uses to retrieve the
DSV Secret. If the role is present, it must map to Client Credential and Tenant
mapping. If the role is absent, the injector will use the default Credential
and Tenant a mapping.
The setAnnotation, addAnnotation and updateAnnotation contain the path to
the DSV Secret that the injector will use to mutate the Kubernetes Secret.
addAnnotationadds missing fields without overwriting or removing existing fields.updateAnnotationadds and overwrites existing fields but does not remove fields.setAnnotationoverwrites fields and removes fields that do not exist in the DSV Secret.
NOTE: A Kubernetes Secret should specify only one of the "add," "update," or
"set" annotations. The order of precedence is setAnnotation, then
addAnnotation, then updateAnnotation when multiple are present.
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
injector will overwrite the existing contents of the Kubernetes Secret; if
/test/secret contains a username and password but no domain, then the
Kubernetes Secret would get the username and password from the DSV Secret
Data but, the injector will remove the domain field.
There are more examples in the examples directory. Each one shows how each
annotation works when run against an example with only a username and
private-key in it but no domain.