Assume I know the following secret parameters:
"name": "aaa",
"docker-server": "a.b.com",
"docker-username": "aaa",
"docker-password": "aaaa",
"docker-email": "aaa#gmail.com"
Then I want to use client-go to create a pull-image secret
secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "pull-image-secret",
Namespace: "aaaaaa",
},
Type: "kubernetes.io/dockerconfigjson",
Data: map[string][]byte{".dockerconfigjson": []byte(secretData)},
}
err = k8sClient.Create(context.Background(), secret)
My question is, how to convert secret parameters into secretData?
From docs:
the data field of the Secret object must contain a .dockerconfigjson key, in which the content for the ~/.docker/config.json file is provided as a base64 encoded string
So if you want to use Data field you need to modify code to base64 encode secret data, something like that should work:
import b64 "encoding/base64"
...
base64EncodedData := make([]byte, b64.StdEncoding.EncodedLen(len(secretData)))
b64.StdEncoding.Encode(base64EncodedData, []byte(secretData))
secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "pull-image-secret",
Namespace: "aaaaaa",
},
Type: "kubernetes.io/dockerconfigjson",
Data: map[string][]byte{".dockerconfigjson": base64EncodedData},
}
Otherwise, you can try to use StringData field without base64 encoding:
secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "pull-image-secret",
Namespace: "aaaaaa",
},
Type: "kubernetes.io/dockerconfigjson",
StringData: map[string]string{".dockerconfigjson": secretData},
}
Related
I have a terraform code as given below
locals {
file_path = format("%s-%s", var.test1, var.test2)
test_decode = yamldecode((data.github_repository_file.test.content))
}
data "github_repository_file" "test" {
repository = "test-repo"
branch = "develop"
file = "${local.file_path}/local/test.yaml"
}
test_encode = ${yamlencode(local.test_decode.spec.names)}
This is working fine when a ".spec.names" attribute present in the test.yaml file. Since we are selecting the test.yaml based on local.file_path some times attribute .spec.names might not present in the test.yaml and the plan failing with "Error: Unsupported attribute". How to check ".spec.names" attribute present in the test.yaml?
Updating the question to add yaml example
Yaml with names attribute
apiVersion: helm.toolkit.gitops.io/v2beta1
kind: HelmRelease
metadata:
name: "test"
namespace: "test-system"
spec:
chart:
spec:
chart: "test-environment"
version: "0.1.10"
names:
key1: "value1"
key2: "value2"
key3: "value3"
key4: "value4"
YAML without names attribute
apiVersion: helm.toolkit.gitops.io/v2beta1
kind: HelmRelease
metadata:
name: "test"
namespace: "test-system"
spec:
chart:
spec:
chart: "test-environment"
version: "0.1.10"
You can use try:
test_encode = yamlencode(try(local.test_decode.spec.names, "some_default_value"))
I don't know if a more elegant way exists, but you can check if a property exists like this:
contains([for k, v in local.test_decode : k], "spec")
chaining this to check if the spec and the names exists like this did not work for me as the second condition was still evaluated even if the first condition failed:
contains([for k, v in local.test_decode : k], "spec") && contains([for k, v in local.test_decode.spec : k], "names")
this does the trick, but I don't like it, because I consider it to be quite hacky:
contains([for k, v in local.test_decode : k], "spec") ? contains([for k, v in local.test_decode.spec : k], "names") : false
I am using Crossplane and AWS.
when I go for
kubectl apply -f aws-rds.yaml
got error
dbsubnetgroup.database.aws.crossplane.io/prod-subnet-group unchanged
error: error validating "aws-rds.yaml": error validating data: ValidationError(RDSInstance.spec.forProvider.vpcSecurityGroupIDRefs): invalid type for io.crossplane.aws.database.v1beta1.RDSInstance.spec.forProvider.vpcSecurityGroupIDRefs: got "map", expected "array"
Yaml file
apiVersion: database.aws.crossplane.io/v1beta1
kind: RDSInstance
metadata:
name: production-rds
spec:
forProvider:
allocatedStorage: 50
autoMinorVersionUpgrade: true
applyModificationsImmediately: false
backupRetentionPeriod: 0
caCertificateIdentifier: rds-ca-2019
copyTagsToSnapshot: false
dbInstanceClass: db.t2.small
dbSubnetGroupName: prod-subnet-group
vpcSecurityGroupIDRefs:
name: ["rds-access-sg"]
If I change to what #gohm'c suggested
i got error again
error: error validating "aws-rds.yaml": error validating data: ValidationError(RDSInstance.spec.forProvider.vpcSecurityGroupIDRefs[0]): invalid type for io.crossplane.aws.database.v1beta1.RDSInstance.spec.forProvider.vpcSecurityGroupIDRefs: got "string", expected "map"
Security group
kubectl get SecurityGroup
NAME READY SYNCED ID VPC AGE
rds-access-sg True True sg-0p04733a3e2p8pp63 vpc-048b00e0000e7c1b1 19h
From crds crossplane
vpcSecurityGroupIDRefs:
description: VPCSecurityGroupIDRefs are references to VPCSecurityGroups
used to set the VPCSecurityGroupIDs.
items:
description: A Reference to a named object.
properties:
name:
description: Name of the referenced object.
type: string
required:
- name
type: object
type: array
How to change vpcSecurityGroupIDRefs to get the array?
...vpcSecurityGroupIDRefs: got "map", expected "array"
Try:
...
vpcSecurityGroupIDRefs:
- name: rds-access-sg
Does the following configuration for configMap create the test.json file of type empty array or string []
kind: ConfigMap
apiVersion: v1
metadata:
name: myconfigmap
data:
test.json: |-
[]
The convertor to JSON suggests string:
{
"kind": "ConfigMap",
"apiVersion": "v1",
"metadata": {
"name": "myconfigmap"
},
"data": {
"test.json": "[]"
}
}
My goal is to create configMap file with empty array.
Sure, you can make it whatever string you want, it just has to be a string. The thing you can't do is test.json: [] since that's an array. The fact that your string happens to be valid JSON is not something K8s knows or cares about.
I've declared a kubernetes secret in pulumi like:
const tlsSecret = new k8s.core.v1.Secret('tlsSecret', {
metadata: {
name: 'star.builds.qwil.co'
},
data: {
'tls.crt': tlsCert,
'tls.key': tlsKey
}
});
However, I'm finding that when the secret is created only tls.key is present in the secret. When I look at the Diff View from the pulumi deployment on app.pulumi.com I see the following:
tlsSecret (kubernetes:core:Secret)
+ kubernetes:core/v1:Secret (create)
[urn=urn:pulumi:local::ledger::kubernetes:core/v1:Secret::tlsSecret]
apiVersion: "v1"
data : {
tls.key: "[secret]"
}
kind : "Secret"
metadata : {
labels: {
app.kubernetes.io/managed-by: "pulumi"
}
name : "star.builds.qwil.co"
}
Why is only tls.key being picked up even though I've also specified a tls.crt?
Turns out the variable tlsCert was false-y (I was loading it from config with the wrong key for Config.get()). Pulumi was smart and didn't create a secret with an empty string.
I'm using the terraform kubernetes-provider and I'd like to translate something like this kubectl command into TF:
kubectl create secret generic my-secret --from-file mysecret.json
It seems, however the secret resource's data field expects only a TF map.
I've tried something like
data "template_file" "my-secret" {
template = "${file("${path.module}/my-secret.json")}"
}
resource "kubernetes_secret" "sgw-config" {
metadata {
name = "my-secret"
}
type = "Opaque"
data = "{data.template_file.my-secret.template}"
}
But it complains that this is not a map. So, I can do something like this:
data = {
"my-secret.json" = "{data.template_file.my-secret.template}"
}
But this will write the secret with a top-level field named my-secret.json and when I volume mount it, it won't work with other resources.
What is the trick here?
as long the file is UTF-8 encoded you can use something like this
resource "kubernetes_secret" "some-secret" {
metadata {
name = "some-secret"
namespace = kubernetes_namespace.some-ns.metadata.0.name
labels = {
"sensitive" = "true"
"app" = "my-app"
}
}
data = {
"file.txt" = file("${path.cwd}/your/relative/path/to/file.txt")
}
}
If the file is a binary one you will have an error like
Call to function "file" failed: contents of
/your/relative/path/to/file.txt are not valid UTF-8; use the
filebase64 function to obtain the Base64 encoded contents or the other
file functions (e.g. filemd5, filesha256) to obtain file hashing
results instead.
I tried encoding the file in base64 but then the problem is that the resulting text will be re-encoded in base64 by the provider. So I guess there is no solution for binary files at the moment...
I'll edit with what I find next for binaries.
This might be a bit off-topic, but I've been facing similar problem except that the file might not be present in which case the terraform [plan|apply] fails.
To be exact: I needed to duplicate a secret from one namespace to another one.
I realized that by using hashicorp/external provider.
The steps are pretty simple:
Load data by calling external program
Refer to the data in kubernetes_secret resource
The program should accept (and process) JSON on STDIN and produce valid JSON on STDOUT as response to the parameters passed-in in the STDIN's JSON.
Example shell script:
#!/bin/bash
set -e
/bin/echo -n '{ "token": "'
kubectl get -n consul secrets/hashicorp-consul-bootstrap-acl-token --template={{.data.token}}
/bin/echo -n '"}'
tarraform source:
data "external" "token" {
program = ["sh", "${path.module}/consul-token.sh"]
}
resource "kubernetes_secret" "consul-token" {
depends_on = [data.external.token]
metadata {
name = "consul-token"
namespace = "app"
}
data = {
token = base64decode(data.external.token.result.token)
}
}
and requirements:
terraform {
required_providers {
external = {
source = "hashicorp/external"
version = ">= 2.0.0"
}
}
}
Just use
https://www.terraform.io/docs/providers/kubernetes/r/config_map.html#binary_data
resource "kubernetes_config_map" "example" {
metadata {
name = "my-config"
}
binary_data = {
"my_payload.bin" = "${filebase64("${path.module}/my_payload.bin")}"
}
}
I believe you can use binary_data attribute in the secret now.
e.g.
binary_data = {
"my_payload.bin" = "${filebase64("${path.module}/my_payload.bin")}"
}
reference:
https://github.com/hashicorp/terraform-provider-kubernetes/pull/1228
https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret#binary_data
Basically you need to provide a map like this :
resource "kubernetes_secret" "sgw-config" {
metadata {
name = "my-secret"
}
type = "Opaque"
data {
"key1" = "value1"
"key2" = "value2"
}
}
you can refer to your internal variables using
resource "kubernetes_secret" "sgw-config" {
metadata {
name = "my-secret"
}
type = "Opaque"
data {
"USERNAME" = "${var.some_variable}"
"PASSWORD" = "${random_string.root_password.result}"
}
}
It seems if you run the command kubectl create secret generic my-secret --from-file mysecret.json
and then
$ kubectl get secrets my-secret -o yaml
apiVersion: v1
data:
my-secret.json: ewogICA.....
kind: Secret
metadata:
creationTimestamp: "2019-03-25T18:20:43Z"
name: my-secret
namespace: default
resourceVersion: "67026"
selfLink: /api/v1/namespaces/default/secrets/my-secret
uid: b397a29c-4f2a-11e9-9806-000c290425d0
type: Opaque
it stores it similarly with the filename as the single key. When I mount this in a volume/volumeMount it works as expected. I was afraid that it wouldn't but when I create the secret using the --from-file argument, this is exactly how it stores it.