Use Secrets with Oracle Cloud Native Environment

0
0
Send lab feedback

Use Secrets with Oracle Cloud Native Environment

Introduction

Many applications have information, such as passwords, that only authorized users should access. This situation is where Kubernetes Secrets can help. They provide a way to securely manage sensitive data such as passwords, SSH, and API keys. Using secrets allows the separation of confidential data from the application's code, which reduces the risk of sensitive data being exposed or modified during the workflow of your Pods.

Before you start, it helps to know some basic details about Kubernetes Secrets:

  • They must be present before being used by a Pod.
  • Defined using a KEY and VALUE pair.
  • Limited to a maximum size of 1MB to prevent them from using all of the kube-apiserver and kubelet memory.
  • Define them as immutable to protect them from accidental or unwanted modification.

Important: Kubernetes Secrets are not encrypted by default because they are only Base64-encoded and are stored unencrypted in etcd. So anyone with access to etcd can view or alter a Secret. Using Kubernetes Secrets can be made safe by using any of these methods:

  • Enable Encryption at Rest for Secrets.
  • Configure least-privilege access by using RBAC authorization .
  • Restrict access to secrets to specific containers.
  • Using an external secrets management service.

This tutorial covers the basics of Kubernetes Secrets and demonstrates a simple use case.

For more information about Oracle Cloud Native Environment 2, please refer to the current Release Documentation site.

Objectives

In this tutorial, you'll learn to:

  • Create a Secret
  • View a Secret
  • Decode a Secret
  • Use a Secret to define an environment variable in a deployment

Prerequisites

  • Installation of Oracle Cloud Native Environment (Oracle CNE)
  • A single control node and one worker node

Configure Oracle Cloud Native Environment

Note: If running in your own tenancy, read the linux-virt-labs GitHub project README.md and complete the prerequisites before deploying the lab environment.

  1. Open a terminal on the Luna Desktop.

  2. Clone the linux-virt-labs GitHub project.

    git clone https://github.com/oracle-devrel/linux-virt-labs.git
  3. Change into the working directory.

    cd linux-virt-labs/ocne2
  4. Install the required collections.

    ansible-galaxy collection install -r requirements.yml
  5. Deploy the lab environment.

    ansible-playbook create_instance.yml -e localhost_python_interpreter="/usr/bin/python3.6" -e install_ocne_rpm=true -e create_ocne_cluster=true -e "ocne_cluster_node_options='-n 1 -w 1'"

    The free lab environment requires the extra variable local_python_interpreter, which sets ansible_python_interpreter for plays running on localhost. This variable is needed because the environment installs the RPM package for the Oracle Cloud Infrastructure SDK for Python, located under the python3.6 modules.

    The default deployment shape uses the AMD CPU and Oracle Linux 8. To use an Intel CPU or Oracle Linux 9, add -e instance_shape="VM.Standard3.Flex" or -e os_version="9" to the deployment command.

    Important: Wait for the playbook to run successfully and reach the pause task. At this stage of the playbook, the installation of the Oracle CNE is complete, and the instances are ready. Take note of the previous play, which prints the public and private IP addresses of the nodes it deploys and any other deployment information needed while running the lab.

Access the Kubernetes Cluster

  1. Open a terminal and connect via SSH to the ocne instance.

    ssh oracle@<ip_address_of_instance>
  2. Wait for the cluster to stabilize and all pods to report in a running state.

    watch kubectl get pods -A

    Once all the pods show a STATUS of Running, type ctrl-c to exit the watch command.

  3. Confirm how many nodes are present.

    kubectl get nodes

Creating Secrets

There are three ways to create Kubernetes Secrets, which are:

  • Using the kubectl command-line tool to manage secrets directly from the command line.
  • Using the kubectl command-line tool with a resource configuration file.
  • Using the Kustomize object management tool with a kustomization.yaml file.

Using Kubectl Directly from the Command Line

