DMCA.com Protection Status Trending Topics About Devops: 06/04/21

Friday, 4 June 2021

What Are Kubernetes Secrets?

 

A Kubernetes secret is an object storing sensitive pieces of data such as usernames, passwords, tokens, and keys. Secrets are created by the system during an app installation or by users whenever they need to store sensitive information and make it available to a pod.

If passwords, tokens, or keys were simply part of a pod definition or container image, they could be accidentally exposed during Kubernetes operations. Therefore, the most important function of the secret is to prevent accidental exposure of the information stored in it while at the same time making it available wherever the user needs it.


Note: Secrets are not the only way to manage sensitive information in Kubernetes. By using the system’s declarative nature, it is easy to integrate third-party information management solutions.


Kubernetes Secret Types

Kubernetes features two categories of secrets:

  • The system’s service accounts automatically create built-in secrets and associate them with containers together with API credentials.
  • You can also create customized secrets for credentials you need to make available to pods.

Built-in secrets come in several types, corresponding to popular usage scenarios:

Built-in TypeDescription
OpaqueThis is the default type of secret. The secrets whose configuration file does not contain the type statement are all considered to be of this type. Opaque secrets are designed to store arbitrary user data.
kubernetes.io/service-account-tokenService account token secrets store tokens identifying service accounts. Upon creation of a pod, Kubernetes automatically creates this secret and associates it with the pod, enabling secure access to the API. This behavior can be disabled.
kubernetes.io/dockercfgAccessing a Docker registry for images requires valid Docker credentials. This type of secret is used to store a serialized ~/.dockercfg legacy format for Docker command-line configuration. It contains the base64-encoded .dockercfg key.
kubernetes.io/dockerconfigjsonThis type of secret features a .dockerconfigjson key, which is a base64-encoded version of the ~/.docker/config.json file, a new version of the deprecated .dockercfg.
kubernetes.io/basic-authThe secret for storing basic authentication data. It must contain two keys – username and password.
kubernetes.io/ssh-authFor storing data necessary for establishing an SSH connection, use ssh-auth type. This type’s data field must contain an ssh-privatekey key-value pair.
kubernetes.io/tlsThis type is used to store TLS certificates and keys. The most common usage scenario is Ingress resource termination, but the tls type is also sometimes used with other resources.
bootstrap.kubernetes.io/tokenTokens used during the node bootstrap process are stored using the token secret type. This type is usually created in the kube-system namespace.

Note: The basic-authssh-auth, and tls types are provided for the user’s convenience, given that the Opaque type already offers the same functionality. However, using a specific built-in format for each scenario helps organize credentials.


To define a customized type of secret, assign a non-empty string as a value in the type field of the secret file. Leaving the field empty tells Kubernetes to assume the Opaque type. The customized type frees the secret of constraints posed by built-in types.

Using Kubernetes Secrets

When you create a secret, it needs to be referenced by the pod that will use it. To make a secret available for a pod:

1. Mount the secret as a file in a volume available to any number of containers in a pod.

2. Import the secret as an environment variable to a container.

3. Use kubelet, and the imagePullSecrets field.

The following sections explain how to create Kubernetes secrets, as well as how to decode and access them.

Create Kubernetes Secrets

To create a Kubernetes secret, apply one of the following methods:

  • Use kubectl for a command-line based approach.
  • Create a configuration file for the secret.
  • Use a generator, such as Kustomize to generate the secret.

Note: A secret must have a name that is a valid DNS subdomain name.


Create Secrets Using kubectl

1. To start creating a secret with kubectl, first create the files to store the sensitive information:

echo -n '[username]' > [file1]
echo -n '[password]' > [file2]
Using echo -n to append text to a file

The -n option tells echo not to append a new line at the end of the string. The new line is also treated as a character, so it would be encoded together with the rest of the characters, producing a different encoded value.

2. Now, use kubectl to create a secret using the files from the previous step. Use the generic subcommand to create an Opaque secret. Also, add the --from-file option for each of the files you want to include:

kubectl create secret generic [secret-name] \  
--from-file=[file1] \
--from-file=[file2]

The output confirms the creation of the secret:

Creating a secret using kubectl create secret

3. To provide keys for values stored in the secret, use the following syntax:

kubectl create secret generic [secret-name] \  
--from-file=[key1]=[file1] \  
--from-file=[key2]=[file2]

4. Check that the secret has been successfully created by typing:

