KSP - Kubernetes Secret Proxy
KSP does annotation based secret data injection and decryption.
It runs locally and acts as proxy to your kubernetes api server. This means it integrates seamless with kubectl
and tools that build on it.
Table of Contents
Installation
Go
export GO111MODULE=on
go get github.com/clstb/ksp
Binary (Recommended)
Download the latest binary here.
Docker (In Development)
Docker images are available here.
Getting started
GPG
- Start the ksp proxy with enabled gpg injector.
ksp proxy --port 8000 --config $HOME/.kube/config --injector-gpg
- Verify
kubectl
is still working.
kubectl version
- Encrypt a file.
ksp g e --keys {YOUR_KEY_ID} --file ./secret.env
# secret.env
BAR=foo
FOO=bar
- Set annotations.
apiVersion: v1
kind: Secret
metadata:
annotations:
'ksp/inject': gpg
data:
BAR: .....
Either add encrypted data manually to the secret or use other tooling to import it.
For example kustomize
supports it with the .env secret generator.
- Apply it.
kubectl apply -f secret.yaml
Injectors
Injectors modify secrets passed to them based on annotations.
They use following interface:
type Injector interface {
Inject(*corev1.Secret) (*corev1.Secret, error)
}
GPG
The GPG injector decrypts all data fields of the secret using the local gpg cli.
Annotations
Notes
- You can use
ksp gpg encrypt
to encrypt basic JSON files.
- You can encrypt the secret data with multiple public keys. That way it is possible to have a seperate keys for CI/CD or other developers.
Rationale
Following API endpoints need to be handled:
POST
/api/v1/namespaces/{namespace}/secrets
PATCH
/apis/v1/namespaces/{namespace}/secrets/{name}
POST
This endpoint handles secret creation.
The proxy applies following steps:
- Read secret from request body
- Call configured injectors with secret
- Rewrite request body with injected secret
- Forward request to the kubernetes API server
PATCH
This endpoint handles secret modification.
If a secret already exists kubectl
pulls it from the cluster and computes a diff between the local and cluster state.
This diff is incorrect because the local state contains encrypted or no secret data.
The proxy applies following steps to solve this problem:
- Read patch from request body
- Retrieve cluster state of the secret
- Compute local state by patching the cluster state
- Call configured injectors with secret
- Compute fixed patch from injected secret and cluster state
- Rewrite request body with fixed patch
- Forward request to the kubernetes API server