Kubectl creates secrets in one of two ways:

  • Passing them directly via the command line.
  • Storing them as credentials in files.
  1. Create a secret using literal values passed directly from the command line.

    kubectl create secret generic my-literal-secret --from-literal=username=my-user --from-literal=password=my-password

    Note: Use single quotes '' to escape special characters such as $, \, $, &, = and ! included in the string values. Otherwise, the command shell will interpret them.

    Example Output:

    [oracle@ocne ~]$ kubectl create secret generic my-literal-secret --from-literal=username=my-user --from-literal=password=my-password
    secret/my-literal-secret created

Using Kubectl with Stored Credential Files

The file's contents become the VALUE, and the filename becomes the KEY.

  1. Create the credential files.

    echo -n 'admin' > ./username.txt
    echo -n 'S!B\*d$zDsb=' > ./password.txt
  2. Create a Secret using saved files.

    kubectl create secret generic my-file-secret \
     --from-file=username=./username.txt \
     --from-file=password=./password.txt

    Note: The default behavior uses the filename as the KEY value to show how to override the default behavior and declare the KEY name-value directly from the command line using the --from-file=[key]=[path to file] method.

    Extra Information:

    Alternatively, you can create a secret from multiple files stored in a sub-directory.

    1. Create a subdirectory.

      mkdir secrets
    2. Create the credential files.

      echo -n 'user1' > ./secrets/username.txt
      echo -n 'my-super-secret-password' > ./secrets/password.txt
    3. Create a Secret using credential files in a subdirectory.

      kubectl create secret generic my-secret --from-file=./secrets/

      Note: This method uses each filename as the KEY value and the file's contents as the VALUE.

Using Kubectl to Apply a YAML Configuration File

  1. Create the Secrets YAML definition file.

    cat << EOF | tee db-credentials.yaml > /dev/null
    apiVersion: v1
    kind: Secret
    metadata:
      name: db-credentials
      # immutable: true
    type: Opaque
    data:
      username: "bXktdXNlcg=="
      password: "bXktcGFzc3dvcmQ="
    EOF

    Note: The Secret values in the YAML file must be BASE64 encoded.

  2. Apply the Secret.

    kubectl apply -f db-credentials.yaml

Using Kustomize with a kustomization.yaml File

Creating Secrets with Kustomize requires a kustomization.yaml file. That file should define a secretGenerator using one of the following methods:

  • Files storing the secret data value(s) and the filenames become the KEY values.
  • The unencrypted literal version of the data value in a file.
  • Environment variable (.env) files.

All the above do not require the secret values to be Base64 encoded when using Kustomize. The name of the YAML file used by Kustomize must be either kustomization.yaml or kustomization.yml.

This example shows how to use Literals to create a Secret.

  1. Create the secretGenerator file.

    cat << EOF | tee kustomization.yaml > /dev/null
    secretGenerator:
    - name: database-credentials
      literals:
      - username=admin
      - password=password
    EOF
  2. Generate the secret with Kustomize.

    kubectl -n default apply -k .

    Example Output:

    [oracle@ocne ~]$ kubectl -n default apply -k .
    secret/database-credentials-fd8288cb7g created

Managing Kubernetes Secrets

You can store Kubernetes Secrets in different namespaces. So you need to use the -n option to retrieve Secrets from a specific namespace, or use --all-namespaces or -A to retrieve Secrets from all namespaces. The kubectl command uses the default namespace if you don't specify a namespace. The same behavior applies when creating a Kubernetes Secret.

