How to embed JSON string as the value in a Kubernetes Secret - json

Part of our orchestration uses envsubst to update a YAML template file with our desired values.
envsubst < "${SECRET_TEMPLATE}" | kubectl apply -f -
The value for our keyword config is a JSON string:
data=$(jq -c . ${JSON_FILE})
This results in YAML that looks like this (trimmed for brevity):
apiVersion: v1
kind: Secret
metadata:
name: reporting-config
type: Opaque
data:
config: {"database": "foo"}
This apparently worked in some earlier versions of Kube, I wanna say 1.8. Anyways, we are running 1.15 and now kubectl interprets this as a map type and complains:
error: error validating "STDIN": error validating data: ValidationError(Secret.data.config): invalid type for io.k8s.api.core.v1.Secret.data: got "map", expected "string"; if you choose to ignore these errors, turn validation off with --validate=false
Is there a trick to doing this now. I've played around with quoting and various places, escaping quotes, and all that jazz and nada.
* update 1 *
Using stringData still results in the same error:
apiVersion: v1
kind: Secret
metadata:
name: monsoon-storage-reporting-config
type: Opaque
stringData:
config: {"database": "foo"}
error: error validating "STDIN": error validating data: ValidationError(Secret.stringData.config): invalid type for io.k8s.api.core.v1.Secret.stringData: got "map", expected "string"; if you choose to ignore these errors, turn validation off with --validate=false

You may use stringData as below. Note the pipe after stringData:
apiVersion: v1
kind: Secret
metadata:
name: monsoon-storage-reporting-config
type: Opaque
stringData: |
config: {"database": "foo"}

I had to base64 encode the value
$ echo {"database": "foo"} | base64
e2RhdGFiYXNlOiBmb299Cg==
and then use the base64 encoded value in the data: field
apiVersion: v1
kind: Secret
metadata:
name: reporting-config
type: Opaque
data:
config: e2RhdGFiYXNlOiBmb299Cg==
Also note this on base64 encoding:
When using the base64 utility on Darwin/macOS users should avoid using the -b option to split long lines. Conversely Linux users should add the option -w 0 to base64 commands or the pipeline base64 | tr -d '\n' if -w option is not available.

Related

How to create kubernetes secret using json file content and stringData field