kubectl get secrets

The command shows the list of available secrets – their names, types, number of data values they contain, and their age:

Using kubectl get secrets to view a list of available secrets

Create Secrets in a Configuration File

1. To create a secret by specifying the necessary information in a configuration file, start by encoding the values you wish to store:

echo -n '[value1]' | base64
echo -n '[value2]' | base64
Piping the output of the echo command to base64 command for encoding

2. Now create a yaml file using a text editor. The file should look like this:

apiVersion: v1
kind: Secret
metadata:  
  name: newsecret
type: Opaque
data:
  username: dXNlcg==
  password: NTRmNDFkMTJlOGZh

3. Save the file and use the kubectl apply command to create the secret:

kubectl apply -f [file]
Using kubectl apply to create a secret from a file

Create Kubernetes Secret with Generators

Generators such as Kustomize help quickly generate secrets.

1. To create a secret with Kustomize, create a file named kustomization.yaml and format it as follows:

secretGenerator:
- name: db-credentials 
  files:
  - username.txt
  - password.txt

The example above states db-credentials as the name of the secret and uses two previously created files, username.txt, and password.txt, as data values.

2. Alternatively, to provide the unencrypted, literal version of the data values, include the literals section with key-value pairs you wish to store:

secretGenerator:
- name: db-credentials
  literals:
  - username=user
  - password=54f41d12e8fa

3. Save the file and use the following command in the folder where kustomization.yaml is located:

kubectl apply -k .

The output confirms the creation of the secret:

Using kubectl apply -k to create a secret using the Kustomize generator

Use kubectl describe to See Created Secrets

The kubectl describe command shows basic information about Kubernetes objects. Use it to view the description of a secret.

kubectl describe secrets/[secret]

The first example shows the secret created by providing files as data values:

Using kubectl describe to view information about secrets

The second example describes the secret created using string literals. Notice the change in the Data section, which now shows names of the keys instead of filenames:

Using kubectl describe to view information about secrets made with string literals

Decode Secrets

1. To decode the values in a secret, access them by typing the following command:

kubectl get secret [secret] -o jsonpath='{.data}'

The output shows the encoded key-value pairs stored in the data section:

Using kubectl get to see keys and values in a json file

2. Use the echo command to type the encoded string and pipe the output to the base64 command:

echo '[encoded-value]' | base64 --decode

The decoded strings appear as the output:

Piping the output of echo to base64 for decoding

Access Secrets Loaded in a Volume

1. To access secrets mounted to a pod in a separate volume, modify the definition of the pod to include a new volume. Choose any volume name you want, but make sure that it is the same as the name of the secret object.

2. Be sure to specify readOnly as true. For example, the pod definition may look like this:

apiVersion: v1
kind: Pod
metadata:
  name: test-pod
  spec:
    containers:
      - name: test-pod
        image: redis
        volumeMounts:
        - name: newsecret
          mountPath: “/etc/newsecret”
          readOnly: true
    volumes:
    - name: newsecret
      secret:
        secretName: newsecret

2. Open another terminal instance and use the kubectl exec command to access the pod’s bash shell:

kubectl exec -it [pod] -- /bin/bash
Bashing into a pod by using kubectl exec


3. cd into /etc/newsecret, and find the files contained in the secret:

cd /etc/newsecret
Finding secret files in the mounted folder

Project Secrets into a Container Using Environment Variables

1. Another way to access secrets in a Kubernetes pod is to import them as environment variables by modifying the pod definition to include references to them. For example:

apiVersion: v1 
kind: Pod 
metadata: 
  name: secret-env-pod 
spec: 
  containers: 
  - name: secret-env-pod
    image: redis 
    env: 
      - name: SECRET_USERNAME 
        valueFrom: 
          secretKeyRef: 
            name: newsecret 
            key: username 
      - name: SECRET_PASSWORD 
        valueFrom: 
          secretKeyRef: 
            name: newsecret 
            key: password 
  restartPolicy: Never

2. Use kubectl exec again to bash into a pod.

3. Test the environment variable using the echo command:

echo $[VARIABLE]

The command output shows the value mapped to the variable:

Exposing the value of an environment variable using echo

Use Secrets to Pull Docker Images from Private Docker Registries

1. To use private Docker registries, first, you need to log in to Docker:

docker login

2. When prompted, provide your login credentials:

Loging into Docker from the command-line

3. If the login is successful, Docker updates the config.json file with your data. Use the cat command to view the file:

cat ~/.docker/config.json
Using the cat command to view data keys and values in a json file

The auths section contains the auth key, which is an encoded version of the Docker credentials.

4. Use kubectl to create a secret, providing the location of the config.json file and the type of the secret:

kubectl create secret generic [secret] \
--from-file=.dockerconfigjson=./.docker/config.json \
--type=kubernetes.io/dockerconfigjson
Creating a Docker registry secret using kubectl create

Alternatively, perform all the steps above, including logging in to Docker, on the same line:

kubectl create secret docker-registry [secret] --docker-server:[address] --docker-username=[username] --docker-password=[password] --docker-email=[email]
Creating a Docker registry secret in one line

5. To create a pod that has access to this secret, create a yaml file that defines it. The file should look like this:

apiVersion: v1
kind: Pod
metadata:
  name: private-reg
spec: 
  containers:
  - name: private-reg-container
    image:   
  imagePullSecrets:  
  - name: regcred

6. Finish creating the pod by activating it with kubectl apply:

kubectl apply -f [file]
Creating a pod with access to the Docker registry secret

Kubernetes Secrets Considerations

Kubernetes secrets are a secure way to store sensitive information. However, before you decide on the best method for your usage scenario, you should consider the following points:

  • Usernames and passwords in Secrets are encoded with base-64. This text-encoding technique obscures data and prevents accidental exposure, but it is not secure against malicious cyber attacks.
  • Secrets are only available in the cluster in which they are located.
  • Secrets usually rely on a master key which is used to unlock them all. While there are methods to secure the master key, using them only creates another master key scenario.

To mitigate these problems, apply some of the solutions below:

  • Integrate a secrets management tool that uses the Kubernetes Service account to authenticate users who need access to the secret vault.
  • Integrate an IAM (Identity and Access Management) tool to allow the system to use tokens from a Secure Token Service.
  • Integrate a third-party secrets manager into pods.

Conclusion

After reading this tutorial, you should know what Kubernetes secrets are, which types exist, and how to create a Kubernetes secret. The tutorial also presented ways in which secrets are accessed.

Use secrets

 


When deploying and orchestrating services, you often need to configure them with sensitive information like passwords, TLS certificates, or private keys.

Kubernetes Engine allows you to store this sensitive information, also known as secrets, in a secure way. It also gives you role-based access control so that you can control which users can use a secret in their services and which ones can manage the secret.

MKE extends the functionality provided by Mirantis Container Runtime, so you can continue using the same workflows and tools you already use, like the Docker CLI client.

In this example, we’re going to deploy a WordPress application that’s composed of two services:

  • wordpress: The service that runs Apache, PHP, and WordPress

  • wordpress-db: a MySQL database used for data persistence

Instead of configuring our services to use a plain text password stored in an environment variable, we’re going to create a secret to store the password. When we deploy those services, we’ll attach the secret to them, which creates a file with the password inside the container running the service. Our services will be able to use that file, but no one else will be able to see the plain text password.

To make things simpler, we’re not going to configure the database service to persist data. When the service stops, the data is lost.

Create a secret

In the MKE web UI, open the Swarm section and click Secrets.

Click Create Secret to create a new secret. Once you create the secret you won’t be able to edit it or see the secret data again.

Assign a unique name to the secret and set its value. You can optionally define a permission label so that other users have permission to use this secret. Also note that a service and secret must have the same permission label, or both must have no permission label at all, in order to be used together.

In this example, the secret is named wordpress-password-v1, to make it easier to track which version of the password our services are using.

Use secrets in your services

Before creating the MySQL and WordPress services, we need to create the network that they’re going to use to communicate with one another.

Navigate to the Networks page, and create the wordpress-network with the default settings.

Now create the MySQL service:

  1. Navigate to the Services page and click Create Service. Name the service “wordpress-db”, and for the Task Template, use the “mysql:5.7” image.

  2. In the left pane, click Network. In the Networks section, click Attach Network, and in the dropdown, select wordpress-network.

  3. In the left pane, click Environment. The Environment page is where you assign secrets, environment variables, and labels to the service.

  4. In the Secrets section, click Use Secret, and in the Secret Name dropdown, select wordpress-password-v1. Click Confirm to associate the secret with the service.

  5. In the Environment Variable section, click Add Environment Variable and enter the string “MYSQL_ROOT_PASSWORD_FILE=/run/secrets/wordpress-password-v1” to create an environment variable that holds the path to the password file in the container.

  6. If you specified a permission label on the secret, you must set the same permission label on this service. If the secret doesn’t have a permission label, then this service also can’t have a permission label.

  7. Click Create to deploy the MySQL service.

