Kubernetes based CRD and controller for synchronizing google secret manager data to application runs on kubernetes. This makes Google Secret Manager as the first class citizen of Kubernetes.
Credits: This project is inspired by Hashicorp's vault-k8s project. This project uses some code/components from that repository. However it is used to fetch secret from Google Secret Manager instead of Vault.
This project creates a kubernetes controller and an operator named GoogleSecretEntry
to store these informations:
- Kubernetes
Secret
name and the key used to store base64 encoded string of GCP service account key. - Path to the secret in Google Secret Manager and the name of the file where the secret will be written in the
Pod
's mounted memory.
Besides that controller, this project creates another RESTful service which uses Kubernetes Admission Controller feature to intercept the creation of an Pod and mutate the pod definition to add an init container.
This init container later is used to fetch the credentials from Google Secret Manager and store it to /google/secrets
directory by default. This removes the user needs to put logics to fetch the secret from the code.
$ kubectl create namespace secret-operator-system
$ helm install gsecret-k8s charts/gsecret-k8s --namespace secret-operator-system
- As Google Cloud authenticates the client by using service account and its json key. We need to create a Kubernetes
Secret
to store this information.
Assuming that you are creating a Secret
name mysecret
whose data
with sa-key.json
and base64 encoded values of the service account key.
apiVersion: v1
kind: Secret
metadata:
name: mysecret
namespace: default
type: Opaque
data:
sa-key.json: <BASE64_ENCODED_GCP_SERVICE_ACCOUNT_KEY>
Run:
$ kubectl apply -f mysecret.yaml
-
Create a
GoogleSecretEntry
Custom Resoruce to store the reference to the secret created on previous steps and list of secret path you want to fetch for the application.The example below shows that you will fetch a secret stored in Google Secret Manager with path
projects/imre-demo/secrets/db_creds/versions/latest
and then store the data to a file namedb-creds
in directory named/google/secrets
on the application container.
apiVersion: secret.security.imrenagi.com/v1alpha1
kind: GoogleSecretEntry
metadata:
name: googlesecretentry-sample
namespace: default
spec:
secretRef:
name: mysecret
namespace: default
key: sa-key.json
secrets:
- path: projects/imre-demo/secrets/db_creds/versions/latest
name: db-creds
Run:
$ kubectl apply -f googlesecretentry.yaml
-
Bind this role to Kubernetes
ServiceAccount
you use for your applications. To learn more about RoleBinding, take a look here.This
RoleBinding
is necessary since the init container will have to doGET
call to Kubernetes API to retrieve theSecret
andGoogleSecretEntry
.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: gsecret-agent-role
labels:
app.kubernetes.io/name: static-web
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs:
- "get"
- apiGroups:
- secret.security.imrenagi.com
resources:
- googlesecretentries
verbs:
- get
- list
- watch
- apiGroups:
- secret.security.imrenagi.com
resources:
- googlesecretentries/status
verbs:
- get
- Add the following extra annotations to your pods. For complete example take a look this file:
apiVersion: v1
kind: Pod
metadata:
...
annotations:
google.secret.security.imrenagi.com/agent-inject: "true"
google.secret.security.imrenagi.com/agent-google-secret-crd: "googlesecretentry-sample"
Run:
$ kubectl apply -f pod.yaml
Once the pod is created, you should see the pod starts with an init container.
To see all supported annotations, please refer to this file
The annotations above are used by the agent-injector to decide whether to mutate the Pod
definition with additional an init container. This init container will fetch the secret defined from Google Secret Manager before your application starts.