I am trying to create a secret using JSON file content and stringData like below but giving some error which I am not able to identify after multiple tries.
apiVersion: v1
kind: Secret
metadata:
name: image-secret
type: Opaque
stringData:
creds: _json_key:{"type": "service_account","project_id": "xyz","private_key_id": "9b0eb25b41ae9161123dbfh56mgj","private_key": "-----BEGIN PRIVATE KEY-----\nmch0iiFz1DAdM8vQTXiETI+3gvSnknXQ0M5WmkA1dkiJgyhe3r8tpeb42jo4FCd\nbHLf9eeIql8TKEm9BAk+qnQZq8FykWEnQLuU7APrFNZ0qtYP8t1Y7HSGpdVmmCyK\nykJAGznKaiEf9SJiNy8HqJy1kOhajn1fL3CdcShWcY793qRLyeFyrIZ\n6lfnjSE9IW5iEOBmxEpXf5Q=\n-----END PRIVATE KEY-----\n","client_email": "argocd-image-updater#xyz.iam.","client_id": "113522222222222222222222222","auth_uri": "https://accounts.google.com,"token_uri": "https://oauth.googleap,"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth/v1/certs","client_x509_cert_url": "https://www.googleapis.com/v1"}
username as _json_key and password is "json file content"
The error which I am getting is as below:-
error: error parsing argocd-image-updater-secret.yaml: error converting YAML to JSON: yaml: line 7: mapping values are not allowed in this context
You're getting bitten by a yaml-ism, as yaml2json or yamllint would inform you
Error: Cannot parse as YAML (mapping values are not allowed here
in "<byte string>", line 5, column 28:
creds: _json_key:{"type": "service_account","project_id" ...
^)
what you'll want is to fold that scalar so the : is clearly character data and not parsed as a yaml key
metadata:
name: image-secret
type: Opaque
stringData:
creds: >-
_json_key:{"type": "service_account","project_id": "xyz","private_key_id": "9b0eb25b41ae9161123dbfh56mgj","private_key": "-----BEGIN PRIVATE KEY-----\nmch0iiFz1DAdM8vQTXiETI+3gvSnknXQ0M5WmkA1dkiJgyhe3r8tpeb42jo4FCd\nbHLf9eeIql8TKEm9BAk+qnQZq8FykWEnQLuU7APrFNZ0qtYP8t1Y7HSGpdVmmCyK\nykJAGznKaiEf9SJiNy8HqJy1kOhajn1fL3CdcShWcY793qRLyeFyrIZ\n6lfnjSE9IW5iEOBmxEpXf5Q=\n-----END PRIVATE KEY-----\n","client_email": "argocd-image-updater#xyz.iam.","client_id": "113522222222222222222222222","auth_uri": "https://accounts.google.com,"token_uri": "https://oauth.googleap,"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth/v1/certs","client_x509_cert_url": "https://www.googleapis.com/v1"}

How to pass param file when applying a new yaml

I am on on openshift 4.6. I want to pass parameters when to a yaml file so i tried the below code but it threw an error
oc apply -f "./ETCD Backup/etcd_backup_cronjob.yaml" --param master-node = oc get nodes -o name | grep "master-0" | cut -d'/' -f2
Error: unknown flag --param
What you most likely want to use is OpenShift Templates. Using Templates you can have variables in your YAML files and then change them using oc process.
So your YAML would look like so:
kind: Template
apiVersion: v1
metadata:
name: my-template
objects:
- apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: pi
spec:
schedule: "*/1 * * * *"
concurrencyPolicy: "Replace"
startingDeadlineSeconds: 200
suspend: true
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
metadata:
labels:
parent: "cronjobpi"
spec:
containers:
- name: pi
image: perl
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(${{DIGITS}})"]
restartPolicy: OnFailure
parameters:
- name: DIGITS
displayName: Number of digits
description: Digits to compute
value: 200
required: true
Then you can use oc process like so:
oc process my-template.yml --param=DIGITS=300 | oc apply -f -

Parse byte array for yaml value - kubebuilder

We are using kubebuilder to build our custom controller, the problem is we are not able to parse raw data as it comes empty when you apply the file.
I’ve created very minimal example which describe the issue.
apiVersion: mygroup.test.com/v1alpha1
kind: Rawtest
metadata:
name: rawtest-sample
spec:
system:
type: test
provider:
type: aws
infrastructureConfig:
kind: InfrastructureConfig
apiVersion: v1alpha1
networks:
vpc:
cidr: aaa
zones:
- name: abc
internal: 123
workers:
- name: myworker
machine:
type: "mt"
image:
name: name1
version: "2"
maximum: 2
minimum: 1
maxUnavailable: 0
volume:
type: a1
size: 20Gi
zones:
- zone1
In runtime I was able to get the the spec.system.type value=test and spec.system.provider.type value="aws", however I wasn’t able to get all the data under the infrastructureConfig: (line 10) any idea how can I overcome this ?
I’ve created this very simple project to demonstrate the issue ,
See the api/type folder, after getting the reconcile object (after apply the config/sample/ file ,you see that the infrastructureconfig and all related data are
https://github.com/JennyMet/
Here is the code which is trying to read the raw value
https://github.com/JennyMet/kuberaw/blob/master/controllers/rawtest_controller.go#L57
&rawtest should contain all the data
please see the type
https://github.com/JennyMet/kuberaw/blob/master/api/v1alpha1/rawtest_types.go#L32
raw type
https://github.com/gardener/gardener/blob/bf32324d9d1a366d8a0a7514956dc39c2f22f7b7/pkg/apis/core/v1beta1/types_shoot.go#L945
https://github.com/gardener/gardener/blob/bf32324d9d1a366d8a0a7514956dc39c2f22f7b7/pkg/apis/core/types_shoot.go#L774
https://github.com/gardener/gardener/blob/bf32324d9d1a366d8a0a7514956dc39c2f22f7b7/vendor/k8s.io/apimachinery/pkg/runtime/types.go#L94:6
I need a way to make it work in the kubebuilder, as while I apply the file I dont get the values in debug ...
debug pic
if something is missing please let me know.
I did the following
visit a site such as https://yaml.to-go.online/ convert the yaml to a go Struct
make a struct
t := AutoGenerated{}
I assume that the yaml data is loaded into memory as []byte
using "gopkg.in/yaml.v2", Unmarshall the yaml to the struct
err := yaml.Unmarshal([]byte(data), &t)
the infrastructureconfig field is available as t.Spec.System.Provider.InfrastructureConfig
see https://play.golang.org/p/syx8v7gAmDH

Helm3 - Reading json file into configmap produces a string?

Problem:
I want to read a json file into a configmap so it looks like:
apiVersion: v1
kind: ConfigMap
metadata:
name: json-test
data:
test.json: |-
{
"key": "val"
}
Instead I get
apiVersion: v1
kind: ConfigMap
metadata:
name: json-test
data:
test.json: |-
"{\r\n \"key\": \"val\"\r\n}"
What I've done:
I have the following helm chart:
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2020-02-06 10:51 AM static
d----- 2020-02-06 10:55 AM templates
-a---- 2020-02-06 10:51 AM 88 Chart.yaml
static/ contains a single file: test.json:
{
"key": "val"
}
templates/ contains a single configmap that reads test.json: test.yml:
apiVersion: v1
kind: ConfigMap
metadata:
name: json-test
data:
test.json: |-
{{ toJson ( .Files.Get "static/test.json" ) | indent 4}}
When I run helm install test . --dry-run --debug I get the following output
NAME: test
LAST DEPLOYED: Thu Feb 6 10:58:18 2020
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
USER-SUPPLIED VALUES:
{}
COMPUTED VALUES:
{}
HOOKS:
MANIFEST:
---
# Source: sandbox/templates/test.yml
apiVersion: v1
kind: ConfigMap
metadata:
name: json-test
data:
test.json: |-
"{\r\n \"key\": \"val\"\r\n}"
The problem here is my json is wrapped in double quotes. My process that wants to read the json is expecting actual json, not a string.
I see that this is not specific behavior only for helm 3. It generally works in kubernetes this way.
I've just tested it on kubernetes v1.13.
First I created a ConfigMap based on this file:
apiVersion: v1
kind: ConfigMap
metadata:
name: json-test
data:
test.json: |-
{
"key": "val"
}
When I run:
$ kubectl get configmaps json-test -o yaml
I get the expected output:
apiVersion: v1
data:
test.json: |-
{
"key": "val"
}
kind: ConfigMap
metadata:
...
but when I created my ConfigMap based on json file with the following content:
{
"key": "val"
}
by running:
$ kubectl create configmap json-configmap --from-file=test-json.json
Then when I run:
kubectl get cm json-configmap --output yaml
I get:
apiVersion: v1
data:
test-json.json: " { \n \"key\": \"val\"\n } \n"
kind: ConfigMap
metadata:
...
So it looks like it's pretty normal for kubernetes to transform the original json format into string when a ConfigMap is created from file.
It doesn't seem to be a bug as kubectl doesn't have any problems with extracting properly formatted json format from such ConfigMap:
kubectl get cm json-configmap -o jsonpath='{.data.test-json\.json}'
gives the correct output:
{
"key": "val"
}
I would say that it is application responsibility to be able to extract json from such string and it can be done probably in many different ways e.g. making direct call to kube-api or using serviceaccount configured to use kubectl in Pod.
I hade the samed problem with the format, also when creating the configmap from a yaml file. The fix for me was to remove all trailing whitspace.

Openshift templates with array parameters

I am trying to create an Openshift template for a Job that passes the job's command line arguments in a template parameter using the following template:
apiVersion: v1
kind: Template
metadata:
name: test-template
objects:
- apiVersion: batch/v2alpha1
kind: Job
metadata:
name: "${JOB_NAME}"
spec:
parallelism: 1
completions: 1
autoSelector: true
template:
metadata:
name: "${JOB_NAME}"
spec:
containers:
- name: "app"
image: "batch-poc/sample-job:latest"
args: "${{JOB_ARGS}}"
parameters:
- name: JOB_NAME
description: "Job Name"
required: true
- name: JOB_ARGS
description: "Job command line parameters"
Because the 'args' need to be an array, I am trying to set the template parameter using JSON syntax, e.g. from the command line:
oc process -o=yaml test-template -v=JOB_NAME=myjob,JOB_ARGS='["A","B"]'
or programmatically through the Spring Cloud Launcher OpenShift Client:
OpenShiftClient client;
Map<String,String> templateParameters = new HashMap<String,String>();
templateParameters.put("JOB_NAME", jobId);
templateParameters.put("JOB_ARGS", "[ \"A\", \"B\", \"C\" ]");
KubernetesList processed = client.templates()
.inNamespace(client.getNamespace())
.withName("test-template")
.process(templateParameters);
In both cases, it seems to fail because Openshift is interpreting the comma after the first array element as a delimiter and not parsing the remainder of the string.
The oc process command sets the parameter value to '["A"' and reports an error: "invalid parameter assignment in "test-template": "\"B\"]"".
The Java version throws an exception:
Error executing: GET at: https://kubernetes.default.svc/oapi/v1/namespaces/batch-poc/templates/test-template. Cause: Can not deserialize instance of java.util.ArrayList out of VALUE_STRING token\n at [Source: N/A; line: -1, column: -1] (through reference chain: io.fabric8.openshift.api.model.Template[\"objects\"]->java.util.ArrayList[0]->io.fabric8.kubernetes.api.model.Job[\"spec\"]->io.fabric8.kubernetes.api.model.JobSpec[\"template\"]->io.fabric8.kubernetes.api.model.PodTemplateSpec[\"spec\"]->io.fabric8.kubernetes.api.model.PodSpec[\"containers\"]->java.util.ArrayList[0]->io.fabric8.kubernetes.api.model.Container[\"args\"])
I believe this is due to a known Openshift issue.
I was wondering if anyone has a workaround or an alternative way of setting the job's parameters?
Interestingly, if I go to the OpenShift web console, click 'Add to Project' and choose test-template, it prompts me to enter a value for the JOB_ARGS parameter. If I enter a literal JSON array there, it works, so I figure there must be a way to do this programmatically.
We worked out how to do it; template snippet:
spec:
securityContext:
supplementalGroups: "${{SUPPLEMENTAL_GROUPS}}"
parameters:
- description: Supplemental linux groups
name: SUPPLEMENTAL_GROUPS
value: "[14051, 14052, 48, 65533, 9050]"
In our case we have 3 files :
- environment configuration,
- template yaml
- sh file which run oc process.
And working case looks like this :
environment file :
#-- CORS ---------------------------------------------------------
cors_origins='["*"]'
cors_acceptable_headers='["*","Authorization"]'
template yaml :
- apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: plugin-common-cors
annotations:
kubernetes.io/ingress.class: ${ingress_class}
config:
origins: "${{origins}}"
headers: "${{acceptable_headers}}"
credentials: true
max_age: 3600
plugin: cors
sh file running oc :
if [ -f templates/kong-plugins-template.yaml ]; then
echo "++ Applying Global Plugin Template ..."
oc process -f templates/kong-plugins-template.yaml \
-p ingress_class="${kong_ingress_class}" \
-p origins=${cors_origins} \
-p acceptable_headers=${cors_acceptable_headers} \
-p request_per_second=${kong_throttling_request_per_second:-100} \
-p request_per_minute=${kong_throttling_request_per_minute:-2000} \
-p rate_limit_by="${kong_throttling_limit_by:-ip}" \
-o yaml \
> yaml.tmp && \
cat yaml.tmp | oc $param_mode -f -
[ $? -ne 0 ] && [ "$param_mode" != "delete" ] && exit 1
rm -f *.tmp
fi
The sh file should read environment file.