This creates a MySQL service that’s attached to the wordpress-network network and that uses the wordpress-password-v1 secret. By default, this creates a file with the same name at /run/secrets/<secret-name> inside the container running the service.

We also set the MYSQL_ROOT_PASSWORD_FILE environment variable to configure MySQL to use the content of the /run/secrets/wordpress-password-v1 file as the root password.

Now that the MySQL service is running, we can deploy a WordPress service that uses MySQL as a storage backend:

  1. Navigate to the Services page and click Create Service. Name the service “wordpress”, and for the Task Template, use the “wordpress:latest” image.

  2. In the left pane, click Network. In the Networks section, click Attach Network, and in the dropdown, select wordpress-network.

  3. In the left pane, click Environment.

  4. In the Secrets section, click Use Secret, and in the Secret Name dropdown, select wordpress-password-v1. Click Confirm to associate the secret with the service.

  5. In the Environment Variable, click Add Environment Variable and enter the string “WORDPRESS_DB_PASSWORD_FILE=/run/secrets/wordpress-password-v1” to create an environment variable that holds the path to the password file in the container.

  6. Add another environment variable and enter the string “WORDPRESS_DB_HOST=wordpress-db:3306”.

  7. If you specified a permission label on the secret, you must set the same permission label on this service. If the secret doesn’t have a permission label, then this service also can’t have a permission label.

  8. Click Create to deploy the WordPress service.

This creates the WordPress service attached to the same network as the MySQL service so that they can communicate, and maps the port 80 of the service to port 8000 of the cluster routing mesh.

Once you deploy this service, you’ll be able to access it using the IP address of any node in your MKE cluster, on port 8000.

Update a secret

If the secret gets compromised, you’ll need to rotate it so that your services start using a new secret. In this case, we need to change the password we’re using and update the MySQL and WordPress services to use the new password.

Since secrets are immutable in the sense that you can’t change the data they store after they are created, we can use the following process to achieve this:

  1. Create a new secret with a different password.

  2. Update all the services that are using the old secret to use the new one instead.

  3. Delete the old secret.

Let’s rotate the secret we’ve created. Navigate to the Secrets page and create a new secret named wordpress-password-v2.

This example is simple, and we know which services we need to update, but in the real world, this might not always be the case.

Click the wordpress-password-v1 secret. In the details pane, click Inspect Resource, and in the dropdown, select Services.

Start by updating the wordpress-db service to stop using the secret wordpress-password-v1 and use the new version instead.

The MYSQL_ROOT_PASSWORD_FILE environment variable is currently set to look for a file at /run/secrets/wordpress-password-v1 which won’t exist after we update the service. So we have two options:

  1. Update the environment variable to have the value /run/secrets/wordpress-password-v2, or

  2. Instead of mounting the secret file in /run/secrets/wordpress-password-v2 (the default), we can customize it to be mounted in/run/secrets/wordpress-password-v1 instead. This way we don’t need to change the environment variable. This is what we’re going to do.

When adding the secret to the services, instead of leaving the Target Name field with the default value, set it with wordpress-password-v1. This will make the file with the content of wordpress-password-v2 be mounted in /run/secrets/wordpress-password-v1.

Delete the wordpress-password-v1 secret, and click Update.

Then do the same thing for the WordPress service. After this is done, the WordPress application is running and using the new password.

inject config file in pods

 apiVersion: v1

kind: Pod

metadata:

  name: nginx

 spec:

      containers:

      - name: nginx

        image: nginx

        env:

         - name: variablefromcm

           valueFrom:

              conFigMapKeyRef:

                      key: variable2

                      name : cm12


kubectl apply -f pod.yml


kubectl exec -it nginx/bin/bash


inside pod

env




how to add multiple varibales :

kubectl explain pod --recursive



vi pod.yml



apiVersion: v1

kind: Pod

metadata:

  name: nginx

 spec:

      containers:

      - name: nginx

        image: nginx

        envFrom:

           valueFrom:

              - conFigMapKeyRef:

                 name:cm12





kubectl apply -f pod.yml