ASP.NET Core on K8S Deep Learning Secret & Configmap

Posted by sneskid on Fri, 06 Sep 2019 10:37:16 +0200

Secret

1.1 About Secret

Some sensitive information such as database username and password is needed in the application startup process. If it is not safe to store directly in the container image, K8S provides the scheme of Secret.

Secret stores data in ciphertext, avoiding storing sensitive information directly in configuration files.

Secret is mount ed to Pod in the form of Volume. Containers can use sensitive data in Secret in the form of files or environment variables.

1.2 Create and view Secret

Suppose we want to create a Secret that contains the following information:

(1) User name: Edison

(2) Password: EDC123456*

There are four ways to create Secret:

(1) By - literal:

kubectl create secret generic mysecret --from-literal=username=Edison --from-literal=password=EDC123456*

PS: Each -- from-literal corresponds to an information entry

(2) Through -- from-file:

echo -n Edison > ./username
echo -n EDC123456* > ./password
kubectl create secret generic mysecret --from-file=./username --from-file=./password

PS: Each file content corresponds to an information entry

(3) Through -- from-env-file:

cat << EOF > env.txt
username=Edison
password=EDC123456*
EOF
kubectl create secret generic mysecret --from-env-file=env.txt

PS: Each row of Key=Value in the file env.txt corresponds to an information entry

(4) Create through YAML configuration file: (Recommendation)

Since sensitive data in the configuration file must be encoded by base64, it is necessary to obtain Base64 encoded values:

The following is the content of the YAML file:

apiVersion: v1
kind: Secret
metadata:
  name: edc-secret
data:
  username: RWRpc29u
  password: RURDMTIzNDU2Kg==

Create Secret through kubectl application:

After the creation is successful, verify and check out the Secret:

kubectl get secret edc-secret      // View the existing secret
kubectl describe secret edc-secret  // View Key entries
kubectl edit secret edc-secret     // View the Value of the entry

Value is decoded with base64, as shown below, consistent with expectations:

1.3 Use Secret in Pod

There are two ways to use Secret in Pod in K8S, one is Volume mode, the other is environment variable mode.

(1) Volume approach

Here we show an example of how to use Secret through Volume. First, we define a Pod:

apiVersion: v1
kind: Pod
metadata:
  name: secret-demo
spec:
  containers:
  - name: secret-demo-pod
    image: busybox
    args:
    - /bin/sh
    - -c
    - sleep 10; touch /tmp/healthy; sleep 30000
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:
  - name: foo
    secret:
      secretName: edc-secret

The Pod uses the newly defined secret (edc-secret), and then volumeMounts defines the directory where the path from foo mount to container is / etc/foo, and specifies read-write permission as read-only.

After the creation of kubectl application, we try to read secret in the container to verify it, as shown in the following figure:

As you can see, K8S creates a file for each sensitive data, and its Value is stored in plaintext.

Of course, you can also customize the directory where the data is stored, as shown in the following configuration:

apiVersion: v1
kind: Pod
metadata:
  name: secret-demo
spec:
  containers:
  - name: secret-demo-pod
    image: busybox
    args:
    - /bin/sh
    - -c
    - sleep 10; touch /tmp/healthy; sleep 30000
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:
  - name: foo
    secret:
      secretName: edc-secret
      items:
      - key: username
        path: /edc-group/username
      - key: password
        path: /edc-group/password

At this point, the secret will be stored in / etc/foo/edc-group/username and / etc/foo/edc-group/password directories.

(2) Dynamic update

One of the advantages of using Secret in Volume mode is that it supports dynamic updates. For example, we will update Secret and re-apply it to K8S:

apiVersion: v1
kind: Secret
metadata:
  name: edc-secret
data:
  username: RWRpc29u
  password: YWJjZGVmZyo=    // For abcdefg*

After the kubectl application is re-applied, wait for a period of time and then enter the container again to verify:

It has been changed to abcdefg*, which meets expectations.

(2) Ways of Environmental Variables

Using Secret through Volume seems a bit cumbersome, and the container has to read data through files. K8S provides another way, that is, the environment variable way.

The following example is to modify the configuration file:

apiVersion: v1
kind: Pod
metadata:
  name: secret-demo
spec:
  containers:
  - name: secret-demo-pod
    image: busybox
    args:
    - /bin/sh
    - -c
    - sleep 10; touch /tmp/healthy; sleep 30000
    env:
      - name: EDC_SECRET_USERNAME
        valueFrom:
          secretKeyRef:
            name: edc-secret
            key: username
      - name: EDC_SECRET_PASSWORD
        valueFrom:
          secretKeyRef:
            name: edc-secret
            key: password

