Keeper Secrets Manager integration into Kubernetes for dynamic secrets retrieval
My Vault> sm client add --app MyAdd --unlock-ip --config-init k8s
Successfully generated Client Device
====================================
Initialized Config:
apiVersion: v1
data:
config: ewog2N...ICIxMCIKfQ==
metadata:
name: ksm-config
namespace: default
type: Opaque
IP Lock: Disabled
Token Expires On: 2021-10-13 12:45:45
App Access Expires on: Never$ kubectl apply -f secret.yaml$ ksm init k8s XX:XXX
apiVersion: v1
data:
config: ewog2N[...]ICIxMCIKfQ==
kind: Secret
metadata:
name: ksm-config
namespace: default
type: Opaque$ ksm init k8s XX:XXX > secret.yaml
$ kubectl apply -f secret.yaml
secret/ksm-config createdapiVersion: v1
kind: Pod
metadata:
name: secret-env-pod
spec:
containers:
- name: mycontainer
image: my_container:XXXXX
env:
- name: KSM_CONFIG
valueFrom:
secretKeyRef:
name: ksm-config
key: config
restartPolicy: Neverfrom flask import Flask
from keeper_secrets_manager_core import SecretsManager
import os
app = Flask(__name__)
@app.route("/")
def hello_world():
sm = SecretsManager()
return """
<h1>Database</h1>
<ul>
<li>Type: {}</li>
<li>Host: {}</li>
<li>Port: {}</li>
<li>Login: {}</li>
<li>Password: {}</li>
</ul>
""".format(
sm.get_notation(os.environ.get("DB_TYPE")),
sm.get_notation(os.environ.get("DB_HOST")),
sm.get_notation(os.environ.get("DB_PORT")),
sm.get_notation(os.environ.get("DB_LOGIN")),
sm.get_notation(os.environ.get("DB_PASS")))FROM python:3.10.0-slim-bullseye
RUN apt-get update \
&& apt-get install -y gcc make libffi-dev curl libssl-dev \
&& apt-get clean
RUN pip3 install --upgrade pip wheel
# cryptology requires Rust to build
RUN curl https://sh.rustup.rs -sSf > /tmp/rust.sh \
&& chmod a+x /tmp/rust.sh \
&& /tmp/rust.sh -y
ENV PATH $PATH:/root/.cargo/bin
RUN pip3 install \
flask \
keeper-secrets-manager-core
RUN groupadd -g 5000 demo
RUN useradd -g demo demo
# Copy our application into the image
COPY demo.py /demo.py
USER demo
ENV FLASK_APP demo
EXPOSE 5000
CMD ["flask", "run"]$ docker build -t ksm_demo .$ ksm init k8s --apply XX:XXXXXXXXXXX
secret/ksm-config created
Created secret for KSM config.$ kubectl get secret ksm-config
NAME TYPE DATA AGE
ksm-config Opaque 1 55s---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ksm-demo-deployment
labels:
app: ksm-demo
spec:
replicas: 1
selector:
matchLabels:
app: ksm-demo
template:
metadata:
labels:
app: ksm-demo
spec:
nodeSelector:
kubernetes.io/hostname: work
dnsPolicy: "None"
dnsConfig:
nameservers:
- 10.0.1.207
- 1.1.1.1
containers:
- name: ksm-demo
image: ksm_demo:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 5000
protocol: TCP
env:
- name: KSM_CONFIG
valueFrom:
secretKeyRef:
name: ksm-config
key: config
- name: DB_TYPE
value: "keeper://IUCvqyWcx7sG-BGIK1R9-g/field/Type"
- name: DB_HOST
value: "keeper://IUCvqyWcx7sG-BGIK1R9-g/field/host[hostName]"
- name: DB_PORT
value: "keeper://IUCvqyWcx7sG-BGIK1R9-g/field/host[port]"
- name: DB_LOGIN
value: "keeper://IUCvqyWcx7sG-BGIK1R9-g/field/login"
- name: DB_PASS
value: "keeper://IUCvqyWcx7sG-BGIK1R9-g/field/password"
---
apiVersion: v1
kind: Service
metadata:
name: ksm-demo-service
spec:
ports:
- name: http
port: 5000
targetPort: 5000
protocol: TCP
selector:
app: ksm-demo
externalIPs:
- 10.0.1.18$ kubectl apply -f ksm_demo.yaml
deployment/ksm-demo-deployment created
service/ksm-demo-service created$ kubectl get deployment ksm-demo-deployment
NAME READY UP-TO-DATE AVAILABLE AGE
ksm-demo-deployment 1/1 1 1 46m
$ kubectl get svc ksm-demo-service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ksm-demo-service ClusterIP 10.107.91.89 10.0.1.18 5000/TCP 56m$ ksm init k8s XX:XXX > secret.yaml
$ kubectl apply -f secret.yaml
secret/ksm-config created---
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-html-config
namespace: default
labels:
app: nginx
data:
index.html: |
<html>
<head>
<title>Nginx Test Page</title>
</head>
<body>
<h1>Hello From Keeper Secrets Manager!</h1>
</body>
</html>---
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
namespace: default
labels:
app: nginx
data:
default.conf: |
server {
listen 80 default;
server_name localhost;
location / {
root /var/www/nginx-default;
index index.html index.htm;
}
}
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /etc/keys/example.com.crt;
ssl_certificate_key /etc/keys/example.com.key;
ssl_password_file /etc/keys/global.pass;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
root /var/www/nginx-default;
index index.html index.htm;
}
}---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
initContainers:
- name: ksm
image: keeper/keeper-secrets-manager-writer:latest
env:
- name: KSM_CONFIG
valueFrom:
secretKeyRef:
name: ksm-config
key: config
- name: SECRETS
value: |
5x0v0VFwYj2VvuhamrJhzQ/field/password > file:/etc/keys/global.pass
5x0v0VFwYj2VvuhamrJhzQ/file/example.com.crt > file:/etc/keys/example.com.crt
5x0v0VFwYj2VvuhamrJhzQ/file/example.com.key > file:/etc/keys/example.com.key
volumeMounts:
- mountPath: "/etc/keys"
name: keys-volume
containers:
- name: nginx
image: nginx:1.21.4-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
protocol: TCP
- containerPort: 443
protocol: TCP
volumeMounts:
- mountPath: "/etc/keys"
name: keys-volume
- mountPath: "/etc/nginx/conf.d/default.conf"
name: nginx-config-file
subPath: default.conf
- mountPath: "/var/www/nginx-default/index.html"
name: nginx-html-file
subPath: index.html
volumes:
- name: keys-volume
emptyDir: {}
- name: nginx-config-file
configMap:
name: nginx-config
- name: nginx-html-file
configMap:
name: nginx-html-config
imagePullSecrets:
- name: my-docker-hub-secrets---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
- name: https
port: 443
targetPort: 443
protocol: TCP
selector:
app: nginx
externalIPs:
- XXX.XXX.XXX.XX



