Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kustomize controller unable to decrypt kms encoded yaml file data #1147

Open
Satcomproj opened this issue Apr 26, 2024 · 1 comment
Open

Comments

@Satcomproj
Copy link

i am using S3 as source and before pushing the data to S3 i am encrypting the data with kms key.
i have added a irsa role to decrypt the kms key to the kustomization controller service account. but kustomize controller is failing to decode the data.

getting error:
"error":"failed to decode Kubernetes YAML from /tmp/kustomization-3479328615/resources/prod/org_ns79.yaml: MalformedYAMLError: yaml: control characters are not allowed "}

here is the complete code

package main

import (
"bytes"
"encoding/gob"
"fmt"
"io/fs"
"io/ioutil"
"log"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/kms"
"github.com/aws/aws-sdk-go/service/s3"
"gopkg.in/yaml.v2"

)

type Organization struct {
APIVersion string yaml:"apiVersion"
Kind string yaml:"kind"
Metadata Metadata yaml:"metadata"
Spec Spec yaml:"spec"
Status Status yaml:"status"
}

type Metadata struct {
Annotations map[string]interface{} yaml:"annotations"
CreationTime time.Time yaml:"creationTimestamp"
Generation int yaml:"generation"
Name string yaml:"name"
ResourceVersion string yaml:"resourceVersion"
UID string yaml:"uid"
}

type Spec struct {
ConfigRef ConfigRef yaml:"configRef"
OrganizationType string yaml:"organizationType"
Scopes []Scope yaml:"scopes"
}

type ConfigRef struct {
Name string yaml:"name"
}

type Scope struct {
AccessMode string yaml:"accessMode"
AuthClientRef AuthClientRef yaml:"authClientRef"
IsolationRef IsolationRef yaml:"isolationRef"
}

type AuthClientRef struct {
Name string yaml:"name"
}

type IsolationRef struct {
Name string yaml:"name"
Namespace string yaml:"namespace,omitempty"
}

type Status struct {
Conditions []Condition yaml:"conditions"
}

type Condition struct {
LastTransitionTime time.Time yaml:"lastTransitionTime"
Message string yaml:"message"
ObservedGeneration int yaml:"observedGeneration"
Reason string yaml:"reason"
Status string yaml:"status"
Type string yaml:"type"
}

func main() {

bucket := "gitops-flux-1"
key := "resources/prod/org_ns79.yaml"
var org Organization

fmt.Println("test add org")

dataOrg, err := ioutil.ReadFile("org_1.yaml")
if err != nil {
	fmt.Println("Error reading encrypted YAML file:", err)
}

if err := yaml.Unmarshal(dataOrg, &org); err != nil {
	log.Fatalf("failed to unmarshal YAML: %v", err)
}
fmt.Println(org)

updateOrg(&org)

keyID := "280653b3-28d8-4154-bcea-3391fb0797cb"

data, err := yaml.Marshal(org)
if err != nil {
	log.Fatalf(" failed to create updated spec : %v", err)
	return
}

WriteToAExternalFile("resource_status.yaml", data, 0644)

cypherData, err := encryptDataWithKMS(data, keyID)
if err != nil {
	log.Fatalf(" failed to encrypt data : %v", err)
	return
}

if err = uploadFileToS3(bucket, key, cypherData); err != nil {
	log.Fatalf("failed to upload file %v", err)
}

}

func WriteToAExternalFile(filename string, data []byte, perm fs.FileMode) error {
err := ioutil.WriteFile(filename, data, perm)
if err != nil {
fmt.Println("Error writing YAML file:", err)
return err
}

fmt.Printf(" file  %s created successfully!", filename)
return nil

}

func StructToBytes(org Organization) ([]byte, error) {
var buffer bytes.Buffer
encoder := gob.NewEncoder(&buffer)
err := encoder.Encode(org)
if err != nil {
return nil, err
}
return buffer.Bytes(), nil
}

func BytesToStruct(data []byte) (*Organization, error) {
var org Organization
buffer := bytes.NewBuffer(data)
decoder := gob.NewDecoder(buffer)
err := decoder.Decode(&org)
if err != nil {
return nil, err
}
return &org, nil
}

func encryptDataWithKMS(data []byte, keyID string) ([]byte, error) {
// Create a new session
sess, err := session.NewSession(&aws.Config{
Region: aws.String("us-east-1"),
// Optionally provide credentials, leave this out to use default credentials.
// Credentials: credentials.NewStaticCredentials("YOUR_AWS_ACCESS_KEY_ID", "YOUR_AWS_SECRET_ACCESS_KEY", ""),
})
if err != nil {
fmt.Println("Error creating session:", err)
return nil, err
}
// Create a KMS client
kmsClient := kms.New(sess)

// Encrypt the data using the specified KMS key
params := &kms.EncryptInput{
	KeyId:     aws.String(keyID),
	Plaintext: data, // by default encoded base 64
}

resp, err := kmsClient.Encrypt(params)
if err != nil {
	return nil, err
}

//ciphertextBase64 := base64.StdEncoding.EncodeToString(resp.CiphertextBlob)
// Return the encrypted data (ciphertext)
//return bytes.NewBufferString(ciphertextBase64).Bytes(), nil

return resp.CiphertextBlob, nil

}

func updateOrg(org *Organization) *Organization {

org.Metadata.Name = "98e64260-f154-4d0d-be7d-fa217ea72937"
//fmt.Println(org)
return org

}

func uploadFileToS3(bucketName, fileName string, fileContent []byte) error {
// Create a new AWS session
sess, err := session.NewSession(&aws.Config{
Region: aws.String("us-east-1"),
// Optionally provide credentials, leave this out to use default credentials.
// Credentials: credentials.NewStaticCredentials("YOUR_AWS_ACCESS_KEY_ID", "YOUR_AWS_SECRET_ACCESS_KEY", ""),
})
if err != nil {
fmt.Println("Error creating session:", err)
return err
}

// Create S3 service client
svc := s3.New(sess)

// Upload file to S3 bucket
_, err = svc.PutObject(&s3.PutObjectInput{
	Bucket: aws.String(bucketName),
	Key:    aws.String(fileName),
	Body:   bytes.NewReader(fileContent),
})
if err != nil {
	return err
}
return nil

}

1.is it a valid approach?
2. apart from adding irsa i have not done anything else. here is the kustomization resouce

apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: flux-test-kustomization
namespace: flux-test-1
spec:
interval: 1m
sourceRef:
kind: Bucket
name: my-bucket
namespace: flux-system
path: /resources/prod
prune: true

@stefanprodan
Copy link
Member

You need to use the sops CLI to encrypt the Kubernetes secret, then enabled decryption in the Flux Kustomization. Docs here:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants