Secrets

A secret is a set of name/value pairs where the value is encrypted. When you create a secret, it will have a name associated with it. The secret is also created in a specific namespace.

You should query the user for secret values so that the values are not embedded in source code.

from getpass import getpass
import pprint

from k9.core import (
    set_default_namespace,
    create_namespace,
    delete_namespace,
    create_secret,
    delete_secret
)

try:
    # Name everything that we will later delete first.
    ns = "tomcat-dev"
    secret_name = "database-secrets"

    # Create a namespace for this test
    set_default_namespace(ns)
    create_namespace()


    print("Database Secrets Setup")
    print("----------------------")

    # Collect three super secret values: url, username and password
    url = getpass("Enter database URL:")

    username = getpass("Enter username [postgres]:")
    if len(username.strip()) < 1:
        username = 'postgres'

    password = getpass("Enter database password:")

    # Create the secret object
    secrets = {
        'url': url,
        'username': username,
        'password': password
    }
    result = create_secret(secret_name, secrets)

    # Show the resulting secret
    pp = pprint.PrettyPrinter(indent=2)
    pp.pprint(result)

finally:
    # Since this is a test, we are removing everything we just created
    delete_secret(secret_name)
    delete_namespace(ns)

Example Output:

{'api_version': 'v1',
 'data': {'password': 'TXlTdXBlclNlY3JldFBhc3N3b3Jk',
          'url': 'aHR0cHM6Ly9sb2NhbGhvc3Q=',
          'username': 'cG9zdGdyZXM='},
 'kind': 'Secret',
 'metadata': {'annotations': None,
              'cluster_name': None,
              'creation_timestamp': datetime.datetime(2019, 10, 23, 20, 10, tzinfo=tzutc()),
              'deletion_grace_period_seconds': None,
              'deletion_timestamp': None,
              'finalizers': None,
              'generate_name': None,
              'generation': None,
              'initializers': None,
              'labels': None,
              'managed_fields': None,
              'name': 'database-secrets',
              'namespace': 'tomcat-dev',
              'owner_references': None,
              'resource_version': '2857937',
              'self_link': '/api/v1/namespaces/tomcat-dev/secrets/database-secrets',
              'uid': '1769123c-f5d1-11e9-aa89-025000000001'},
 'string_data': None,
 'type': 'Opaque'}

Secrets are most often passed to deployments through environment variables. Here is an example of how that is done in a deployment.yml file:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat-dev
spec:
  replicas: 2
  selector:
    matchLabels:
      app: tomcat
      env: dev
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  minReadySeconds: 5
  template:
    metadata:
      labels:
        app: tomcat
        env: dev
    spec:
      containers:
      - name: tomcat
        image: tomcat:8
        ports:
          - containerPort: 8080
        env:
          - name: DS_URL
            valueFrom:
              secretKeyRef:
                name: database-secrets
                key: url
          - name: DS_USR
            valueFrom:
              secretKeyRef:
                name: database-secrets
                key: username
          - name: DS_PWD
            valueFrom:
              secretKeyRef:
                name: database-secrets
                key: password

Take note of the fact that the environment value is taken from a secret, specifying the secret database name and key of each value. These values are then assigned to the specified environment variable.

k9.core.list_secrets(namespace: Optional[str] = None)[source]

Lists secrets in a given namespace.

Parameters

namespace – Namespace you want to search. If None, the default namespace is used.

Returns

A list of dictionaries with name, type, data (for number of entries), and age

k9.core.secret_exists(name: str, namespace: Optional[str] = None)[source]

Determines if a secret exists.

Parameters
  • name – Name of secret

  • namespace – Namespace to search, if None, uses default namespace

Returns

True if specfied secret exists.

k9.core.get_secret(name: str, namespace: Optional[str] = None)[source]

Gets a secret’s metadata and value(s).

Parameters
  • name – Name of secret

  • namespace – Namespace to search, if None, uses default namespace

Returns

None if not found, otherwise V1Secret

k9.core.create_secret(name: str, secrets: dict, namespace: Optional[str] = None)[source]

Creates a secret.

Parameters
  • name – Name of secret

  • secrets – Dictionary containing name value pairs of secrets

  • namespace

Returns

V1Secret

Example:

# Note that you should not embed secrets in your source code, this is
# simply to illustrate how the function call works.
secret_name = "tomcat-dev"
secrets = {
    'ds-url': 'https://some/url',
    'password': 'My1SecretPassword',
    'username': 'postgres'
}

# Test create_secret()
result = create_secret(secret_name, secrets)

Output:

{'api_version': 'v1',
 'data': {'ds-url': 'aHR0cHM6Ly9zb21lL3VybA==',
          'password': 'TXkxU2VjcmV0UGFzc3dvcmQ=',
          'username': 'cG9zdGdyZXM='},
 'kind': 'Secret',
 'metadata': {'annotations': None,
              'cluster_name': None,
              'creation_timestamp': datetime.datetime(2019, 10, 17, 17, 20, 56, tzinfo=tzutc()),
              'deletion_grace_period_seconds': None,
              'deletion_timestamp': None,
              'finalizers': None,
              'generate_name': None,
              'generation': None,
              'initializers': None,
              'labels': None,
              'managed_fields': None,
              'name': 'tomcat-dev',
              'namespace': 'default',
              'owner_references': None,
              'resource_version': '2053051',
              'self_link': '/api/v1/namespaces/default/secrets/tomcat-dev',
              'uid': '7ab378c0-f102-11e9-a715-025000000001'},
 'string_data': None,
 'type': 'Opaque'}
k9.core.delete_secret(name: str, namespace: Optional[str] = None)[source]

Delete specified secret.

Parameters
  • name – Name of secret to delete.

  • namespace – Namespace to delete from. If None, default namespace is used.

Returns

V1Status if secret exists, if not, None.