After the application of kubectl application, enter the container to verify:

As you can see, you can easily get Value from environment variables.

_ PS: Note that although it is convenient to read Secret through environment variables, it can not support dynamic update of Secret!

Configmap

2.1 On Configmap

The Secret mentioned above can store confidential data for Pod, while Configmap can be used for some non-confidential sensitive data, such as configuration information for some applications.

Configmap was created and used in a very similar way to Secret, except that the data was stored in plaintext (but I don't think Secret's ciphertext is ciphertext, it's simply encoding).

2.2 Create Configmap

Like Secret, it can be created by -- from-literal, -- from-file and -- from-env-file, so let's skip and go straight to our most commonly used yaml configuration file.

apiVersion: v1
kind: ConfigMap
metadata:
  name: service-configmap
data:
  LogLevel: Error
  LogFile: service-timestamp.log
  AllowedHosts: edc.com

2.3 Use Configmap

Like Secret, Configmap can also be used through Volume or environment variables.

(1) Volume approach

apiVersion: v1
kind: Pod
metadata:
  name: configmap-demo
spec:
  containers:
  - name: configmap-demo-pod
    image: busybox
    args:
    - /bin/sh
    - -c
    - sleep 10; touch /tmp/healthy; sleep 30000
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:
  - name: foo
    configMap:
      name: service-configmap

(2) Ways of Environmental Variables

apiVersion: v1
kind: Pod
metadata:
  name: secret-demo
spec:
  containers:
  - name: secret-demo-pod
    image: busybox
    args:
    - /bin/sh
    - -c
    - sleep 10; touch /tmp/healthy; sleep 30000
    env:
      - name: SERVICE_LOG_LEVEL
        valueFrom:
          configMapKeyRef:
            name: service-configmap
            key: LogLevel
      - name: SERVICE_LOG_FILE
        valueFrom:
          configMapKeyRef:
            name: service-configmap
            key: LogFile
      - name: SERVICE_ALLOWED_HOSTS
        valueFrom:
          configMapKeyRef:
            name: service-configmap
            key: AllowedHosts

2.4 Best Practices

In most cases, the best practices recommended are:

(1) Create ConfigMap with YAML configuration=> easy to reuse and version management

(2) Read ConfigMap by Volume=> to facilitate configuration of dynamic updates

Next, we create a Configmap whose YAML content is as follows:

apiVersion: v1
kind: ConfigMap
metadata:
  name: service-configmap
data:
  appsettings.json: |
    LogHandler: NLogHandler
    LogLevel: Error
    LogFile: %hostname-%timestamp.log

Note here that don't forget: the following | symbol, and then create & view Configmap:

If you want to use this Configmap in Pod, you can configure it in YAML as follows:

apiVersion: v1
kind: Pod
metadata:
  name: configmap-demo
spec:
  containers:
  - name: configmap-demo-pod
    image: busybox
    args:
    - /bin/sh
    - -c
    - sleep 10; touch /tmp/healthy; sleep 30000
    volumeMounts:
    - name: configmap
      mountPath: "/etc/configmap"
  volumes:
  - name: configmap
    configMap:
      name: service-configmap
      items:
        - key: appsettings.json
          path: appsettings.json

Here we mount Volume into the container's / etc/configmap directory. Let's verify that:

At this point, we will update configmap as follows:

apiVersion: v1
kind: ConfigMap
metadata:
  name: service-configmap
data:
  appsettings.json: |
    Logging:
      LogLevel:
        Default: "Error"
    AllowedHosts: "*"

Update configmap through kubectl application, and then go to pod to verify whether the update is dynamic:

As you can see, it has been updated dynamically and meets expectations!

2.5 ASP.NET Core appSettings

Our configurations in ASP.NET Core are written in the appSettings.json file. How can we convert appSettings.json to ConfigMap? Saint It has been summarized as follows:< NET Core uses the correct posture of K8S Configmap > Interested readers can refer to this article.

Summary

This article explores how to manage configuration in K8S. Secret can be used if ciphertext configuration is required, and ConfigMap can be used if general application configuration is required. Although Secret and ConfigMap both define several definitions, we generally use YAML configuration creation and Volume mode to read, because Volume mode can support dynamic updates. Finally, by sharing an article of St. Jay, I introduce how to use Configmap under ASP.NET Core. I hope it will be helpful to you!

Topics: Javascript JSON Database encoding