Skip to main content
Skip table of contents

Manage Secrets

Overview

Enabling data scientists and machine learning engineers to utilize 3rd-party services that live outside Kubeflow (or even outside the Konvoy cluster on which Kubeflow resides), requires a simple and secure mechanism for distributing usernames, passwords, and other sensitive data. Luckily, Kubeflow administrators can share specific credentials with specific Kubeflow platform tenants in a granular fashion, while tenants can access that sensitive data without exposing it in plain text.

Manage Secrets with Kubeflow

To expose a Kubernetes Secret to Jupyter notebooks launched from Kubeflow, ensure you have Kubeflow administrator privileges, then go to the Kubernetes cluster that houses the Kubeflow tenant’s workspace namespace, create a secret, and deploy a PodDefault object.

Then, when a Kubeflow tenant launches a Jupyter notebook, they can select any secrets (or ConfigMaps, environment variables, etc.) configured via PodDefaults for the Kubeflow namespace in the launcher configuration window. The Kubeflow MutatingWebhookConfiguration (pre-configured with Kubeflow and requiring no further adjustment by Kubeflow administrators) ensures that any notebooks launched in the tenant’s namespace are injected with that data per the PodDefault specification.

Manage Secrets Tutorial

Step 1 - Confirm the Kubeflow tenant namespace name

Each Kubeflow tenant receives their own namespace on the shared Konvoy cluster. Although the Kubeflow UI will suggest that the tenant use a namespace name that matches the login from the OIDC provider attached to Konvoy, there is no requirement that the tenant do so.

As a result, Kubeflow administrators must confirm the name selected by the tenant upon first login.

Furthermore, as PodDefault objects are namespaced, and the tenant’s namespace is only created after logging in for the first time, administrators must wait until the tenant logs in for the first time before continuing with the steps below.

The following output shows a Kubeflow tenant who has logged in and named their namespace “alice”:

CODE
kubectl get namespaces                                                                  

NAME              STATUS   AGE
alice             Active   54m
cert-manager      Active   107m
default           Active   108m
istio-system      Active   104m
knative-serving   Active   104m
kube-node-lease   Active   108m
kube-public       Active   108m
kube-system       Active   108m
kubeaddons        Active   107m
kubeflow          Active   66m

Step 2 - Create a secret in Kubeflow tenant’s namespace

Next, create a Secret in the “alice” namespace.

CODE
kubectl create secret generic -n alice test-secret --from-literal=foo=bar  
secret/test-secret created

Step 3 - CreatePodDefaultin Kubeflow tenant’s namespace

With the command below, create a PodDefault object that injects the test-secret Secret created in step 2 into any new notebook created that requires it.

CODE
cat << EOF | kubectl apply -f -
apiVersion: "kubeflow.org/v1alpha1"
kind: PodDefault
metadata:
  name: test-secret
  namespace: alice
spec:
 selector:
  matchLabels:
    test-secret: "true"
 desc: "test-secret"
 volumeMounts:
 - name: secret-volume
   mountPath: /secret/test-secret
 volumes:
 - name: secret-volume
   secret:
    secretName: test-secret
EOF

CODE
poddefault.kubeflow.org/test-secret created

Step 4 - Launch Jupyter notebook and select test-secret from the Configurations drop-down

After successfully deploying the PodDefault, select the test-secret for injection into the new Jupyter notebook.

notebook-configs

Step 5 - Confirm secret successfully injected into Jupyter notebook pod

To confirm the secret was successfully injected into the new Jupyter notebook pod, first run the below command to confirm the name of the notebook pod launched:

CODE
kubectl get pods -n alice                    
NAME       READY   STATUS            RESTARTS   AGE

tf-gpu-0   0/2     PodInitializing   0          5m47s

Next, retrieve a description of the pod to confirm the secret was mounted to /secret/test-secret:

CODE
kubectl describe pod tf-gpu-0 -n alice


Name:         tf-gpu-0
Namespace:    alice
Priority:     0
Node:         ip-10-0-128-154.us-west-2.compute.internal/10.0.128.154
Start Time:   Wed, 13 May 2020 17:06:30 -0400
Labels:       app=tf-gpu
              controller-revision-hash=tf-gpu-89f5fc69b
              notebook-name=tf-gpu
              security.istio.io/tlsMode=istio
              statefulset=tf-gpu
              statefulset.kubernetes.io/pod-name=tf-gpu-0
              test-secret=true
...
    Mounts:
      /etc/certs/ from istio-certs (ro)
      /etc/istio/proxy from istio-envoy (rw)
      /secret/test-secret from secret-volume (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from default-editor-token-mkxkh (ro)
...

From within a Jupyter notebook cell, the contents of the secret can be retrieved by running:

CODE
! cat /secret/test-secret/foo

Manage Docker Credentials Tutorial

Step 1 - Encode Docker credentials in base64

From the terminal shell, execute the below command:

CODE
docker_credentials=$(echo -n "<Docker username>:<Docker password>" | base64)

Step 2 - Save encoded Docker credentials inconfig.json

Run:

CODE
cat << EOF > config.json -
{
  "auths": {
    "https://index.docker.io/v1/": { 
      "auth": "${docker_credentials}"
     }
  }
}
EOF

Step 3 - Create aSecretin the user’s namespace

Run:

CODE
export NAMESPACE=<Kubeflow user's namespace>
kubectl create secret -n ${NAMESPACE} generic docker-config \
    --from-file=.dockerconfigjson=config.json \
    --type=kubernetes.io/dockerconfigjson

Step 4 - Create aPodDefaultobject to mount theSecret

Run:

CODE
cat << EOF | kubectl apply -f -
apiVersion: "kubeflow.org/v1alpha1"
kind: PodDefault
metadata:
  name: docker-config
  namespace: ${NAMESPACE}
spec:
 selector:
  matchLabels:
    docker-config: "true"
 desc: "Add Docker config"
 volumeMounts:
 - name: docker-config
   mountPath: /home/kubeflow/.docker
 volumes:
  - name: docker-config
    secret:
      secretName: docker-config
      items:
      - key: ".dockerconfigjson"
        path: config.json
EOF

Step 5 - Launch Jupyter notebook and select “Add Docker config” from the Configurations drop-down

After successfully deploying the PodDefault, select the “Add Docker config” option for injection into the new Jupyter notebook.

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.