generatebundlefile/bundle.go (142 lines of code) (raw):
package main
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"path"
"strings"
"time"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/kms"
"github.com/aws/aws-sdk-go-v2/service/kms/types"
"gopkg.in/yaml.v2"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
api "github.com/aws/eks-anywhere-packages/api/v1alpha1"
sig "github.com/aws/eks-anywhere-packages/pkg/signature"
)
const (
// Excludes .spec.packages[].source.registry .spec.packages[].source.repository
Excludes = "LnNwZWMucGFja2FnZXNbXS5zb3VyY2UucmVnaXN0cnkKLnNwZWMucGFja2FnZXNbXS5zb3VyY2UucmVwb3NpdG9yeQo="
)
var (
FullSignatureAnnotation = path.Join(sig.EksaDomain.Name, sig.SignatureAnnotation)
FullExcludesAnnotation = path.Join(sig.EksaDomain.Name, sig.ExcludesAnnotation)
DefaultExcludesAnnotation = map[string]string{
FullExcludesAnnotation: Excludes,
}
)
var generatedMetadataFields = []string{"creationTimestamp", "generation", "managedFields", "uid", "resourceVersion"}
type BundleGenerateOpt func(config *BundleGenerate)
type SDKClients struct {
ecrClient *ecrClient
stsClient *stsClient
}
// NewBundleGenerate is used for generating YAML for generating a new sample CRD file.
func NewBundleGenerate(bundleName string, opts ...BundleGenerateOpt) *api.PackageBundle {
annotations := make(map[string]string)
annotations[FullExcludesAnnotation] = Excludes
return &api.PackageBundle{
TypeMeta: metav1.TypeMeta{
Kind: api.PackageBundleKind,
APIVersion: api.SchemeBuilder.GroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: bundleName,
Namespace: api.PackageNamespace,
Annotations: DefaultExcludesAnnotation,
CreationTimestamp: metav1.Time{Time: time.Time{}},
},
Spec: api.PackageBundleSpec{
Packages: []api.BundlePackage{
{
Name: "sample-package",
Source: api.BundlePackageSource{
Repository: "sample-Repository",
Versions: []api.SourceVersion{
{
Name: "v0.0",
Digest: "sha256:da25f5fdff88c259bb2ce7c0f1e9edddaf102dc4fb9cf5159ad6b902b5194e66",
},
},
},
},
},
},
}
}
// NewPackageFromInput finds the SHA tags for any images in your BundlePackage
func (c *SDKClients) NewPackageFromInput(project Project) (*api.BundlePackage, error) {
var versionList []api.SourceVersion
var err error
// Check bundle Input registry for ECR Private Registry
if strings.Contains(project.Registry, "amazonaws.com") {
versionList, err = c.ecrClient.GetShaForInputs(project)
if err != nil {
return nil, err
}
}
if len(versionList) < 1 {
return nil, fmt.Errorf("unable to find SHA sum for given input tag %v", project.Versions)
}
bundlePkg := &api.BundlePackage{
Name: project.Name,
WorkloadOnly: project.WorkloadOnly,
Source: api.BundlePackageSource{
Repository: project.Repository,
Registry: project.Registry,
Versions: versionList,
},
}
return bundlePkg, nil
}
// AddMetadata adds the corresponding metadata to the crd files.
func AddMetadata(s api.PackageBundleSpec, name string) *api.PackageBundle {
return &api.PackageBundle{
TypeMeta: metav1.TypeMeta{
Kind: api.PackageBundleKind,
APIVersion: api.SchemeBuilder.GroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: api.PackageNamespace,
Annotations: DefaultExcludesAnnotation,
CreationTimestamp: metav1.Time{Time: time.Now()},
},
Spec: s,
}
}
// GetBundleSignature calls KMS and retrieves a signature, then base64 decodes it and returns that back
func GetBundleSignature(ctx context.Context, bundle *api.PackageBundle, key string) (string, error) {
digest, _, err := sig.GetDigest(bundle, sig.EksaDomain)
if err != nil {
return "", err
}
conf, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion(defaultRegion))
if err != nil {
return "", err
}
client := kms.NewFromConfig(conf)
input := &kms.SignInput{
KeyId: &key,
SigningAlgorithm: types.SigningAlgorithmSpecEcdsaSha256,
MessageType: types.MessageTypeDigest,
Message: digest[:],
}
out, err := client.Sign(context.Background(), input)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(out.Signature), nil
}
func serializeBundle(bundle *api.PackageBundle) ([]byte, error) {
out, err := json.Marshal(bundle)
if err != nil {
return nil, err
}
raw := make(map[string]interface{})
err = json.Unmarshal(out, &raw)
if err != nil {
return nil, err
}
delete(raw, "status")
meta := raw["metadata"].(map[string]interface{})
for _, f := range generatedMetadataFields {
delete(meta, f)
}
return yaml.Marshal(raw)
}