List Existing Kubernetes Secrets

  1. List the newly created Secrets.

    kubectl get secrets

    Example Output:

    NAME                              TYPE     DATA   AGE
    database-credentials-fd8288cb7g   Opaque   2      34s
    db-credentials                    Opaque   2      2m16s
    my-file-secret                    Opaque   2      2m40s
    my-literal-secret                 Opaque   2      2m51s
  2. Get more details about the newly created Secrets.

    kubectl describe secrets

    Example Output:

    [oracle@ocne ~]$ kubectl describe secrets
    Name:         database-credentials-fd8288cb7g
    Namespace:    default
    Labels:       <none>
    Annotations:  <none>
    
    Type:  Opaque
    
    Data
    ====
    password:  8 bytes
    username:  5 bytes
    
    
    Name:         db-credentials
    Namespace:    default
    ...
    ...
    
    Name:         my-literal-secret
    Namespace:    default
    Labels:       <none>
    Annotations:  <none>
    
    Type:  Opaque
    
    Data
    ====
    username:  7 bytes
    password:  11 bytes

    Notice that the kubectl get and kubectl describe commands do not display the contents of a secret to prevent accidental exposure or inclusion in a log file.

  3. View information for one of the Secrets.

    kubectl -n default describe secret db-credentials

    Example Output:

    [oracle@ocne ~]$ kubectl -n default describe secret db-credentials
    Name:         db-credentials
    Namespace:    default
    Labels:       <none>
    Annotations:  <none>
    
    Type:  Opaque
    
    Data
    ====
    password:  11 bytes
    username:  7 bytes

Decode a Kubernetes Secret

  1. View the stored data for one of the Secrets.

    kubectl -n default get secret db-credentials -o jsonpath='{.data}'

    Example Output:

    [oracle@ocne ~]$ kubectl -n default get secret db-credentials -o jsonpath='{.data}'
    {"password":"bXktcGFzc3dvcmQ=","username":"bXktdXNlcg=="}[oracle@ocne ~]$ 

    The output displays the encoded Key:Value pairs for the secret data. The value data is base64-encoded.

  2. Decode the encoded Key:Value data.

    echo <BASE64-VALUE-FOR-PASSWORD> | base64 --decode

    Example Output:

    [oracle@ocne ~]$ echo bXktc3VwZXItc2VjcmV0LXBhc3Nvd3Jk | base64 --decode
    my-password[oracle@ocne ~]$ 

    WARNING: These steps could result in a record of the secret data in your shell history. Avoid this by combining both steps, as shown in the next step.

  3. A more secure method to decode encoded Key:Value data.

    kubectl -n default get secret db-credentials -o jsonpath='{.data.password}' | base64 --decode

    Example Output:

    [oracle@ocne ~]$ kubectl -n default get secret db-credentials -o jsonpath='{.data.password}' | base64 --decode
    my-password[oracle@ocne ~]$ 

Edit a Secret

Like many Kubernetes objects, you can edit a Kubernetes Secret. The only exception is when a secret is declared immutable .

  1. Edit a Secret.

    kubectl edit secrets my-literal-secret

    The default editor opens (vi by default) to allow you to update the Base64 encoded secret values in the data: field.

    Example Output:

    # Please edit the object below. Lines beginning with a '#' will be ignored,
    # and an empty file will abort the edit. If an error occurs while saving this file will be
    # reopened with the relevant failures.
    #
    apiVersion: v1
    data:
      password: bXktcGFzc3dvcmQ=
      username: bXktdXNlcg==
    kind: Secret
    metadata:
      creationTimestamp: "2025-05-09T10:56:14Z"
      name: my-literal-secret
      namespace: default
      resourceVersion: "1689"
      uid: 394dfda3-025a-417d-bbfe-c4851a6b6cff
    type: Opaque
    ~                                                                                                                                       
    ~                                                                                                                                             
    ~                                                                                                                                       
    ~                                                                                                                                             
    "/tmp/kubectl-edit-1267071353.yaml" 16L, 480C
  2. Exit the editor without saving by pressing the Esc key, followed by the :q! keys.

    Example Output:

    [oracle@ocne ~]$ kubectl edit secrets my-literal-secret
    Edit cancelled, no changes made.

Delete a Secret

Yo u can remove a secret using the kubectl -n <NAMESPACE> delete command.

  1. Delete the Secrets.

    kubectl -n default delete secret my-file-secret my-literal-secret

    Example Output:

    [oracle@ocne ~]$ kubectl -n default delete secret my-file-secret  my-literal-secret
    secret "my-file-secret" deleted
    secret "my-literal-secret" deleted

    Note: You can delete multiple secrets by space-delimiting them.

