Storing Secrets in Kubernetes

Last updated 26 days ago

Kubernetes has the capability to store secrets and make them available to your services. You can store different secrets and use them through your CX Cloud deployment environment variables. To store a secret in applications namespace (it's the default namespace for CX Cloud apps) run the following command:

$ kubectl create secret generic prod-db-secret \
--from-literal=username=produser \
--from-literal=password=Y4nys7f11 \
--namespace=applications

You have to specify which namespace you want your secret to be created in, because only deployments in that namespace will be able to access the secrets.

Now when you create a deployment, you can reference your secret:

.cxcloud.yaml
deployment:
name: my-backend
image:
name: my-backend-image
repository: YOUR_AWS_ECR_REPOSITORY_URL_HERE
version: 1.1.1
containerPort: 8080
replicas: 2
env:
- name: NODE_ENV
value: production
- name: PROD_DB_USERNAME
valueFrom:
secretKeyRef:
name: prod-db-secret
key: username
- name: PROD_DB_PASSWORD
valueFrom:
secretKeyRef:
name: prod-db-secret
key: password

When the service is deployed, your secrets will become available under the environment variables you have specified. For example in NodeJS, you can access them like so:

console.log(process.env.PROD_DB_USERNAME); // produser
console.log(process.env.PROD_DB_PASSWORD); // Y4nys7f11

For more information about Kubernetes secrets, visit this article.

Example: Storing and using secrets in NodeJS and `node-config` module

One of the core services that you can generate using the CX Cloud CLI is Commerce service. It is communicating with commercetools platform and thus requires some configurations (like API key, etc). We can take advantage of Kubernetes secrets explained above to store these information without having to publish them to GitHub.

First, generate a service using the CLI and choose Commercetools, as explained in its section.

Then, according to node-config's documentation, create a file named custom-environment-variables.json in the config folder of the generated service with the following content:

{
"commerceTools": {
"projectKey": "COMMERCETOOLS_PROJECT_KEY",
"admin": {
"clientId": "COMMERCETOOLS_ADMIN_CLIENT_ID",
"clientSecret": "COMMERCETOOLS_ADMIN_CLIENT_SECRET"
},
"user": {
"clientId": "COMMERCETOOLS_USER_CLIENT_ID",
"clientSecret": "COMMERCETOOLS_USER_CLIENT_SECRET"
}
}
}

This file will tell node-config to look for those environment variables and map them to certain keys. For example the configuration key commerceTools.admin.clientId will map to COMMRCETOOLS_ADMIN_CLIENT_ID and so on.

Now we have to store those data in Kubernetes and make them available to our service using the specified environment variables. To do that, first let's create a secret in applications namespace:

$ kubectl create secret generic prod-commercetools \
--from-literal=projectKey=xxxxxxx \
--from-literal=adminClientId=xxxxxxx \
--from-literal=adminClientSecret=xxxxxxx \
--from-literal=userClientId=xxxxxxx \
--from-literal=userClientSecret=xxxxxxx \
--namespace=applications

Replace the xxxxxxx above with your actual data. A secret will be created.

Now modify your .cxcloud.yaml file and add the proper environment variables referencing the secret you just created (new values are added from line 12):

.cxcloud.yaml
deployment:
name: $APP_NAME
image:
name: $APP_NAME
repository: xxxxxx.dkr.ecr.eu-west-1.amazonaws.com/newsite.example.com
version: $APP_VERSION
containerPort: 4003
replicas: 2
env:
- name: NODE_ENV
value: production
- name: COMMERCETOOLS_PROJECT_KEY
valueFrom:
secretKeyRef:
name: prod-commercetools
key: projectKey
- name: COMMERCETOOLS_ADMIN_CLIENT_ID
valueFrom:
secretKeyRef:
name: prod-commercetools
key: adminClientId
- name: COMMERCETOOLS_ADMIN_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: prod-commercetools
key: adminClientSecret
- name: COMMERCETOOLS_USER_CLIENT_ID
valueFrom:
secretKeyRef:
name: prod-commercetools
key: userClientId
- name: COMMERCETOOLS_USER_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: prod-commercetools
key: userClientSecret

When done, increase the version in your package.json file and run:

$ cxcloud deploy