Use Secrets with a Deployment

Next, you will create a deployment using the Kubernetes Secret data you created.

  1. List all Secrets in the default namespace.

    kubectl get secrets -n default

    Example Output:

    [oracle@ocne ~]$ kubectl get secrets -n default
    NAME                              TYPE     DATA   AGE
    database-credentials-fd8288cb7g   Opaque   2      10m
    db-credentials                    Opaque   2      8m
  2. Create a deployment YAML file.

    cat << EOF | tee echo-deployment.yaml > /dev/null
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: echo-deployment
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: echo
      template:
        metadata:
          labels:
            app: echo
        spec:
          containers:
          - name: echo
            image: ghcr.io/oracle/oraclelinux:9
            command: ["/bin/bash", "-c"]
            args: ["echo 'Username: $USER' 'Password: $PASSWORD'; sleep infinity"]
            env:
            - name: USER
              valueFrom:
                secretKeyRef:
                  name: db-credentials
                  key: username
            - name: PASSWORD
              valueFrom:
                secretKeyRef:
                  name: db-credentials
                  key: password
          restartPolicy: Always
    EOF
  3. Create the deployment

    kubectl -n default apply -f echo-deployment.yaml
  4. Confirm it deploys.

    kubectl get deployments

    You may need to re-query a few times while it deploys.

    Example Output:

    [oracle@ocne ~]$ kubectl get deployments 
    NAME              READY   UP-TO-DATE   AVAILABLE   AGE
    echo-deployment   1/1     1            1           4m
  5. Get the name of the deployed Pod.

    kubectl get pods

    Example Output:

    [oracle@ocne ~]$ kubectl get pods
    NAME                               READY   STATUS    RESTARTS   AGE
    echo-deployment-59bff74847-9nnkq   1/1     Running   0          6m

    Note: Your Pod's name will be different.

  6. Verify the deployed Pod used the secret.

    kubectl -n default describe pod <POD-NAME>

    Where:

    • <POD-NAME> - The Pod name in your deployment.

    Example Output:

    [oracle@ocne ~]$ kubectl -n default describe pod echo-deployment-59bff74847-9nnkq
    Name:             echo-deployment-59bff74847-9nnkq
    Namespace:        default
    Priority:         0
    Service Account:  default
    Node:             ocne-worker-1/192.168.122.77
    Start Time:       Mon, 12 May 2025 13:42:25 +0000
    ...
    ...
        Ready:          True
        Restart Count:  0
        Environment:
          USER:      <set to the key 'username' in secret 'db-credentials'>  Optional: false
          PASSWORD:  <set to the key 'password' in secret 'db-credentials'>  Optional: false
        Mounts:
          /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-5fp4d (ro)
    Conditions:
      Type                        Status
      PodReadyToStartContainers   True 
      Initialized                 True
    ...
    ..
    QoS Class:                   BestEffort
    Node-Selectors:              <none>
    Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                                 node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
    Events:                      <none>
    [oracle@ocne ~]$ 

    Note: Check the Environment: section confirms the $USER and $PASSWORD variables are present.

  7. Confirm the environment variables are present in the deployed Pod.

    kubectl exec -it <POD-NAME> -- printenv USER PASSWORD

    Where:

    • <POD-NAME> - The Pod name in your deployment.

    Example Output:

    [oracle@ocne ~]$ kubectl exec -it echo-deployment-59bff74847-9nnkq -- printenv USER PASSWORD
    my-user
    my-password

    The output confirms you have successfully used Kubernetes Secrets as an environment variable in the deployed pod.

Next steps

This tutorial demonstrated how to create and use Kubernetes Secrets to restrict unauthorized access to sensitive information. However, this is only the start. Check out the Oracle Linux Training Station for additional tutorials and content.

SSR